【智能体Agent】ReAct智能体的实现思路和关键技术

news2025/3/9 21:59:17

基于ReAct(Reasoning + Acting)框架的自主智能体

import re
from typing import List, Tuple

from langchain_community.chat_message_histories.in_memory import ChatMessageHistory
from langchain_core.language_models.chat_models import BaseChatModel
from langchain.output_parsers import PydanticOutputParser, OutputFixingParser
from langchain.schema.output_parser import StrOutputParser
from langchain.tools.base import BaseTool
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.tools import  render_text_description
from pydantic import ValidationError
from langchain_core.prompts import HumanMessagePromptTemplate

from Agent.Action import Action
from Utils.CallbackHandlers import *


class ReActAgent:
    """AutoGPT:基于Langchain实现"""

    @staticmethod
    def __format_thought_observation(thought: str, action: Action, observation: str) -> str:
        # 将全部JSON代码块替换为空
        ret = re.sub(r'```json(.*?)```', '', thought, flags=re.DOTALL)
        ret += "\n" + str(action) + "\n返回结果:\n" + observation
        return ret

    @staticmethod
    def __extract_json_action(text: str) -> str | None:
        # 匹配最后出现的JSON代码块
        json_pattern = re.compile(r'```json(.*?)```', re.DOTALL)
        matches = json_pattern.findall(text)
        if matches:
            last_json_str = matches[-1]
            return last_json_str
        return None

    def __init__(
            self,
            llm: BaseChatModel,
            tools: List[BaseTool],
            work_dir: str,
            main_prompt_file: str,
            max_thought_steps: Optional[int] = 10,
    ):
        self.llm = llm
        self.tools = tools
        self.work_dir = work_dir
        self.max_thought_steps = max_thought_steps

        # OutputFixingParser: 如果输出格式不正确,尝试修复
        self.output_parser = PydanticOutputParser(pydantic_object=Action)
        self.robust_parser = OutputFixingParser.from_llm(
            parser=self.output_parser,
            llm=llm
        )

        self.main_prompt_file = main_prompt_file

        self.__init_prompt_templates()
        self.__init_chains()

        self.verbose_handler = ColoredPrintHandler(color=THOUGHT_COLOR)

    def __init_prompt_templates(self):
        with open(self.main_prompt_file, 'r', encoding='utf-8') as f:
            self.prompt = ChatPromptTemplate.from_messages(
                [
                    MessagesPlaceholder(variable_name="chat_history"),
                    HumanMessagePromptTemplate.from_template(f.read()),
                ]
            ).partial(
                work_dir=self.work_dir,
                tools=render_text_description(self.tools),
                tool_names=','.join([tool.name for tool in self.tools]),
                format_instructions=self.output_parser.get_format_instructions(),
            )

    def __init_chains(self):
        # 主流程的chain
        self.main_chain = (self.prompt | self.llm | StrOutputParser())

    def __find_tool(self, tool_name: str) -> Optional[BaseTool]:
        for tool in self.tools:
            if tool.name == tool_name:
                return tool
        return None

    def __step(self,
               task,
               short_term_memory,
               chat_history,
               verbose=False
               ) -> Tuple[Action, str]:

        """执行一步思考"""

        inputs = {
            "input": task,
            "agent_scratchpad": "\n".join(short_term_memory),
            "chat_history": chat_history.messages,
        }

        config = {
            "callbacks": [self.verbose_handler]
            if verbose else []
        }
        response = ""
        for s in self.main_chain.stream(inputs, config=config):
            response += s
        # 提取JSON代码块
        json_action = self.__extract_json_action(response)
        # 带容错的解析
        action = self.robust_parser.parse(
            json_action if json_action else response
        )
        return action, response

    def __exec_action(self, action: Action) -> str:
        # 查找工具
        tool = self.__find_tool(action.name)
        if tool is None:
            observation = (
                f"Error: 找不到工具或指令 '{action.name}'. "
                f"请从提供的工具/指令列表中选择,请确保按对顶格式输出。"
            )
        else:
            try:
                # 执行工具
                observation = tool.run(action.args)
            except ValidationError as e:
                # 工具的入参异常
                observation = (
                    f"Validation Error in args: {str(e)}, args: {action.args}"
                )
            except Exception as e:
                # 工具执行异常
                observation = f"Error: {str(e)}, {type(e).__name__}, args: {action.args}"

        return observation

    def run(
            self,
            task: str,
            chat_history: ChatMessageHistory,
            verbose=False
    ) -> str:
        """
        运行智能体
        :param task: 用户任务
        :param chat_history: 对话上下文(长时记忆)
        :param verbose: 是否显示详细信息
        """
        # 初始化短时记忆: 记录推理过程
        short_term_memory = []

        # 思考步数
        thought_step_count = 0

        reply = ""

        # 开始逐步思考
        while thought_step_count < self.max_thought_steps:
            if verbose:
                self.verbose_handler.on_thought_start(thought_step_count)

            # 执行一步思考
            action, response = self.__step(
                task=task,
                short_term_memory=short_term_memory,
                chat_history=chat_history,
                verbose=verbose,
            )

            # 如果是结束指令,执行最后一步
            if action.name == "FINISH":
                reply = self.__exec_action(action)
                break

            # 执行动作
            observation = self.__exec_action(action)

            if verbose:
                self.verbose_handler.on_tool_end(observation)

            # 更新短时记忆
            short_term_memory.append(
                self.__format_thought_observation(
                    response, action, observation
                )
            )

            thought_step_count += 1

        if thought_step_count >= self.max_thought_steps:
            # 如果思考步数达到上限,返回错误信息
            reply = "抱歉,我没能完成您的任务。"

        # 更新长时记忆
        chat_history.add_user_message(task)
        chat_history.add_ai_message(reply)
        return reply

