🧠 Reasoning + Acting | 思维链 + 工具调用 | 数学原理 + 代码实现 | LangChain实战 | 完整项目代码
📖 什么是ReAct框架?
核心思想
ReAct = Reasoning(推理)+ Acting(行动)
传统LLM: 输入 → 直接输出答案
ReAct: 输入 → 思考 → 行动 → 观察 → 思考 → 行动 → ... → 输出
关键洞察:
- 人类解决问题时,会交替进行"思考"和"行动"
- 纯思维链(CoT)缺乏外部信息
- 纯工具调用缺乏推理过程
- ReAct结合两者优势
为什么需要ReAct?
问题1:纯LLM的局限
# 问题:2023年诺贝尔文学奖得主的出生地人口是多少?
# 纯LLM回答
llm.invoke("2023年诺贝尔文学奖得主的出生地人口是多少?")
# 输出: "抱歉,我不知道" ❌
# 原因:训练数据截止,无法获取最新信息
问题2:纯工具调用的局限
# 直接调用搜索工具
search("2023年诺贝尔文学奖得主")
# 输出: "Jon Fosse"
search("Jon Fosse 出生地")
# 输出: "Haugesund, Norway"
search("Haugesund 人口")
# 输出: "37,000"
# 问题:
# - 没有推理过程,难以调试
# - 无法处理复杂逻辑
# - 容易陷入死循环
ReAct的解决方案
Thought: 我需要先找到2023年诺贝尔文学奖得主
Action: search["2023年诺贝尔文学奖得主"]
Observation: Jon Fosse
Thought: 现在我知道得主是Jon Fosse,需要找他的出生地
Action: search["Jon Fosse 出生地"]
Observation: Haugesund, Norway
Thought: 我找到了出生地是Haugesund,现在需要查这个城市的人口
Action: search["Haugesund 人口"]
Observation: 37,000
Thought: 我已经获得了所有信息,可以给出最终答案
Final Answer: 2023年诺贝尔文学奖得主Jon Fosse的出生地Haugesund人口约为37,000人 ✅
优势:
- ✅ 有清晰的推理过程
- ✅ 可以获取实时信息
- ✅ 易于调试和优化
- ✅ 可解释性强
🏗️ ReAct架构详解
核心组件
┌─────────────────────────────────────────┐
│ ReAct Agent │
├─────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ Thought │───→│ Action │ │
│ │ (推理) │ │ (行动) │ │
│ └──────────┘ └────┬─────┘ │
│ ↑ │ │
│ │ ┌────▼─────┐ │
│ │ │Observation│ │
│ │ │ (观察) │ │
│ │ └──────────┘ │
│ │ │ │
│ └───────────────┘ │
│ 迭代循环 │
└─────────────────────────────────────────┘
执行流程
Step 1: 接收用户问题
↓
Step 2: Thought - 分析问题,决定下一步
↓
Step 3: Action - 选择并执行工具
↓
Step 4: Observation - 获取工具返回结果
↓
Step 5: 判断是否完成?
├─ 是 → Final Answer
└─ 否 → 回到 Step 2
状态机模型
class ReActState:
"""ReAct状态机"""
def __init__(self):
self.question: str = "" # 原始问题
self.thoughts: List[str] = [] # 思考历史
self.actions: List[dict] = [] # 行动历史
self.observations: List[str] = [] # 观察历史
self.final_answer: str = None # 最终答案
self.step_count: int = 0 # 步数计数
self.max_steps: int = 10 # 最大步数
🛠️ ReAct数学原理
形式化定义
ReAct可以看作一个马尔可夫决策过程(MDP):
状态空间 S:
- s_t = (q, h_t)
- q: 原始问题
- h_t: 历史轨迹 {(thought_1, action_1, obs_1), ..., (thought_t, action_t, obs_t)}
动作空间 A:
- a_t ∈ {Tool_1, Tool_2, ..., Tool_n, Finish}
- 可以选择的工具或结束
转移函数 T:
- s_{t+1} = T(s_t, a_t)
- 执行动作a_t,获得观察obs_t,更新历史
奖励函数 R:
- R = 1 如果最终答案正确
- R = 0 否则
目标:
- 最大化期望奖励:max E[R | policy]
- policy: π(a_t | s_t) - 策略函数
与传统方法的对比
| 方法 | 公式 | 特点 |
|---|---|---|
| Standard Prompting | P(y | x) | 直接生成答案 |
| Chain-of-Thought | P(y, r | x) | 生成推理+答案 |
| Tool Use | P(a | x) → y | 选择工具→执行 |
| ReAct | P(r, a, o | x, h) | 推理+行动+观察 |
其中:
- x: 输入问题
- y: 最终答案
- r: 推理(thought)
- a: 行动(action)
- o: 观察(observation)
- h: 历史轨迹
💻 ReAct代码实现
方案1:从零实现ReAct
from typing import List, Dict, Optional
import re
class ReActAgent:
"""ReAct Agent实现"""
def __init__(self, llm, tools: List[callable], max_steps: int = 10):
self.llm = llm
self.tools = {tool.__name__: tool for tool in tools}
self.max_steps = max_steps
# 历史记录
self.thoughts = []
self.actions = []
self.observations = []
def run(self, question: str) -> str:
"""运行ReAct流程
Args:
question: 用户问题
Returns:
最终答案
"""
print(f"🤔 问题: {question}\n")
for step in range(self.max_steps):
print(f"--- Step {step + 1} ---")
# Step 1: Thought - 生成思考
thought = self._generate_thought(question)
self.thoughts.append(thought)
print(f"💭 Thought: {thought}")
# Step 2: Action - 解析并执行行动
action_name, action_input = self._parse_action(thought)
if action_name == "Finish":
# 完成任务
final_answer = action_input
print(f"✅ Final Answer: {final_answer}")
return final_answer
# 执行工具
if action_name in self.tools:
observation = self.tools[action_name](action_input)
self.actions.append({"name": action_name, "input": action_input})
self.observations.append(observation)
print(f"🔧 Action: {action_name}({action_input})")
print(f"👁️ Observation: {observation}\n")
else:
observation = f"未知工具: {action_name}"
print(f"❌ {observation}\n")
# 超过最大步数
return "抱歉,我无法在限定步数内解决这个问题"
def _generate_thought(self, question: str) -> str:
"""生成思考内容"""
# 构建提示词
history = self._format_history()
prompt = f"""你是一个智能助手,使用ReAct框架解决问题。
可用工具:
{self._format_tools()}
当前问题:{question}
{history}
请按照以下格式回答:
Thought: <你的思考>
Action: <工具名>[<参数>]
或者如果你已经知道答案:
Thought: 我已经知道了答案
Action: Finish[<最终答案>]
"""
response = self.llm.invoke(prompt).content
return response
def _parse_action(self, thought: str) -> tuple:
"""解析行动"""
# 提取Action行
action_match = re.search(r'Action:\s*(\w+)\[(.+?)\]', thought)
if action_match:
action_name = action_match.group(1)
action_input = action_match.group(2)
return action_name, action_input
# 如果没有找到Action,默认Finish
return "Finish", thought
def _format_history(self) -> str:
"""格式化历史记录"""
if not self.thoughts:
return ""
history_parts = []
for i, (thought, obs) in enumerate(zip(self.thoughts, self.observations)):
history_parts.append(f"Step {i+1}:")
history_parts.append(f"Thought: {thought}")
if i < len(self.actions):
action = self.actions[i]
history_parts.append(f"Action: {action['name']}[{action['input']}]")
if obs:
history_parts.append(f"Observation: {obs}")
history_parts.append("")
return "\n".join(history_parts)
def _format_tools(self) -> str:
"""格式化工具列表"""
tools_desc = []
for name, tool in self.tools.items():
doc = tool.__doc__ or "无描述"
tools_desc.append(f"- {name}: {doc.split(chr(10))[0]}")
return "\n".join(tools_desc)
# ==================== 工具定义 ====================
def search(query: str) -> str:
"""搜索网络信息"""
# 模拟搜索引擎
knowledge_base = {
"2023年诺贝尔文学奖得主": "Jon Fosse",
"Jon Fosse 出生地": "Haugesund, Norway",
"Haugesund 人口": "37,000",
"Python最新版本": "Python 3.12",
"北京天气": "晴,25°C"
}
return knowledge_base.get(query, f"未找到'{query}'的信息")
def calculate(expression: str) -> str:
"""计算数学表达式"""
try:
result = eval(expression, {"__builtins__": {}}, {})
return str(result)
except:
return "计算错误"
# ==================== 使用示例 ====================
def example_react_agent():
"""ReAct Agent使用示例"""
from langchain_openai import ChatOpenAI
# 创建LLM
llm = ChatOpenAI(model="gpt-4", temperature=0)
# 创建Agent
agent = ReActAgent(
llm=llm,
tools=[search, calculate],
max_steps=10
)
# 测试问题
question = "2023年诺贝尔文学奖得主的出生地人口是多少?"
answer = agent.run(question)
print(f"\n🎯 最终答案: {answer}")
if __name__ == "__main__":
example_react_agent()
方案2:使用LangChain ReAct
from langchain.agents import create_react_agent, AgentExecutor
from langchain.tools import tool
from langchain_openai import ChatOpenAI
from langchain.prompts import PromptTemplate
# 定义工具
@tool
def search_knowledge(query: str) -> str:
"""搜索知识库获取信息"""
knowledge_base = {
"2023年诺贝尔文学奖": "Jon Fosse",
"Jon Fosse": "挪威作家,出生于Haugesund",
"Haugesund": "挪威城市,人口约37,000"
}
for key, value in knowledge_base.items():
if key in query:
return value
return "未找到相关信息"
@tool
def calculate_math(expression: str) -> str:
"""计算数学表达式"""
try:
result = eval(expression, {"__builtins__": {}}, {})
return str(result)
except:
return "计算错误"
# 创建ReAct Agent
def create_react_agent_example():
"""创建LangChain ReAct Agent"""
llm = ChatOpenAI(model="gpt-4", temperature=0)
tools = [search_knowledge, calculate_math]
# ReAct提示词模板
react_prompt = PromptTemplate.from_template("""
Answer the following questions as best you can. You have access to the following tools:
{tools}
Use the following format:
Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should be one of [{tool_names}]
Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question
Begin!
Question: {input}
Thought:{agent_scratchpad}
""")
# 创建Agent
agent = create_react_agent(llm, tools, react_prompt)
# 创建执行器
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True,
max_iterations=10,
handle_parsing_errors=True
)
return agent_executor
# 使用示例
def example_langchain_react():
"""LangChain ReAct示例"""
agent = create_react_agent_example()
question = "2023年诺贝尔文学奖得主的出生地人口是多少?"
result = agent.invoke({"input": question})
print(f"\n✅ 答案: {result['output']}")
if __name__ == "__main__":
example_langchain_react()
🎯 ReAct优化技巧
1. 提示词工程优化
# 好的ReAct提示词
react_prompt = """
你是一个智能助手,使用ReAct框架逐步解决问题。
可用工具:
- search: 搜索信息
- calculate: 数学计算
- get_weather: 查询天气
重要规则:
1. 每次只执行一个动作
2. 仔细观察每个动作的结果
3. 基于观察结果进行下一步推理
4. 当确信知道答案时,使用Finish
格式:
Thought: <推理过程>
Action: <工具名>[<参数>]
Observation: <工具返回>
...
Final Answer: <最终答案>
"""
2. 工具设计优化
# 好的工具设计
@tool
def search_precise(query: str) -> str:
"""精确搜索特定信息
参数应该是具体的查询词,如:
- "2023年诺贝尔文学奖得主"
- "Python 3.12发布日期"
避免模糊查询。
"""
pass
# 不好的工具设计
@tool
def search(x):
"""搜索"""
pass
3. 早期停止策略
class SmartReActAgent(ReActAgent):
"""智能ReAct Agent - 带早期停止"""
def _should_stop(self, thought: str, observation: str) -> bool:
"""判断是否应该停止"""
# 策略1:观察到明确答案
if "答案是" in observation or "结果是" in observation:
return True
# 策略2:重复观察(可能陷入循环)
if observation in self.observations[-3:]:
return True
# 策略3:达到置信度阈值
confidence = self._estimate_confidence(thought, observation)
if confidence > 0.9:
return True
return False
def _estimate_confidence(self, thought: str, observation: str) -> float:
"""估计答案置信度"""
# 简化实现:基于关键词
confidence_keywords = ["确定", "确认", "显然是", "毫无疑问"]
score = sum(1 for kw in confidence_keywords if kw in thought)
return min(score / len(confidence_keywords), 1.0)
4. 并行探索(Tree of Thoughts扩展)
class ParallelReActAgent(ReActAgent):
"""并行ReAct - 同时探索多个思路"""
def run_parallel(self, question: str, num_paths: int = 3) -> str:
"""并行运行多个ReAct路径"""
results = []
for i in range(num_paths):
# 每个路径独立运行
agent_copy = self.clone()
result = agent_copy.run(question)
results.append({
"path": i + 1,
"answer": result,
"steps": agent_copy.step_count
})
# 投票选择最佳答案
best_answer = self._vote(results)
return best_answer
def _vote(self, results: List[dict]) -> str:
"""投票机制"""
# 统计相同答案的出现次数
answer_counts = {}
for r in results:
answer = r["answer"]
answer_counts[answer] = answer_counts.get(answer, 0) + 1
# 返回出现最多的答案
return max(answer_counts, key=answer_counts.get)
📊 ReAct性能评估
评估指标
| 指标 | 说明 | 目标值 |
|---|---|---|
| 准确率 | 正确答案比例 | > 85% |
| 平均步数 | 完成任务的平均步数 | < 5步 |
| 成功率 | 成功完成任务的比例 | > 90% |
| 响应时间 | 从输入到输出的时间 | < 10秒 |
| Token消耗 | 每次任务的Token数 | < 2000 |
基准测试
def benchmark_react():
"""ReAct性能基准测试"""
test_cases = [
{
"question": "2023年诺贝尔文学奖得主的出生地人口是多少?",
"expected_answer": "37000"
},
{
"question": "计算 (123 + 456) * 789",
"expected_answer": "456831"
},
{
"question": "Python的最新版本是什么?",
"expected_answer": "3.12"
}
]
agent = ReActAgent(llm, tools=[search, calculate])
results = []
for test in test_cases:
start_time = time.time()
answer = agent.run(test["question"])
elapsed = time.time() - start_time
# 评估准确性
is_correct = test["expected_answer"] in answer
results.append({
"question": test["question"],
"correct": is_correct,
"steps": agent.step_count,
"time": elapsed
})
# 统计结果
accuracy = sum(1 for r in results if r["correct"]) / len(results)
avg_steps = sum(r["steps"] for r in results) / len(results)
avg_time = sum(r["time"] for r in results) / len(results)
print(f"准确率: {accuracy:.2%}")
print(f"平均步数: {avg_steps:.1f}")
print(f"平均时间: {avg_time:.2f}秒")
🔍 ReAct vs 其他框架
对比分析
| 框架 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| ReAct | 推理+行动,可解释性强 | 步数多,速度慢 | 复杂多步任务 |
| CoT | 简单快速 | 无法获取外部信息 | 纯推理任务 |
| Toolformer | 自动学习工具使用 | 训练成本高 | 大规模部署 |
| Self-Ask | 分解子问题 | 需要预定义分解 | 结构化问题 |
选择建议
任务类型判断:
├─ 需要外部信息?
│ ├─ 是 → ReAct 或 Self-Ask
│ └─ 否 → CoT
│
├─ 需要多步推理?
│ ├─ 是 → ReAct
│ └─ 否 → Standard Prompting
│
└─ 需要高可解释性?
├─ 是 → ReAct
└─ 否 → Toolformer
💡 最佳实践总结
1. 提示词设计
# ✅ 好的提示词
prompt = """
按以下步骤思考:
1. 理解问题的核心
2. 确定需要的信息
3. 选择合适的工具
4. 执行并观察结果
5. 基于结果继续推理
"""
# ❌ 不好的提示词
prompt = "回答问题"
2. 工具粒度
# ✅ 细粒度工具(推荐)
@tool
def search_person(name: str): ...
@tool
def search_place(place: str): ...
@tool
def search_number(query: str): ...
# ❌ 粗粒度工具
@tool
def search_anything(query: str): ...
3. 错误处理
try:
observation = tool(action_input)
except Exception as e:
observation = f"工具执行失败: {str(e)}"
# 在下一步Thought中处理错误
4. 调试技巧
# 启用详细日志
agent = ReActAgent(llm, tools, verbose=True)
# 保存执行轨迹
trajectory = {
"thoughts": agent.thoughts,
"actions": agent.actions,
"observations": agent.observations
}
save_to_file(trajectory, "debug.json")
🔗 相关资源
📝 总结
ReAct框架通过结合推理(Reasoning)和行动(Acting),让Agent能够:
✅ 像人类一样思考 - 清晰的推理过程
✅ 获取外部信息 - 调用工具弥补知识盲区
✅ 自我修正 - 基于观察调整策略
✅ 可解释性强 - 每一步都有据可查
掌握ReAct框架,你就能构建出真正智能的Agent系统!
下一步: 动手实现一个ReAct Agent,从简单的问答开始,逐步增加复杂度。
专栏: AI Agent实战专栏
日期: 2026年5月12日
系列: Agent底层原理与前沿技术系列第1篇