
字节笔记本
2026年10月24日 · 约 11 分钟读完
Agent 为什么有效:ReAct 的认知科学基础

本文是《从 0 写 Agent》系列第 41 章。这个系列基于开源项目 agents-go(OpenAI Agents SDK 的 Go 移植版),用 Go 从零实现一个生产级 Agent 运行时;本章讲「Agent 为什么有效:ReAct 与认知科学基础」。
前 40 章我们讲了"怎么写 Agent"。这一章退一步问,为什么 Agent 这种架构有效?为什么"循环调模型+工具"能解决问题,而单纯调模型不行?
答案藏在认知科学和 2022 年的一篇论文里,ReAct。这一章讲 Agent 的理论基础。
引子:一个直觉的疑问
你可能会想,"大模型本身就很聪明,为什么不能直接问它复杂问题,非要搞循环调工具这么复杂?"
试一下。问大模型:"我们公司华东区上周销售下滑,主要是什么原因?"
它答不了。 不是因为它不聪明,而是它没有数据,它不知道你的销售数据、库存数据、促销节奏。即使是最强的模型,没有信息也推理不出来。
Agent 解决的不是"推理能力"问题,是"信息获取"问题。 它通过工具调用,让模型能在推理过程中主动获取信息,查数据库、读文档、调 API。
但"边推理边获取信息"这件事,背后有个深刻的理论,ReAct。

