拆解 Claude Code:一个"停不下来"的 AI Agent 是怎么炼成的

有一些 AI Agent 产品,你问它一个问题,它思考一下、调用一两次工具,然后就给你个回答,结束了。哪怕任务还没做完,它也像”到点下班”一样停下来了。
但 Claude Code 不一样。你跟它说”帮我重构这个认证模块”,它会自己去搜索代码、阅读文件、分析依赖关系、动手改代码、跑测试、发现测试挂了、再改、再跑……直到任务真正完成。整个过程可能会经历几十轮工具调用,完全不需要你中间催它。
上周 Claude Code 的源码泄露了,我就试着从源码中找答案。这其实不是某个单一的黑科技,而是四个层面的精心设计——架构、提示词、工具、容错——叠加在一起,构成了一个让模型”停不下来”的系统。
先看一个直觉类比
想象你雇了一个装修工人。
普通 Agent 的做法:工人到你家,看了一眼墙,说”这墙需要刷漆”,然后就走了。你得再叫他来,他才会刷第一遍。刷完你再叫,他才刷第二遍。每一步都要你推着走。
Claude Code 的做法:工人到你家,先看看整体情况,列个清单,然后自己去买漆、铲旧墙皮、刷底漆、刷面漆、检查有没有刷花的地方、补一下、收拾工具、最后跟你汇报。全程你只需要说一声”帮我把墙刷了”。
两者的核心差别在于:谁在驱动下一步?
第一层:一个永不主动停下的循环
Claude Code 的核心是一个极其简单但极其有效的设计——一个 while(true) 无限循环。
工作流程可以这样理解:
就这么简单。只要模型在回复中包含了工具调用——比如”我要读一下这个文件”或者”我要执行这条命令”——循环就不会停。它会执行工具、把结果反馈给模型、让模型继续思考、模型可能再调用工具……如此往复,直到模型认为任务完成,不再调用任何工具,循环才自然结束。
这里有一个有趣的设计决策:Claude Code 判断”要不要继续”时,不看模型返回的停止原因(stop_reason),只看回复里有没有工具调用的内容块。源码里甚至有一条注释说”stop_reason === ‘tool_use’ is unreliable”。这种务实的做法让系统更健壮——不依赖 API 的某个字段是否准确,而是看实际行为。
第二层:教会模型”别停下来”的提示词艺术
光有循环机制还不够。如果模型本身倾向于早早给出一个表面答案然后收工,循环也没用。Claude Code 的 system prompt(系统提示词)在这方面下了大功夫。
但它的做法很巧妙——**从来不说”请一直循环”**,而是通过一系列间接指令,塑造出一个”天然会持续工作”的角色。
身份定位:你是一个”动手干活”的 Agent
You are an interactive agent that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.
注意措辞——“use the tools available to you”。它不是说”回答用户的问题”,而是说”用工具去帮助用户”。这从根本上把模型从”回答者”变成了”执行者”。一个”回答者”说完就完了,一个”执行者”则必须把事情做到位。
激发雄心:别怕大任务
You are highly capable and often allow users to complete ambitious tasks that would otherwise be too complex or take too long.
这句话的潜台词是:不要因为任务看起来复杂就退缩或者简化。一般的 Agent 遇到复杂任务可能会说”这个任务太大了,建议您分步骤来做”——Claude Code 被鼓励直接上手干。
失败韧性:遇到问题别放弃
If an approach fails, diagnose why before switching tactics — read the error, check your assumptions, try a focused fix. Don’t retry the identical action blindly, but don’t abandon a viable approach after a single failure either.
这可能是最关键的一条指令。很多 Agent 一碰到报错就停下来跟你说”我遇到了一个错误”。Claude Code 被明确要求:遇到错误,先诊断原因,做针对性修复,不要傻傻重试,但也不要一次失败就放弃。
这意味着一个 Edit 操作报错了,模型不会停下来问你怎么办,而是会去 Read 文件看看实际内容,找到问题所在,重新 Edit,然后继续。这种”自我修复”行为天然产生更多轮次的工具调用。
任务拆解:先列计划再干活
Break down and manage your work with the TodoWrite tool… Mark each task as completed as soon as you are done.
鼓励模型把大任务拆成小步骤,逐个完成并打勾。这不仅让用户看到进度,也让模型自己有了一个”待办清单”的心智模型——“还有 3 件事没做完,不能停”。
并行工作:一次多做几件事
You can call multiple tools in a single response… Maximize use of parallel tool calls where possible to increase efficiency.
模型被鼓励在一次回复中同时调用多个工具——比如同时读 3 个文件,而不是读一个等一个。这让每一轮的信息密度更高,整体效率也更好。
子代理的指令更直接
对于子代理(通过 AgentTool 启动的独立工作线程),提示词更加直白:
Complete the task fully — don’t gold-plate, but don’t leave it half-done.
翻译过来就是:把活干完,别镀金(过度优化),但也别做一半就撂挑子。
第三层:工具设计的”小而专”哲学
Claude Code 提供了 20 多个工具,每个工具只做一件很小的事。这个设计选择的核心目的不是让循环转更多圈,而是让每一步都走得更稳。
想想看,如果你给模型一个”万能编辑器”工具——输入文件路径和新内容,一步到位完成修改——看起来效率很高,但模型必须在没有充分了解代码的情况下就做出修改决策。一旦改错了,很难定位是哪个环节出了问题。
Claude Code 选择了一条不同的路——把能力拆成最小单元:
Read— 只读文件,不能改Grep— 只搜索内容,不能读整个文件Glob— 只按名字找文件,不看内容Edit— 只做字符串替换,必须先知道原文Bash— 只执行命令Agent— 只启动子代理
这种设计的好处是:模型被迫先理解、再行动。你不能跳过 Read 直接 Edit,因为 Edit 要求你提供准确的原文。你不能跳过 Grep 直接改代码,因为你都不知道相关代码在哪个文件里。
一个典型的 bug 修复流程:
1 | Grep 搜索关键词 → Read 读取相关文件 → Read 读取测试文件 |
每一步都有明确的目的,每一步的结果都可以被用户审查和回滚。模型不是在”为了多跑几轮”而拆步骤——而是因为解决问题本身就需要这些步骤:先搞清楚状况,再动手修改,最后验证结果。
这就像一个经验丰富的工程师拿到 bug 报告后的自然工作流:先搜、再读、再改、再测。工具的设计只是让模型遵循了同样的最佳实践。
第四层:不让循环意外死掉的容错系统
一个 while(true) 循环如果没有保护机制,很容易因为各种边缘情况崩掉。Claude Code 为此设计了多层”安全气囊”。
输出被截断?自动续上
模型每次回复有 token 上限。当一个复杂的回复写到一半被截断时,Claude Code 不会就此结束,而是自动注入一条系统消息:
Output token limit hit. Resume directly — no apology, no recap of what you were doing. Pick up mid-thought if that is where the cut happened. Break remaining work into smaller pieces.
这条消息告诉模型:直接接着说,不要道歉,不要重新复述,从断点继续。最多允许这样续接 3 次。
注意措辞的精妙之处——“no apology, no recap”。如果不加这个限制,模型会本能地说”抱歉,刚才被截断了,让我从头说一下之前做了什么……”这样不仅浪费 token,还可能再次被截断,形成死循环。
上下文太长?自动压缩
当对话历史(所有消息、工具调用、工具结果)累积得太长、快要超出模型的上下文窗口时,Claude Code 有多层压缩策略:
- Snip — 裁剪掉最早的、不太重要的消息
- Microcompact — 对工具结果做细粒度压缩
- Autocompact — 自动触发完整的上下文摘要
- Reactive Compact — 当 API 返回”输入太长”错误时,紧急压缩后重试
这意味着 Claude Code 的工作轮数不受上下文窗口大小的硬性限制——它能在长任务中持续工作,因为它会自己”整理笔记”,把不重要的历史细节浓缩成摘要,腾出空间给当前工作。
模型想停但不该停?Stop Hook 介入
这是一个很巧妙且真实可用的机制。当模型决定”我做完了”不再调用工具时,Claude Code 并不立即结束。它先运行一组你预先配置的 Stop Hook——这些 Hook 可以检查模型的最终输出,如果发现任务实际上没有完成,就把模型”打回去”继续干。
协议非常简单:hook 脚本 exit 0 表示放行,exit 2 表示打回——脚本的 stderr 会作为反馈注入对话,模型看到后继续工作。
举个例子,你可以在 ~/.claude/settings.json 里配一个”每次停止前必须跑测试”的 hook:
1 | { |
效果就是:模型说”改好了”→ hook 自动跑测试 → 测试挂了 → exit 2 把”Tests failing”反馈给模型 → 模型继续修 → 再次停下 → hook 再跑测试 → 通过 → exit 0 放行。整个过程全自动,你只管等最终结果。
Token 预算用不完?继续干(内部功能,尚未公开)
源码中还藏着一个有趣的机制:Token Budget。代码显示,如果启用,用户可以在提示中写 +500k 或 spend 2M tokens,系统会解析出 token 预算,即使模型觉得”差不多了”想停下来,也会注入一条 “Keep working — do not summarize” 强制继续,直到预算用完。
不过需要注意,这个功能目前被 feature('TOKEN_BUDGET') 门控,在公开发布的 Claude Code 中并未启用,属于 Anthropic 内部测试中的功能。但从设计意图可以看出,Claude Code 团队在”让模型不要过早停下来”这件事上的思考有多深入。
完整的画面
现在我们可以把所有层面拼在一起,看看当你对 Claude Code 说”帮我修复这个 bug 并确保测试通过”时,实际发生了什么:
四层设计层层叠加,缺一不可。
Claude Code 做对了什么
回顾全文,Claude Code 在 agent loop 上的关键设计可以归纳为:
- 循环策略 — 只要有工具调用就继续,没有人为设定的轮数上限
- 错误处理 — 遇到报错自己诊断、自己修复,不轻易把问题抛给用户
- 上下文管理 — 接近窗口极限时自动压缩历史,不会因为聊得太多而罢工
- 输出截断恢复 — 被截断时自动续接,最多 3 次,不丢失工作进度
- 工具粒度 — 20+ 个小工具各司其职,迫使模型先理解再行动,每一步都可审查可回滚
- 任务拆解 — 内置 TodoWrite 跟踪进度,大任务被拆成可管理的小步骤
- 角色塑造 — System Prompt 定位为”执行者”而非”回答者”,鼓励大胆接手复杂任务
总结:没有银弹,但有系统
Claude Code 能持续工作的秘密,不是某个天才的单一设计,而是四个层面的协同:
架构上,一个
while(true)循环 + 一个简单的判断——有工具调用就继续,没有就停。简单到不可能出错。提示词上,不说”请循环”,而是塑造一个”大胆接受挑战、遇错不放弃、会拆解任务”的角色。模型自然会想要继续工作。
工具设计上,20+ 个细粒度工具,让模型遵循”先搜索、再阅读、再修改、最后验证”的工程最佳实践,每一步都有明确目的。
容错上,输出截断能续接、上下文满了能压缩、Stop Hook 能拦住不合格的”完成”。各种意外都被兜住了。
本质上,Claude Code 构建了一个让模型”停不下来”的环境。它不是强迫模型循环——而是创造了一组条件,在这组条件下,模型自然而然地会继续调用工具,而系统层面确保了没有任何意外能让这个过程提前终止。