Stately Agent
用 XState 状态机驱动 LLM 代理:机器掌控控制流,模型只能提出合法事件,非法代理行为从根本上不可能发生。
最小权限:机器只允许合法事件、executors 是普通函数,无内置高危权限,得 2(未演示对模型调用方的鉴权/工具权限约束)。用户确认:examples 提及 human-in-the-loop、审批状态与人工投票,但本样本中仅见于文档链接与 Chameleon 描述,扣分因未见实现代码。数据流透明度:journal/stateHash/事件日志加 MERmaid 架构图与只追加日志声明,机器永不直接访问模型,透明度高,给 3。敏感数据处理:README 未讨论提示词中用户数据/密钥的处理,仅测试刻意保持 OPENAI_API_KEY 为空,给 1。依赖安全:peer 依赖均为可选且版本范围明确,CI frozen-lockfile、权限最小化(permissions: contents: read / 空),给 2;未提供依赖审计或 SBOM。外部效应:模型调用、邮箱发送等副作用均由应用层 executor 承担且在测试中避免计费调用,给 2;未展示发送邮件前的强制确认。回滚:快照迁移(version/migrate)与 journal 折叠可恢复,append 失败时不落日志,给 2;无显式回滚 API。来源归属:LICENSE MIT、author 与 repository 字段清晰,给 2;发布者未经注册表验证。
自一致性:README、package.、示例与测试之间对 runAgent/setupAgent/executors 的 API 描述一致,安装注释与 peers 匹配,给 3。依赖可用性:xstate 处于 alpha(v6 alpha.46+),ai@^7 与 @ai-sdk/openai@^4 匹配说明到位,给 2;核心依赖本身未达稳定,是客观扣分点。失败信息:测试明确断言 400 'does not apply'、500 而非 TypeError、'Invalid JSON' 结构化错误、拒收未解析模型响应,失败信息处理扎实,给 3。
受众与场景:三条起点(新建/改造/复制模式)明确指向不同受众,示例覆盖游戏、邮件、triage 等,给 3。能力边界:声明 '机器拥有控制流,模型只选合法事件' 划清边界,但 alpha 阶段 API 可能变化仅在标题提及,给 2。触发精度:allowedEvents、守卫拒绝并重试、非法事件不改状态并有测试证明,给 3。环境适配:Node 22.18+、ESM/CJS 双构建、Cloudflare workerd 原生测试,环境说明充分;但 Next/TanStack 宿主仅出现在 typecheck 脚本,未见运行验证,给 2。
信息架构:README 层级清晰(三个起点/安装/架构/示例/相关文档链接齐全),给 3。安装说明:含预发布通道、peer 版本匹配陷阱、Node 版本,给 3。命名稳定:导出路径规划完整但包处于 2.0.0-alpha.22,API 明示可能变更,给 2。示例与 FAQ:8 个具名示例 + patterns + LangGraph 对比文档,给 3;无明确 FAQ。已知局限:alpha 状态与 'APIs may change' 有声明,但对存储/并发限制未见讨论,给 2。许可:MIT 全文,package. license 字段一致,给 3。版本与变更日志:使用 changesets 工作流,但样本中未见 CHANGELOG 内容,给 2。维护责任:author、repo URL、受保护发布流程(OIDC trusted publishing)可见,但维护者团队与响应渠道未在样本中说明,给 2。
输出可用性:结构化 zod 输出、类型化事件、result.status/output 明确,给 3。边际价值:以状态机约束 LLM 动作是差异化卖点,guard 拒绝非法决策并重试是 XState 之外难以免费获得的,给 3。成本收益:scripted executors 免 key 测试、usage 计量、避免计费调用的测试设计体现成本意识;但要求 xstate alpha + Node 22.18 对采用者有门槛,给 2。
主张可追溯:README 每个主张都链接到文档/示例,测试断言与文档声明(durability、replay、400/500 行为)对应,给 3。交叉印证:README、package.、CI、Cloudflare 测试三方一致(版本、executors、conformance suite),给 3。事实/推断分离:README 事实与营销语('deterministic, inspectable')混合,后者由架构与测试部分支持但未完全证明,给 2。
- 核心依赖 xstate 处于 alpha 阶段,包本身为 2.0.0-alpha.22,API 可能变动,生产使用需锁定精确版本。
- 敏感数据与提示词内容的处理策略未在文档中说明;将用户数据送入模型前需自行评估合规。
- 未验证发布者身份;依赖 npm 信任发布(OIDC)机制,供应链仍需自行审计。
- 机器守卫只约束事件选择,executor 内的工具/网络访问权限需应用层自行实现最小权限。
- 样本中 human-in-the-loop 仅有文档引用,实际确认流程需自行验证实现。
这个 Agent 能做什么,适合哪些场景?
Stately Agent(仓库 statelyai/agent,MIT 许可)是一个把代理逻辑建模为 XState 状态机的 TypeScript 库。状态机定义代理能做什么,应用层选择模型、运行请求并保存状态;模型只能在被允许的事件中做选择,守卫(guard)会拒绝越权选择并重试决策。核心包不依赖 AI SDK,通过可替换的执行器(executors)与模型交互,官方提供 Vercel AI SDK 执行器和用于测试的脚本化执行器。状态以原生 XState 快照表示,可持久化、迁移、检查和可视化。当前处于 2.0 alpha 阶段,API 在稳定版发布前可能变更。
开发者用 setupAgent 定义模型、Zod 校验的 context/input/output 以及类型化事件,再用 createMachine 编写含守卫和请求的状态机。运行时调用 runAgent 启动机器:机器到达决策状态时通过 invoke 中的 agent.decide 发出模型请求,执行器调用所选模型(如 openai("gpt-5.4-mini")),模型返回的事件先经机器守卫校验,合法则触发转移,非法则重试。createScriptedExecutors 可在不调用任何 API 的情况下端到端跑通机器用于测试;@statelyai/agent/ai-sdk 的 defineModels 提供基于 Vercel AI SDK 的默认执行器,也可自定义执行器。原生 XState 快照可由应用代码持久化并使用 version/migrate 迁移。
- 需要在代码层面硬性限制模型权限的团队,例如退款审批中模型可提议自动退款但金额上限 $100 由机器守卫强制执行
- 想把现有 while 循环代理重构为状态机、保留原有 SDK 调用和重试逻辑的开发者(docs/from-a-loop.md)
- 需要无 API key 的确定性测试的团队,用 createScriptedExecutors 驱动机器
- 希望采用 ReAct、反思、计划执行、RAG、supervisor 等已知代理模式的开发者,文档提供单文件可运行示例
- 需要长期运行、可暂停恢复的代理流程,利用原生 XState 快照做持久化和迁移
- 正在从 LangGraph 迁移的团队,可参考 docs/langgraph-comparison.md
这个 Agent 有哪些优点和局限?
- 守卫在代码层面拒绝模型的非法选择,使越权行为(如超限退款)结构性不可能,而非依赖提示词约束
- 机器不直接调用模型,执行器(AI SDK、脚本化、自定义函数)可整体替换而不改动机器逻辑
- 无需 API key 即可端到端测试,测试、检查和状态机可视化是状态机模型的自然产物
- 原生 XState 快照带来持久化、版本迁移和可移植存储,可嵌入任意框架或运行时
- 2.0 处于 alpha 阶段,API 在稳定版前可能变更,生产采用有迁移风险
- 需要 Node.js 22.18+ 和 XState v6 alpha.46+,且 xstate 本身也需安装 alpha 渠道版本
- AI SDK 依赖有严格的主版本配对要求(ai@^7 与 @ai-sdk/openai@^4),配错会直接安装失败或运行异常
- 将现有代理迁移到状态机需要重写控制流,存在学习与改造成本,README 未提供独立评估指标证明性能优势
如何安装或部署这个 Agent?
需要 Node.js 22.18 或更新版本。安装核心依赖:pnpm add @statelyai/agent@alpha xstate@alpha zod。如需可选的 Vercel AI SDK 执行器:pnpm add ai@^7 @ai-sdk/openai@^4。注意 @ai-sdk/openai 的主版本必须与 ai 匹配(@ai-sdk/openai@^4 配 ai@^7),裸装 @ai-sdk/openai 会解析到 @latest 导致 peer 不匹配。包为 ESM 优先,同时发布 CommonJS 构建以支持 require()。
如何使用这个 Agent?
1) 用 setupAgent 声明 models(经 defineModels 绑定,如 openai("gpt-5.4-mini"))、context/input/output(Zod schema)和 events。2) 用 agentSetup.createMachine 编写状态机,在决策状态通过 invoke: { src: "agent.decide" } 发起模型请求并声明 allowedEvents,用 on 转移加守卫约束事件(如 amount <= 100 才允许 AUTO_REFUND)。3) 调用 runAgent(machine, { input: {...} }),完成后从 result.status === "done" 时读取 result.output。测试时传入 executors: createScriptedExecutors({ decisions: [...] }) 即可离线运行。模型提供方的 API 凭证由所选 AI SDK 提供方包按其标准方式配置。
这个 Agent 与同类方案有什么区别?
README 提供了专门文档 docs/langgraph-comparison.md,面向从 LangGraph 迁移的开发者,说明其定位是与 LangGraph 不同的以状态机为中心的代理构建方式。