ReAct Agent 技术实现主要依赖于精心设计的 Prompt 模板、输出解析器和执行循环三大核心机制。
1. 核心 Prompt 工程
LangChain 使用特定的 Prompt 模板引导 LLM 按 Thought → Action → Observation 格式输出:
1# 简化的 Prompt 结构 2template = """ 3用以下工具回答问题: 4 5工具: 6- search: 搜索引擎, 输入: "查询词" 7- calculator: 计算器, 输入: "算式" 8 9现在开始! 10 11问题: {input} 12Thought: {agent_scratchpad} 13""" 14
关键设计:
agent_scratchpad:存储历史 Thought-Action-Observation 链,确保上下文连续- 工具描述:每个工具都有标准化描述,帮助 LLM 理解何时使用
- Few-shot 示例:内置典型交互样例,教会 LLM 输出格式
2. 输出解析机制
LLM 输出纯文本后,通过 AgentOutputParser 解析结构化数据:
1# LLM 输出示例文本 2""" 3Thought: 需要计算 2+2*2 4Action: calculator 5Action Input: "2+2*2" 6""" 7
解析过程:
- 正则匹配:提取
Thought:/Action:/Action Input:块 - 格式验证:确保符合预定 schema,否则触发格式错误处理
- 工具映射:将 Action 字符串映射到具体工具实例
关键代码(简化):
1class ReActParser: 2 def parse(self, text: str): 3 thought = re.search(r"Thought: (.*?)\n", text).group(1) 4 action = re.search(r"Action: (.*?)\n", text).group(1) 5 action_input = re.search(r"Action Input: (.*?)\n", text).group(1) 6 return AgentAction(tool=action, input=action_input, log=thought) 7
3. AgentExecutor 循环控制
这是 ReAct 的"大脑",管理整个执行流程:
1class AgentExecutor: 2 def run(self, query): 3 # 初始化 4 scratchpad = "" # 交互历史 5 steps = 0 6 7 while steps < max_iterations: 8 # 1. 调用 LLM 生成下一步 9 llm_output = self.llm( 10 prompt.format(input=query, agent_scratchpad=scratchpad) 11 ) 12 13 # 2. 解析输出 14 action = self.output_parser(llm_output) 15 16 # 3. 判断终止条件 17 if isinstance(action, AgentFinish): 18 return action.return_values["output"] 19 20 # 4. 执行工具 21 observation = self.tools[action.tool].run(action.input) 22 23 # 5. 更新 scratchpad 24 scratchpad += f"{action.log}\nObservation: {observation}\nThought: " 25 26 steps += 1 27 28 return "达到最大迭代次数" 29
关键设计模式:
- while 循环 :实现 Thought-Action-Observation 循环
- scratchpad 累积:将每轮结果追加,形成完整上下文
- 终止判断:当解析出
AgentFinish时返回最终结果
4. 工具调用架构
工具通过标准化接口集成:
1class BaseTool: 2 name: str # 工具唯一标识 3 description: str # 给 LLM 看的说明 4 args_schema: BaseModel # 参数结构 5 6 def _run(self, input: str) -> str: 7 # 具体实现 8 pass 9
动态注册机制:
1# 工具自动发现 2tools = [ 3 Tool(name="search", func=search_api, description="搜索引擎..."), 4 Tool(name="calculator", func=calculate, description="计算器...") 5] 6 7# 传递给 Agent 8agent = create_react_agent(llm, tools, prompt) 9
5. 错误处理与鲁棒性
常见错误类型:
- 格式错误:LLM 未按指定格式输出 → 捕获异常并重新提示
- 工具不存在:LLM 幻想了不存在的工具 → 返回错误 Observation
- 参数错误:工具调用参数格式不对 → 捕获异常并反馈
自我修复机制:
1except OutputParserException: 2 # 将错误信息加入 scratchpad,让 LLM 自我纠正 3 scratchpad += f"解析错误,请严格遵循格式:Action: tool_name\nAction Input: input\n" 4 continue # 重新循环 5
6. 记忆管理
ReAct Agent 的记忆体现在两个层面:
短期记忆(核心):
agent_scratchpad:当前任务的交互历史- 每轮循环自动清空,任务结束即丢弃
长期记忆(可选):
- 集成
ConversationBufferMemory实现多轮对话 - 在 Prompt 中注入历史对话摘要
技术实现总结
| 组件 | 实现方式 | 关键技术 |
|---|---|---|
| 推理生成 | Prompt Engineering + LLM 调用 | Few-shot、Scratchpad |
| 行动解析 | 正则/结构化输出解析 | Pydantic、OutputParser |
| 工具执行 | 标准化接口 + 动态调用 | BaseTool、回调机制 |
| 循环控制 | While 循环 + 状态机 | AgentExecutor、终止判断 |
| 错误恢复 | 异常捕获 + 上下文反馈 | Try-Except、自我修复 |
这种设计将确定性代码逻辑(循环、解析)与非确定性 LLM 生成完美结合,既保证了流程可控,又充分发挥了 LLM 的灵活性。
《三分钟说清楚 ReAct Agent 的技术实现》 是转载文章,点击查看原文。