为什么 Claude Code 不用 ReAct
问题从哪里来
ReAct(Reasoning + Acting)几乎是 AI Agent 入门课的标配。
Thought → Action → Observation 三步循环:模型先输出一段」思考」,再选工具,再拿结果,周而复始。
很多 Agent 框架 ——LangChain、AutoGPT、CrewAI—— 都直接或间接用了这个模式。看起来天经地义。
所以读 Claude Code 源码时,第一反应是困惑:它没有 ReAct。
没有显式的 Thought 步骤。主循环就是一个 while(true),模型直接返回 tool_use 或 end_turn。
这不是偷懒,是刻意设计。
真正卡住的是哪一步
要理解为什么不用 ReAct,先得理解 ReAct 有什么问题。
不是 ReAct」不好」,而是它在面对强模型时会暴露三个缺陷。
第一个问题:Token 浪费。
ReAct 要求模型每一轮都输出一段 Thought 文本。编程 Agent 一次任务可能循环 50 轮,每轮写一句」我打算先读取这个文件然后分析它的结构……」,加起来好几万 Token。这些 Token 作为上下文发给 API,占用宝贵的窗口空间。
第二个问题:应用层代码复杂。
实现 ReAct 意味着要解析模型输出,区分」哪部分是 Thought、哪部分是 Action」,提取 Action 调用工具,再把 Observation 拼回去。这个解析很脆弱 —— 输出格式不一定标准,一旦解析失败整个循环就崩了。
第三个问题最关键:ReAct 是为弱模型设计的。
模型推理能力不够强时,用显式 Thought」强迫」它一步步思考是有意义的。但 Claude Opus 级别的模型,推理能力已经足够强,完全可以在内部完成推理,不需要在输出里显式写出来。
这三个问题揭示了一个深层事实:ReAct 的设计哲学是」帮模型思考」,而 Claude Code 面对的是不需要帮忙的模型。
我最后怎么处理
Claude Code 的做法出奇简单,核心就是一个 while(true) 循环:
while (true) { |
没有 Thought 步骤。模型在内部通过 Extended Thinking 完成推理(生成回复前的一段不可见深度推理,不占用上下文空间),然后直接返回两种结果之一:
tool_use:」我要用某个工具」,应用层执行,结果拼入消息列表,继续循环。end_turn:」我说完了」,跳出循环,返回最终结果。
应用层不需要解析任何文本格式。tool_use 和 end_turn 是 API 层面的原语,语义清晰,不需要正则、不需要格式检查。
两者的区别:
flowchart TB
subgraph ReAct[ReAct]
R1[输出 Thought 文本] --> R2[解析提取 Action]
R2 --> R3[调用工具]
R3 --> R4[拼接 Observation]
R4 --> R1
end
subgraph Loop[Tool-Use Loop]
L1[调 API] --> L2{stop_reason}
L2 -->|tool_use| L3[执行工具]
L3 --> L1
L2 -->|end_turn| L4[返回结果]
end| 维度 | ReAct | Tool-Use Loop |
|---|---|---|
| 推理方式 | 显式 Thought 文本 | 模型内部 Extended Thinking |
| 工具调用 | 解析文本提取 Action | API 原生 tool_use |
| 终止判断 | 检测「Final Answer」标记 | API 原生 end_turn |
| Token 开销 | 每轮输出 Thought | 无额外开销 |
| 编排复杂度 | 高(解析 Thought / Action) | 低(只需要 if / else) |
| 适合场景 | 弱模型 + 简单工具 | 强模型 + 复杂工具集 |
核心哲学就一句话:信任模型的推理能力,把应用层框架做得尽可能简单。
不教模型怎么想,不在应用层做推理,不用复杂编排弥补模型不足。推理留在模型内部,执行留在工具层,编排只做最简单的事 —— 调 API、执行工具、再调 API。
这种」大道至简」的设计,反而最高效。
这件事留下的经验
读完 Tool-Use Loop,我反思了之前做的 Agent 项目。一个典型错误:在应用层做了太多本该模型做的事。
自己写推理流程、自己定义状态机、自己解析模型输出 —— 本质上都在」帮模型思考」。但对强模型来说,最好的帮助就是别帮倒忙。给它清晰的工具描述、明确的终止信号,剩下的交给它自己。
另一个收获:架构的简洁性依赖底层的可靠性。
Tool-Use Loop 能用 while(true) + if/else 这么简单的结构,前提是 Claude API 稳定提供 tool_use 和 end_turn 两种 response type。如果 API 层面没有这些原语,应用层就得自己解析 —— 然后回到 ReAct 的老路。
所以选 Agent 框架时,一个判断标准:看它的核心循环有多复杂。主循环超过 50 行,很可能在应用层做了模型该做的事。
这也延伸到 Plan Mode。Plan Mode 本质上也只是一个工具调用(EnterPlanMode / ExitPlanMode),引擎层完全不需要特殊处理。同一个 while(true),同一个 if / else。「工具即能力」—— 新增能力只需要新增工具,引擎永远不变。
简洁不是简陋,是把复杂度放在正确的位置。
参考资料
- Anthropic Claude API 文档:https://docs.anthropic.com/en/docs/build-with-claude/tool-use
- ReAct 论文:https://arxiv.org/abs/2210.03629