结合LangChain框架和工具调用能力来逐步解决用户任务。

以下是代码的逐模块解析:


1. 核心结构

class ReActAgent:
    """AutoGPT:基于Langchain实现"""
  • 核心类:实现了ReAct范式(推理+行动循环)的自主智能体
  • 核心能力
    • 多步思考推理
    • 工具调用
    • 长短期记忆管理
    • 异常处理与自我修正

2. 关键静态方法

@staticmethod
def __format_thought_observation(...):  # 格式化思考记录
@staticmethod
def __extract_json_action(...):         # 提取JSON动作
  • 功能
    • __format_thought_observation:将思考过程、动作执行和观察结果格式化为可读文本,存入短期记忆
    • __extract_json_action:用正则表达式提取模型输出中的最后一个JSON代码块(确保获取最新动作)

3. 初始化模块

def __init__(...):
    # 核心组件初始化
    self.llm = llm                    # 大语言模型
    self.tools = tools                # 可用工具列表
    self.work_dir = work_dir          # 工作目录
    self.max_thought_steps = ...      # 最大思考步数
    
    # 输出解析系统
    self.output_parser = PydanticOutputParser(pydantic_object=Action)
    self.robust_parser = OutputFixingParser.from_llm(...)
    
    # 提示工程
    self.__init_prompt_templates()
    self.__init_chains()
  • 关键技术点
    • 双解析器机制OutputFixingParser可在格式错误时自动修复输出
    • Pydantic验证:确保动作符合预定义结构(Action模型)
    • 工具描述渲染render_text_description将工具转化为自然语言描述

4. 提示工程系统

def __init_prompt_templates(self):
    with open(self.main_prompt_file) as f:
        self.prompt = ChatPromptTemplate.from_messages(...)
            .partial(
                tools=...,             # 工具描述
                tool_names=...,        # 工具名称列表
                format_instructions=..., # 格式说明
            )
  • 核心要素
    • 动态加载提示模板文件
    • 包含:
      • 聊天历史占位符
      • 工具使用说明
      • 输出格式要求
      • 工作目录上下文

5. 执行流程控制

