从零手写一个支持ReAct模式的轻量级智能体框架,其核心在于构建一个能够驱动大型语言模型(LLM)进行“思考-行动-观察”循环迭代的系统。这个过程涉及多个紧密协作的模块。

以下是构建该框架必须掌握的五大核心模块及其技术要点:


1. 核心逻辑层:智能体的“决策大脑”

这是框架的顶层设计,负责驱动整个ReAct循环的逻辑。其核心是提示工程模块,旨在激活LLM的推理与规划能力,而无需对其进行微调。

模块 功能描述 比喻 技术要点与实现
推理引擎 基于任务目标和历史上下文,生成逻辑连贯的推理轨迹(Thought),明确下一步行动的依据。 侦探的案情分析板,根据现有线索推理出下一步侦查方向。 1. 提示词模板设计:构建强约束的提示词,强制LLM按“Thought: ... Action: ... ”格式输出。
2. 系统指令注入:在提示词开头明确智能体的角色、可用工具列表及输出格式规范。
行动规划器 将推理结果(Thought)转化为标准化的、可执行的行动指令(Action),包括工具名称和输入参数。 任务派发单,将分析结论转化为具体的、可操作的指令。 1. 结构化输出解析:要求LLM输出严格的JSON或特定分隔符格式,以便程序自动解析出 actionaction_input
2. 工具描述集成:在提示词中清晰描述每个工具的功能和输入格式,帮助LLM做出正确选择。

核心代码结构示例

# 提示词模板示例
REACT_PROMPT_TEMPLATE = """
你是一个智能助理。请使用以下工具完成任务:
{tools_descriptions}

任务:{user_input}

你必须严格按照以下格式回应:
Thought: 分析当前情况和下一步该做什么
Action: 要使用的工具名称
Action Input: 工具的输入参数

开始!
历史记录:
{history}

当前情况:{observation}
"""

2. 执行循环层:智能体的“中枢调度”

此模块是ReAct(Reasoning + Action)循环的物理实现,负责串联“推理→行动→观察→再推理”的完整流程。

模块 功能描述 比喻 技术要点与实现
循环控制器 管理ReAct循环的启动、执行和终止。 交通环岛的控制中心,确保车辆(任务状态)按规则循环,并在到达目的地时驶出。 1. 最大迭代次数:设置循环上限,防止智能体陷入无限循环。
2. 终止条件判断:在每次循环后,检查LLM的输出是否包含最终答案(如“Final Answer:”)或任务已完成的信号。
上下文管理器 存储、管理和裁剪历史交互记录(TAO轨迹),确保LLM始终在有效的上下文窗口内工作。 智能录音笔,只保留最近和最相关的对话片段,避免内存爆满。 1. 状态维护:维护一个包含用户输入、历史TAO序列、当前观察等信息的“状态”对象。
2. 上下文裁剪策略:当历史记录过长时,采用“近期完整保留+早期关键信息摘要”的策略进行压缩。

核心代码结构示例

class ReActAgent:
    def __init__(self, llm, tools, max_iterations=10):
        self.llm = llm
        self.tools = {tool.name: tool for tool in tools}
        self.max_iterations = max_iterations
        self.history = []  # 存储历史 (Thought, Action, Observation)

    def run(self, user_input):
        state = {"input": user_input, "observation": "", "answer": None}
        for i in range(self.max_iterations):
            # 1. 生成Thought和Action
            prompt = self._build_prompt(state)
            llm_response = self.llm.invoke(prompt)
            thought, action, action_input = self._parse_response(llm_response)

            # 检查是否已得出最终答案
            if "Final Answer:" in thought:
                state["answer"] = thought.split("Final Answer:")[-1].strip()
                break

            # 2. 执行Action(工具调用)
            if action in self.tools:
                observation = self.tools[action].run(action_input)
            else:
                observation = f"Error: Unknown action '{action}'."

            # 3. 更新状态和历史
            self.history.append((thought, action, observation))
            state["observation"] = observation

            # 4. 构建新的提示词,进入下一轮循环
        return state["answer"]

3. 工具集成层:智能体的“手脚”

智能体通过调用工具与外部世界交互,扩展其能力边界。此层负责工具的抽象、注册和调用。

