长时间运行的任务
后台执行、断点续跑、异步通知与进度汇报。
一句话理解:长任务的难点不在“多调几次模型”,而在于它必然会跨越进程重启、上下文上限和用户离开;Harness 要把任务从“一次请求”升级为“一个可暂停、可恢复、可观察的作业”。
一个 SEO 诊断 Agent 检查 5 个页面,两分钟就能跑完,用户盯着屏幕等结果就好。同一个 Agent 检查全站 3,000 个页面,要跑两三个小时。这时候会冒出一连串新问题:
- 用户不可能一直开着页面,关掉之后任务还在跑吗?
- 部署新版本会重启服务,跑到第 1,800 页的进度怎么办?
- 上下文窗口不可能装下 3,000 页的检查结果,模型怎么记得前面发现了什么?
- 跑到一半发现需要人确认某个判断,Agent 是干等着,还是先做别的?
- 用户回来时,怎么一眼看懂“做了多少、发现了什么、还剩多少”?
这一课讲 Harness 需要为长任务提供的能力。长任务的交互设计见 异步任务体验,上下文压缩的细节见 长任务的上下文管理。
长任务会撞上的四堵墙
| 墙 | 表现 | Harness 的对策 |
|---|---|---|
| 进程会死 | 部署、崩溃、机器回收导致任务中断 | 持久化执行:检查点 + 从中断处恢复 |
| 上下文会满 | 历史越来越长,成本上升、注意力下降,最终超限 | 压缩、清理旧工具结果、外置笔记、子任务隔离 |
| 人会离开 | 用户不在线,审批和问题无人回应 | 后台运行、异步通知、审批时暂停并保存状态 |
| 世界会变 | 两小时前查到的数据已经过期 | 关键动作前重新确认,状态带时间戳 |
Anthropic 工程团队在一篇关于长时间运行 Agent 的文章中总结过几种典型失败:Agent 想一次做完整个项目,结果上下文在实现中途耗尽;后续会话看到已有进展,就过早宣布完成;没有端到端测试就把功能标为完成。他们的对策是:先生成一份结构化的功能清单(初始全部标为未通过),每次只做一项,用 Git 提交记录进度,每次会话结束更新进度文件,并在标记完成前做端到端验证。这些做法不限于写代码,对任何长任务都适用。
架构:从“请求—响应”到“作业”
几个关键设计点:
- 任务 ID 立即返回:创建任务的请求不等待完成。队列、Webhook、定时任务的基础知识见 异步、队列、Webhook 与定时任务。
- 检查点粒度:太粗(整个任务一个检查点)等于没有;太细(每次模型调用都存完整历史)存储和性能开销大。常见做法是 每个业务步骤或每个有副作用的动作一个检查点。
- 心跳与租约:Worker 定期声明“我还活着”,超时未续约的任务会被其他 Worker 接管。接管时要防止两个 Worker 同时执行同一个写操作,这又回到了 错误恢复与重试 中的幂等设计。
五个关键能力
1. 后台执行与断点续跑
需要区分两种“恢复”:
- 对话恢复:把历史消息重新加载给模型,让它“记得刚才聊到哪”。
- 任务恢复:知道哪些步骤已完成、产物在哪、下一步是什么。
只做对话恢复不够。对话历史可能已被压缩,模型也未必能从几百条消息里准确还原进度。长任务应该以 结构化的任务状态 为准,对话历史只是辅助。详见 任务状态与 Checkpoint。
以全站 SEO 诊断为例,一次崩溃加一次审批的完整时间线是这样的:
2. 上下文跨窗口
3,000 个页面的检查结果不可能全部留在上下文里。常用组合是:
- 每检查完一批页面,把结论写入外部文件或数据库,上下文里只保留摘要;
- 用子 Agent 处理单个页面,主 Agent 只接收精简结论(见 Subagent 与上下文隔离);
- 开启自动压缩,并在项目说明中写明压缩时必须保留的信息(任务目标、已完成范围、关键发现)。Claude Agent SDK 的文档就建议把需要长期遵守的规则放在项目说明文件里,因为压缩可能丢失早期对话中的指令。
3. 暂停等待人工
长任务里的审批不能“阻塞式等待”:人可能几个小时后才回复。正确做法是 保存完整状态后暂停,人回复后再恢复。不同框架的实现方式:
| 框架 | 暂停与恢复机制 |
|---|---|
| OpenAI Agents SDK | 工具标记 needs_approval 后,运行结果中出现待审批项;把运行转为 RunState,可序列化为 JSON 保存,审批后再恢复运行 |
| LangGraph | 节点内调用 interrupt() 保存图状态并暂停,之后用 Command(resume=...) 恢复;需要配置 Checkpointer 和 thread_id |
| Claude Agent SDK | PreToolUse Hook 返回 permissionDecision: "defer" 会结束本次运行,稍后恢复 |
审批期间,能并行推进的其他工作不必停下:例如 SEO Agent 等待“是否批量修改标题”的确认时,可以继续检查剩余页面。
4. 进度汇报
用户回来时需要回答三个问题:做到哪了?发现了什么?还要多久?这要求 Harness 维护一份“给人看”的进度,而不是让用户翻日志:
全站 SEO 诊断 · 运行中 1 小时 12 分
进度:1,840 / 3,000 页(61%)
发现:缺失 meta 描述 212 页 · 标题重复 37 组 · 404 链接 19 个
等待你确认:是否对 37 组重复标题生成改写建议?
预计剩余:约 45 分钟 · 已用预算:58%
计划与进度的呈现方式见 计划与进度。
5. 预算与超时
长任务更需要多重上限:总时长、总花费、单步超时、连续失败次数。触达上限时优先“保存进度并暂停”,而不是直接丢弃。Claude Agent SDK 在达到轮数或金额上限时返回带会话 ID 的结果,可以调高上限后恢复;托管平台 Claude Managed Agents 也支持在创建会话时设置花费上限,达到后会话暂停并进入空闲状态。
托管平台与持久化执行
如果不想自建队列、Worker 和状态存储,可以考虑现成方案:
- 托管 Agent 平台:Claude Managed Agents(目前为 Beta)面向长时间运行和异步任务,会话在服务端保存对话历史与沙箱状态,通过事件流推送进度,可以中途发送消息引导或打断,还支持按 cron 表达式定时运行。需要注意,它因为有状态设计,目前不适用零数据保留(ZDR)安排。
- 持久化执行引擎:OpenAI Agents SDK 的文档列出了与 Temporal、Restate、DBOS、Dapr 的集成,用于支持带故障恢复和人工介入的长时间运行 Agent。
- 自带持久化的编排框架:LangGraph 通过 Checkpointer 持久化每个线程的图状态,用于对话延续、人工介入和容错。
选型的完整讨论见 框架与 SDK 选型。
常见误区
- “把超时时间调到两小时就行。” 单个请求撑两小时,任何一次网络抖动或部署都会让全部进度归零。
- “对话历史就是进度。” 历史会被压缩、会很长、很难被程序解析。进度必须是结构化状态。
- “后台任务不用管体验。” 恰恰相反,看不见的任务最容易让用户焦虑,也最容易被重复提交。
设计要点
- 创建任务立即返回任务 ID,并防止用户重复提交同一任务。
- 每个业务步骤写检查点,每个写操作带幂等键。
- 审批时保存状态并暂停,不阻塞等待;能并行的工作继续推进。
- 维护一份面向用户的进度摘要:已完成、发现、待确认、预计剩余。
- 恢复前重新确认关键业务状态;数据带上查询时间。
- 设置总时长、总花费、单步超时与连续失败上限,触达后保存并暂停。
练习
把「全站 SEO 诊断 Agent」设计成长任务,用 60 分钟完成:
- 画出它的作业架构(参考本课的图),标出检查点写在哪几步。
- 设计一份任务状态 JSON,至少包含:总页数、已完成页数、每类问题的计数、待确认事项、已花费。
- 写出三个中断场景的恢复流程:Worker 在第 1,800 页崩溃;用户两小时后才审批;站点在诊断期间更新了 200 个页面。
延伸阅读
- Effective harnesses for long-running agents:跨多个上下文窗口的长任务实践。
- Effective context engineering for AI agents:压缩、结构化笔记与子 Agent 架构。
- Claude Managed Agents overview:托管式长任务运行的核心概念。
- OpenAI Agents SDK:Human-in-the-loop:审批暂停与
RunState序列化。
下一步
长任务往往没有人守在屏幕前。下一课「无人值守运行:SDK、CLI 与 CI」讲怎么把 Agent 放进 CI 和定时任务:用非交互模式运行、输出结构化结果、设好预算与权限上限。