def run(...):
    while thought_step_count < self.max_thought_steps:
        # 单步思考
        action, response = self.__step(...)
        
        if action.name == "FINISH":
            break
            
        # 执行动作
        observation = self.__exec_action(action)
        
        # 记忆更新
        short_term_memory.append(...)
  • ReAct循环
    1. Reasoning:生成思考与动作(__step
    2. Acting:执行工具调用(__exec_action
    3. Observing:记录执行结果
    4. Loop:直到达到终止条件

6. 关键技术实现

6.1 单步推理 (__step)
def __step(...):
    inputs = {
        "input": task,
        "agent_scratchpad": "\n".join(short_term_memory),
        "chat_history": chat_history.messages,
    }
    
    # 流式处理LLM输出
    for s in self.main_chain.stream(inputs):
        response += s
    
    # 提取并解析动作
    json_action = self.__extract_json_action(response)
    action = self.robust_parser.parse(...)
  • 输入组成
    • 任务目标
    • 短期记忆(推理过程)
    • 长期记忆(聊天历史)
  • 流式处理:实时显示思考过程
  • 错误恢复:自动修复格式错误的JSON输出
6.2 动作执行 (__exec_action)
def __exec_action(...):
    tool = self.__find_tool(action.name)
    try:
        observation = tool.run(action.args)
    except ValidationError:
        # 参数验证错误处理
    except Exception:
        # 通用错误处理
  • 异常处理机制
    • 工具不存在
    • 参数验证错误
    • 运行时异常
  • 观察反馈:将错误信息转化为自然语言,供后续推理使用

7. 记忆系统

# 短期记忆
short_term_memory = []  # 存储格式化的推理过程

# 长期记忆
chat_history = ChatMessageHistory()  # 保存完整对话记录
  • 记忆类型
    • 短期记忆:当前任务的推理过程(最多保留max_thought_steps步)
    • 长期记忆:跨会话的完整对话历史

8. 关键设计亮点

  1. 自愈式输出解析

    • 通过OutputFixingParser实现格式错误自动修复
    • 示例场景:当LLM返回非法JSON时,自动尝试修正
  2. 渐进式推理

    # 示例输出格式
    Thought: 我需要先查找用户信息
    Action: {"name": "user_search", "args": {"id": 123}}
    Observation: 用户张三,年龄30
    • 通过agent_scratchpad维护推理上下文
  3. 工具发现机制

    • 动态渲染工具描述到提示词
    • 支持工具的热插拔
  4. 多级异常处理

    • 工具不存在
    • 参数验证错误
    • 执行时异常
    • 最大步数限制

9. 使用示例

# 初始化组件
llm = ChatOpenAI()
tools = [SearchTool(), Calculator()]
agent = ReActAgent(llm, tools, work_dir="/data")

# 执行任务
result = agent.run(
    task="计算马云当前年龄的平方根",
    chat_history=ChatMessageHistory(),
    verbose=True
)
  • 典型执行流程
    1. 搜索"马云年龄" → 得到60岁
    2. 调用计算器计算√60 → 约7.746
    3. 返回最终结果

10. 可扩展性建议

  1. 增强记忆管理

    • 添加向量数据库长期记忆
    • 实现记忆压缩/摘要
  2. 改进推理质量

    • 添加自我验证步骤
    • 实现多路径推理
  3. 性能优化

    • 添加异步执行
    • 实现工具并行调用

该实现展示了如何结合LangChain框架构建复杂的自主智能体系统,平衡了LLM的创造力和结构化工具调用的可靠性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2312362.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

贝塞尔曲线学习

1、一阶贝塞尔曲线 一阶贝塞尔曲线其实是一条直线——给定点 P0、P1&#xff0c;线性贝塞尔曲线就是一条两点之间的直线&#xff0c;公式如下&#xff1a; 一阶曲线很好理解, 就是根据t来线性插值。 void MainWindow::mousePressEvent(QMouseEvent *e) {list.append(e->pos…

机器学习(六)

一&#xff0c;决策树&#xff1a; 简介&#xff1a; 决策树是一种通过构建类似树状的结构&#xff08;颠倒的树&#xff09;&#xff0c;从根节点开始逐步对数据进行划分&#xff0c;最终在叶子节点做出预测结果的模型。 结构组成&#xff1a; 根节点&#xff1a;初始的数据集…

【江协科技STM32】ADC数模转换器-学习笔记

ADC简介 ADC&#xff08;Analog-Digital Converter&#xff09;模拟-数字转换器ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量&#xff0c;建立模拟电路到数字电路的桥梁&#xff0c;ADC是一种将连续的模拟信号转换为离散的数字信号的设备或模块12位逐次逼近型…

嵌入式学习笔记-卡尔曼滤波,PID,MicroPython

文章目录 卡尔曼滤波卡尔曼滤波的核心思想卡尔曼滤波的数学模型1. 状态转移模型&#xff08;预测系统状态&#xff09;2. 观测模型&#xff08;预测测量值&#xff09; 卡尔曼滤波的五个关键步骤1. 预测状态2. 预测误差协方差3. 计算卡尔曼增益4. 更新状态5. 更新误差协方差 卡…

upload-labs文件上传

第一关 上传一个1.jpg的文件&#xff0c;在里面写好一句webshell 保留一个数据包&#xff0c;将其中截获的1.jpg改为1.php后重新发送 可以看到&#xff0c;已经成功上传 第二关 写一个webshell如图&#xff0c;为2.php 第二关在过滤tpye的属性&#xff0c;在上传2.php后使用b…

C++20 格式化库:强大的字符串格式化工具

文章目录 格式化语法常见用法1. 填充和对齐2. 数值格式化3. 进制格式化4. 自定义类型 示例代码注意事项 C20 的格式化库是一个强大的工具&#xff0c;用于处理字符串的格式化操作。它提供了类似于 Python 中 str.format() 的功能&#xff0c;但语法和用法更符合 C 的风格。以下…

[傻瓜式教学]如何将MathType公式编辑器内嵌到WPS工具栏中

[傻瓜式教学]如何将MathType公式编辑器内嵌到WPS工具栏中 将MathType公式编辑器内嵌到WPS工具栏中 下载好所需文件 我用夸克网盘分享了「mathtype安装教程超简单易上手.zip」&#xff0c;点击链接即可保存。打开「夸克APP」 链接&#xff1a;https://pan.quark.cn/s/4726c684…

分析TCP三次握手与四次挥手

TCP&#xff08;传输控制协议&#xff09;通过三次握手建立连接&#xff0c;四次挥手终止连接&#xff0c;确保数据传输的可靠性。 TCP的三个控制标志位&#xff1a; SYN——用于建立连接&#xff0c;同步序列号。 ACK——用于确认收到的数据。 FIN——用于终止连接。 ISN…

【深度学习】宠物品种分类Pet Breeds Classifier

文章目录 宠物品种数据集制作宠物品种标签图像预处理Presizing 损失函数loss观察模型的性能提升模型的性能learning rate finder使用CLR算法训练选择学习率的策略重新训练 迁移学习微调fine_tunefit_one_cycle有判别力的学习率 选择epoch的数量更深的网络架构 宠物品种数据集 …

【从零开始学习计算机科学】HLS算子调度

算子调度 调度是HLS 中的核心问题,为无时序或部分时序的输入指定时钟边界,其对最终结果质量具有很大的影响。调度会影响时钟频率、延时、吞吐率、面积、功耗等多种因素。 调度的输入是控制数据流图,其节点表示算子/操作,有向边表示数据依赖,控制依赖,优先依赖。如果没有…

centos 安装composer 教程

打开命令行 php -r "copy(https://getcomposer.org/installer, composer-setup.php);" sudo php composer-setup.php --install-dir/usr/local/bin --filenamecomposer composer --version sudo chmod us /usr/local/bin/composer Super18120/article/details/14388…

C语言_数据结构总结2:动态分配方式的顺序表

0——静态分配内存的顺序表和动态分配内存的顺序表的相同之处和不同之处 相同之处 基本操作逻辑相同&#xff1a;无论是静态分配还是动态分配的顺序表&#xff0c;其核心的操作逻辑是一致的。例如插入操作都需要将插入位置之后的元素依次后移&#xff0c;删除操作都需要将删除…

WSL安装及问题

1 概述 Windows Subsystem for Linux&#xff08;简称WSL&#xff09;是一个在Windows 10\11上能够运行原生Linux二进制可执行文件&#xff08;ELF格式&#xff09;的兼容层。它是由微软与Canonical公司合作开发&#xff0c;开发人员可以在 Windows 计算机上同时访问 Windows 和…

基于SpringBoot的商城管理系统(源码+部署教程)

运行环境 数据库&#xff1a;MySql 编译器&#xff1a;Intellij IDEA 前端运行环境&#xff1a;node.js v12.13.0 JAVA版本&#xff1a;JDK 1.8 主要功能 基于Springboot的商城管理系统包含管理端和用户端两个部分&#xff0c;主要功能有&#xff1a; 管理端 首页商品列…

HeidiSQL:一款免费的数据库管理工具

HeidiSQL 是一款免费的图形化数据库管理工具&#xff0c;支持 MySQL、MariaDB、Microsoft SQL、PostgreSQL、SQLite、Interbase 以及 Firebird&#xff0c;目前只能在 Windows 平台使用。 HeidiSQL 的核心功能包括&#xff1a; 免费且开源&#xff0c;所有功能都可以直接使用。…

Ae 效果详解:VR 色差

Ae菜单&#xff1a;效果/沉浸式视频/VR 色差 Immersive Video/VR Chromatic Aberrations VR 色差 VR Chromatic Aberrations效果用于模拟镜头色散现象&#xff0c;在 VR 视频中制造 RGB 通道错位的色彩偏移&#xff0c;以增强视觉风格或创造数字失真效果。 本效果适用于所有色深…

计算机毕业设计SpringBoot+Vue.js制造装备物联及生产管理ERP系统(源码+文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

【Linux内核系列】:深入解析输出以及输入重定向

&#x1f525; 本文专栏&#xff1a;Linux &#x1f338;作者主页&#xff1a;努力努力再努力wz ★★★ 本文前置知识&#xff1a; 文件系统以及文件系统调用接口 用c语言简单实现一个shell外壳程序 内容回顾 那么在此前的学习中&#xff0c;我们对于Linux的文件系统已经有了…

PyTorch系列教程:Tensor.view() 方法详解

这篇简明扼要的文章是关于PyTorch中的tensor.view()方法的介绍与应用&#xff0c;与reshape()方法的区别&#xff0c;同时给出示例进行详细解释。 Tensor基础 Tensor(张量)的视图是一个新的Tensor&#xff0c;它与原始Tensor共享相同的底层数据&#xff0c;但具有不同的形状或…

软件测试的基础入门(二)

文章目录 一、软件&#xff08;开发&#xff09;的生命周期什么是生命周期软件&#xff08;开发&#xff09;的生命周期需求分析计划设计编码测试运行维护 二、常见的开发模型瀑布模型流程优点缺点适应的场景 螺旋模型流程优点缺点适应的场景 增量模型和迭代模型流程适应的场景…