Skip to content
imshengli blog
Go back

为什么你的 Agent 跑不了长程任务?

单 Agent 跑大任务必然撞上 context 膨胀→压缩→遗忘的死循环。本文拆解根因,给出主-子 Agent 调度模式的完整解法。

· 9 min

结论先行

单个 Agent 跑不了大任务,不是它”不想干”,而是它的记忆有硬上限。

解法:用”主-子 Agent”模式——主 Agent 只负责调度,子 Agent 各自独立执行小任务,进度写到文件里持久化。

一句话总结:多个 Agent 各司其职、快进快出,把进度交给文件系统来记忆。

你可能遇到过这个问题

给 Claude Code 安排一个大任务,比如”把项目里大概 1000 个单元测试全部补全”。结果它跑了 200 个就停下来,问你”要继续吗?”

你回复”继续”,它又跑了一会儿,这次更快就停了,而且开始出现奇怪的行为——重复检查已经修好的测试、忘记之前的修改思路。

这不是 bug,是单 Agent 架构的物理限制。

根因:Context 的”记忆衰退”

要理解这个问题,先搞清楚一个核心概念:

Context window(上下文窗口):AI 模型一次对话中能”看到”的全部信息量,包括你的指令、它的回复、工具调用结果等。你可以把它想象成一张桌子——桌子大小固定,放的东西越多,就越挤。

当单个 Agent 执行大任务时,会经历这样一个过程:

阶段 1:高效期

刚开始,context 还很空旷。Agent 指令遵循度高,执行又快又准。就像一张干净的桌子,放什么都看得清。

阶段 2:逼近上限

跑了大约 80k tokens 后,context 开始接近 compact 阈值(compaction threshold,即系统自动压缩对话历史的触发点)。桌子快满了。

阶段 3:压缩与遗忘

系统触发 auto-compact——把之前的对话历史压缩成摘要。这就像把桌上的一摞文件塞进一个信封,写上”之前做的事情”。信封里的细节?没了。

Agent 开始忘记:第 53 个测试报错的具体原因是什么、它是怎么修的、为什么那样修。

阶段 4:退化与退出

再经过一两轮 compact,Agent 甚至会重复检查已经修好的测试(因为它不记得修过了)。当触发 maxTurns(最大轮次限制)且 response 里没有工具调用指令时,它判定”当前任务告一段落”,于是停下来问你。

整个过程用一条链来概括:

context 膨胀 → 触发 compact → 细节丢失 → 效率下降 → 行为异常 → 退出

为什么”回复继续”没用?

因为 compact 后的 context 已经是”残缺的记忆”。在这个基础上继续工作,就像拿着一份只有目录没有正文的笔记去接着干活——不仅效率更低,还更容易出错,退出得也更快。

解法:主-子 Agent 调度模式

既然单 Agent 的瓶颈是”一张桌子放不下所有东西”,那就用多张桌子:

这样每个子 Agent 都在”干净的桌子”上工作,不受之前任务的干扰,也不会撞上 context 上限。

具体怎么做:三个关键设计

1. 任务分解——把大象切成肉片

错误做法:给 Agent 一句”修复所有失败的单测”。

正确做法

  1. 先让 Agent 扫描所有失败测试
  2. 按目录或模块分组,每组 15-30 个
  3. 为每组生成一个自包含的任务描述

“自包含”是关键——每个子任务的 prompt 必须写清楚:

绝对不能写”根据之前的分析来修复”,因为子 Agent 看不到主 Agent 的历史。这就像你给外包团队派活,必须把需求写得明明白白,不能假设他们知道你之前开了什么会。

2. 进度持久化——把记忆交给文件系统

在项目根目录维护一个 progress.json

{
  "completed": ["tests/user/login.test.ts", "tests/user/signup.test.ts"],
  "failed": ["tests/payment/refund.test.ts"],
  "pending": ["tests/order/create.test.ts", "tests/order/cancel.test.ts"]
}

工作流程:

  1. 主 Agent 每轮调度前读 progress.json,决定下一批任务
  2. 子 Agent 完成后更新对应条目
  3. 即使主 Agent 自己被 compact,重读文件就能恢复全部状态

这就是把”记忆”从 Agent 的脑子里(context)搬到了硬盘上(file system)。硬盘不会忘事。

3. 失败策略——不要无限重试

子 Agent 报错时,有三种应对:

情况策略原因
错误可修复(如少导入了一个模块)用 SendMessage 继续同一个子 Agent保留错误上下文,修复效率最高
方向完全错了(如用了错误的 API)启动新的子 Agent避免锚定效应,老 Agent 会沿着错误路径继续走
多次失败(如超过 3 次)上报用户,人工介入不要无限重试烧 token

类比:就像你管理团队——小问题让开发者自己修,大方向错了换个人重做,反复搞不定就升级到你这里决策。

在 Claude Code 中的实现

Claude Code 已经内建了这套能力,最直接的方式是启用 Coordinator Mode(输入 /coordinator):

常见误区

误区为什么是错的
”我给足够详细的 prompt 就能让单 Agent 跑完”context 物理上限无法靠 prompt 质量突破
”回复继续就能接着跑”compact 后的 context 已经是残缺记忆,继续只会更差
”子 Agent 的 prompt 可以引用主 Agent 的分析”子 Agent 看不到主 Agent 的历史,prompt 必须自包含
”失败了就一直重试”重试烧 token 且可能锚定在错误路径上

总结

单 Agent 跑长程任务失败的本质原因是 context 有限且不可恢复。解决方案不是”让 Agent 更聪明”,而是改变架构:

  1. 任务分解:大任务拆成独立的小任务,每个 prompt 自包含
  2. 进度持久化:用文件系统记录状态,不依赖 Agent 的记忆
  3. 失败策略:可修复就继续,方向错就重启,反复失败就上报

这就是从”一个人干所有活”到”一个团队分工协作”的架构升级。

FAQ

Q:每个子任务分组 15-30 个测试,这个数字怎么来的?

A:经验值。太少(比如 3-5 个)调度开销大,主 Agent 要频繁启动/回收子 Agent;太多(比如 100 个)子 Agent 自己也会撞上 context 上限。15-30 是一个”子 Agent 在 compact 之前能舒服完成”的甜区,具体数字可以根据任务复杂度调整。

Q:progress.json 被子 Agent 写坏了怎么办?

A:可以在主 Agent 端加一层校验:读取后检查格式是否合法、条目是否重复、状态是否自洽。本质上就是给”共享状态”加一把锁。实践中用 JSON Schema 校验就够了。

Q:Coordinator Mode 和手动写调度脚本有什么区别?

A:Coordinator Mode 是 Claude Code 内建的轻量方案,开箱即用,适合中等规模任务。如果你的任务需要更复杂的调度逻辑(如优先级队列、依赖关系图、并发度控制),可以自己写 harness 脚本来精细控制。两者不冲突,可以组合使用。

Q:这套方案适用于所有 AI coding agent 吗?

A:核心思路(任务分解 + 进度持久化 + 主子调度)是通用的,不限于 Claude Code。任何有 context 上限的 LLM Agent 都适用。具体实现方式(如 AgentTool、SendMessage)是 Claude Code 特有的 API,其他工具需要用各自的 agent 调度接口。


Share this post on:

Previous Post
AI 原住民开发者:当编程遇上大模型
Next Post
组合不同 LLM 完成任务,会成为必备技能之一