给 Agent 加人审暂停点时,我会先把状态快照和恢复口令写清楚
最近给一个桌面端自动化助手加半自动执行能力时,我没有急着让 Agent 直接调用写文件、发通知和改配置的工具。模型生成计划这一步已经足够快,真正容易出问题的是人审之后怎么继续执行。用户点了同意,后台进程可能已重启,原工具参数也可能被后续对话改写。

原创示意图:高风险工具调用先进入审批闸门,保存状态快照,审批通过后再沿同一上下文恢复执行。 来源:Codex image generation
问题背景
这个助手会读取用户需求,拆成几步,再调用本地工具完成批量修改。后来我们希望让它能在用户确认后继续跑,比如创建配置文件、发送日志摘要、把 RAG 导入任务排进队列。风险随之变高,因为这些动作会改变外部状态。
LangGraph 的 interrupt 文档给了我一个明确参考:图执行可以在指定位置暂停,保存状态,等待外部输入后再通过 Command 继续。它还强调 thread_id 是恢复同一个检查点的指针。Persistence 文档也说明,带 checkpointer 的图会按 thread 保存每一步状态快照。
关键难点
第一个难点是暂停点放在哪里。很多人会把审批放在工具调用外面,先让 Agent 生成一个 tool call,再由前端问用户是否继续。如果恢复时重新让模型决定参数,就可能生成另一组调用。我的做法是把审批点放在工具执行前一刻,并把工具名、参数摘要、风险级别、预览文本和运行上下文一起落库。
第二个难点是恢复时不能重复副作用。LangGraph 文档提到,从中断恢复时,中断所在节点会从头重新运行,所以中断前的副作用要能幂等。我的规则是,审批点之前只允许做纯计算和状态写入,影响文件、网络、数据库的动作都放到审批通过之后,并带上同一个 idempotencyKey。
第三个难点是拒绝和过期也要有结论。用户没有点同意时,任务不能永远卡在 pending。审批记录里需要有 approved、rejected、expired、resumed 这些状态,审计日志也要记录是谁在什么时候处理了哪一个 actionDigest。
解决思路
我最后把人审暂停点拆成四个对象:run 记录整次 Agent 运行,checkpoint 记录暂停时的状态快照,approval 记录待审批动作,resumeToken 记录一次性恢复口令。前端只展示 approval 里的预览和风险说明,后端恢复时会同时校验 threadId、checkpointId、actionDigest 和审批人权限。任意一项对不上,恢复就会失败并写入审计日志。
Temporal 的 Durable Execution 文档也给了我相似的工程直觉:可靠工作流要能在失败、崩溃或服务中断后保留状态和进度,并从记录过的位置继续。桌面端 Agent 可以借用这个思想,把每一次人审都当成一个明确的持久化边界。
关键步骤很少。先给高风险工具声明 riskLevel、previewBuilder 和 idempotencyScope。调度器判断需要人审时,创建 checkpoint 和 approval,然后停止本轮执行。用户确认后,服务端用 resumeToken 找回 checkpoint,把审批结果写入状态,再继续执行后续节点。工具真正执行时只认 idempotencyKey,避免双击确认、页面重试或后台恢复造成重复写入。
可复用经验
我现在判断 Agent 是否适合半自动执行,会先问三个问题:暂停时有没有足够的信息让用户做判断,恢复时能否找到同一个状态快照,副作用动作能否用幂等键保护。三个答案都清楚,确认按钮才有意义。
这套做法也适合 RAG 导入、批量文件整理、Electron 自动更新辅助和后台任务编排。人审更像工作流里的一道持久化闸门。Agent 才能从“会提建议”走到“能被托付一部分执行”。