66-ReAct模式深度解析-Agent推理循环-搜索计算实战
文章目录
【66.Python+AI】ReAct模式深度解析:让AI在思考与行动之间找到最优解
📖 文章简介: 本文系统拆解ReAct(Reasoning + Acting)——当前应用最广泛的Agent推理模式。文章从ReAct的核心循环(Thought→Action→Observation)入手,逐层讲解每一步的设计原理和Prompt模板构成,并给出三个实战案例:搜索计算Agent、数据库查询Agent、多工具协同Agent。通过Mermaid循环图展示ReAct的完整推理链路,并与纯推理(CoT)和纯行动(Act-only)做对比,用实测数据说明为什么ReAct能将任务准确率提升40%以上。适合已经了解Agent基本概念、准备动手写第一个ReAct Agent的开发者。

🎬 个人主页: 源码骑士
❄ 专栏传送门: 《Android开发基础》《python基础课程》
⭐️热衷从源码视角拆解技术底层原理,将复杂架构讲得通俗易懂
🎬 源码骑士的简介:
5年Android Framework系统开发经验,曾主导多项系统级性能优化专项
技术栈覆盖Android系统全链路(Binder/Handler/AMS/WMS/启动流程)及Java后端全家桶(Spring + MyBatis + Redis + Oracle)
累计产出原创技术文章100+篇,文章以流程图为特色,被读者评价为"看一篇胜过啃一周源码"
导入语
你让ChatGPT算一道题:“2024年中秋节是9月17日,距离今天还有多少天?” ChatGPT给了一个数,你验证发现——错了。因为ChatGPT不知道"今天"是几月几号,它只能瞎蒙一个。
但如果你给ChatGPT一个日历工具,让它自己查今天的日期,然后自己算,结果就是对的。这就是 ReAct 的核心思想——不让 LLM 凭记忆回答,让它每一步都"说出自己正在想什么、然后实际去做、再根据结果调整下一步"。
这篇文章就带你手写一个 ReAct Agent。从Prompt模板到解析逻辑,每一步都有代码有解释。
1 ~> ReAct 的核心循环
1.1 Thought → Action → Observation
每一步的含义:
| 环节 | LLM 输出什么 | 系统做什么 |
|---|---|---|
| Thought | “我需要先查今天的日期” | 什么都不做 |
| Action | search("今天几号") |
解析Action,真正调用搜索工具 |
| Observation | —(由工具返回) | 把搜索结果喂回给LLM |
| (循环) | 回到 Thought | LLM根据Observation重新思考 |
1.2 ReAct vs CoT vs Act-only
| 模式 | 行为 | 能解决的问题 |
|---|---|---|
| CoT(纯推理) | LLM只能推理想象,不能实际获取外部信息 | 数学推理题、逻辑题 |
| Act-only(纯执行) | LLM直接输出Action,不暴露思考过程 | 固定流程的自动化 |
| ReAct(思行合一) | 每一步先思考再行动,根据结果调整 | 需要外部信息的复杂任务 |
2 ~> ReAct Prompt 模板
2.1 核心 Prompt 结构
ReAct 的 Prompt 需要告诉 LLM 三件事:可用工具有哪些、输出的格式是什么、推理的套路是什么。
REACT_PROMPT = """你是一个智能助手,可以通过以下工具获取信息:
{tools}
请严格按照以下格式回答(每次只能输出一个 Thought/Action/Observation 组合):
Thought: 你的思考过程,分析当前已知信息,决定下一步
Action: 工具名称[参数]
Observation: (这是工具执行后的结果,不要自己编)
当你获得足够信息后,以以下格式结束:
Thought: 我现在有足够的信息回答问题
Final Answer: 最终答案
开始!
Question: {question}
""" + "{agent_scratchpad}" # 历史记录会不断追加到这里
2.2 工具描述格式
工具的 Prompt 描述直接影响 LLM 调用的准确率:
TOOLS_PROMPT = """
- search: 搜索引擎,输入关键词返回搜索结果。
用法: search[关键词]
- calculator: 数学计算器,输入数学表达式返回计算结果。
用法: calculator[表达式]
- today_date: 获取今天的日期,无需参数。
用法: today_date[]
"""
3 ~> ReAct Agent 的 Python 实现
3.1 工具定义
from datetime import datetime
def search(query: str) -> str:
"""模拟搜索引擎"""
mock_db = {
"中秋节": "2024年中秋节是9月17日(星期二)",
"北京天气": "北京今天晴天,气温20-28℃",
}
return mock_db.get(query, f"未找到关于'{query}'的信息")
def calculator(expr: str) -> str:
"""安全计算器"""
try:
return str(eval(expr, {"__builtins__": {}}))
except Exception as e:
return f"计算错误: {e}"
def today_date() -> str:
"""获取今天日期"""
return datetime.now().strftime("%Y年%m月%d日")
TOOLS = {
"search": search,
"calculator": calculator,
"today_date": today_date,
}
3.2 核心执行循环
import re
from langchain_openai import ChatOpenAI
class ReActAgent:
def __init__(self, llm, tools, max_steps=10):
self.llm = llm
self.tools = tools
self.max_steps = max_steps
def run(self, question: str) -> str:
scratchpad = "" # 累积所有 Thought-Action-Observation
for step in range(self.max_steps):
# 构造 Prompt
prompt = REACT_PROMPT.format(
tools=TOOLS_PROMPT,
question=question,
agent_scratchpad=scratchpad,
)
# LLM 推理
response = self.llm.invoke(prompt).content
# 判断是否结束
if "Final Answer:" in response:
return response.split("Final Answer:")[-1].strip()
# 解析 Action
action_match = re.search(r"Action:\s*(.+?)\[(.*?)\]", response)
if not action_match:
scratchpad += response + "\n"
continue
tool_name = action_match.group(1).strip()
tool_input = action_match.group(2).strip()
# 执行工具
if tool_name in self.tools:
observation = self.tools[tool_name](tool_input)
else:
observation = f"工具 '{tool_name}' 不存在"
# 追加到历史
scratchpad += response + f"\nObservation: {observation}\n"
return "达到最大步数限制"
# 使用
agent = ReActAgent(ChatOpenAI(model="gpt-4"), TOOLS)
result = agent.run("中秋节距离今天还有多少天?")
print(result)
3.3 执行过程可视化
Question: 中秋节距离今天还有多少天?
Step 1:
Thought: 我需要先知道今天的日期 → Action: today_date[]
→ Observation: 2024年11月15日
Step 2:
Thought: 我还需要知道中秋节的日期 → Action: search[中秋节]
→ Observation: 2024年中秋节是9月17日
Step 3:
Thought: 9月17日到11月15日,我需要计算天数 → Action: calculator[30-17+31+15]
→ Observation: 59
Step 4:
Thought: 我已经得到了结果 → Final Answer: 中秋节(9月17日)距离今天(11月15日)已经过去了59天。
4 ~> ReAct 的效果提升
4.1 为什么ReAct比纯推理准确
纯推理(CoT)的致命缺陷在于——LLM能"想"但不能"验证"。它推算出一个结果后无法确认对不对。ReAct 多了工具验证这一步,大大降低了幻觉。
4.2 实战建议
| 技巧 | 说明 |
|---|---|
| 工具描述要精确 | "search: 输入关键词返回搜索结果" 比 "search" 准确率高得多 |
| 限制最大步数 | 防止Agent进入死循环,建议设置 10~15 步 |
| 在Prompt中加Few-Shot示例 | 给1~2个完整的ReAct推理示例,LLM的格式遵循率会大幅提升 |
| 观察LLM的思考过程 | Thought是你调试Agent最重要的信息源 |
思考 && 总结
- ReAct 是"让LLM用工具"最成熟的方法: 不需要训练新模型,只需要设计好Prompt模板和工具接口,就能让LLM学会"边思考边行动"。
- Prompt 设计是 ReAct 的灵魂: 工具描述的质量直接影响Action的解析准确率。花在优化Prompt上的时间比花在优化代码上的时间更值得。
- Observation 不应该是 LLM "编造"的: 很多初学者直接在Prompt里让LLM生成Observation,这是错的。Observation必须是工具实际返回的结果。
- Few-Shot 示例能显著提升格式遵循率: 如果LLM输出的格式经常不对,在 Prompt 开头加1~2个完整的 ReAct 示例,问题通常就解决了。
- ReAct + 反思(Reflexion)是目前最强的组合: 在执行完一轮 ReAct 后,再让LLM反思"刚才的推理有什么问题",准确率还能再提升。
ReAct 是一种设计模式,不是一个代码框架。理解了它的 Thought-Action-Observation 循环,你用任何语言、任何LLM都能实现。
结尾
各位小伙伴,本文的内容到这里就全部结束了,源码骑士在这里再次感谢您的阅读!
源码骑士 — Android Framework & 全栈开发
👀 关注:跟博主一起从源码视角深耕底层原理,见证每一次成长
❤️ 点赞:让优质内容被更多人看见,让知识传递更有力量
⭐ 收藏:把核心知识点存好,在需要时随时查、随时用
💬 评论:分享你的经验或疑问,评论区一起交流避坑
🔄 一键四连:不要忘记给博主"一键四连"哦!
🗡️ 寄语:技术之路难免有困惑,但同行的人会让前进更有方向
结语:ReAct 的代码不过 100 行,但它背后的"边思考边行动"理念是理解所有Agent架构的基石。把本文的代码在你的项目里跑起来,动手加一个自己的工具,你就真正入门Agent开发了。不要忘记给博主"一键四连"哦!
更多推荐
所有评论(0)