ReAct 模式:推理 + 行动#
什么是 ReAct?#
ReAct = Reasoning + Acting
ReAct 是一种让大模型交替进行「思考」和「行动」的框架。每次行动后,模型会观察结果,再决定下一步。这是构建智能 Agent 的主流方式。
核心循环#
思考(Thought) → 行动(Action) → 观察(Observation) → 思考 → ...
优势#
可解释性:每一步都有明确的思考过程
灵活性:可以根据观察结果动态调整策略
鲁棒性:遇到错误可以换一种方式重试
本章将从手动文本解析版本,逐步过渡到使用 Function Calling 的现代实现。
import json
import os
import re
import litellm
litellm.drop_params = True
from dotenv import load_dotenv
load_dotenv()
MODEL = os.getenv("LLM_MODEL")
print(f"使用模型:{MODEL}")
# gpt-5/o系列不支持自定义temperature值,统一用安全wrapper
def _c(**kw):
_m = kw.get('model', MODEL)
if any(_m.startswith(p) for p in ('openai/gpt-5','openai/o1','openai/o3','openai/o4')):
kw.pop('temperature', None)
return litellm.completion(**kw)
使用模型:openai/gpt-5-mini
Section 1:ReAct 提示格式#
经典 ReAct 格式要求模型以固定的文本结构输出,方便程序解析。
格式规范:
Thought:模型的推理过程Action:要调用的工具名称Action Input:工具的输入参数Observation:(程序填入)工具返回结果Final Answer:最终回答用户的内容
# ── 工具定义 ──────────────────────────────────────────────
def search(query: str) -> str:
"""模拟搜索引擎(返回假数据用于演示)"""
results = {
"北京天气": "北京今日晴,气温 18°C,风力 3 级,适合户外活动",
"上海天气": "上海今日多云,气温 22°C,风力 2 级,湿度较高",
"量子计算": "量子计算利用量子力学原理进行计算,比传统计算机更快",
}
for key, val in results.items():
if key in query:
return val
return f"未找到关于 '{query}' 的相关信息"
def calculate(expr: str) -> str:
"""安全计算数学表达式"""
try:
# 只允许数字和基本运算符
allowed = set("0123456789+-*/()., ")
if not all(c in allowed for c in expr):
return "错误:表达式包含非法字符"
result = eval(expr) # noqa: S307 # 生产中请用更安全的方式
return str(result)
except Exception as e:
return f"计算错误:{e}"
def get_date() -> str:
"""返回今天的日期"""
from datetime import date
return str(date.today())
TOOLS = {
"search": search,
"calculate": calculate,
"get_date": get_date,
}
# ── ReAct 系统提示 ────────────────────────────────────────
REACT_SYSTEM_PROMPT = """你是一个智能助手,通过「思考-行动-观察」循环来解决问题。
你可以使用以下工具:
- search(query):搜索信息,query 是搜索关键词
- calculate(expr):计算数学表达式,expr 是数学表达式字符串
- get_date():获取今天的日期,无需参数
每次输出必须严格遵循以下格式之一:
格式 A(需要使用工具时):
Thought: 你的推理过程
Action: 工具名称
Action Input: 工具输入参数
格式 B(已有足够信息时):
Thought: 你的推理过程
Final Answer: 你的最终回答
重要规则:
1. 每次只输出一个 Action 或 Final Answer
2. 等待 Observation 后再继续
3. 不要编造工具返回的结果
"""
print("工具已定义:", list(TOOLS.keys()))
print("系统提示已准备好")
工具已定义: ['search', 'calculate', 'get_date']
系统提示已准备好
Section 2:手动 ReAct 循环#
通过文本解析来驱动 ReAct 循环,是最直观的实现方式。
核心逻辑:
将任务发给模型
解析模型输出中的
Action和Action Input调用对应工具,得到
Observation将 Observation 追加到对话历史,继续循环
直到出现
Final Answer:停止
def parse_action(text: str):
"""
从模型输出中解析 Action 和 Action Input。
返回 (action_name, action_input) 或 None。
"""
action_match = re.search(r"Action:\s*(.+)", text)
input_match = re.search(r"Action Input:\s*(.+)", text)
if action_match and input_match:
return action_match.group(1).strip(), input_match.group(1).strip()
return None
def parse_final_answer(text: str):
"""从模型输出中解析 Final Answer"""
match = re.search(r"Final Answer:\s*(.+)", text, re.DOTALL)
if match:
return match.group(1).strip()
return None
def execute_tool(tool_name: str, tool_input: str, tools: dict) -> str:
"""执行工具并返回结果"""
if tool_name not in tools:
return f"错误:工具 '{tool_name}' 不存在。可用工具:{list(tools.keys())}"
try:
tool_fn = tools[tool_name]
# get_date 不需要参数
if tool_name == "get_date":
return tool_fn()
return tool_fn(tool_input)
except Exception as e:
return f"工具执行错误:{e}"
def react_agent(task: str, tools: dict, max_steps: int = 5) -> str:
"""
手动文本解析版 ReAct Agent。
参数:
task: 用户任务描述
tools: 工具字典 {name: function}
max_steps: 最大循环步数(防止无限循环)
返回:
最终回答字符串
"""
messages = [
{"role": "system", "content": REACT_SYSTEM_PROMPT},
{"role": "user", "content": task},
]
print(f"\n{'='*60}")
print(f"任务:{task}")
print(f"{'='*60}")
for step in range(max_steps):
print(f"\n── 步骤 {step + 1} ──")
# 调用模型
response = _c(
model=MODEL,
messages=messages,
temperature=0,
max_tokens=512,
)
assistant_text = response.choices[0].message.content
print(f"模型输出:\n{assistant_text}")
# 追加助手消息
messages.append({"role": "assistant", "content": assistant_text})
# 检查是否已有最终答案
final_answer = parse_final_answer(assistant_text)
if final_answer:
print(f"\n{'='*60}")
print(f"最终答案:{final_answer}")
print(f"{'='*60}")
return final_answer
# 解析并执行工具
action_result = parse_action(assistant_text)
if action_result:
action_name, action_input = action_result
print(f"\n执行工具:{action_name}({action_input})")
observation = execute_tool(action_name, action_input, tools)
print(f"观察结果:{observation}")
# 将 Observation 作为用户消息追加
messages.append({
"role": "user",
"content": f"Observation: {observation}"
})
else:
print("无法解析 Action,终止循环")
break
return "达到最大步数限制,未能得出最终答案"
# 简单测试
result = react_agent(
task="今天是几号?",
tools=TOOLS,
max_steps=3,
)
============================================================
任务:今天是几号?
============================================================
── 步骤 1 ──
模型输出:
Thought: 需要调用获取当前日期的工具来回答“今天是几号?”
Action: get_date
Action Input: 无
执行工具:get_date(无)
观察结果:2026-03-14
── 步骤 2 ──
模型输出:
Thought: 已有今天的日期信息,可以直接回答具体日期。
Final Answer: 今天是2026年3月14日。
============================================================
最终答案:今天是2026年3月14日。
============================================================
Section 3:用 Function Calling 实现 ReAct#
文本解析方式脆弱,容易因格式不规范而失败。 现代做法是使用 Function Calling(工具调用),让模型返回结构化 JSON。
优势对比:
维度 |
文本解析 |
Function Calling |
|---|---|---|
可靠性 |
依赖格式规范 |
结构化,稳定 |
参数类型 |
全是字符串 |
支持数字、列表等 |
错误处理 |
复杂 |
简单 |
模型支持 |
所有模型 |
需要支持 tool_calls |
# ── Function Calling 工具描述(JSON Schema 格式)─────────────
FC_TOOLS = [
{
"type": "function",
"function": {
"name": "search",
"description": "搜索互联网上的信息",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "搜索关键词"
}
},
"required": ["query"]
}
}
},
{
"type": "function",
"function": {
"name": "calculate",
"description": "计算数学表达式",
"parameters": {
"type": "object",
"properties": {
"expr": {
"type": "string",
"description": "数学表达式,如 '(18 + 22) / 2'"
}
},
"required": ["expr"]
}
}
},
{
"type": "function",
"function": {
"name": "get_date",
"description": "获取今天的日期",
"parameters": {
"type": "object",
"properties": {},
"required": []
}
}
}
]
def react_agent_fc(task: str, tools: dict, max_steps: int = 5) -> str:
"""
Function Calling 版 ReAct Agent。
使用结构化工具调用代替文本解析。
"""
messages = [
{"role": "system", "content": "你是一个智能助手,通过调用工具来解决问题。先思考需要哪些信息,再调用合适的工具。"},
{"role": "user", "content": task},
]
print(f"\n{'='*60}")
print(f"任务:{task}")
print(f"{'='*60}")
for step in range(max_steps):
print(f"\n── 步骤 {step + 1} ──")
response = _c(
model=MODEL,
messages=messages,
tools=FC_TOOLS,
tool_choice="auto",
temperature=0,
)
msg = response.choices[0].message
finish_reason = response.choices[0].finish_reason
# 追加助手消息(包含可能的 tool_calls)
messages.append(msg)
# 没有工具调用 → 直接返回文本答案
if finish_reason == "stop" or not msg.tool_calls:
answer = msg.content or "(无文本回答)"
print(f"最终答案:{answer}")
return answer
# 处理工具调用
for tool_call in msg.tool_calls:
fn_name = tool_call.function.name
fn_args = json.loads(tool_call.function.arguments)
print(f"调用工具:{fn_name},参数:{fn_args}")
# 执行工具
if fn_name not in tools:
observation = f"错误:工具 '{fn_name}' 不存在"
elif fn_name == "get_date":
observation = tools[fn_name]()
else:
observation = tools[fn_name](**fn_args)
print(f"工具结果:{observation}")
# 将工具结果追加到消息历史
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": observation,
})
return "达到最大步数限制"
# 测试 Function Calling 版本
result = react_agent_fc(
task="计算 (123 + 456) * 2 的结果",
tools=TOOLS,
)
============================================================
任务:计算 (123 + 456) * 2 的结果
============================================================
── 步骤 1 ──
调用工具:calculate,参数:{'expr': '(123 + 456) * 2'}
工具结果:1158
── 步骤 2 ──
最终答案:(123 + 456) = 579,579 × 2 = 1158。因此结果是 1158。
Section 4:实际任务演示#
任务:查询北京和上海的天气,计算平均温度,并告诉我哪个城市更适合今天跑步。
这个任务需要:
搜索北京天气
搜索上海天气
计算平均温度
综合判断给出推荐
# 使用 Function Calling 版本演示多步任务
weather_task = "查询北京和上海的天气,计算平均温度,并告诉我哪个城市更适合今天跑步"
result = react_agent_fc(
task=weather_task,
tools=TOOLS,
max_steps=6,
)
print(f"\n最终推荐:{result}")
============================================================
任务:查询北京和上海的天气,计算平均温度,并告诉我哪个城市更适合今天跑步
============================================================
── 步骤 1 ──
调用工具:search,参数:{'query': '北京 今日 天气 温度'}
工具结果:未找到关于 '北京 今日 天气 温度' 的相关信息
调用工具:search,参数:{'query': '上海 今日 天气 温度'}
工具结果:未找到关于 '上海 今日 天气 温度' 的相关信息
── 步骤 2 ──
最终答案:我刚才搜索当前天气时没有找到结果。你想怎么继续?有几个选项(请选择一个):
1) 我再试一次网上查询(我会改用更宽泛的关键词如“北京 天气 现在/实时温度”并获取上海同样的信息)。
2) 你直接告诉我北京和上海现在的气温(摄氏度),我立即帮你计算平均温度并给出跑步建议。
3) 只按常规经验让我直接给出建议(例如理想跑步温度区间、考虑空气质量和降水等因素的通用建议)。
另外请告诉我是否需要考虑空气质量、降雨/湿度或风速等因素,结果用摄氏度还是华氏度。你选哪个?
最终推荐:我刚才搜索当前天气时没有找到结果。你想怎么继续?有几个选项(请选择一个):
1) 我再试一次网上查询(我会改用更宽泛的关键词如“北京 天气 现在/实时温度”并获取上海同样的信息)。
2) 你直接告诉我北京和上海现在的气温(摄氏度),我立即帮你计算平均温度并给出跑步建议。
3) 只按常规经验让我直接给出建议(例如理想跑步温度区间、考虑空气质量和降水等因素的通用建议)。
另外请告诉我是否需要考虑空气质量、降雨/湿度或风速等因素,结果用摄氏度还是华氏度。你选哪个?
# 同一任务,用手动解析版本对比
print("\n\n对比:使用手动文本解析版本\n")
result2 = react_agent(
task=weather_task,
tools=TOOLS,
max_steps=8,
)
对比:使用手动文本解析版本
============================================================
任务:查询北京和上海的天气,计算平均温度,并告诉我哪个城市更适合今天跑步
============================================================
── 步骤 1 ──
模型输出:
Thought: 我需要先获取北京今天的天气信息,然后再获取上海的天气,最后计算平均温度并给出跑步建议。先查询北京今天天气。
Action: search
Action Input: 北京 今天天气
执行工具:search(北京 今天天气)
观察结果:未找到关于 '北京 今天天气' 的相关信息
── 步骤 2 ──
模型输出:
Thought: 上次搜索未返回结果,我改用更具体的关键词重新查询北京今天天气(包含实时温度与空气质量)。
Action: search
Action Input: 北京 今天天气 实时 温度 空气质量
执行工具:search(北京 今天天气 实时 温度 空气质量)
观察结果:未找到关于 '北京 今天天气 实时 温度 空气质量' 的相关信息
── 步骤 3 ──
模型输出:
Thought: 改用不同词组和更通用的关键词再搜一次,尝试“北京市 今日 天气 实时 温度 空气质量”以获取所需信息。
Action: search
Action Input: 北京市 今日 天气 实时 温度 空气质量
执行工具:search(北京市 今日 天气 实时 温度 空气质量)
观察结果:未找到关于 '北京市 今日 天气 实时 温度 空气质量' 的相关信息
── 步骤 4 ──
模型输出:
无法解析 Action,终止循环
Section 5:错误恢复#
Agent 遇到工具错误时,应该能够:
识别错误信息
调整策略(换一个工具,或换一种输入)
继续完成任务
我们通过添加一个「有时会失败」的工具来演示错误恢复。
import random
# 一个不稳定的工具(50% 概率失败)
_unstable_call_count = 0
def unstable_search(query: str) -> str:
"""模拟不稳定的搜索服务"""
global _unstable_call_count
_unstable_call_count += 1
# 第一次调用必定失败,后续正常
if _unstable_call_count == 1:
return "错误:搜索服务暂时不可用,请稍后重试或使用其他关键词"
return search(query)
def get_stock_price(symbol: str) -> str:
"""获取股票价格(演示用)"""
prices = {
"AAPL": "185.20",
"GOOG": "141.80",
"BTC": "67500",
}
symbol = symbol.upper()
if symbol in prices:
return f"{symbol} 当前价格:${prices[symbol]}"
return f"错误:找不到股票代码 '{symbol}',请检查代码是否正确"
RESILIENT_FC_TOOLS = [
{
"type": "function",
"function": {
"name": "unstable_search",
"description": "搜索信息(有时可能失败,失败时需要重试或换关键词)",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "搜索关键词"}
},
"required": ["query"]
}
}
},
{
"type": "function",
"function": {
"name": "get_stock_price",
"description": "获取股票或加密货币价格,symbol 为股票代码如 AAPL、GOOG、BTC",
"parameters": {
"type": "object",
"properties": {
"symbol": {"type": "string", "description": "股票代码"}
},
"required": ["symbol"]
}
}
},
{
"type": "function",
"function": {
"name": "calculate",
"description": "计算数学表达式",
"parameters": {
"type": "object",
"properties": {
"expr": {"type": "string"}
},
"required": ["expr"]
}
}
}
]
RESILIENT_TOOLS = {
"unstable_search": unstable_search,
"get_stock_price": get_stock_price,
"calculate": calculate,
}
def react_agent_resilient(task: str, max_steps: int = 8) -> str:
"""具备错误恢复能力的 ReAct Agent"""
messages = [
{
"role": "system",
"content": (
"你是一个智能助手。当工具调用失败时,不要放弃,"
"尝试换一种方式(如换关键词重试、使用备选工具)。"
)
},
{"role": "user", "content": task},
]
print(f"\n{'='*60}")
print(f"任务(错误恢复测试):{task}")
print(f"{'='*60}")
for step in range(max_steps):
print(f"\n── 步骤 {step + 1} ──")
response = _c(
model=MODEL,
messages=messages,
tools=RESILIENT_FC_TOOLS,
tool_choice="auto",
temperature=0,
)
msg = response.choices[0].message
messages.append(msg)
if not msg.tool_calls:
answer = msg.content or "(无回答)"
print(f"最终答案:{answer}")
return answer
for tc in msg.tool_calls:
fn_name = tc.function.name
fn_args = json.loads(tc.function.arguments)
print(f"调用工具:{fn_name},参数:{fn_args}")
tool_fn = RESILIENT_TOOLS.get(fn_name)
if tool_fn is None:
observation = f"错误:工具 '{fn_name}' 不存在"
else:
observation = tool_fn(**fn_args)
# 标记错误消息,引导模型注意
if "错误" in observation:
print(f"工具报错:{observation}")
else:
print(f"工具结果:{observation}")
messages.append({
"role": "tool",
"tool_call_id": tc.id,
"content": observation,
})
return "达到最大步数限制"
# 重置计数器,测试错误恢复
_unstable_call_count = 0
result = react_agent_resilient(
task="查询北京天气,并告诉我今天是否适合骑行"
)
============================================================
任务(错误恢复测试):查询北京天气,并告诉我今天是否适合骑行
============================================================
── 步骤 1 ──
调用工具:unstable_search,参数:{'query': '北京 今天天气 实时 温度 降雨 风速 空气质量 AQI'}
工具报错:错误:搜索服务暂时不可用,请稍后重试或使用其他关键词
── 步骤 2 ──
调用工具:unstable_search,参数:{'query': '北京市 今天天气 预报 逐小时 风速 降雨 概率 空气质量 AQI'}
工具结果:未找到关于 '北京市 今天天气 预报 逐小时 风速 降雨 概率 空气质量 AQI' 的相关信息
── 步骤 3 ──
最终答案:我刚尝试获取实时天气但搜索服务暂时不可用,暂时无法直接拉取北京的实时数据。可以这样继续,你选一个告诉我就行:
- 我现在重试一次在线查询(我会换关键词或再试几次)。
- 或者你把手机/网页上看到的当前温度、降雨情况、风速/风力、AQI(空气质量)给我,我来判断是否适合骑行。
- 或者你想要我给出一份「如何自己快速判断是否适合骑行」的清单和决策规则(我下面先把清单发给你,直接可用)。
先把判断要点和决策规则给你(可直接按此自查):
1. 是否下雨/路面情况
- 不下雨且路面干燥:适合。
- 毛毛雨/细雨(小雨)且有挡泥/护具:勉强可行,注意防滑、减速。
- 中到大雨、路面积水或有雨夹雪/结冰:不建议骑行。
2. 风力
- 风速 < 6–8 m/s(约 20–30 km/h):一般可安全骑行。
- 风速 8–12 m/s(30–43 km/h):会影响稳定性,遇阵风要谨慎、选择避风路线或改乘。
- 风速 > 12–15 m/s(>43–54 km/h)或有强阵风:不安全,建议不骑。
3. 温度
- 舒适:约 10–28°C(根据个人耐寒/耐热略有差异)。
- 冷:< 5°C 要穿暖、注意路面结冰,低于 -5°C 严重影响安全与制动。
- 热:> 35°C 不建议进行长时间或高强度骑行,注意补水与避暑。
4. 空气质量(AQI)
- 0–50(优):安全。
- 51–100(良):多数人可骑,敏感人群注意短时逗留。
- 101–150(轻度污染,对敏感人群不利):建议短途且强度低;敏感者避免。
- >150(中度或以上污染):不建议骑行(尤其是长时间或高速骑行)。
5. 能见度/其他
- 大雾、能见度低、路灯不足、施工路段或路况差时不建议骑行或选择短程路线并开灯/穿反光衣。
6. 装备和安全建议(无论天气都应遵守)
- 佩戴头盔、灯、反光衣/条;下雨带挡泥板或穿防水外套;备水、手机、充电宝;选择有自行车道或车流少路线;遇到大风/暴雨/空气污染可改乘地铁/公交/网约车。
简单决策规则(把上面条件综合):
- 如果(无降雨)且(风速 < 8 m/s)且(AQI ≤ 100)且(温度适中),则“适合骑行(正常骑行)”。
- 如果只有一项轻微不利(小雨、风速接近阈值或AQI 100-150),则“可骑但需注意并缩短/放慢行程或选避风路线”。
- 如果有一项严重不利(大雨、风 >12 m/s、AQI >150、能见度差或路面结冰),则“不建议骑行”。
如何快速查到这些信息(你可以在手机上或电脑上照做):
- 搜索关键词:“北京 天气 实况” / “Beijing weather” 或 打开天气类APP(墨迹天气、彩云天气、和风天气、天气通、苹果/安卓系统自带天气)。
- 查风速/风向:在逐小时预报里看“风速/风向”或“风力等级(几级)”。
- 查降雨概率/分钟级雷达:看“未来1小时降雨/雷达回波”。
- 查AQI:搜索“北京 AQI”或打开 aqicn.org(世界空气质量项目)、中国环境监测总站或本地空气质量APP。
- 若你愿意,把你看到的“当前温度 / 降雨(有/无或降雨量) / 风速(m/s 或 km/h 或几级) / AQI”发给我,我马上判断并给出建议和替代路线建议。
要我现在重试在线查询吗?还是你贴一下当前数据?
进阶:ReAct 步骤追踪可视化#
为了更好地理解 Agent 的执行路径,我们可以记录每一步的详细信息。
def react_agent_traced(task: str, tools: dict, fc_tools: list, max_steps: int = 6):
"""
带完整追踪记录的 ReAct Agent。
返回 (最终答案, 追踪记录列表)
"""
messages = [
{"role": "system", "content": "你是一个智能助手,通过调用工具来解决复杂问题。"},
{"role": "user", "content": task},
]
trace = [] # 记录每一步
for step in range(max_steps):
response = _c(
model=MODEL,
messages=messages,
tools=fc_tools,
tool_choice="auto",
temperature=0,
)
msg = response.choices[0].message
messages.append(msg)
step_record = {
"step": step + 1,
"thought": msg.content,
"actions": [],
}
if not msg.tool_calls:
step_record["final_answer"] = msg.content
trace.append(step_record)
return msg.content, trace
for tc in msg.tool_calls:
fn_name = tc.function.name
fn_args = json.loads(tc.function.arguments)
if fn_name == "get_date":
observation = tools[fn_name]()
else:
observation = tools[fn_name](**fn_args)
step_record["actions"].append({
"tool": fn_name,
"args": fn_args,
"result": observation,
})
messages.append({
"role": "tool",
"tool_call_id": tc.id,
"content": observation,
})
trace.append(step_record)
return "达到步数限制", trace
# 运行并打印可视化追踪
answer, trace = react_agent_traced(
task="今天几号?(18 + 22) / 2 等于多少?",
tools=TOOLS,
fc_tools=FC_TOOLS,
)
print("\n" + "="*60)
print("执行追踪记录")
print("="*60)
for record in trace:
print(f"\n[步骤 {record['step']}]")
if record.get('thought'):
print(f" 思考:{record['thought']}")
for action in record.get('actions', []):
print(f" 行动:{action['tool']}({action['args']})")
print(f" 结果:{action['result']}")
if record.get('final_answer'):
print(f" ✓ 最终答案:{record['final_answer']}")
============================================================
执行追踪记录
============================================================
[步骤 1]
行动:get_date({})
结果:2026-03-14
行动:calculate({'expr': '(18 + 22) / 2'})
结果:20.0
[步骤 2]
思考:今天是 2026年3月14日。(18 + 22) / 2 = 20。需要我帮你算其他题吗?
✓ 最终答案:今天是 2026年3月14日。(18 + 22) / 2 = 20。需要我帮你算其他题吗?
练习题#
扩展工具集:添加一个
get_weather(city)工具,返回真实天气数据(可以用 OpenWeatherMap API)。自定义最大步数:当任务特别复杂时,
max_steps=5可能不够。试着运行一个需要 8 步的任务,观察会发生什么。并行工具调用:部分模型支持在一次响应中调用多个工具(
parallel_tool_calls)。修改react_agent_fc以支持并行调用,并测试查询两个城市天气的任务是否变快。自定义停止条件:除了
Final Answer,添加一个「置信度检查」:如果模型输出包含「我不确定」,自动重新搜索。
总结#
ReAct 让模型具备了「先想后做」的能力#
核心概念 |
说明 |
|---|---|
Thought |
模型的推理过程,可见、可调试 |
Action |
调用外部工具(搜索、计算、API 等) |
Observation |
工具返回的真实结果 |
循环 |
不断迭代直到得出最终答案 |
两种实现方式对比#
方式 |
优点 |
缺点 |
|---|---|---|
文本解析 |
兼容所有模型 |
格式脆弱,易出错 |
Function Calling |
结构化、稳定、支持复杂参数 |
需要模型支持 |
最佳实践#
始终设置
max_steps防止无限循环工具函数要有清晰的错误返回(让模型知道失败原因)
系统提示中明确工具的使用边界
记录执行追踪,便于调试
下一章我们将学习如何为 Agent 添加记忆能力,处理长期任务。
# 知识检验:完整演示
print("ReAct Agent 完整能力演示")
print("="*60)
print(f"模型:{MODEL}")
print(f"可用工具:{list(TOOLS.keys())}")
print()
# 综合任务
final_result = react_agent_fc(
task=(
"先告诉我今天日期,然后查一下北京天气,"
"再计算 18 摄氏度转华氏温度(公式:F = C * 9/5 + 32)"
),
tools=TOOLS,
max_steps=6,
)
print(f"\n任务完成!")
ReAct Agent 完整能力演示
============================================================
模型:openai/gpt-5-mini
可用工具:['search', 'calculate', 'get_date']
============================================================
任务:先告诉我今天日期,然后查一下北京天气,再计算 18 摄氏度转华氏温度(公式:F = C * 9/5 + 32)
============================================================
── 步骤 1 ──
调用工具:get_date,参数:{}
工具结果:2026-03-14
调用工具:search,参数:{'query': '北京 天气'}
工具结果:未找到关于 '北京 天气' 的相关信息
调用工具:calculate,参数:{'expr': '18 * 9/5 + 32'}
工具结果:64.4
── 步骤 2 ──
调用工具:search,参数:{'query': '北京 今天 天气 现在'}
工具结果:未找到关于 '北京 今天 天气 现在' 的相关信息
── 步骤 3 ──
最终答案:今天是 2026-03-14。
关于北京的即时天气:我刚尝试检索当前的天气信息,但未能获取到实时天气数据。要么是检索受限,要么暂时无法访问天气源。你想让我再试一次吗?或者你可以告诉我你希望查的具体区/街道,我再精确检索。
如果你需要一个大致参考:3月的北京通常是春季过渡期,日间气温常在约 5–15°C 之间,早晚偏凉,空气相对干燥并可能有风,有时会下小雨或沙尘(仅作典型季节性参考,非实时预报)。
温度换算:
F = C * 9/5 + 32
代入 C = 18:
F = 18 * 9/5 + 32 = 64.4°F
要不要我再尝试获取实时天气,或为你查具体时段的预报(今天/24小时/7天)?
任务完成!