什么是ReactAgent?
ReactAgent是基于**ReAct(Reasoning and Acting)范式的智能体架构,让大模型通过交替进行推理(Reasoning)和行动(Acting)**来解决复杂任务。
传统方法的局限
在ReAct出现之前,AI解决问题主要有两种方式:
方式1:纯推理(Chain-of-Thought)
用户问题:明天北京的天气怎么样?
AI思考过程:
1. 用户想知道明天北京的天气
2. 这需要实时天气数据
3. 我的知识截止到2024年1月
4. 因此我无法准确回答
AI回答:抱歉,我无法获取实时天气信息...
问题:只能思考,无法采取实际行动获取信息。
方式2:纯行动(Action-Only)
用户问题:明天北京的天气怎么样?
系统:检测到"天气"关键词
→ 调用天气API(location="北京", date="明天")
→ 返回:晴天,10-20°C
AI回答:明天北京晴天,温度10-20°C
问题:无法处理复杂的多步骤任务,缺乏灵活性。
ReAct:思考与行动的结合
ReAct将推理和行动交织在一起:
用户问题:明天北京的天气怎么样?
Thought 1: 我需要查询明天北京的天气信息
Action 1: search_weather(location="北京", date="明天")
Observation 1: {"weather": "晴", "temp": "10-20°C"}
Thought 2: 我已经获得了天气信息,可以回答用户了
Action 2: finish(answer="明天北京是晴天,温度在10-20°C之间")
优势:
- 有思考:知道该做什么
- 有行动:能够执行工具获取信息
- 有观察:根据反馈调整策略
ReAct的核心概念
三大组件
ReAct循环包含三个核心组件:
┌─────────────────────────────────────┐
│ Thought (思考) │
│ 分析当前情况,规划下一步 │
└─────────────┬───────────────────────┘
↓
┌─────────────────────────────────────┐
│ Action (行动) │
│ 执行具体操作(调用工具/API) │
└─────────────┬───────────────────────┘
↓
┌─────────────────────────────────────┐
│ Observation (观察) │
│ 获取行动结果,作为下一步输入 │
└─────────────┬───────────────────────┘
↓
(回到Thought)
Thought(思考)
作用:
- 分析当前任务状态
- 规划下一步行动
- 决定是否需要更多信息
示例:
Thought 1: 用户想知道埃隆·马斯克的年龄,我需要查询最新信息
Thought 2: 我已经知道他的出生日期(1971年6月28日),现在需要计算年龄
Thought 3: 计算完成,我可以给出最终答案了
Action(行动)
作用:
- 调用外部工具/API
- 执行具体操作
- 与环境交互
常见操作:
# 搜索操作
Action: search("Elon Musk age")
# 计算操作
Action: calculate("2024 - 1971")
# 结束操作
Action: finish("Elon Musk is 53 years old")
Observation(观察)
作用:
- 接收行动的反馈
- 提供给下一轮思考
- 更新任务状态
示例:
Observation 1: 搜索结果显示埃隆·马斯克出生于1971年6月28日
Observation 2: 计算结果为53
ReAct的工作流程
完整示例
任务:查询"北京到上海的高铁票价"
User: 北京到上海的高铁票价是多少?
Thought 1: 用户想知道北京到上海的高铁票价,我需要查询交通信息
Action 1: search_train("北京", "上海")
Observation 1: 查询结果:二等座553元,一等座933元,商务座1748元
Thought 2: 我已经获得了票价信息,但用户可能想知道最常见的二等座价格
Action 2: finish("北京到上海的高铁二等座票价是553元,一等座933元,商务座1748元")
流程图
开始
↓
[用户输入问题]
↓
┌─────────────────────┐
│ 大模型生成Thought │ ← 理解任务,规划行动
└──────────┬──────────┘
↓
┌─────────────────────┐
│ 大模型生成Action │ ← 决定执行什么操作
└──────────┬──────────┘
↓
需要工具?
↙ ↘
是 否(finish)
↓ ↓
[调用工具] [返回答案]
↓ ↓
[Observation] 结束
↓
添加到上下文
↓
回到Thought
实现ReactAgent
基础版本
import re
from typing import List, Dict, Callable
class ReactAgent:
def __init__(self, llm, tools: Dict[str, Callable], max_steps: int = 10):
"""
llm: 大语言模型(如GPT-4、Claude等)
tools: 可用工具字典 {"工具名": 工具函数}
max_steps: 最大循环步数
"""
self.llm = llm
self.tools = tools
self.max_steps = max_steps
def run(self, question: str) -> str:
"""运行ReAct循环"""
# 初始化上下文
context = f"Question: {question}\n\n"
for step in range(1, self.max_steps + 1):
# 1. 生成Thought和Action
prompt = self._build_prompt(context, step)
response = self.llm.generate(prompt)
# 2. 解析响应
thought, action, action_input = self._parse_response(response)
# 3. 记录Thought
context += f"Thought {step}: {thought}\n"
# 4. 执行Action
if action == "finish":
# 任务完成
return action_input
if action not in self.tools:
context += f"Action {step}: {action}({action_input})\n"
context += f"Observation {step}: Error - Unknown action '{action}'\n"
continue
# 调用工具
try:
observation = self.tools[action](action_input)
context += f"Action {step}: {action}({action_input})\n"
context += f"Observation {step}: {observation}\n\n"
except Exception as e:
context += f"Action {step}: {action}({action_input})\n"
context += f"Observation {step}: Error - {str(e)}\n\n"
return "达到最大步数限制,任务未完成"
def _build_prompt(self, context: str, step: int) -> str:
"""构建prompt"""
return f"""你是一个智能助手,可以通过思考和行动来回答问题。
可用工具:
{self._format_tools()}
你必须按照以下格式回答:
Thought: 分析当前情况,决定下一步
Action: 工具名称
Action Input: 工具参数
或者,当你有了最终答案:
Thought: 我已经有了答案
Action: finish
Action Input: 最终答案
{context}
现在开始思考第{step}步:"""
def _format_tools(self) -> str:
"""格式化工具描述"""
tool_desc = []
for name, func in self.tools.items():
doc = func.__doc__ or "无描述"
tool_desc.append(f"- {name}: {doc}")
return "\n".join(tool_desc)
def _parse_response(self, response: str):
"""解析模型响应"""
thought_pattern = r"Thought:\s*(.+?)(?=\n|$)"
action_pattern = r"Action:\s*(.+?)(?=\n|$)"
input_pattern = r"Action Input:\s*(.+?)(?=\n|$)"
thought = re.search(thought_pattern, response)
action = re.search(action_pattern, response)
action_input = re.search(input_pattern, response)
thought = thought.group(1).strip() if thought else ""
action = action.group(1).strip() if action else ""
action_input = action_input.group(1).strip() if action_input else ""
return thought, action, action_input
定义工具
def search_web(query: str) -> str:
"""在网上搜索信息"""
# 实际应该调用搜索API
# 这里用模拟数据
mock_results = {
"埃隆马斯克年龄": "埃隆·马斯克出生于1971年6月28日",
"北京天气": "北京今天晴,温度15-25°C",
}
for key, value in mock_results.items():
if key in query:
return value
return "未找到相关信息"
def calculate(expression: str) -> str:
"""执行数学计算"""
try:
result = eval(expression)
return str(result)
except Exception as e:
return f"计算错误: {str(e)}"
def get_current_time() -> str:
"""获取当前时间"""
from datetime import datetime
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 工具字典
tools = {
"search": search_web,
"calculate": calculate,
"get_time": get_current_time,
}
使用示例
# 初始化Agent
agent = ReactAgent(
llm=your_llm_model, # 你的语言模型
tools=tools,
max_steps=5
)
# 运行
question = "埃隆·马斯克今年多少岁?"
answer = agent.run(question)
print(answer)
执行过程:
Question: 埃隆·马斯克今年多少岁?
Thought 1: 我需要查询埃隆·马斯克的出生日期
Action 1: search("埃隆马斯克年龄")
Observation 1: 埃隆·马斯克出生于1971年6月28日
Thought 2: 我知道他出生于1971年,现在需要计算他的年龄
Action 2: calculate("2024 - 1971")
Observation 2: 53
Thought 3: 计算完成,我可以给出答案了
Action 3: finish("埃隆·马斯克今年53岁(出生于1971年6月28日)")
最终答案:埃隆·马斯克今年53岁(出生于1971年6月28日)
Prompt工程:让模型学会ReAct
核心要素
一个好的ReAct prompt需要包含:
- 角色定义:明确Agent的身份
- 工具描述:列出可用工具及其用法
- 格式示范:通过Few-shot展示ReAct格式
- 约束规则:限制行为,避免错误
完整Prompt模板
REACT_PROMPT = """你是一个能够使用工具解决问题的智能助手。
你可以使用以下工具:
{tool_descriptions}
请严格按照以下格式回答:
Thought: 你对当前情况的思考
Action: 工具名称
Action Input: 传给工具的参数
当你获得观察结果后,继续思考:
Thought: 基于观察结果的思考
Action: 下一个工具
Action Input: 参数
或者,当你有最终答案时:
Thought: 我现在知道最终答案了
Action: finish
Action Input: [你的最终答案]
重要规则:
1. 每次只执行一个Action
2. 必须先Thought再Action
3. 不要编造观察结果
4. 如果工具返回错误,重新思考并尝试其他方法
以下是一些例子:
--- 例子 1 ---
Question: 今天是几号?北京的天气怎么样?
Thought 1: 我需要先获取当前日期
Action 1: get_time
Action Input 1:
Observation 1: 2024-03-15 14:30:00
Thought 2: 现在我知道是3月15日,需要查询北京天气
Action 2: search
Action Input 2: 北京天气
Observation 2: 北京今天晴,温度15-25°C
Thought 3: 我已经有了完整答案
Action 3: finish
Action Input 3: 今天是2024年3月15日,北京天气晴朗,温度在15-25°C之间
--- 例子 2 ---
Question: 123 * 456 等于多少?
Thought 1: 这是一个数学计算问题,我应该使用计算器工具
Action 1: calculate
Action Input 1: 123 * 456
Observation 1: 56088
Thought 2: 计算完成,我可以回答了
Action 2: finish
Action Input 2: 123 * 456 = 56088
---
现在开始回答新问题:
Question: {question}
"""
Few-shot示例的重要性
没有Few-shot:模型容易犯错
❌ 错误示例:
Question: 明天北京天气?
Thought: 我需要查天气
我去搜索一下
答案是晴天
(混乱,没有结构)
有Few-shot:模型遵循格式
✅ 正确示例:
Question: 明天北京天气?
Thought 1: 我需要查询明天北京的天气
Action 1: search
Action Input 1: 明天北京天气
Observation 1: 明天北京晴,10-20°C
Thought 2: 我已经获得答案
Action 2: finish
Action Input 2: 明天北京是晴天,温度10-20°C
常见问题与解决方案
问题1:模型不遵循格式
症状:
Thought: 我需要搜索
让我来搜索一下吧,我觉得应该是...
(模型开始自由发挥)
解决方案:
- 强化格式约束:
def enforce_format(response: str) -> str:
"""强制检查格式"""
required_keywords = ["Thought:", "Action:", "Action Input:"]
for keyword in required_keywords:
if keyword not in response:
return f"错误:响应缺少必需的关键词 '{keyword}'。请重新按格式输出。"
return response
- 使用结构化输出(如果模型支持):
# OpenAI Function Calling
response = openai.ChatCompletion.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}],
functions=[{
"name": "react_step",
"parameters": {
"type": "object",
"properties": {
"thought": {"type": "string"},
"action": {"type": "string"},
"action_input": {"type": "string"}
},
"required": ["thought", "action", "action_input"]
}
}],
function_call={"name": "react_step"}
)
问题2:无限循环
症状:
Thought 1: 我需要搜索
Action 1: search("天气")
Observation 1: 未找到信息
Thought 2: 我需要搜索
Action 2: search("天气")
Observation 2: 未找到信息
(重复相同操作)
解决方案:
- 检测重复行动:
class ReactAgent:
def __init__(self, ...):
self.action_history = [] # 记录历史行动
def run(self, question: str):
for step in range(self.max_steps):
# ... 生成action ...
# 检测重复
if (action, action_input) in self.action_history:
context += "Warning: 你刚才已经尝试过这个操作了,请尝试其他方法\n"
continue
self.action_history.append((action, action_input))
# ... 执行action ...
- 添加反思机制:
def add_reflection(context: str, step: int) -> str:
"""每3步添加反思"""
if step % 3 == 0:
return context + "\n[Reflection: 回顾一下目前的进展,是否需要改变策略?]\n"
return context
问题3:工具使用错误
症状:
Action: search
Action Input: {"query": "天气", "location": "北京"}
(工具只接受字符串,不接受JSON)
解决方案:
- 明确工具签名:
def search_web(query: str) -> str:
"""
在网上搜索信息
参数:
query (str): 搜索关键词,纯文本字符串
示例:
search_web("北京天气")
search_web("埃隆马斯克年龄")
"""
# ...
- 参数验证:
def validate_and_call_tool(tool_name: str, tool_input: str):
"""验证并调用工具"""
tool = tools[tool_name]
# 获取函数签名
import inspect
sig = inspect.signature(tool)
# 检查参数类型
if len(sig.parameters) == 1:
# 单参数,直接传入
return tool(tool_input)
else:
# 多参数,尝试解析JSON
import json
try:
kwargs = json.loads(tool_input)
return tool(**kwargs)
except:
return f"Error: 参数格式错误。工具需要{len(sig.parameters)}个参数"
问题4:过早结束
症状:
Thought 1: 我需要查询天气
Action 1: finish
Action Input 1: 我需要查询天气
(还没查询就结束了)
解决方案:
- 延迟finish:
def can_finish(context: str, step: int) -> bool:
"""判断是否可以结束"""
# 至少执行2步才能finish
if step < 2:
return False
# 检查是否至少调用了一次工具
if "Observation" not in context:
return False
return True
- 添加验证问题:
PROMPT_WITH_VERIFICATION = """
...
在使用finish之前,问自己:
1. 我是否已经获得了足够的信息?
2. 我的答案是否直接回答了用户的问题?
3. 答案是否准确完整?
只有当你对以上三个问题的回答都是"是"时,才能使用finish。
"""
进阶优化
1. 自我修正(Self-Correction)
让Agent能够识别并修正自己的错误:
def add_self_correction(context: str) -> str:
"""添加自我修正机制"""
return context + """
[Self-Check] 在继续之前,检查:
- 上一步的操作是否成功?
- 观察结果是否合理?
- 如果失败,原因是什么?
- 需要调整策略吗?
"""
示例:
Thought 1: 我需要搜索"北京天气明天"
Action 1: search("北京天气明天")
Observation 1: 未找到相关信息
[Self-Check]
Thought 2: 搜索失败了,可能是查询词太具体。我应该简化查询
Action 2: search("北京天气")
Observation 2: 北京今天晴,明天多云...
(成功修正)
2. 记忆机制(Memory)
让Agent记住之前的交互:
class ReactAgentWithMemory:
def __init__(self, ...):
self.short_term_memory = [] # 当前会话的记忆
self.long_term_memory = [] # 跨会话的记忆
def run(self, question: str):
# 添加相关记忆到上下文
relevant_memories = self.retrieve_memories(question)
context = f"Relevant past experiences:\n{relevant_memories}\n\n"
# ... 正常ReAct循环 ...
# 保存这次的经验
self.save_memory(question, answer, steps_taken)
def retrieve_memories(self, question: str) -> str:
"""检索相关记忆"""
# 简化版:关键词匹配
relevant = [m for m in self.long_term_memory
if any(word in m["question"] for word in question.split())]
return "\n".join([f"- {m['summary']}" for m in relevant[:3]])
def save_memory(self, question: str, answer: str, steps: int):
"""保存记忆"""
memory = {
"question": question,
"answer": answer,
"steps": steps,
"summary": f"问题:{question[:20]},用了{steps}步"
}
self.long_term_memory.append(memory)
3. 并行工具调用
同时调用多个工具,提升效率:
def run_parallel(self, question: str):
"""支持并行工具调用"""
# ... 前面步骤相同 ...
# 解析是否有并行请求
if "parallel" in response.lower():
# 提取多个action
actions = self._parse_parallel_actions(response)
# 并行执行
from concurrent.futures import ThreadPoolExecutor
with ThreadPoolExecutor() as executor:
futures = [executor.submit(self.tools[a], inp)
for a, inp in actions]
observations = [f.result() for f in futures]
# 合并观察结果
for i, obs in enumerate(observations):
context += f"Observation {step}.{i+1}: {obs}\n"
使用示例:
Question: 北京和上海今天的天气分别是什么?
Thought 1: 我需要同时查询两个城市的天气
Action 1: parallel
Action Input 1:
- search("北京天气")
- search("上海天气")
Observation 1.1: 北京今天晴,15-25°C
Observation 1.2: 上海今天多云,18-26°C
Thought 2: 我已经获得了两个城市的天气信息
Action 2: finish
Action Input 2: 北京今天晴天(15-25°C),上海今天多云(18-26°C)
4. 分层规划(Hierarchical Planning)
将复杂任务分解为子任务:
def hierarchical_react(self, question: str):
"""分层ReAct"""
# 第一阶段:高层规划
plan_prompt = f"""
分解任务:{question}
将其分解为3-5个子任务,每个子任务应该:
1. 明确且可执行
2. 相互独立
3. 完成后能推进整体目标
输出格式:
Subtask 1: ...
Subtask 2: ...
...
"""
plan = self.llm.generate(plan_prompt)
subtasks = self._parse_subtasks(plan)
# 第二阶段:逐个执行子任务
results = []
for i, subtask in enumerate(subtasks):
result = self.run(subtask) # 递归调用ReAct
results.append(result)
# 第三阶段:合并结果
final_prompt = f"""
原始问题:{question}
子任务结果:
{self._format_results(results)}
请基于这些结果给出最终答案。
"""
final_answer = self.llm.generate(final_prompt)
return final_answer
实际应用案例
案例1:数学应用题求解
# 工具定义
def calculator(expression: str) -> str:
"""执行数学计算"""
return str(eval(expression))
def extract_numbers(text: str) -> str:
"""从文本中提取数字"""
import re
numbers = re.findall(r'\d+\.?\d*', text)
return str(numbers)
# 问题
question = """
小明有15个苹果,他给了小红3个,又给了小华5个。
请问小明还剩多少个苹果?
"""
# ReAct过程
"""
Thought 1: 这是一个数学应用题,我需要先提取数字
Action 1: extract_numbers("小明有15个苹果,他给了小红3个,又给了小华5个")
Observation 1: ['15', '3', '5']
Thought 2: 小明初始有15个,给出去3个和5个,需要计算15-3-5
Action 2: calculator("15 - 3 - 5")
Observation 2: 7
Thought 3: 计算完成,小明还剩7个苹果
Action 3: finish("小明还剩7个苹果")
"""
案例2:信息聚合
# 工具定义
def search_news(keyword: str) -> str:
"""搜索最新新闻"""
# 调用新闻API
pass
def summarize(text: str) -> str:
"""总结文本"""
# 调用摘要模型
pass
# 问题
question = "总结一下最近关于AI的重要新闻"
# ReAct过程
"""
Thought 1: 我需要先搜索关于AI的最新新闻
Action 1: search_news("AI人工智能")
Observation 1: [新闻1] OpenAI发布GPT-5... [新闻2] Google推出Gemini Ultra...
Thought 2: 我获得了多条新闻,现在需要总结它们
Action 2: summarize("OpenAI发布GPT-5... Google推出Gemini Ultra...")
Observation 2: 最近AI领域的重要进展包括:1) OpenAI发布更强大的GPT-5...
Thought 3: 总结完成,我可以给出答案了
Action 3: finish("最近AI领域有以下重要新闻:...")
"""
案例3:代码调试助手
# 工具定义
def run_code(code: str) -> str:
"""运行Python代码并返回结果"""
try:
exec_globals = {}
exec(code, exec_globals)
return "代码运行成功"
except Exception as e:
return f"错误:{str(e)}"
def search_error(error_msg: str) -> str:
"""搜索错误解决方案"""
# 调用Stack Overflow API
pass
# 问题
question = """
以下代码有错误,请帮我修复:
```python
def sum_list(lst):
total = 0
for i in range(len(lst)):
total += lst[i+1]
return total
"""
ReAct过程
""" Thought 1: 我需要先运行代码,看看具体错误 Action 1: run_code(code) Observation 1: 错误:IndexError: list index out of range
Thought 2: 出现了索引越界错误,是因为循环中使用了i+1 Action 2: fix_code("将lst[i+1]改为lst[i]") Observation 2: 修复建议已生成
Thought 3: 验证修复后的代码 Action 3: run_code(fixed_code) Observation 3: 代码运行成功
Thought 4: 问题已解决 Action 4: finish("错误原因是循环中使用lst[i+1]导致索引越界,应改为lst[i]") """
## ReAct vs 其他Agent范式
### 1. ReAct vs Chain-of-Thought (CoT)
| 特性 | CoT | ReAct |
|------|-----|-------|
| 核心 | 纯推理 | 推理+行动 |
| 工具使用 | ❌ 不支持 | ✅ 支持 |
| 适用场景 | 数学、逻辑推理 | 需要外部信息的任务 |
| 复杂度 | 低 | 中等 |
**示例对比**:
问题:明天北京的天气?
CoT:
- 用户想知道明天北京的天气
- 这需要实时天气数据
- 我无法获取实时数据 答:抱歉,我无法回答
ReAct: Thought: 需要查询天气 Action: search("明天北京天气") Observation: 晴,15-25°C 答:明天北京晴天,15-25°C
### 2. ReAct vs Plan-and-Execute
| 特性 | Plan-and-Execute | ReAct |
|------|-----------------|-------|
| 规划 | 先完整规划 | 边做边规划 |
| 灵活性 | 低(计划固定) | 高(动态调整) |
| 效率 | 高(无重复规划) | 中(可能重新规划) |
| 容错性 | 低(计划失败需重来) | 高(及时调整) |
**示例对比**:
问题:预订北京到上海的机票
Plan-and-Execute: Plan:
- 查询北京到上海的航班
- 比较价格
- 选择最便宜的
- 预订 Execute: 按计划执行
(问题:如果步骤2发现没有便宜的,计划就失效了)
ReAct: Thought 1: 查询航班 Action 1: search_flights() Observation 1: 所有航班都很贵
Thought 2: 价格太贵了,考虑改坐高铁 Action 2: search_trains() Observation 2: 高铁553元 ... (灵活调整策略)
### 3. ReAct vs ReWOO(Reasoning WithOut Observation)
ReWOO是ReAct的改进版本,特点是**先规划所有行动,再批量执行**。
**ReWOO流程**:
-
Planner: 规划所有步骤(不执行) Plan: #E1 = search("天气") #E2 = search("交通") #E3 = combine(#E1, #E2)
-
Worker: 批量执行所有工具 并行执行 E1, E2
-
Solver: 基于所有结果回答
**对比**:
| 特性 | ReAct | ReWOO |
|------|-------|-------|
| 规划 | 逐步规划 | 一次性规划 |
| 执行 | 串行(等待观察) | 并行(批量执行) |
| Token消耗 | 高(多轮对话) | 低(一次规划) |
| 适应性 | 高 | 低 |
| 速度 | 慢 | 快 |
**选择建议**:
- 任务明确,步骤可预知 → ReWOO
- 任务复杂,需要动态调整 → ReAct
## 最佳实践
### 1. 工具设计原则
**单一职责**:
```python
# ❌ 不好:工具做太多事
def handle_all(action_type, param1, param2):
if action_type == "search":
# 搜索逻辑
elif action_type == "calculate":
# 计算逻辑
# ...
# ✅ 好:每个工具一个职责
def search(query): ...
def calculate(expr): ...
def get_time(): ...
清晰的文档:
def search(query: str) -> str:
"""
在互联网上搜索信息
参数:
query: 搜索关键词,应该是简洁的短语或问题
返回:
搜索结果的摘要文本
示例:
search("埃隆马斯克") → "埃隆·马斯克是..."
search("北京天气") → "北京今天晴..."
注意事项:
- 使用简短关键词,不要太长的句子
- 一次只查询一个主题
"""
pass
错误处理:
def search(query: str) -> str:
try:
result = api.search(query)
if not result:
return "未找到相关信息,请尝试其他关键词"
return result
except RateLimitError:
return "搜索API达到速率限制,请稍后再试"
except Exception as e:
return f"搜索失败:{str(e)},请检查查询词"
2. Prompt优化技巧
明确约束:
❌ 不明确:
"使用工具回答问题"
✅ 明确:
"你必须使用工具来获取信息,不要依赖你的训练数据"
"每次只调用一个工具"
"如果工具返回错误,尝试改变参数或使用其他工具"
提供反例:
正确示例:
Thought: 我需要搜索
Action: search
Action Input: 北京天气
错误示例(不要这样做):
Thought: 北京天气应该是晴天吧
Action: finish
Action Input: 晴天
(错误:没有使用工具就给出答案)
3. 调试技巧
详细日志:
import logging
class ReactAgent:
def __init__(self, ..., verbose=True):
self.verbose = verbose
self.logger = logging.getLogger("ReactAgent")
def run(self, question):
if self.verbose:
self.logger.info(f"[Question] {question}")
for step in range(self.max_steps):
if self.verbose:
self.logger.info(f"[Step {step}]")
self.logger.debug(f"Context:\n{context}")
# ... 执行步骤 ...
if self.verbose:
self.logger.info(f"Thought: {thought}")
self.logger.info(f"Action: {action}({action_input})")
self.logger.info(f"Observation: {observation}")
中间状态检查:
def run_with_checkpoints(self, question):
"""带检查点的运行"""
checkpoints = []
for step in range(self.max_steps):
# ... 执行步骤 ...
# 保存检查点
checkpoint = {
"step": step,
"thought": thought,
"action": action,
"observation": observation,
"context": context
}
checkpoints.append(checkpoint)
# 可以在任何时候检查
if self.debug_mode:
print(f"检查点 {step}:")
print(json.dumps(checkpoint, indent=2))
input("按Enter继续...")
return answer, checkpoints
4. 性能优化
缓存工具结果:
from functools import lru_cache
@lru_cache(maxsize=100)
def search(query: str) -> str:
"""缓存搜索结果"""
return expensive_search_api(query)
批量处理:
# 如果需要处理多个问题
def batch_run(self, questions: List[str]):
"""批量运行"""
from concurrent.futures import ThreadPoolExecutor
with ThreadPoolExecutor(max_workers=5) as executor:
results = executor.map(self.run, questions)
return list(results)
小结
ReAct的核心价值
- 结合思考和行动:不再是"只想不做"或"只做不想"
- 动态适应:根据观察结果及时调整策略
- 可解释性强:每一步的思考过程都是透明的
- 易于扩展:添加新工具即可扩展能力
关键组件
| 组件 | 作用 | 关键点 |
|---|---|---|
| Thought | 推理规划 | 分析情况,决定行动 |
| Action | 执行操作 | 调用工具,与环境交互 |
| Observation | 获取反馈 | 提供给下一轮思考 |
| Tools | 能力来源 | 设计要清晰、文档要详细 |
| Prompt | 行为指南 | Few-shot示例很重要 |
适用场景
适合ReAct:
- ✅ 需要外部信息(搜索、API调用)
- ✅ 多步骤任务
- ✅ 需要动态决策
- ✅ 工具调用频繁
不适合ReAct:
- ❌ 纯推理任务(数学证明)
- ❌ 单步即可完成的任务
- ❌ 需要极快响应(ReAct有多轮开销)
实践建议
开发阶段:
- 从简单工具开始(如搜索、计算)
- 使用详细的Few-shot示例
- 开启verbose模式,观察每一步
- 记录失败案例,优化prompt
生产部署:
- 添加工具调用限制(防止滥用API)
- 实现超时机制
- 监控token消耗
- 准备降级方案(ReAct失败时的备选)
持续改进:
- 收集真实用户query
- 分析哪些任务成功/失败
- 扩展工具库
- 优化prompt(基于失败案例)
未来发展方向
- 更好的规划:从ReAct到ReWOO,减少token消耗
- 多模态:不仅是文本,还有图像、视频工具
- 自我学习:从交互中学习,改进工具使用策略
- 协作Agent:多个ReAct Agent协同完成复杂任务
ReactAgent代表了AI从"知识库"到"行动者"的转变,它让AI不再局限于已知知识,而是能够主动探索、获取信息、解决实际问题。掌握ReAct,你就掌握了构建实用AI系统的核心范式!