Agent 任务中断恢复:状态机比聊天记录更可靠
一、Agent 会在真实世界里被打断
Agent 系统跑 Demo 时往往一路顺利:接收任务、规划步骤、调用工具、返回结果。但真实产品里,任务会被打断。工具超时、网络失败、用户取消、权限不足、上下文过长、服务重启,都会让 Agent 处在半完成状态。
如果系统只保存聊天记录,恢复时模型需要重新猜任务进度。聊天记录能保留对话上下文,但无法可靠标识哪些步骤已完成、工具调用结果是否已消费。状态机则用显式字段回答这些问题。更稳的方式是把 Agent 任务设计成状态机,明确当前阶段、已完成动作、待确认动作和可重试动作。
二、任务状态要显式建模
stateDiagram-v2 [*] --> planning planning --> waiting_permission waiting_permission --> executing executing --> waiting_tool waiting_tool --> executing executing --> completed executing --> failed failed --> retrying状态机能表达哪些阶段可以恢复,哪些必须重新开始。和单纯靠时间戳或返回码恢复不同,状态机还区分了「系统失败」和「用户主动中断」——前者可以自动重试,后者则需要询问用户意图。比如等待用户授权时,不能自动继续;等待工具返回时,可以根据请求 ID 查询结果;执行失败时,要看失败是否可重试。
每个工具调用也应有幂等键。否则恢复任务时重复调用工具,可能造成重复下单、重复写文件、重复发送通知。
三、恢复记录要独立于模型上下文
type AgentRunState = { runId: string taskId: string status: "planning" | "waiting_permission" | "executing" | "failed" | "completed" completedSteps: string[] pendingToolCall?: { name: string; idempotencyKey: string } lastError?: string }模型上下文可以帮助解释任务,但不能作为唯一状态源。状态应该保存在数据库里,由系统控制迁移。模型只负责根据状态生成下一步建议。
agent_recovery_policy: retry_tool_timeout: true require_user_confirm_after_permission_gap: true max_resume_age_hours: 24 idempotency_required: true恢复策略要有时间限制。一天前中断的任务,环境可能已经变化,继续执行反而危险。
四、恢复体验要让用户看懂
用户回到任务页面时,应该看到任务停在哪里、哪些步骤已经完成、下一步需要什么。不要只显示“任务恢复中”。Agent 自动化越强,用户越需要理解系统正在做什么。
还要区分系统失败和用户决策。权限不足、用户拒绝、工具异常、模型规划失败,应该给出不同提示。错误提示越细,用户越能准确决策;但分类过多又会增加 UI 复杂度。可以合并展示、展开详情。这样用户才能决定重试、修改输入还是放弃任务。
恢复流程也要防止“继续错方向”。Agent 中断前的计划可能已经不适合当前环境,例如文件被用户修改、外部订单状态变化、工具权限过期。恢复前应重新校验关键前置条件,而不是直接从上一步继续。
type ResumeCheck = { runId: string requiredFacts: string[] staleFacts: string[] canResume: boolean reason: string }对于长任务,可以把中间产物分层保存:用户输入、计划、工具结果、最终草稿。恢复时只重算受影响的部分,避免因为一个工具超时就从头开始。这样既节省成本,也降低重复执行副作用。
观测指标同样重要。需要记录任务恢复成功率、重复工具调用次数、用户取消率和平均恢复耗时。没有这些指标,就不知道状态机设计是否真的提升了可靠性。
五、总结
Agent 任务中断恢复要依赖状态机、幂等工具调用和独立状态存储,而不是只保存聊天记录。
可靠的 Agent 不是永远不失败,而是失败后知道自己停在哪里,并能安全地继续或退出。