模块 功能描述 比喻 技术要点与实现
工具抽象 定义统一的工具接口,任何函数或API只要遵循此接口,就能被智能体调用。 电源插座标准,所有电器(工具)只要插头匹配(接口一致)就能通电(被调用)。 1. 标准化工具类:每个工具应有 namedescriptionparameters 和一个 run 方法。
2. 工具描述生成:自动或手动生成清晰、简洁的工具功能描述,用于提示词。
工具执行器 根据LLM解析出的行动指令,动态查找并执行对应的工具,捕获执行结果或错误。 万能遥控器,接收到“打开空调”的指令后,自动找到空调遥控器并按下开关。 1. 工具路由:根据 action 名称在工具注册表中查找对应工具。
2. 安全执行:在沙箱或受控环境中执行工具,特别是执行代码类工具时。
3. 错误处理:捕获工具执行异常,并将友好的错误信息作为“观察”返回给LLM。

核心代码结构示例

from typing import Any, Dict
import requests

class BaseTool:
    """工具基类"""
    name: str = ""
    description: str = ""
    
    def run(self, input_str: str) -> str:
        """执行工具的主要逻辑,返回字符串格式的观察结果"""
        raise NotImplementedError

class SearchTool(BaseTool):
    name = "search_web"
    description = "在互联网上搜索信息。输入是一个搜索查询词。"
    
    def run(self, query: str) -> str:
        try:
            # 模拟搜索,实际应调用搜索引擎API
            results = f"关于'{query}'的搜索结果:..."
            return results
        except Exception as e:
            return f"搜索工具执行出错:{str(e)}"

class CalculatorTool(BaseTool):
    name = "calculator"
    description = "执行数学计算。输入是一个数学表达式,如 '2 + 3 * 4'。"
    
    def run(self, expression: str) -> str:
        try:
            result = eval(expression)  # 注意:生产环境应使用更安全的评估方法
            return f"计算结果:{result}"
        except Exception as e:
            return f"计算错误:{str(e)}"

4. 记忆与状态管理层:智能体的“工作记忆”

为了使智能体能在多轮交互中保持连贯性,必须有能力记住过去的交互。

模块 功能描述 比喻 技术要点与实现
短期记忆 存储当前会话或任务循环中的完整TAO序列,直接作为上下文提供给LLM。 白板,记录当前会议的所有讨论要点。 1. 序列存储:使用列表或队列存储每一步的 (Thought, Action, Observation) 三元组。
2. 上下文构建:在生成下一轮提示时,将短期记忆中的序列格式化后插入历史记录部分。
状态对象 封装智能体运行过程中的所有动态数据,是循环各模块间传递信息的载体。 快递包裹面单,上面写着收件人、货物信息、当前到达哪个中转站。 1. 结构化定义:使用字典或Pydantic模型定义状态,包含inputhistoryobservationintermediate_steps等字段。
2. 不可变性或版本管理:每次循环产生新状态,便于调试和实现更复杂的流程(如分支、循环)。

5. 输出解析与流程控制层:智能体的“质检员与交警”

此层负责理解LLM的输出并控制流程走向,确保系统的鲁棒性。

模块 功能描述 比喻 技术要点与实现
输出解析器 将LLM的自由文本输出,解析为程序可理解的、结构化的数据(Thought, Action等)。 文书翻译官,将一份自由书写的报告,翻译成格式规范的表格。 1. 正则表达式匹配:使用正则从文本中提取关键字段。
2. 后备解析逻辑:当标准格式解析失败时,尝试启发式方法或要求LLM重试。
3. 支持结构化输出:直接使用支持JSON等结构化输出的LLM API。
流程控制器 根据解析结果和当前状态,决定下一步是继续循环、调用工具还是返回最终答案。 十字路口的智能信号灯,根据车流(状态)决定是放行(继续循环)还是切换红灯(终止)。 1. 终止判定:检测LLM输出中是否包含“Final Answer”、“Answer:”等终止关键词。
2. 异常流程处理:处理未知工具、解析失败、工具执行错误等情况,决定是重试、报错还是继续。

总结与推演:手写一个轻量级ReAct智能体框架,就是将这五个模块像拼装乐高一样组合起来。

工作流始于用户输入,核心逻辑层生成推理和行动指令,输出解析器将其结构化,流程控制器判断是否需要调用工具。

若需调用,工具集成层执行具体操作并返回结果,记忆与状态管理层更新历史,然后执行循环层开启下一轮迭代,直到流程控制器判定任务完成。

掌握这些模块,你就掌握了构建自主智能体的核心蓝图。


参考来源

 

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