1 引言
- Reason(推理):借鉴"Chain-of-Thought(思维链)",让模型先"自言自语"地分析问题。
- Act(行动):根据推理结果,调用工具执行操作(如 API、计算器、搜索)。
- Observation(观察):查看行动结果,进入下一轮推理或行动。

2 手搓一个ReAct
需求:我现在要输入一个问题,例如"华为有限公司"成立多少年呢?
(1)模型首先会进行思考:我需要查询华为公司的成立时间,然后计算从成立到当前年份的年数。首先应该获取当前时间,然后联网查询华为成立的具体年份。
(2)然后采取行动:调用get_current_time工具,获取当前的时间
(3)观察:模型观察到当前时间为:2026-04-20 19:08:53
===>
(4)模型再次思考,我拿到了当前的时间,现在需要联网查询华为公司成立的时间
(5)再次采取行动:调用fetch_real_time_info工具,获取华为公司成立的时间
(6)再次观察:模型获取到华为成立的时间为:华为成立于1987年...
===>
(7)模型最后思考:当前时间是2026年4月20日。华为成立于1987年,我需要计算从1987年到2026年的年数。由于没有具体的成立月份和日期信息,我假设按整年计算。
(8)模型最后采取行动:调用calculate工具: 2026 - 1987
(9)最后观察:39
===>
(10)输出:华为有限公司成立于1987年,截至2026年4月20日,已经成立了39年。
上面只是一个小小的案例,在实际中,模型可能远远不止循环3次。
下面给出代码实现的详细过程:
【系统提示词】
python
system_prompt = """
你按照 思考→行动→观测→答案 的循环流程运行。
循环结束后输出最终答案。
使用【思考】描述你针对用户问题的分析思路。
使用【行动】调用你可用的工具操作。
【观测】为执行对应行动后得到的结果。
【答案】为分析观测结果后得出的最终结论。
查询当前时间**必须调用函数**。
你可用的操作工具:
get_current_time(获取当前时间)
示例:get_current_time: ''
功能:获取系统当前时间
作用原理:获取实时时间,用于后续逻辑判断与运算
calculate(数值计算)
示例:calculate: 4 * 7 / 3
功能:执行数学运算并返回结果,采用Python语法,浮点运算请规范书写格式
fetch_real_time_info(实时联网查询)
示例:fetch_real_time_info: 阿里
功能:通过SerperAPI检索实时网络信息
只要适用,就必须优先使用联网查询工具。
示例对话1:
问题:中国首都是哪里?
思考:我需要通过联网查询获取答案
行动:fetch_real_time_info: 中国首都
暂停
你将收到如下内容:
观测:中国是一个国家,首都是北京。
思考:我已经得到准确答案
行动:北京
随后输出:
答案:中国的首都是北京
示例对话2:
问题:地球质量乘以2等于多少?
思考:我需要先联网查询地球质量
行动:fetch_real_time_info: 地球质量
暂停
你将收到如下内容:
观测:地球质量为5.972×10^24
思考:需要将数值乘以2进行计算
行动:calculate: 5.972e24 * 2
暂停
你将收到如下内容:
观测:1.1944×10^25
得到结果后直接输出答案
答案:地球质量的2倍是1.1944×10^25
示例对话3:
问题:需要获取当前时间进行年份计算
思考:需要获取当前年份
行动:get_current_time
观测:2025-12-01 09:01:01
答案:2025-12-01 09:01:01
""".strip()
【工具】
python
# 定义工具
def fetch_real_time_info(query):
"""
通过Serper API获取实时搜索信息
使用Serper的Google搜索API查询指定问题,并返回最相关结果的摘要片段。
参数:
query (str): 要搜索的查询字符串,表示用户提出的问题
返回:
str: 搜索结果摘要片段。若无结果则返回提示信息
"""
# API参数配置
params = {
'api_key': ".........", # 使用您自己的API密钥
'q': query, # 查询参数,表示要搜索的问题。
'num': 1 # 返回结果的数量设为1,API将返回一个相关的搜索结果。
}
# 发起API请求
api_result = requests.get('https://google.serper.dev/search', params)
# 解析JSON响应数据
search_data = api_result.json()
# 提取并返回查询到的信息
if search_data["organic"]:
return search_data["organic"][0]["snippet"]
else:
return "没有找到相关结果。"
def calculate(operation: str) -> float:
"""
计算字符串数学表达式的值
使用内置eval()函数执行传入的数学表达式字符串,并返回浮点数结果。
注意:eval()会执行任何传入的Python代码,存在严重安全风险,
请确保仅传入可信来源的数学表达式。
Args:
operation: 包含数学表达式的字符串,例如 "2 * 3 + 4"
Returns:
表达式计算结果的浮点数值
Raises:
SyntaxError: 当传入字符串不是合法表达式时
TypeError: 当表达式结果无法转换为浮点数时
ZeroDivisionError: 当表达式中包含除以零操作时
"""
return eval(operation)
def get_current_time():
"""
获取当前系统时间并格式化为字符串
返回:
str: 格式为'YYYY-MM-DD HH:MM:SS'的当前时间字符串
"""
return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
【定义模型】
python
# 定义模型
class ChatBot:
def __init__(self, system=""):
self.system = system # 系统提示词
self.messages = [] # 保存对话历史
# 如果存在系统指令,添加到消息列表开头
if self.system:
self.messages.append({"role": "system", "content": system})
def __call__(self, message):
self.messages.append({"role": "user", "content": message})
# 调用模型执行并获取回复
result = self.execute()
# 将AI回复添加到对话历史
self.messages.append({"role": "assistant", "content": result})
return result
def execute(self):
completion = client.chat.completions.create(
model="deepseek-chat", # 模型名固定
messages=self.messages,
temperature=0.5,
stream=False, # 必须关闭流式输出
stop=["观测:", "观测:", "Observation:", "Observation:"]
)
return completion.choices[0].message.content
【调用智能体】
python
def AgentExecutor(question, max_turns=5):
"""
执行多轮对话代理的核心逻辑
通过有限轮次的对话交互处理用户问题,当模型输出包含工具调用指令时,
自动执行相应工具并观察结果,否则返回完整对话记录
Args:
question (str): 用户输入的初始问题
max_turns (int, optional): 最大对话轮次数,默认5轮
Returns:
list: 当未触发工具调用时返回完整对话记录
str: 当触发工具调用时返回最后观察结果(循环中)
"""
i = 0
# 初始化对话机器人并加载系统预设
bot = ChatBot(system_prompt)
# 通过 next_prompt 标识每一个子任务的阶段性输入
next_prompt = question
# 解析AI返回结果中的动作指令
action_re = re.compile(r'^行动[::]\s*([a-zA-Z_]+)(?:[::]\s*(.*))?$', re.MULTILINE)
# 限制最大交互轮次防止无限循环
while i < max_turns:
i += 1
# 调用ChatBot模型获取当前轮次响应
result = bot(next_prompt)
print(f"result:{result}")
actions = action_re.findall(result)
# 检测到工具调用指令时执行
if actions:
# 解析工具名称和调用参数
action, action_input = actions[0] # 取第一个动作指令
# 验证工具是否在允许列表中
if action not in available_actions:
raise Exception("Unknown action: {}: {}".format(action, action_input))
print(f"running: {action} {action_input}")
if action_input != "":
# 执行工具并获取返回结果
observation = available_actions[action](action_input)
else:
# 执行工具并获取返回结果
observation = available_actions[action]()
print(f"Observation: {observation}")
# 将工具结果作为下一轮输入
next_prompt = "观测:{}".format(observation)
else:
# 未检测到工具指令则终止流程并返回对话记录
return bot.messages
【完整代码】
python
import re
import requests
import datetime
from dotenv import load_dotenv
from openai import OpenAI
load_dotenv()
client = OpenAI(
api_key="sk-30cacfee1f4a4c2d9163454078d7138f",
base_url="https://api.deepseek.com"
)
system_prompt = """
你按照 思考→行动→观测→答案 的循环流程运行。
循环结束后输出最终答案。
使用【思考】描述你针对用户问题的分析思路。
使用【行动】调用你可用的工具操作。
【观测】为执行对应行动后得到的结果。
【答案】为分析观测结果后得出的最终结论。
查询当前时间**必须调用函数**。
你可用的操作工具:
get_current_time(获取当前时间)
示例:get_current_time: ''
功能:获取系统当前时间
作用原理:获取实时时间,用于后续逻辑判断与运算
calculate(数值计算)
示例:calculate: 4 * 7 / 3
功能:执行数学运算并返回结果,采用Python语法,浮点运算请规范书写格式
fetch_real_time_info(实时联网查询)
示例:fetch_real_time_info: 阿里
功能:通过SerperAPI检索实时网络信息
只要适用,就必须优先使用联网查询工具。
示例对话1:
问题:中国首都是哪里?
思考:我需要通过联网查询获取答案
行动:fetch_real_time_info: 中国首都
暂停
你将收到如下内容:
观测:中国是一个国家,首都是北京。
思考:我已经得到准确答案
行动:北京
随后输出:
答案:中国的首都是北京
示例对话2:
问题:地球质量乘以2等于多少?
思考:我需要先联网查询地球质量
行动:fetch_real_time_info: 地球质量
暂停
你将收到如下内容:
观测:地球质量为5.972×10^24
思考:需要将数值乘以2进行计算
行动:calculate: 5.972e24 * 2
暂停
你将收到如下内容:
观测:1.1944×10^25
得到结果后直接输出答案
答案:地球质量的2倍是1.1944×10^25
示例对话3:
问题:需要获取当前时间进行年份计算
思考:需要获取当前年份
行动:get_current_time
观测:2025-12-01 09:01:01
答案:2025-12-01 09:01:01
""".strip()
# 定义工具
def fetch_real_time_info(query):
"""
通过Serper API获取实时搜索信息
使用Serper的Google搜索API查询指定问题,并返回最相关结果的摘要片段。
参数:
query (str): 要搜索的查询字符串,表示用户提出的问题
返回:
str: 搜索结果摘要片段。若无结果则返回提示信息
"""
# API参数配置
params = {
'api_key': ".......", # 使用您自己的API密钥
'q': query, # 查询参数,表示要搜索的问题。
'num': 1 # 返回结果的数量设为1,API将返回一个相关的搜索结果。
}
# 发起API请求
api_result = requests.get('https://google.serper.dev/search', params)
# 解析JSON响应数据
search_data = api_result.json()
# 提取并返回查询到的信息
if search_data["organic"]:
return search_data["organic"][0]["snippet"]
else:
return "没有找到相关结果。"
def calculate(operation: str) -> float:
"""
计算字符串数学表达式的值
使用内置eval()函数执行传入的数学表达式字符串,并返回浮点数结果。
注意:eval()会执行任何传入的Python代码,存在严重安全风险,
请确保仅传入可信来源的数学表达式。
Args:
operation: 包含数学表达式的字符串,例如 "2 * 3 + 4"
Returns:
表达式计算结果的浮点数值
Raises:
SyntaxError: 当传入字符串不是合法表达式时
TypeError: 当表达式结果无法转换为浮点数时
ZeroDivisionError: 当表达式中包含除以零操作时
"""
return eval(operation)
def get_current_time():
"""
获取当前系统时间并格式化为字符串
返回:
str: 格式为'YYYY-MM-DD HH:MM:SS'的当前时间字符串
"""
return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 定义模型
class ChatBot:
def __init__(self, system=""):
self.system = system # 系统提示词
self.messages = [] # 保存对话历史
# 如果存在系统指令,添加到消息列表开头
if self.system:
self.messages.append({"role": "system", "content": system})
def __call__(self, message):
self.messages.append({"role": "user", "content": message})
# 调用模型执行并获取回复
result = self.execute()
# 将AI回复添加到对话历史
self.messages.append({"role": "assistant", "content": result})
return result
def execute(self):
completion = client.chat.completions.create(
model="deepseek-chat", # 模型名固定
messages=self.messages,
temperature=0.5,
stream=False, # 必须关闭流式输出
stop=["观测:", "观测:", "Observation:", "Observation:"]
)
return completion.choices[0].message.content
available_actions = {
# 实时信息获取操作:调用fetch_real_time_info函数处理
"fetch_real_time_info": fetch_real_time_info,
# 计算操作:调用calculate函数处理
"calculate": calculate,
# 获取当前时间操作:调用get_current_time函数处理
"get_current_time": get_current_time,
}
def AgentExecutor(question, max_turns=5):
"""
执行多轮对话代理的核心逻辑
通过有限轮次的对话交互处理用户问题,当模型输出包含工具调用指令时,
自动执行相应工具并观察结果,否则返回完整对话记录
Args:
question (str): 用户输入的初始问题
max_turns (int, optional): 最大对话轮次数,默认5轮
Returns:
list: 当未触发工具调用时返回完整对话记录
str: 当触发工具调用时返回最后观察结果(循环中)
"""
i = 0
# 初始化对话机器人并加载系统预设
bot = ChatBot(system_prompt)
# 通过 next_prompt 标识每一个子任务的阶段性输入
next_prompt = question
# 解析AI返回结果中的动作指令
action_re = re.compile(r'^行动[::]\s*([a-zA-Z_]+)(?:[::]\s*(.*))?$', re.MULTILINE)
# 限制最大交互轮次防止无限循环
while i < max_turns:
i += 1
# 调用ChatBot模型获取当前轮次响应
result = bot(next_prompt)
print(f"result:{result}")
actions = action_re.findall(result)
# 检测到工具调用指令时执行
if actions:
# 解析工具名称和调用参数
action, action_input = actions[0] # 取第一个动作指令
# 验证工具是否在允许列表中
if action not in available_actions:
raise Exception("Unknown action: {}: {}".format(action, action_input))
print(f"running: {action} {action_input}")
if action_input != "":
# 执行工具并获取返回结果
observation = available_actions[action](action_input)
else:
# 执行工具并获取返回结果
observation = available_actions[action]()
print(f"Observation: {observation}")
# 将工具结果作为下一轮输入
next_prompt = "观测:{}".format(observation)
else:
# 未检测到工具指令则终止流程并返回对话记录
return bot.messages
if __name__ == "__main__":
AgentExecutor("华为有限公司成立多少年了?")
【注】:本篇文章参考:一文详解ReAct Agent!手把手带你从零构建 ReAct Agent-CSDN博客
感谢博主的分享