让Agent跑8小时不死:长时间后台任务的状态、恢复与预算控制
短会话Agent和长任务Agent是两个物种。本文拆解长时任务Agent的三个失效机制——上下文漂移、状态丢失、预算失控,并给出可落地的检查点设计与看门狗模式。
演示 Agent 时,大家跑的都是30秒的任务。真实场景里,你需要它跑8小时:爬取分析200个竞品、逐条处理3000张工单、为一个大型重构改50个文件。
这两个场景的工程难度不在一个量级。跑3分钟的任务可以容忍一切粗糙设计,跑8小时的任务会把每个设计缺陷放大成事故。
三个失效机制
机制一:上下文漂移(drift)
任务跑了几十轮之后,Agent 的行为开始偏离初始目标。原因很具体:
- 上下文被中间结果填满,早期的核心指令被推到极远处,注意力权重下降;
- 每轮产生的小偏差累积,几轮之后就是另一件事了;
- 中间某轮的工具报错,Agent 为了绕过它自行修改了策略,且没记录。
典型表现:一个“抓取并对比竞品定价”的任务,跑到第40轮开始抓无关页面,因为某次抓取失败了,它“聪明地”扩大范围找替代。
机制二:状态丢失
进程重启、API 超时、容器被驱逐。短任务不需要考虑,8小时任务必须假设一定会中断至少一次。
如果没有持久化状态,中断就意味着从头开始——而成本已经付过了。
机制三:预算失控
长任务最恐怖的地方是它的成本结构。假设每轮调用 5万 token,跑200轮就是 1000万 token。如果哪一轮陷入循环(反复调用同一工具),成本会在几分钟内翻十倍。
而你可能在账单来的时候才知道。
解法一:检查点(Checkpoint)
每完成一个逻辑单元,写一份检查点到外部存储:
{
"task_id": "t_2931",
"goal": "抓取并对比50家竞品定价",
"step": 23,
"completed": ["competitor_12", "competitor_13", ...],
"pending": ["competitor_24", ...],
"decisions": [
{"at_step": 8, "decision": "竞品7页面改版,改用搜索页数据", "reason": "..."}
],
"spent_tokens": 412000,
"spent_usd": 3.84,
"started_at": "2026-10-27T09:00:00Z",
"last_heartbeat": "2026-10-27T14:22:11Z"
}
三个字段最关键:
completed/pending:恢复时只跑未完成的,这是省钱的核心;decisions:记录“为什么偏离了原计划”,这是防漂移的核心;spent_*:预算的实时账本。
检查点的粒度要选对:太细(每轮)写盘开销大且无意义;太粗(每完成10%才存)恢复代价大。经验是每个逻辑单元一次,一个逻辑单元对应“一件对用户可报告的事”。
恢复时最重要的一步:重述目标
从检查点恢复,不要只喂状态,要重新完整注入目标和约束,并把 decisions 摘要成几句“你之前做过这些判断,保持一致性”。
这一步的效果比想象中好。实测中,加上“重述+决策摘要”之后,长任务的路径一致性(与首次执行路径的相似度)从 61% 提升到 84%。
解法二:看门狗(Watchdog)
在主循环之外,跑一个独立的监督进程,只做三件事:
1. 心跳超时检测。 Agent 每轮必须更新 last_heartbeat。超过阈值(比如5分钟)无更新,判定卡死,触发重启。
2. 循环检测。 记录最近20次的(工具名 + 参数hash)。如果连续3次完全相同,判定为循环,立即中断并上报。
这一条挡掉的是最烧钱的事故。LLM 陷入工具循环时,单次循环成本可能只有几美分,但它会一直转下去。
3. 预算熔断。 三道闸门:
| 闸门 | 触发条件 | 动作 |
|---|---|---|
| 软阈值 | 预算 60% 且进度 < 40% | 告警,并注入“成本偏高,请优先完成剩余任务” |
| 硬阈值 | 预算 90% | 停止开启新单元,只收尾 |
| 熔断 | 预算 100% | 立即停止,保存检查点,转人工 |
“软阈值 + 进度检查”这个组合很重要——单纯按花费告警会产生大量误报,按“花费 vs 进度”的比例告警才能指出真正的问题。
解法三:上下文管理
跑200轮,上下文一定会爆。三种手段组合使用:
- 滚动摘要:每完成10个单元,把前面的过程压缩成一段摘要,原文丢弃。摘要要保留“决定”和“结论”,丢弃过程细节;
- 外置记忆:中间结果写文件,上下文里只保留文件路径和一句话描述。让 Agent 用工具去读,而不是全塞进 prompt;
- 目标锚定:system prompt 里固定一段不可变的“任务契约”,并在每 N 轮由框架主动注入一次(而不是靠模型自觉记住)。
第三个手段常常被忽略。不要把关键约束放在对话历史里指望它一直在,它会被淹没。由框架周期性重申,是唯一可靠的做法。
最终形态:把长任务当成分布式作业
一个成熟的实现,形态上非常接近分布式任务队列:
- 任务有 ID、状态机、持久化进度;
- 每个单元可独立重试;
- 有监督者、有预算、有熔断;
- 人类可以在任意时刻查看进度、介入、补位。
LLM 在其中只负责一件事:决定下一个单元做什么。其他所有保证可靠性的机制,都用传统工程的确定性手段实现。
这个分工是长时任务Agent的稳定架构。想让模型负责可靠性,是这类系统失败的最常见原因。