ReAct:推理与行动的交织
2022 年,论文《ReAct: Synergizing Reasoning and Acting in Language Models》提出了一个关键洞察,推理(Reasoning)和行动(Acting)应该交织进行,而不是分开。
传统方式的局限
只推理不行动(纯思维链 CoT):
模型:让我想想...华东销售下滑可能是...(基于训练数据的猜测,没有实时信息)
问题,模型在"空想",没有真实信息支撑。
只行动不推理(纯工具调用):
模型:调 get_sales → 返回数据 → 调 get_inventory → 返回数据 → ???
问题,调了一堆工具,但不知道"调完之后该干什么",没有把结果串成结论。
ReAct:先想再动,动了再想
ReAct 的核心,Thought → Action → Observation → Thought → ... 交替循环:
Thought: 用户问华东销售下滑原因。我需要先看销售数据。
Action: get_sales(region="华东", period="上周")
Observation: 销售额 500 万,环比下降 15%
Thought: 下降 15% 比较明显。我需要看是哪个品类拖累的。
Action: get_sales_breakdown(region="华东", by="category")
Observation: 电子产品下降 40%,其他品类平稳
Thought: 电子产品暴跌。可能是库存断货或促销结束。查一下。
Action: get_inventory(region="华东", category="电子产品")
Observation: 主力型号库存为 0,已断货 5 天
Thought: 找到原因了,主力型号断货导致电子产品销售暴跌。
Final Answer: 华东区销售下滑的主要原因是电子产品主力型号断货 5 天...看清楚了吗?这就是我们第 1 章讲的 Agent 循环! 每一轮,模型先"想"(这是推理),再"行动"(调工具),看到结果后再"想"。ReAct 就是 Agent 的理论原型。
为什么交织比分开好
推理指导行动,模型通过推理决定"该调哪个工具、传什么参数"。没有推理,工具调用是盲目的。
行动反馈推理,工具返回的真实信息,纠正或深化模型的推理。没有行动,推理是空想。
两者交织形成闭环,推理 → 行动 → 观察 → 更精确的推理 → 更精准的行动 → ... 每轮都比上一轮更接近答案。
这就是 Agent 有效的根本原因,它不是让模型"一次想完",而是让模型"边想边查边修正",逐步逼近答案。
比喻:侦探破案
ReAct 的过程,像侦探破案:
侦探接到案件(用户问题)
→ 推理:"凶手可能从窗户进入"(Thought)
→ 行动:检查窗户(Action: 看现场)
→ 观察:窗户有撬痕(Observation)
→ 推理:"撬痕是新的,说明确实是最近撬的"(Thought)
→ 行动:查附近监控(Action)
→ 观察:监控拍到可疑人物(Observation)
→ ...逐步逼近真相侦探不会"一次想完全案",他是边查边想。 Agent 也是。这就是为什么复杂问题需要 Agent,而不是一次性问答。
agents-go 的循环如何映射 ReAct
回看第 1 章的循环,现在你能看到 ReAct 的影子:
for turn := 0; turn < maxTurns; turn++ {
// ① 模型调用(含 Thought + 可能的 Action)
resp := model.GetResponse(history, tools)
if len(resp.ToolCalls) == 0 {
return resp.Content // Final Answer
}
// ② 执行工具(Action → Observation)
for _, call := range resp.ToolCalls {
result := executeTool(call)
history = append(history, result) // Observation 加入历史
}
// ③ 回到 ①,带着 Observation 重新推理
}每一轮循环就是一次 Thought-Action-Observation。 只不过 agents-go 把"Thought"隐含在模型调用里(模型的内部推理),把"Action"显式化为工具调用。
现代 LLM 的"隐藏 Thought"
o1/o3/Claude 等推理模型,会把 Thought 显式输出(reasoning item)。agents-go 的 processModelResponse(第 4 章)保留了 ReasoningItem,你能看到模型"想了什么"。
这让 Agent 的推理过程可观察、可审计,这是比"黑盒调工具"进步的地方。
为什么不是所有问题都需要 Agent
ReAct 揭示了 Agent 适合的场景,需要"边查边想"的复杂问题。但不是所有问题都这样:
| 问题类型 | 需要 Agent 吗 | 为什么 |
|---|---|---|
| "法国首都是哪" | ❌ 不需要 | 模型训练数据里有,直接答 |
| "总结这篇文章" | ❌ 不需要 | 信息都在输入里,一次生成够 |
| "写一首关于春天的诗" | ❌ 不需要 | 创作不需要外部信息 |
| "查北京天气" | ⚠️ 简单 Agent | 一次工具调用就够 |
| "分析销售下滑原因" | ✅ 需要 Agent | 要查多个数据源,边查边推理 |
| "帮我订机票并安排行程" | ✅ 需要 Agent | 多步骤、要反馈、要决策 |
| "调试这段报错的代码" | ✅ 需要 Agent | 要读代码、跑测试、改代码、再验证 |
判断标准,"这个问题需要边获取信息边推理吗?" 需要 → Agent。不需要 → 普通对话或单次工具调用就够。
别过度用 Agent。 简单问题用 Agent 是杀鸡用牛刀(慢、贵、没必要)。第 1 章讲的"任务分型"就是帮你判断这个的。
ReAct 的局限:模型可能"想歪"
ReAct 不是万能的。它的风险,模型的 Thought 可能推理错误,导致 Action 选错,进入死胡同。
Thought: 销售下滑可能因为竞品降价。我查竞品价格。
Action: get_competitor_prices() ← 这个推理方向可能是错的
Observation: 竞品没降价
Thought: 奇怪,那是什么原因?再查别的...
(在错误方向上浪费轮次)这是 Agent 的固有风险,概率性系统的特性。 模型的推理不是确定性的,可能走弯路。缓解措施:
- 清晰的指令,告诉模型"先查销售数据,再查库存,再查促销",减少它乱猜
- 工具的好 description,让模型知道有什么工具可用,减少选错
- MaxTurns 兜底,防止在死胡同里无限循环
第 42 章会深入"概率性系统的工程哲学",怎么让不确定的 Agent 输出确定的结果。
小结
读完这一章,你应该理解:
- ReAct 是 Agent 的理论基础,推理与行动交织,比纯推理或纯行动有效
- Agent 循环 = Thought-Action-Observation 循环,agents-go 的实现映射 ReAct
- Agent 解决的是"信息获取"问题,让模型能在推理中主动查信息
- 不是所有问题都需要 Agent,"边查边想"的才需要
- ReAct 的局限,模型推理可能走弯路(概率性风险)
理解了 ReAct,你就理解了 Agent"为什么这样设计"的根本原因,不是为了炫技,是因为这种架构最符合复杂问题的解决方式。
下一篇
第 42 章,概率性系统的工程哲学。Agent 的输出是不确定的(同一个输入可能不同结果),这和传统软件"确定性"完全不同。怎么给不确定性加边界、加验证、加兜底?这是 Agent 工程化的核心难题。
本文是《从 0 写 Agent》系列第 41 章,案例代码基于开源项目 agents-go(OpenAI Agents SDK 的 Go 移植版)。全系列目录见总览。
