【整理】Agent中的ReAct架构

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博客

感谢博主的分享

相关推荐
小锋学长生活大爆炸5 小时前
【教程】在Docker中部署Hermes Agent
docker·容器·agent·教程·工具·openclaw·hermes
舒一笑11 小时前
大模型根本不是“学会了”,它只是会“看例子”:一文讲透 In-context Learning(ICL)
langchain·llm·openai
swipe14 小时前
用 Nest + LangChain 打造 OpenClaw 式 Agent 定时任务系统
人工智能·llm·agent
Java后端的Ai之路14 小时前
LangChain ReAct Agent 核心技术问答
前端·react.js·langchain
阿里云大数据AI技术16 小时前
让 AI 帮你写大数据AI开发代码:MaxFrame Coding Skill 正式发布
人工智能·agent
HOHO18 小时前
说起来你可能不信,我写了个跑在浏览器里的 ai agent 框架
aigc·agent
深念Y19 小时前
AI 写代码总跑偏?我逼它回到“函数级颗粒度”
ai·软件工程·agent·函数·coding·vibe coding·代码补全
Java后端的Ai之路19 小时前
LangChain 面试问答指南2
面试·职场和发展·langchain
_志哥_19 小时前
# Agent 时代的底层逻辑:Harness 即操作系统
人工智能·agent·ai编程