AI AI树洞

Chapter 07

第七章 构建你的智能体框架

这一章把前面学过的概念收束成一个小型框架。它不是为了替代成熟框架,而是帮助你理解一个 Agent 框架需要哪些接口:消息、配置、模型、Agent 抽象类、工具注册、经典范式和函数调用。

7.1 框架整体架构设计

7.1.1 为何需要自建 Agent 框架

自建框架的价值不是重复造轮子,而是理解轮子。只有亲手抽象 Message、Config、Agent、ToolBox,你才能判断成熟框架的设计是否适合自己的业务。

7.1.2 框架的设计理念

模块责任边界
Message统一对话消息结构。不关心模型供应商。
Config保存 provider、model、temperature、max_steps。不保存业务状态。
Agent定义 run 接口和历史记录。不直接硬编码工具。
ToolBox注册、描述和调用工具。不决定何时调用工具。

7.1.3 本章学习目标

学完后,你应该能运行 mini_agent_framework.py,并理解 SimpleAgent、ReActAgent、ReflectionAgent、PlanAndSolveAgent、FunctionCallAgent 的共同抽象。

7.2 LLM 扩展

7.2.1 支持多提供商

真实框架通常需要支持多个模型供应商。最小做法是用统一 complete(messages) 接口包住不同 provider,让 Agent 不关心底层 API。

7.2.2 本地模型调用

本地模型可以通过 Ollama、vLLM 或兼容 OpenAI 的本地服务接入。框架层只需要把 base_url、model 和 api_key 作为配置,不要让业务代码到处写供应商判断。

7.2.3 自动检测机制

自动检测可以按环境变量判断 provider,例如优先检测本地服务,再检测云 API。教学代码使用 OfflineModel 保持可运行。

7.3 框架接口实现

7.3.1 Message 类

Role = Literal["system", "user", "assistant", "tool"]


@dataclass
class Message:
    role: Role
    content: str

7.3.2 Config 类

@dataclass
class Config:
    provider: str = "offline"
    model: str = "mini-agent-model"
    temperature: float = 0.1
    max_steps: int = 4

7.3.3 Agent 抽象基类

class Agent(ABC):
    def __init__(self, model=None, config=None) -> None:
        self.model = model or OfflineModel()
        self.config = config or Config()
        self.history: list[Message] = []

    @abstractmethod
    def run(self, task: str) -> str:
        raise NotImplementedError

7.4 Agent 范式的框架化实现

7.4.1 SimpleAgent

SimpleAgent 只负责基础对话,它是所有复杂 Agent 的起点。

7.4.2 ReActAgent

ReActAgent 在框架里接入 ToolBox,把模型输出解析成工具调用。

7.4.3 ReflectionAgent

ReflectionAgent 把“生成、审查、修订”封装为固定流程。

7.4.4 PlanAndSolveAgent

PlanAndSolveAgent 先返回步骤列表,再按步骤执行或交给其他节点。

7.4.5 FunctionCallAgent

FunctionCallAgent 直接把模型输出的 JSON 当作函数调用请求,但必须先经过工具白名单校验。

class FunctionCallAgent(Agent):
    def __init__(self, toolbox: ToolBox, model=None, config=None) -> None:
        super().__init__(model, config)
        self.toolbox = toolbox

    def run(self, task: str) -> str:
        call = json.loads(self.model.complete([...]))
        return self.toolbox.call(call["tool"], call["arguments"])

7.5 工具系统

7.5.1 工具基类与注册机制设计

工具系统至少要支持注册、描述、调用和错误处理。成熟系统还需要参数 schema、权限标签、超时、审计日志和人工确认。

@dataclass
class Tool:
    name: str
    description: str
    handler: Callable[[dict], str]


class ToolBox:
    def register(self, tool: Tool) -> None:
        self.tools[tool.name] = tool

    def call(self, name: str, arguments: dict) -> str:
        if name not in self.tools:
            raise KeyError(f"未知工具:{name}")
        return self.tools[name].handler(arguments)

7.5.2 自定义工具开发

本章示例实现了计算器工具。你可以按同样接口增加搜索、文件读取、数据库查询和 HTTP 请求工具。

7.5.3 多源搜索工具

多源搜索工具应返回结构化来源,包含 title、url、snippet、source_type 和 confidence。不要只返回一段合并文本。

7.5.4 工具系统的高级特性

高级工具系统会支持工具链、异步执行、批处理、重试和权限策略。学习阶段先保证工具可描述、可校验、可追踪。

完整代码见 mini_agent_framework.py

7.6 本章小结

本章实现了一个小型 Agent 框架。它包含 Message、Config、Agent 抽象、离线模型、工具箱和五类 Agent。后续继续学习记忆、检索、上下文工程和评估时,可以把这些能力逐步接入这个骨架。

习题

  1. 练习 7.1:增加 Provider。OfflineModel 增加一个模拟 OpenAI Provider,并通过 Config 选择。
  2. 练习 7.2:扩展 Message。 给 Message 增加 metadata 字段,记录工具调用 ID。
  3. 练习 7.3:工具参数校验。 给 Tool 增加 required 字段,调用前检查参数是否齐全。
  4. 练习 7.4:实现搜索工具。 用本地字典实现 search_notes,并接入 ReActAgent。

参考资料

  • Hello-Agents:公开 Agent 教程项目,用于对照学习路径和章节主题。
  • Function calling:理解工具调用接口的工程参考。
  • LangGraph:状态图和可恢复 Agent 流程的工程参考。