ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

Electric Agents 实体设计审查清单(review-checklist)全面解析:从 Handler 形状到 Gotchas 的 30+ 条硬性规则

Electric Agents 实体设计审查清单(review-checklist)全面解析:从 Handler 形状到 Gotchas 的 30+ 条硬性规则 Electric Agents 实体设计审查清单review-checklist全面解析从 Handler 形状到 Gotchas 的 30 条硬性规则【免费下载链接】electricThe agent platform built on sync.项目地址: https://gitcode.com/GitHub_Trending/el/electric本篇技术指南围绕 packages/agents-runtime/skills/designing-entities/references/review-checklist.md 展开完整解读 Electric Agents 项目在实体Entity设计流程第 4 阶段Review所使用的 Universal Review Checklist——这是一套针对registry.define(...)/defineEntity(...)所定义实体的逐条审查契约覆盖 Handler 签名、Agent 配置、状态与 Schema、消息与生命周期、内置 worker 契约、应用装配六大维度。读完本文你将掌握如何对一个 Electric Agents 实体设计做机械化、可复核的审查识别 15 类高频坑gotchas并学会输出标准化的✓ / ✗ / N/A审查报告。审查清单在实体设计流程中的定位designing-entitiesskill见 SKILL.md将实体设计拆分为 5 个严格有序的阶段Elicit询问→ Clarify澄清加载 pattern-triggers.md→ Propose提出模式与设计→ Review审查加载本文档→ Implement实现。review-checklist.md 在 Phase 4 中被加载其作用对象是 Phase 3 产出的设计草案。它的两个核心定位机械性每条规则用✓通过、✗违反、N/A不适用逐条报告并附一行理由契约性规则被视为实体的字面契约出现✗必须修复后才能进入 Phase 5 写文件除非开发者给出明确理由rationale覆盖。审查流程与各模式专属检查项配合使用——references/patterns/name.md为每个协调模式single-agent、manager-worker、pipeline、map-reduce、dispatcher、blackboard、reactive-observers提供额外规则。例如 manager-worker.md 的 MW1–MW7、pipeline.md 的 P1–P7。审查循环持续迭代直到开发者明确批准looks good, write the file。Handler 形状H1–H4可重入契约的第一道防线第一组规则约束实体 handler 的函数签名与执行形状。这是整个审查的起点因为 handler 是 Electric Agents 运行时调度的最小执行单元。#规则为什么H1签名是handler(ctx, wake): Promisevoid \| void显式标记async或显式返回Promisevoid可重入的 handler 契约纯同步 handler 无法await agent.run()或spawnH2以export function registerName(registry: EntityRegistry) { registry.define(...) }导出而非在模块作用域裸写registry.define(...)匹配仓库的工厂模式让应用的 registry 组合能显式接入H3无闭包状态模块级let、被 handler 捕获的可变const对象跨 wake 携带信息。持久化状态只进ctx.db进程重启会清空闭包ctx.db由 durable stream 支撑H4ctx.firstWake只用于无法以声明式表达的一次性初始化如mkdb、默认行插入绝不用于必须跨进程重启存活的逻辑firstWake只在有史以来第一次 wake 为true重启后标志位正确地变为false因此仅靠firstWake保护的一次性初始化不会自愈。安全的幂等初始化还应同时读取状态守卫if (!ctx.db.collections.status?.get(current)) { ... }H2 的工厂模式是仓库统一的接入方式SKILL.md 第 5 阶段的实现模板要求产出恰好一个实体文件并以registerName(registry)工厂导出随后由开发者在entities/registry.ts或server.ts的 registry 组合处接入。H4 是理解 Electric Agents 持久化模型的钥匙。firstWake只保证有史以来第一次为真这是事件溯源语义下的自然结果——进程重启后durable stream 会从已持久化的事件重放恢复ctx.db的状态但不会重新触发firstWake分支。从 context-factory.ts 的上下文构造看firstWake: config.firstWake第 108 行、第 1061 行来自 wake 配置而非本地进程内存。因此重启后初始化失效是设计上的必然审查时必须要求 H4 的状态读取守卫双重防护。Agent 配置A1–A5仅在调用ctx.useAgent(...)时适用当 handler 内调用了ctx.useAgent(...)即实体内部运行 LLM agent以下规则生效#规则为什么A1...ctx.electricTools必须 spread 进tools数组且始终放在第一位运行时协调工具spawn、observe、send 等都在ctx.electricTools中。遗漏会破坏子实体 wake、共享状态和 inbox 路由A2ctx.useAgent(...)必须在ctx.agent.run()之前调用未先useAgent就run()会抛异常A3每个自定义工具的execute返回{ content: [...], details: {...} }details即使为空也必须返回AgentTool接口强制要求遗漏会导致类型错误以及 agent 消费结果时的运行时崩溃A4model必须是真实的 Claude 标识符如claude-sonnet-4-5-20250929。对手改的拼写错误要标记未知的 model ID 会在 provider 调用时才失败A5systemPrompt必须是非空字符串空 system prompt 会产生糟糕的 agent 行为通常是复制粘贴失误A1 是协调类实体的命脉。所有 pattern 文件的 handler 骨架都贯彻这一条例如 manager-worker.md 的tools: [...ctx.electricTools, analyzeTool]、single-agent.md 的tools: [...ctx.electricTools, ...customTools]。值得注意的是ctx.electricTools在独立standalone应用中是可能为空的——这与 AW1 规则关联见下文应用装配。A3 的details字段是运行时消费工具结果的契约审查时必须逐个自定义工具检查execute的返回形状。AgentTool接口的完整定义可参考 SKILL.md 中列出的/docs/reference/agent-tool权威文档。状态与 SchemaS1–S7数据形状的一致性与类型安全这一组规则约束state: { ... }声明、schema 定义与ctx.args的类型使用#规则为什么S1state中每个 collection 要么有显式primaryKey要么有意依赖默认的key行按该字段做键不一致会造成静默的写入丢失S2每个insert/updatepayload 都包含主键字段不带主键的写入会被拒绝S3若 handler 读取ctx.args则必须定义creationSchema否则 args 是未类型化的unknown无效 spawn 会直达 handlerS4若 handler 按wake.type inbox分支且按消息类型区分 payload则必须定义inboxSchemasSchema 会在 Electric Agents UI/CLI 中呈现并校验入站消息。未类型化的 inbox 静默的数据形状漂移S5Schema 使用 Standard Schema优先 Zod v4或其他 Standard-Schema 兼容校验器运行时只理解 Standard-Schema 兼容的校验器S6ctx.args必须按creationSchema声明的类型进行 cast 或 parse不能直接当原始unknown用校验发生在 spawn 时但ctx.args的类型是ReadonlyRecordstring, unknown——cast/parse 让 handler 类型安全S7collection 的type字段事件类型字符串遵循约定实体状态用state:name共享状态用shared:name保持流事件类型可搜索并与既有实体保持一致S3/S6 的组合非常典型creationSchema在 spawn 边界做校验违规 spawn 在入口被拒但这不等于handler 内部拿到了类型安全的数据——ctx.args仍是unknown形态必须在 handler 内再 cast 或 parse。这与 blackboard.md 子 worker 骨架中的const args ctx.args as { sharedState: {...} }模式完全对应。S4 的 inbox schema 是消息路由的前提没有它ctx.send传来的消息无法按类型路由。这与 M1 规则send 必须带type形成闭环。S5 的 Standard Schema 约定在 SKILL.md 的 Phase 5 模板中得到印证import { z } from zod/v4。Zod v4 是首选实现。S7 的shared:name约定在 blackboard.md 的 BB6 规则中再次强调共享集合的type必须是shared:name以在 durable stream 中区分共享状态事件与实体本地状态事件。同文件共享 schema 示例export const debateSchema { arguments: { schema: z.object({...}), type: shared:argument, primaryKey: key } } as const是 S7 的直接落地。消息与生命周期M1–M5wake 语义下的正确编排#规则为什么M1ctx.send(url, payload, { type: ..., afterMs?: number })在接收方声明了inboxSchemas时必须传type可选的afterMs延迟投递缺type时inboxSchemas校验无法路由消息schema 化 handler 收到的是未类型化 payload。afterMs适合定时重试或延迟通知M2ctx.sleep()用于刻意的提前退出如本次 wake 无事可做不能作为异步工作中途的 return 语句sleep()表示结束本次 wake不重新调度在挂起的 await 之前 return 会留下孤儿工作M3handler 最终必须结束return 或调用sleep()不能无限循环handler 有 idle 超时无限循环会被中途杀掉M4需要子实体结果的ctx.spawn(...)必须用wake: { on: runFinished, includeResponse: true }把子实体元数据记入 state从当前 wake 返回再从稍后的子实体完成 wake 继续同一次 wake 内的子实体 await 不是持久化编排。runFinished wake 才是续延continuation机制M5ctx.observe(entity(url), ...)在需要响应被观察实体时必须带wake选项{ on: change, collections: [...] }或{ on: runFinished, includeResponse: true }。observe()接收ObservationSource用electric-ax/agents-runtime的entity()、cron()或entities()不能传裸字符串不带 wake 的观察是永不重新调用 handler 的静默订阅裸字符串不是合法的ObservationSource对象M4 是协调类 pattern 的共同基石在 manager-worker.md MW4、pipeline.md P4、map-reduce.md MR6、dispatcher.md D3 中反复出现。核心心智模型是spawn 子实体 → 立刻 return → 子实体完成后父实体收到 runFinished 续延 wake → 从续延 wake 继续。dispatcher 的 handler 骨架展示了如何消费续延 wakeasync handler(ctx, wake) { const finished wake.payload?.finished_child if (finished) { ctx.db.actions.children_update({ key: finished.url, updater: (draft) { draft.status finished.run_status draft.response finished.response ?? }, }) // ... 继续处理子实体结果 ... return } // ... 否则走 dispatch 工具分支 ... }M2/M3 共同定义了 wake 的生命周期边界。sleep()的语义是本 wake 到此为止如果放在尚未完成的异步工作中间 return那些 await 的 continuation 会丢失handler 整体必须收敛因为运行时对每个 wake 有 idle 超时从 create-handler.ts 可以看到idleTimeout配置默认 20000ms见第 68–69 行。无限循环的 handler 会在中途被运行时终止。M5 中的观察源函数entity()、cron()、entities({ tags: ... })均从electric-ax/agents-runtime导入见 SKILL.md Phase 3 的 ctx 属性说明其中cron()支持定时唤醒、entities({ tags })支持按标签批量观察。reactive-observers 模式对此的详细约束见 reactive-observers.mdRO1–RO6。内置 worker 契约W1–W4最小权限沙箱的硬边界仅在实体ctx.spawn(worker, ...)——即 Electric Agents 服务器的内置 worker 类型——时应用#规则为什么W1每个ctx.spawn(worker, ...)都传{ systemPrompt, tools }且tools是bash \| read \| write \| edit \| web_search \| fetch_url \| spawn_worker的非空子集内置 worker 在解析期抛[worker] tools must be a non-empty array或unknown tool nameW2Spawn args不包含sharedState、sharedStateToolMode或builtinTools。如果需要这些应 spawn 应用注册的自定义 worker 类型而非内置worker内置 worker 是最小权限沙箱会忽略这些参数。需要共享状态工作流时参考 blackboard 模式W3需要运行时原语的工作ctx.electricTools——cron、任意send等在 spawner 中完成不在 worker 中worker 不接收ctx.electricToolsW4worker 的systemPrompt和initialMessage不能包含 API token、OAuth bearer、cookie、签名 URL 或其他密钥。带认证的 fetch 在 manager可信代码中完成原始响应作为数据传给 workerworker 的 prompt 和消息持久化在实体流中——任何能读流的人都能读到密钥。把process.env.*插值进 prompt 等于发布密钥。内置工具如web_search在调用时自行读取自己的 API key 则没问题因为 key 从不进入 promptW1 的 worker 参数契约在 manager-worker.md 中被形式化为interface WorkerArgs { systemPrompt: string tools: ArrayWorkerToolName // 非空子集bash | read | write | edit | web_search | fetch_url | spawn_worker }W2 是最容易被误用的边界。blackboard 模式之所以要求自定义 worker 类型正是因为内置 worker 不接受sharedState。blackboard.md 明确列出两条路① 在应用中注册接受sharedState的自定义 worker 实体类型playground 的 worker 模板见 examples/agents-playground/entities/researcher.ts 同目录体系② 改用ctx.sendctx.observe替代共享状态工具。playground 之所以能直接 spawnworker并传sharedState是因为 SKILL.md 指出的关键区别playground 注册的是自己的worker类型而真实应用 spawnworker拿到的是服务器内置的最小权限 worker。审查时务必区分这两者。W4 的密钥规则是最容易被忽视的安全边界对应的 gotcha 第 14 条见下文。正确做法是manager 侧做认证 fetchtoken 留在可信代码中把原始响应通过initialMessage或复用时的handle.send(...)传给 workerworker 的 prompt 只描述任务本身。应用装配AW1–AW2、S8作用于 server.ts / 入口点以下规则作用于应用的server.ts/ 入口点而非单个实体。Phase 4 中若设计依赖相关能力则标记#规则为什么AW1若任一实体 spread...ctx.electricTools且期望调度工具则给createRuntimeHandler传createElectricTools: (ctx) createScheduleTools(ctx)。从electric-ax/agents导入createScheduleTools不传则ctx.electricTools是[]。Electric Agents dev server 自动接线独立应用必须显式 opt-inAW2应用进程在启动时环境中要有ANTHROPIC_API_KEY以及其他 provider key——通过.env文件、shell export 或进程管理器agent.run()会调用 LLM provider。缺少 API key 会在 agent 循环内抛异常。若 handler 不捕获会崩溃整个 wake甚至进程。启动时检查并告警S8creationSchema字段尽量使用.default()或.optional()Electric Agents UI 以无参方式 spawn 实体——必填字段缺失时服务器以 422 拒绝。使用默认值让实体可从 UI spawnAW1 的createElectricTools在运行时源码中有直接依据create-handler.ts 第 73 行起定义了createElectricTools?: (context: {...}) ...可选工厂并在每个 wake 上下文构造前调用第 72 行注释Optional tool factory invoked for each wake context before handler execution.上下文包含entityUrl、entityType、args、db、events等。而 context-factory.ts 第 116 行、第 1073 行显示上下文对象的electricTools: ArrayAgentTool字段由config.electricTools注入——这正是 AW1 缺省时为空数组[]的机制原因。dev server 自动接线调度工具独立应用如自建 server.ts则必须显式传入createScheduleTools。AW2 是运行前提与 A4真实 model 标识符同属provider 调用期失败类问题model ID 错误和 API key 缺失都不会在编译期暴露而是运行时抛错。Gotchas 目录所有通用检查的来源文档明确指出上述全部通用检查都追溯自以下 15 个已文档化的脚枪foot-guns。当向开发者解释某条✗时应参考此目录Spawn-once 违规。重复 spawn 相同子 ID 会失败。spawn 前必须先查状态const existing ctx.db.collections.children?.get(childId); if (existing?.url) { ctx.observe(entity(existing.url)) } else { ctx.spawn(...) }。遗漏...ctx.electricTools。静默破坏所有协调能力。工具结果缺details。agent 消费结果时运行时级崩溃。产生结果的 spawn 缺wake: { on: runFinished, includeResponse: true }。父实体永远收不到带响应文本的子实体完成续延。过度依赖firstWake做初始化。进程重启后firstWake为false初始化必须同时检查状态。假设写入同步。insert/update/delete是 fire-and-forget 事务必须等待持久化时用tx.isPersisted.promise。写入时触发 schema 校验。非法行在insert时就抛错——形状稳定前保持 schema 宽松。共享状态 schema 不匹配。父子实体必须用完全相同的 schema同一 import而非重新声明的副本。有creationSchema却不解析 args。spawn 时校验了但 handler 在 cast 前看到的仍是未类型化的unknown。observe不带 wake。静默订阅变更时 handler 永不触发。消息缺type。inboxSchemas路由失效。永不结束的 handler。无限循环被运行时杀掉。必填 creationSchema 字段 无参 UI spawn。Electric Agents UI 以无参 spawn 实体必填字段缺失时服务器以 422 拒绝。用.default()/.optional()让实体可从 UI spawn。worker prompt 中的密钥。把process.env.*插值进 worker 的systemPrompt或initialMessage会把密钥泄漏进实体持久化流。认证 fetch 在 manager 中做原始响应作为数据传给 worker让内置工具自己从 env 读取 key。独立应用中ctx.electricTools为空。给createRuntimeHandler传createElectricTools: (ctx) createScheduleTools(ctx)从electric-ax/agents导入createScheduleTools。这 15 条与前述 33 条规则H1–H4、A1–A5、S1–S8、M1–M5、W1–W4、AW1–AW2一一对应。例如 gotcha 5 ↔ H4gotcha 2 ↔ A1gotcha 3 ↔ A3gotcha 10 ↔ M5gotcha 11 ↔ M1gotcha 13 ↔ S8gotcha 14 ↔ W4gotcha 15 ↔ AW1。审查遇到✗时先定位其对应的 gotcha再向开发者解释根因会比就规则谈规则更有说服力。审查输出格式Phase 4可机器消费的标准报告文档定义了审查报告的规范输出模板设计审查必须按此格式输出Universal checks: ✓ H1 Handler signature correct ✓ H2 registerXxx factory exported ✓ A1 ...ctx.electricTools spread first ✗ M4 runFinished continuation wake missing on result-producing spawn N/A S3 creationSchema — no spawn args expected Pattern-specific (name): see patterns/name.md Proposed fixes: - M4: add wake: { on: runFinished, includeResponse: true } to ctx.spawn() options and return; continue from the later wake Apply these fixes? Anything to override?要点Universal checks逐条列出 H/A/S/M/W/AW 规则的状态每条一行理由模板中以行内说明体现正式报告建议规则号 结论 一句话理由Pattern-specific注明name即加载的references/patterns/name.md中的模式专属规则如 manager-worker 的 MW1–MW7Proposed fixes为每条✗给出具体修改建议迭代循环每次修订后必须重跑完整清单直到开发者明确批准。SKILL.md Phase 4 给出了该格式在实际对话中的变体加入了Pattern-specific示例行如✗ State machine transitions not defined、✓ Parallel spawn loop uses deterministic IDs并规定开发者提出修改 → 修订设计 → 重跑两个清单 → 再次报告循环直至批准。此阶段不写任何文件Invariants 中明确 No files written before phase 5。把通用清单与模式专属清单组合使用review-checklist 是通用层每个 pattern 文件各带一张模式层清单。两者在 Phase 4 中同时应用。以下是各模式清单与通用清单的典型协同点模式模式专属规则示例与通用清单的交叉single-agent.mdSA1 无 spawn/observe/sendSA2 无 mkdbSA3 handler 收敛为 init useAgent runSA3 与 M3handler 必须结束呼应manager-worker.mdMW2 spawn 处有children.get(id)守卫MW3 子 ID 稳定MW4 runFinished wakeMW5Promise.all收集MW2/MW3 ↔ gotcha 1MW7 ↔ W1MW6PERSPECTIVES 声明一次↔ H3无闭包状态pipeline.mdP2 显式状态机idle → stage_1 → ... → stage_N → doneP3 阶段 ID 含阶段号P6 上一阶段输出作下一阶段initialMessageP3 ↔ MW3 同源的确定性 ID 原则P4 ↔ M4map-reduce.mdMR3 spawn counter 入 IDchunk-${i}-${Date.now()}-${counter}MR4 记录子元数据后 returnreduce 只在 runFinished wake 后执行MR3 ↔ gotcha 1Date.now()单独用会碰撞MR5 ↔ MW5 的Promise.all纪律dispatcher.mdD1 dispatch counterD2 四态状态机idle → classifying → dispatching → waitingD5 type 白名单校验或捕获 spawn 错误D5 ↔ A4 的运行时才失败类问题D6 ↔ W1blackboard.mdBB1 共享 schema 单模块导入BB2mkdb只在firstWakeBB3observe(db(...))每个 wake 都调BB6shared:name类型约定BB2 ↔ H4firstWake 纪律BB6 ↔ S7BB7 ↔ W2reactive-observers.mdRO1 每个 observe 带 wakeRO2 handler 无 spawnRO3 用collections过滤RO4 用debounceMsRO1 ↔ M5RO2 ↔ gotcha 12/混合模式警示两条最容易在组合审查中漏掉但后果严重的交叉manager-worker / map-reduce / pipeline 的 spawn-once 守卫MW2/MR3/P3配合确定性 ID——它直接决定实体在进程重启、wake 重放后是否会 spawn 出重复子实体blackboard 的 BB1 单一 schema 来源——父子各声明一份长得一样的 Zod object 也会因引用不同而静默产生写失败对应 gotcha 8。源码级佐证规则的运行时依据本文所有规则均有仓库实现支撑以下是可直接继续深入的关键路径create-handler.tsidleTimeout默认 20000ms、heartbeatInterval默认 10000ms、createElectricTools可选工厂——对应 M3、AW1 的运行时机制context-factory.tswake 上下文中的firstWake: boolean与electricTools: ArrayAgentTool字段注入——对应 H4、AW1 的空数组机制SKILL.md5 阶段工作流、Phase 4 循环规则、实体文件模板、electric-ax/agents-runtime权威文档索引与 playground 规范示例清单pattern-triggers.mdPhase 2 的触发短语表与消歧流程确定采用哪个 pattern 后再加载对应清单examples/agents-playgroundentities/researcher.ts、lib/electric-tools.ts与 examples/agents-playground/server.tsplayground 注册自有 worker 类型的实例用于对照内置 worker 契约差异。需要特别说明的适用前提本清单适用于electric-ax/agents-runtime应用中任何registry.define(...)/defineEntity(...)定义的实体内置 worker 契约W1–W4仅对服务器内置的worker类型成立——playground 自注册的 worker接受sharedState/builtinTools不适用 W2这正是 SKILL.md Canonical material 中特别提示的adjust pattern examples accordingly之处。审查时先确认目标 worker 类型是内置还是应用自定义再决定 W 组规则的取舍。【免费下载链接】electricThe agent platform built on sync.项目地址: https://gitcode.com/GitHub_Trending/el/electric创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表