Chapter 04
第四章 智能体经典范式构建
前三章建立了 Agent 和 LLM 的基础,本章进入构建方法。我们会先准备离线 LLM 客户端和工具系统,再实现 ReAct、Plan-and-Solve、Reflection 三种经典范式。
本章学习目标
4.1 环境准备与基础工具定义
4.1.1 安装依赖库
教学代码全部使用 Python 标准库,不依赖真实模型 API。这样你可以先理解范式结构,再把离线客户端替换成真实 LLM SDK。
python3 public/course/code/chapter4/react_agent.py
python3 public/course/code/chapter4/plan_and_solve.py
python3 public/course/code/chapter4/reflection_agent.py
4.1.2 配置 API 密钥
真实项目通常会通过环境变量配置模型供应商、API Key、模型名和超时时间。本章为了可复现,使用 OfflineLLMClient 模拟模型输出。
from dataclasses import dataclass
@dataclass
class LLMMessage:
role: str
content: str
class OfflineLLMClient:
def complete(self, messages: list[LLMMessage]) -> str:
prompt = "\n".join(message.content for message in messages)
if "Plan-and-Solve" in prompt:
return "1. 收集事实\n2. 计算关键数值\n3. 汇总答案"
return "Thought: 需要先计算。\nAction: calculator\nAction Input: 18 * 7 + 6"
4.1.3 封装基础 LLM 调用函数与工具
工具系统负责把可执行能力暴露给 Agent。工具必须有名称、说明、参数输入和返回值;高风险工具还需要权限和人工确认。
from dataclasses import dataclass
from typing import Callable
@dataclass
class Tool:
name: str
description: str
run: Callable[[str], str]
class ToolRegistry:
def register(self, tool: Tool) -> None:
...
def get(self, name: str) -> Tool:
...
def describe(self) -> str:
...
完整代码见 llm_client.py 和 tools.py。
4.2 ReAct
4.2.1 ReAct 的工作流程
ReAct 的核心是把 Reasoning 和 Acting 交替组织起来。模型先输出 Thought,说明为什么要做某一步;再输出 Action 和 Action Input,调用工具;工具结果作为 Observation 回到上下文,进入下一轮。
4.2.2 工具的定义与实现
ReAct 强依赖工具说明。工具描述太少,模型不知道何时调用;描述太松,模型会生成危险参数。入门阶段建议只暴露只读工具和计算工具。
4.2.3 ReAct 智能体的编码实现
class ReActAgent:
def __init__(self, llm, tools, max_steps: int = 4) -> None:
self.llm = llm
self.tools = tools
self.max_steps = max_steps
self.trace: list[str] = []
def run(self, question: str) -> str:
for _ in range(self.max_steps):
response = self.llm.complete(...)
if "Final Answer:" in response:
return response.split("Final Answer:", 1)[1].strip()
tool_name, tool_input = self.parse_action(response)
observation = self.tools.get(tool_name).run(tool_input)
self.trace.append(f"Observation: {observation}")
完整代码见 react_agent.py。
4.2.4 ReAct 的特点、局限性与调试技巧
| 优点 | 局限 | 调试重点 |
|---|---|---|
| 流程直观,便于观察每轮工具调用。 | 长任务会堆积上下文,错误会在循环中放大。 | 检查 Action 格式、工具返回、最大步数和停止条件。 |
4.3 Plan-and-Solve
4.3.1 Plan-and-Solve 的工作原理
Plan-and-Solve 先把问题拆成计划,再逐步执行。它适合结构较清楚但步骤较多的任务,例如资料整理、报告写作、数学解题和多阶段分析。
4.3.2 规划阶段
规划阶段不急着调用工具,而是生成步骤清单。好的计划要具体、可执行、可验证,避免“分析问题”“给出答案”这类空泛步骤。
4.3.3 执行器与状态管理
class PlanAndSolveAgent:
def plan(self, question: str) -> list[str]:
raw = self.llm.complete(...)
return [line.split(".", 1)[1].strip() for line in raw.splitlines()]
def execute_step(self, step: str) -> str:
if "计算" in step:
return self.tools.get("calculator").run("18 * 7 + 6")
return "根据已有结果组织最终回答"
完整代码见 plan_and_solve.py。
4.3.4 运行实例与分析
如果 ReAct 像边走边问路,Plan-and-Solve 更像先画路线图再出发。它降低了盲目工具调用的概率,但计划一旦错误,也可能把后续步骤带偏。
4.4 Reflection
4.4.1 Reflection 机制的核心思想
Reflection 让 Agent 在生成答案后进行审查,找到缺陷,再修订下一版。它常用于代码生成、长文写作、复杂推理和需要质量把关的任务。
4.4.2 案例设定与记忆模块设计
Reflection 通常需要记录每一轮草稿、反馈和修订结果。这样下一轮才能避免重复犯错,也方便人工审查。
4.4.3 Reflection 智能体的编码实现
class ReflectionAgent:
def run(self, task: str) -> str:
answer = self.draft(task)
for _ in range(self.max_rounds):
critique = self.critique(task, answer)
answer = self.revise(answer, critique)
return answer
完整代码见 reflection_agent.py。
4.4.4 运行实例与分析
运行示例会输出初稿、审查意见和修订稿。你需要重点观察两件事:反馈是否指出了可执行问题,修订稿是否真正响应了反馈。如果反馈只说“需要更好”,Reflection 就会变成重复调用;如果反馈包含证据、边界和改进目标,修订质量才会稳定提升。
4.4.5 Reflection 机制的成本收益分析
Reflection 会增加调用次数和延迟,不适合所有任务。它更适合高价值输出,而不是简单问答。生产中可以只对低置信度、高风险或高价值任务触发反思。
4.5 本章小结
本章实现了三种经典范式:ReAct 适合边观察边行动,Plan-and-Solve 适合先拆解再执行,Reflection 适合先生成再审查。后续学习框架时,你会看到这些范式被封装成节点、角色、图和工具系统。
习题
- 练习 4.1:扩展工具。 给
ToolRegistry增加word_count工具,并让 ReActAgent 调用它。 - 练习 4.2:改进解析。 当模型输出缺少 Action Input 时,让 ReActAgent 安全停止并返回错误原因。
- 练习 4.3:计划校验。 给 Plan-and-Solve 增加计划审查函数,过滤空泛步骤。
- 练习 4.4:反思触发条件。 只在答案长度少于 50 字时触发 Reflection。