跳至主要内容
长任务 Agent 的断点续跑设计

长任务 Agent 的断点续跑设计

上周我把一个批量处理工单的 Agent 从「失败就整条重跑」改成可断点续跑。第一次压测就翻车:它在第 37 步发完通知邮件后被 kill,恢复时又发了一遍。检查点其实存了,问题是我把检查点当成进度条,没把副作用当成状态。

先标出不能重放的动作

长任务和短任务的区别,不是步骤多,而是中途会碰到外部世界。分类、摘要、生成草稿这类动作,失败了重算一遍最多花点 token;发邮件、写 CRM、扣款、关闭工单这类动作,重放一次就是事故。

我现在会先列一张副作用表,把每个动作分成四类:可重算、可覆盖、只能一次、不可逆。可重算的是模型推理和临时文件;可覆盖的是写草稿、刷新缓存,只要写入内容一致就能重来;只能一次的是通知、支付、外部系统状态变更;不可逆的是删除、归档、对外承诺。这张表决定检查点该切在哪,而不是反过来让检查点去适配代码结构。

一个很实用的拆法是「决定」和「执行」分开。Agent 先产出一个计划,计划本身是纯数据,可以反复生成、比较、修改;真正执行时,每个副作用动作单独记账。这样恢复时,计划可以重算,执行记录不能重放。

检查点是一份恢复契约

我见过最常见的检查点长这样:task_id、当前步骤、最后一条消息。它能告诉你「跑到哪了」,但不能告诉你「哪些事已经真的发生了」。恢复逻辑一上来就从这个步骤继续,很容易把半成功状态当成没做。

我现在存的检查点大致包含这些字段:task_id、plan_version、cursor、input_hash、step_outputs、effect_ledger、schema_version、retry_count。step_outputs 只存后续步骤真正需要的结构化结果,不存整段对话;effect_ledger 是副作用账本,每个外部动作一条记录,状态只有三种:intent、committed、unknown。

顺序很关键。对外调用之前先写 intent,调用成功后写 committed,失败或进程被杀就留在 unknown。恢复时对 unknown 不能直接重试,要先查询外部系统,查不到再交给人工确认。这个设计会多一次写库,但它把「不确定」显式暴露出来了。很多重复副作用不是因为重试太多,而是因为系统把不确定当成了失败。

还有 schema_version。工具参数、prompt 结构、输出格式一变,旧检查点可能已经不能安全恢复。我的做法是版本不兼容就不硬续,标记为待迁移或重新开一个任务。断点续跑不是必须从旧状态复活,有时候承认旧状态不可恢复更便宜。

幂等键要贴着副作用走

幂等键不要只在任务级别生成一个。一个长任务里如果有多次通知、多次写库,任务级幂等键要么让所有动作看起来一样,要么在重试时失效。更稳的做法是每个副作用一个稳定键:task_id + step_id + effect_type + payload_hash。同样的意图重试,键不变;内容真的改了,键才变。

如果下游支持幂等键,就直接传下去。如果不支持,本地要有一张去重表,用唯一约束兜底。比如发通知前先插入一条 pending 记录,唯一键冲突就说明这个动作已经发起过。注意这只是本地兜底,跨进程崩溃的窗口还在,所以还需要前面的 unknown 状态和外部查询来对账。

LLM 调用本身通常没有外部副作用,重试相对安全,但也不是完全免费。我会把模型调用和工具调用分开看:模型输出可以重新生成,工具执行要有账本。不要在模型层做复杂的幂等,重点放在工具层。

半成功才是常态

批量任务最容易出问题的地方是半成功:一百条工单处理了六十条,其中三条通知发出去了但状态没回写。如果检查点只记到「批次」这一级,恢复时只能整批重来。所以检查点要细到单条记录,至少让恢复逻辑能按 item 继续,而不是按 batch 继续。

我会在恢复入口加一个 dry-run:先根据检查点算出一份「接下来要做什么」的清单,标出哪些是重算、哪些是重试、哪些需要人工确认。确认后再执行。这个 dry-run 不解决所有问题,但能让我在真正发邮件之前看到重复风险。

测试也简单:在外部调用前后随机 kill 进程,跑几十轮,最后核对外部系统的实际效果数和账本里的 committed 数是否一致。不一致就说明还有一个没被建模的窗口。监控上我会盯三个数:恢复次数、unknown 副作用数、被去重挡掉的重复调用数。unknown 长期大于零,说明对账逻辑没做完。

下次设计长任务,我会先画副作用表,再决定检查点粒度。如果你手里只有一个 job 级检查点,先别急着加更多字段,先把 effect_ledger 补上。你的 Agent 里,哪个动作是绝对不能重放的?把它标出来,恢复逻辑才有起点。

关于本文

由 Lu's Blog 撰写,采用 CC BY-NC 4.0 许可协议。

#容错 #工程 #智能体

评论