Agent 长任务:状态、恢复与验收
分析全年订单,八月查询超时;归档已经成功,执行端却没收到响应。新会话该从哪里继续?
长任务跨越工具、作业和会话,必须留下已验证的结果、原操作身份和剩余预算。下面用订单报告走完恢复过程。
页面交互为教学模拟,刷新后重置,不调用模型或真实业务接口。
缺一个月,就不能交付全年报告
每个月的结果单独保存、核对,汇总等十二份证据齐全。第八个月超时,保留前七个月,只补缺失分区;切换会话后累计消耗继续保留。
会话 1
- 1 月未查询
- 2 月未查询
- 3 月未查询
- 4 月未查询
- 5 月未查询
- 6 月未查询
- 7 月未查询
- 8 月未查询
- 9 月未查询
- 10 月未查询
- 11 月未查询
- 12 月未查询
已核对 0/12 月聚合阻塞:必需分区缺失
- 累计查询
- 0 次
- 恢复时复用
- 0 个月
十二个月尚未查询,全年汇总等待分区证据。
这里的绿色只表示该月已核对。全年数量核对通过之后,异常解释、报告内容和归档仍要分别验收。把整个任务设成一个“完成”节点,会失去局部恢复的依据。
任务契约:每一步依赖什么,凭什么算完成
这里的“长”指任务生命周期跨越多个工具、后台作业和会话,不只指耗时。模型负责分析与选择,程序负责依赖、权限、状态和验收;固定路径用普通工作流即可,确实需要根据中间证据探索时再引入 Agent。本文的月份、次数和阈值用于解释机制,不是线上性能实测。
目标是“解释指定年度订单异常并交付可核对的报告”。任务版本固定统计时区、年度边界、可见订单范围、数据快照和必需指标;禁止读取其他租户、修改订单以及向外部发送报告。
| 步骤 | 输入与依赖 | 完成证据 |
|---|---|---|
| 固定口径 | 已确认范围、字段与权限 | 任务版本、统计口径与快照标识 |
| 按月查询 | 固定快照;可受控并行 | 十二份分区结果、参数摘要、行数与校验摘要 |
| 聚合核对 | 必需分区齐全 | 总量与分区之和一致,币种与金额规则一致 |
| 分析异常 | 已核对统计与可引用明细 | 每项结论关联数据和口径,未知原因单独标记 |
| 验证报告 | 当前版本与验收项 | 必需章节、数值、引用和权限检查记录 |
| 归档 | 报告验收通过;具备既有授权 | 唯一报告 ID,回读内容与当前报告一致 |
拆分粒度以“能独立验证、失败能定位”为准。每次读文件都建任务会增加成本;每个月独立验证则支持局部恢复。探索可以新增只读渠道查询;若改变范围、外发目的地或完成标准,必须更新任务版本并按既有授权处理,不能为了通过验收删掉必需月份。
状态与检查点:对话摘要之外还要保存什么
摘要帮助接手,持久状态决定能否继续。保存目标与约束、步骤依赖、执行尝试、外部操作和验收证据;大文件放文件系统或对象存储,状态中保存引用、摘要和版本。
json
{
"task_id": "annual-report-01",
"task_revision": 3,
"data_snapshot": "orders-snapshot-07",
"step_id": "archive-report",
"status": "unknown",
"depends_on": ["verify-report"],
"input_digest": "sha256:report-content-digest",
"attempt_id": "attempt-02",
"operation_id": "archive-01",
"idempotency_key": "annual-report-01:r3:archive",
"budget_used": { "tool_calls": 18, "retries": 1 },
"next_action": "query_original_operation"
}attempt_id 标识一次尝试,operation_id 与幂等键标识同一个逻辑操作。重试可以新增尝试记录,仍须按服务合同沿用原操作身份;同键不同参数应被拒绝。任务换版本前,也要核清旧版本结果未知的写入。
工具退出成功先进入 verifying,证据符合当前标准后才进入 succeeded。waiting 表示有可追踪的异步作业,unknown 表示无法确认写入是否生效,blocked 表示缺少权限、输入或外部决定,failed 表示本次步骤已终止。
图中未知结果先回查,异步作业按作业 ID 等待,验证失败修正后重做。检查点只保存运行位置,本地状态与远端业务通常不在同一事务里,仍会出现“远端成功、检查点未更新”的窗口。
超时后,先查那一笔操作
“没有收到响应”只能说明执行端不知道结果。归档前保存操作意图、稳定键和参数摘要;超时后用原键回查,再验证已有报告。下面的反例会换一个新键重发:两份报告都成功保存,重复副作用也随之发生。
- 1准备
- 2记意图
- 3丢响应
- 4换会话
- 5恢复
- 6验证
执行端 · 会话 1就绪
ready原操作:archive-01当前键:archive-01归档服务0 份归档尚无归档回读报告:尚未确认归档按逻辑操作键去重
1 / 6
先固定报告内容、版本和归档授权。
重试换的是尝试编号,不能随意换逻辑操作身份。 原结果成功后复用它;仍在处理就受限等待;持续未知则停止自动写入并核查。恢复检查点不会收回已经归档的报告或已经发出的通知。
接口合同与完整时序:查不到是否就能重发
新进程读取旧操作,回查得到报告 ID,再回读内容并补齐验证。会话和进程可以更换,逻辑操作身份保持稳定。
| 回查结果 | 下一动作 |
|---|---|
| 成功,报告可读 | 验证内容、归属、当前权限和版本,复用原结果 |
| 仍在处理 | 保存远端作业 ID,按退避间隔查询,遵守等待期限 |
| 明确未执行且允许重试 | 沿用原操作身份和参数,消耗重试预算 |
| 暂未查到 | 核对一致性和保留期限,不能仅凭暂时不存在新建操作 |
| 持续未知或幂等记录过期 | 停止自动写入,保留证据并转核查 |
工具合同要说明去重期限、并发同键的处理、同键参数冲突和查询一致性。已有结果复用也要复查访问权限,缓存不能延续已经撤销的授权。
失败分类:重试、降级、恢复与补偿
| 现象 | 处理依据 | 动作 |
|---|---|---|
| 只读查询超时、限流 | 重试安全性、服务端重试时间、剩余预算 | 有上限的指数退避与抖动 |
| 参数或业务校验失败 | 错误字段、工具 schema | 修正原因,不盲目重发原参数 |
| 权限拒绝 | 当前身份、任务授权、资源归属 | 停止动作,保存拒绝结果,不换工具绕过 |
| 写入响应丢失 | 原操作的服务端状态 | 先回查,再按幂等合同恢复 |
| 依赖确实不可用 | 替代工具的数据、权限与结果语义 | 合同等价才切换,记录来源变化 |
| 非必需信息缺失 | 是否影响必需验收 | 声明降级范围;核心条件缺失则阻塞 |
查询失败可以从分区恢复,格式失败可以修正后重验;已归档报告通过版本或撤销接口处理,已发通知只能记录或补发更正。恢复代码或检查点都不会撤销这些外部结果。
删掉租户、时间范围或权限过滤,可能让工具“成功”,却改变了任务含义。替代接口只覆盖部分月份时,不能声称全年分析完成。模型可在允许集合中选择读取与分析工具,程序仍要校验参数形状、业务取值、权限、频率和副作用;工具注册表负责能力发现与合同。
会话可以重开,预算不能重置
既要防止无限循环,也要识别“还没到上限,却一直没有进展”。下面的任务已有一项在途作业;新证据会推进任务,相同查询连续三次无变化会暂停。切换会话继续使用同一账本。
可继续调度会话 1
- 已用 / 总额度
- 1 / 6
- 新增证据
- 0 项
- 连续无进展
- 0 次
在途作业远端仍在运行
已提交一个远端作业,消耗 1 次业务调用;等待它返回。
取消分两步:先停新调度、登记 cancel_requested,再核查远端,确认停止后才是 cancelled。实验中的确认来自模拟回执;生产系统要读取真实作业状态。这里仅计算业务调用,取消和核查应另外预留控制额度。
调度预算、停滞诊断与反思触发
总预算覆盖模型、工具、重试与子任务。调用前预留额度,完成后结算实际用量;并发预留需要原子更新,避免每个分支都认为拥有全部余额。恢复后继续读取原截止时间和已用额度;硬期限还需要外部服务配合超时与取消。
每轮执行前检查依赖和余额,返回后检查是否获得新证据、通过一个验证项、缩小问题范围,或取得可追踪的后台进度。相同状态轮询也可能正常,应结合退避间隔、作业进度与期限判断。本文连续三次的阈值用于教学,实际阈值由延迟、成本与历史失败轨迹校准。
子任务验收失败、工具语义异常、计划冲突或停滞时,先整理证据支持的结论、被推翻的假设以及下一步要获取的新信息,再决定是否继续。反思也消耗预算,结论仍需测试或查询验证。
额度耗尽后保存状态、操作身份、已验证产物和所缺外部条件。进度可以报告“十二个月中七个月已核对,第八个月限流等待;尚未聚合”,让接手者明确已完成和未完成的范围。
多执行者与取消竞争:本地文件覆盖不了哪些情况
单进程工具可从原子替换的状态文件开始;多执行者需要事务、条件更新和任务领取。租约过期允许新 Worker 接管,旧 Worker 仍可能运行;执行端应校验递增的持有者代号,或由业务提交端通过幂等与版本条件拒绝旧写入。
取消请求与归档完成可能同时发生。先停新调度,再请求取消并回查;竞争中已完成的归档要保留在账本里,撤销或补偿按业务规则处理。恢复前看到“待处理”也可能很快过期,提交或取消时须由业务服务再次校验当前状态。
旧证据,能覆盖新任务吗
假设只有八月至十二月的数据快照更新:这几个月的分区证据及其下游汇总、报告验收都要重验,一月至七月的有效证据可以复用。变化沿依赖传播,不能看到历史 passed=true 就直接交付。
图中的“可复用”以来源、权限和有效期仍满足要求为前提。任务口径、授权地区、代码或工具配置改变时,影响范围可能扩大到全部分区。
接手检查与证据绑定
新会话先读取当前任务版本、允许范围、未终态步骤和原操作,再核对实际目录、产物与外部状态。编码任务检查 Git HEAD、未提交差异、依赖和测试对象;报告任务检查数据快照、口径与文件摘要。
任务版本 2 只统计国内订单,版本 3 扩展到其他已授权地区时,旧版本“全年数量核对通过”仍是历史记录,却不能覆盖新版交付。按输入与依赖找受影响步骤,重查或重算;不受影响且来源、权限仍有效的分区才能复用。
证据应关联任务版本、数据或代码版本、工具配置与产物摘要。长期经验保存原则和入口;当前 PID、服务状态、余额和权限要回到现场核查。对话摘要是接手索引,持久账本与现场结果决定执行资格。
故障注入与可观测性:交付验收清单
验收同时覆盖需求、过程与结果:必需步骤完整;权限与预算符合约束;产物能从原始数据复核。确定性检查负责金额、分区完整性和字段合同,难以自动判断的业务结论由明确责任人审阅。
| 注入条件 | 应观察到的结果 |
|---|---|
| 第八个月查询失败后重启 | 复用有效分区,补缺失部分,最终覆盖十二个月 |
| 归档成功但响应丢失 | 回查原操作,唯一报告 ID 与内容可读,无额外归档 |
| 同键提交不同报告 | 拒绝冲突,不覆盖原结果 |
| 依赖未完成就尝试聚合 | 调度层拒绝,不生成全年成功结论 |
| 数据、代码或任务版本改变 | 受影响证据过期,重新验证对应链路 |
| 两个执行者同时接手 | 提交合同控制重复,旧持有者无法越过版本条件 |
| 预算耗尽或用户取消 | 停新调度、保存状态、核查在途操作并明确最终状态 |
| 资料诱导删验收或绕权限 | 数据不升级为指令,拒绝行为可追踪 |
以任务、步骤、尝试与外部操作四个 ID 串联追踪,记录输入摘要、状态转移、错误类型、耗时、预算与证据引用,省略凭据及不必要的业务原文。复盘看恢复成功率、重复副作用、停滞消耗、过期证据误用和真实验收完成率;调用次数只说明消耗。
在独立进程中复现恢复
页面实验展示决策过程;下载恢复实验脚本可以验证进程真正退出后能否继续。它使用 Node.js 24 标准库,以 checkpoint.json、service.json 分别模拟执行端与归档服务,输入为 report.json 中已验证的教学报告。
运行命令、预期结果与故障排查
在脚本所在目录打开 macOS 或 Linux 终端,使用新的临时目录:
bash
LAB_DIR=$(mktemp -d)
node long-agent-resume.mjs init "$LAB_DIR"
node long-agent-resume.mjs run "$LAB_DIR" --crash-after-submit
# 预期退出码 75:服务端已保存,执行端尚未收到结果。
node long-agent-resume.mjs inspect "$LAB_DIR"
node long-agent-resume.mjs run "$LAB_DIR"
node long-agent-resume.mjs run "$LAB_DIR"第一次检查:本地 status=unknown,服务端 archive_count=1。新进程通过原键查到报告并验证,状态变为 succeeded;再次运行仍回读同一报告,归档数量保持 1。
在另一个新实验目录初始化后修改 report.json 的金额或标题,脚本应以退出码 2 拒绝过期证据或输入冲突。正确恢复是重新验证新报告、核查旧操作后受控创建新版本,不能清空状态重跑。JSON 损坏时先保留异常现场,核对三个文件与参数摘要,不把解析失败当作重新提交的许可。
此脚本是单执行者、独立进程的本地模拟,不调用模型或真实服务。原子替换没有覆盖掉电、并发、跨主机事务、真实权限和幂等记录过期;生产系统需要验证持久存储与服务端提交合同。它验证恢复信息和原操作查询的作用,不验证模型分析质量。
长任务的可靠性最终落在同一条链上:步骤有证据,写入可回查,预算能停止,变化会使旧证据失效。 编码场景可结合上下文交接与验证交付;基础概念见智能体循环和任务契约,业务写入见工单处理助手。
