第七章 构建自己的agent智能体框架

第七章笔记:从零构建智能体框架 HelloAgents(详细版)

目标:把"会用框架"升级为"能造框架"。本章以版本迭代方式构建 HelloAgents,并将智能体知识点用工程化方式串讲落地。最终框架将支撑后续章节(RAG/Memory/上下文工程/协议等)高级案例。


7.1 框架整体架构设计

7.1.1 为什么需要自建 Agent 框架

(1)市面框架的快速迭代与局限性(四大痛点)
  1. 过度抽象导致复杂性

    • 为追求通用性引入多层抽象与配置
    • 初学者要理解大量概念(Chain/Agent/Tool/Memory/Retriever...)才能做简单任务
  2. 快速迭代造成不稳定

    • 商业化框架 API 经常变更,升级后旧代码不可用
    • 维护成本高、CI/部署频繁故障
  3. 黑盒化实现逻辑

    • 关键机制封装过深,难以理解 Agent 内部工作过程
    • 遇到问题只能依赖文档/社区;社区不活跃时反馈周期长
  4. 依赖关系复杂

    • 依赖包多、体积大、与现有项目容易发生依赖冲突
(2)从使用者到构建者:能力跃迁的价值
  • 深度理解 Agent 原理:思考过程、工具调用、设计模式优劣
  • 完全控制权:可以精确调优,不受第三方框架理念束缚
  • 系统设计能力:模块化/接口抽象/异常处理/工程规范
(3)定制化需求与深度掌握的必要性
  • 垂直领域优化:金融/医疗/教育需要特定提示词、工具、安全策略
  • 性能与资源可控:响应时间、内存、并发能力要求严格
  • 教学透明性:需要可观测/可解释的构建过程,便于学习复现

7.1.2 HelloAgents 的设计理念(四个核心)

(1)轻量级 + 教学友好
  • 核心代码按章节拆分,保证"可读、可理解、可复现"
  • 极简依赖:尽量只用 OpenAI 官方 SDK + 必要基础库
  • 出问题可直接定位框架源码,而不是依赖地狱排查
(2)基于标准 API 的务实选择
  • OpenAI 兼容接口为"事实标准"

  • 好处:

    • 迁移/集成成本低(很多厂商兼容这套接口)
    • 学习成本低(不用再学一套抽象)
(3)渐进式学习路径
  • 每章在前一章基础上迭代,提供可 pip 安装的历史版本
  • 推荐路径:先体验 → 再实现
  • 本章为后续高级模块铺底(RAG/Memory/协议等)
(4)统一的"工具"抽象:万物皆为工具
  • 除核心 Agent 外,Memory/RAG/RL/MCP...全部统一为 Tool

  • 目的:

    • 减少不必要抽象
    • 让学习者抓住核心:Agent 调用 Tool 完成任务

7.1.3 本章学习目标与目录结构(框架蓝图)

复制代码
hello-agents/
├── hello_agents/
│   ├── core/
│   │   ├── agent.py
│   │   ├── llm.py
│   │   ├── message.py
│   │   ├── config.py
│   │   └── exceptions.py
│   ├── agents/
│   │   ├── simple_agent.py
│   │   ├── react_agent.py
│   │   ├── reflection_agent.py
│   │   └── plan_solve_agent.py
│   ├── tools/
│   │   ├── base.py
│   │   ├── registry.py
│   │   ├── chain.py
│   │   ├── async_executor.py
│   │   └── builtin/
│   │       ├── calculator.py
│   │       └── search.py
  • 分层原则:分层解耦 / 职责单一 / 接口统一

  • 快速体验安装:

    • pip install "hello-agents==0.1.1"(python>=3.10)

7.2 HelloAgentsLLM 扩展(模型调用中枢)

7.2 目标(三件事)

  1. 多提供商支持:OpenAI / ModelScope / 智谱等
  2. 本地模型集成:VLLM / Ollama(生产级推理方案)
  3. 自动检测机制:根据环境推断 provider,降低配置负担

7.2.1 支持多提供商:通过继承扩展 Provider

核心思路
  • 不直接改库源码

  • 用继承重写 __init__

    • provider == modelscope → 执行你的自定义逻辑
    • 否则 super().__init__(...) 保留父类能力
关键点
  • 解析 provider 特有环境变量(如 MODELSCOPE_API_KEY
  • 设置默认 base_url / 默认模型
  • 构建 OpenAI SDK Client(因为 provider 兼容 OpenAI API)

7.2.2 本地模型调用:VLLM vs Ollama

VLLM
  • 特点:高吞吐推理(PagedAttention、连续批处理)

  • 启动 OpenAI 兼容服务(示例)

    • python -m vllm.entrypoints.openai.api_server --model ... --port 8000
  • HelloAgents 接入:当成 provider + base_url + dummy api_key

Ollama
  • 特点:极简模型管理与运行
  • 默认 OpenAI 兼容地址:http://localhost:11434/v1
  • 接入方式同理
统一收益
  • Agent 代码不用改,切换云端/本地只改配置即可
  • 有利于:成本控制/隐私保护/离线运行

7.2.3 自动检测机制(_auto_detect_provider + _resolve_credentials)

_auto_detect_provider:推断 provider 的优先级
  1. 最高优先级:特定环境变量

    • 例如:MODELSCOPE_API_KEY / OPENAI_API_KEY / ZHIPU_API_KEY...
  2. 次高优先级:base_url 判断

    • 域名特征识别云服务商(api-inference.modelscope.cn 等)

    • 端口识别本地推理:

      • :11434 → ollama
      • :8000 → vllm
  3. 辅助:API key 格式识别

    • 例如前缀 ms-
  4. 都不满足 → 返回 "auto"(走通用配置)

_resolve_credentials:根据 provider 解析凭证
  • 选定 provider 后:

    • 优先从 provider 专属 env 读 key
    • 给默认 base_url
    • 兜底读 LLM_API_KEYLLM_BASE_URL

7.3 框架接口实现(核心三件套)

7.3.1 Message:统一消息系统

  • 目标:规范对话上下文的传递结构,兼容 OpenAI 格式

  • 关键设计:

    • role 限制为 Literal["user","assistant","system","tool"]
    • timestamp + metadata 为可观测与扩展预留
    • to_dict() 输出 OpenAI API 所需结构
  • 设计原则:对内丰富,对外兼容


7.3.2 Config:集中化配置管理

  • 提供默认配置,保证"零配置可运行"

  • 支持从环境变量覆盖:

    • debug/log_level/temperature/max_tokens...
  • 目的:

    • 统一参数入口
    • 多环境部署更容易

7.3.3 Agent 抽象基类

  • ABC + @abstractmethod 强制子类实现 run

  • 内置历史记录管理:

    • add_message / get_history / clear_history
  • 统一入口:

    • 所有 Agent 都可 agent.run(...) 运行
  • 可打印身份:

    • __str__ 输出 agent 名称与 provider

7.4 Agent 范式的框架化实现(4种经典范式 + 新增)

7.4 重构目标(三点)

  1. 提示词工程系统化:从任务特化 → 通用化 + 强约束格式
  2. 接口标准化:统一初始化参数、run 签名、历史管理
  3. 高度可配置:自定义 prompt、策略、参数

7.4.1 SimpleAgent(基础对话 + 可选工具调用)

MySimpleAgent 的核心能力
  • 基础对话
  • 可选工具调用(prompt 约束版)
  • 支持多轮工具迭代
  • 支持 stream_run(流式输出)
  • 动态工具管理(add/remove/list)
工具调用协议(Prompt 约束)
  • 约定格式:

    • [TOOL_CALL:{tool_name}:{parameters}]
  • Agent 解析工具调用:

    • _parse_tool_calls:正则匹配
    • _execute_tool_call:ToolRegistry 执行
    • 将结果作为"工具执行结果"插回 messages,再让模型生成最终回复
  • 安全点(隐含要求):

    • 控制迭代次数 max_tool_iterations
    • 工具执行 try/except 防崩溃

7.4.2 ReActAgent(推理-行动循环)

Prompt 模板改进点
  • 强制每次输出包含:

    • Thought:
    • Action: tool[input]Finish[answer]
  • 约束"每次只能执行一个步骤",避免混乱

  • 工具描述 {tools} 与历史 {history} 注入 prompt

框架化实现的结构化流程
  1. 构建 prompt(工具描述 + 历史 + question)
  2. 调用 llm.invoke
  3. 解析 Thought/Action
  4. 若 Finish → 结束
  5. 若 tool 调用 → 执行工具,将 Observation 加入历史
  6. 限制 max_steps 防无限循环

7.4.3 ReflectionAgent(执行-反思-优化)

  • 提供默认通用 prompts:

    • initial / reflect / refine
  • 支持 custom_prompts 适配特定领域(如代码生成)

  • 典型流程:

    1. 初次回答
    2. 反思找问题
    3. 根据反馈 refine
    4. 循环直到达到次数/满意度

7.4.4 PlanAndSolveAgent(规划-执行)

  • Planner 输出 强制 Python list 格式,便于解析与稳定执行
  • Executor 每次只解决"当前步骤",输出该步骤结果
  • 加强异常处理,避免解析失败导致崩溃
  • 支持自定义 prompts(例如数学专用)

7.4.5 FunctionCallAgent(原生函数调用)

  • 0.2.8 后引入

  • 基于 OpenAI 原生 tools/function calling schema

  • 相比 prompt 约束式工具调用:

    • 鲁棒性更强(结构化参数、模型更不易"编造格式")
  • 核心能力(摘要):

    • 构建 tool schema
    • 从响应提取文本
    • 解析 JSON 参数并做类型转换
    • 调用底层 client.chat.completions.create(...)

7.5 工具系统(Tooling)

7.5 学习目标(三点)

  1. 统一工具抽象与管理
  2. 实战:自定义工具开发
  3. 高级整合与优化(多源搜索、工具链、异步并行、容错)

7.5.1 工具基类与注册机制

Tool 基类抽象(统一接口)
  • 必须实现:

    • run(parameters: Dict[str,Any]) -> str
    • get_parameters() -> List[ToolParameter]
  • Tool 具备自描述能力:

    • name / description / parameter schema
ToolParameter 参数系统
  • 字段:name/type/description/required/default

  • 支撑:

    • 参数验证
    • 自动文档
    • schema 转换
ToolRegistry(工具管理中枢)
  • 两种注册方式:

    1. register_tool(tool_obj):复杂工具
    2. register_function(name, desc, func):快速集成简单函数
  • 工具发现:

    • get_tools_description() 生成 prompt 工具清单
  • 生成 OpenAI function calling schema:

    • to_openai_schema()(给 FunctionCallAgent 用)

7.5.2 自定义工具开发:My Calculator

  • ast.parse 做安全表达式求值(避免 eval 风险)

  • 支持四则运算 + sqrt + pi

  • ToolRegistry.register_function 快速注册:

    • tool_name: "my_calculator"
  • 测试:

    • 直接调用 registry.execute_tool
    • 与 SimpleAgent 结合:先工具算,再让 LLM 把结果组织成自然语言

7.5.3 多源搜索工具(Tavily + SerpApi)

内置 SearchTool 的设计亮点
  • backend = "hybrid":智能选择后端

  • 自动检测可用性(API key + 依赖库)

  • 降级容错策略

    • 优先 Tavily(AI 优化搜索)
    • Tavily 失败 → fallback SerpApi
    • 都不可用 → 提示配置 API key
统一结果格式化
  • 把不同引擎输出整理为统一结构(标题/摘要/来源)
  • 便于 Agent 接入与后续处理
自定义 MyAdvancedSearchTool(类方式)
  • 类方式适合维护状态(client/配置/可用后端列表)
  • 注册方式:把 search_tool.search 当函数注册到 ToolRegistry

7.5.4 高级特性

(1)工具链 ToolChain(串联多工具)
  • 用"步骤列表"定义链:

    • tool_name
    • input_template(支持变量替换)
    • output_key(存入上下文供后续步骤引用)
  • ToolChainManager 管理多个 chain(注册/执行/列表)

(2)异步工具执行 AsyncToolExecutor(线程池并行)
  • 适用:I/O 密集型工具(网络请求、文件读取、数据库查询)

  • 设计:

    • execute_tool_async:run_in_executor
    • execute_tools_parallel:gather 并行执行多个工具任务
  • 注意:

    • CPU 密集型任务线程池效果有限(GIL、资源争用)
    • 外部服务限流要处理(重试/退避/并发限制)

7.6 本章小结(你应该带走什么)

  • 你完成了 HelloAgents 框架从 0 到 1 的核心骨架:

    • LLM 调用中枢(多 provider + 本地推理 + 自动检测)
    • 核心接口(Message/Config/Agent)
    • 四种经典 Agent 范式框架化(Simple/ReAct/Reflection/PlanAndSolve)
    • 工具系统(Tool/Registry/schema/多源搜索/链式/异步)
  • 本章不是终点,而是后续章节的"地基":

    • 第八章:Memory + RAG
    • 第九章:上下文工程(消息系统扩展)
    • 第十章:协议/工具扩展(MCP 等)

习题区:要点提示与答题框架(按题目逐条拆解)

你后续写答案时可以直接用这些小标题填充内容。

A. 7.1.1 四个局限性:结合某框架的实践经验说明如何影响效率

可从以下角度写:

  • 学习成本:理解概念、调试成本
  • 版本升级:API 变化导致重构
  • 黑盒:无法定制/定位 bug
  • 依赖冲突:与现有项目不兼容、部署困难
  • 结合案例:例如 LangChain、AutoGen、LlamaIndex...(任选一个你实际用过的)

B. "万物皆为工具"优势与局限

优势(写 3-5 点)

  • 统一抽象,学习路径更短
  • 模块可插拔(RAG/Memory/MCP 都是 tool)
  • 更容易做 registry / schema / 自动文档
  • 更利于观测与测试(工具可单测)
  • 工具链/并行执行更自然

局限(写 2-4 点)

  • 过度工具化可能丢失"长期状态"语义(Memory 其实不是一次性调用)
  • Tool 返回 string 过于弱类型,复杂结构需额外规范
  • Tool 调度策略/权限/安全可能需要额外体系
  • "工具即万物"可能导致概念混淆(例如 Planner/Executor 是否也算工具?)

举例:

  • 把 Memory 当 Tool:检索/写入是 tool,但"长期一致性/压缩策略"需要框架层支持

C. 第四章从零实现 vs 本章框架化:具体改进点

可以写成对比表(建议)

  • 统一接口(run、history、Message)
  • 配置集中化(Config/from_env)
  • 工具系统可复用(ToolRegistry、schema)
  • prompt 标准化与可配置(custom_prompt)
  • 异常体系、最大步数/迭代限制、更稳定
  • 可扩展目录结构(core/agents/tools)

如果你设计框架优先原则:

  • 单一职责、低耦合、高内聚
  • 约定优于配置
  • 可观测性(日志、trace)
  • 安全优先(参数验证、沙盒)
  • 可测试性(组件可单测)

D. 7.2 实践题:扩展一个新 provider + 自动检测

写作要点:

  • 通过继承 HelloAgentsLLM

  • 增加 _auto_detect_provider 检查新 env(如 ANTHROPIC_API_KEY

  • _resolve_credentials 增加 provider 分支

  • 如果该 provider 不兼容 OpenAI API:

    • 你需要额外适配 client 层(或使用兼容网关)

E. 自动检测优先级分析题

题目:同时设置 OPENAI_API_KEYLLM_BASE_URL="http://localhost:11434/v1" 会选谁?

  • 按文中优先级:先检查特定服务商 env → 会选 openai

  • 讨论是否合理:

    • 合理:显式 provider key 优先,避免误把生产 key 环境当本地
    • 不合理场景:用户明确想走本地,但忘删 OPENAI_API_KEY
    • 改进:允许用户显式 provider="ollama" 覆盖;或增加一个强制开关

F. 搜索了解 SGLang,并对比 VLLM/SGLang/Ollama

建议写法(表格维度):

  • 易用性:安装、启动、模型管理
  • 资源占用:显存/内存、KV cache 管理
  • 推理速度:吞吐/延迟、并发能力
  • 推理精度:一般取决于模型本身,但推理策略/量化可能影响
  • 生态与兼容:OpenAI API 兼容性、工具链支持

注意:这题如果你要"最新特性",需要联网检索;你也可以把对比框架写好,之后填入调研结论。


G. 7.3:Pydantic、设计模式、单例

Message 用 Pydantic 的优势

  • 类型验证、默认值、序列化方便
  • 数据结构稳定,减少脏数据
  • 便于扩展 metadata、timestamp
  • 错误更早暴露(开发期)

run + _execute:是什么模式?

  • 常见叫法:模板方法模式(Template Method)

  • 好处:

    • 对外统一入口 run
    • 内部把可变步骤留给子类 _execute
    • 保持流程一致性,子类只改差异点

单例模式与配置

  • 单例:全局唯一实例,保证一致配置源

  • 配置需要单例的原因:

    • 避免多个 Config 实例不一致导致行为不确定
    • 方便全局访问与热更新策略
  • 不用单例的问题:

    • 不同模块读到不同配置副本
    • 难排查"为什么同样参数行为不同"

H. 7.4:实践题三连

ReAct 框架化 3 个改进点(示例)

  • 工具通过 ToolRegistry 接入(可插拔)
  • prompt 强约束格式 + history 注入更稳定
  • max_steps 限制 + 统一 history 管理更安全
  • 可配置 custom_prompt(扩展不同任务域)

Reflection 加质量评分机制(思路)

  • reflect 后增加一个 score_prompt
  • LLM 输出分数(如 1-10)
  • score >= threshold → 提前终止
  • 否则继续 refine
  • 注意:要防止模型乱报分,可加格式约束与解析失败兜底

Tree-of-Thought Agent(设计要点)

  • 每步生成 K 条候选思路(branching)
  • 用评分器(LLM 或规则)选择最优路径(best-first / beam search)
  • 迭代直到终止条件(深度/分数/完成标记)
  • 与 ToolRegistry 结合:每条路径可调用工具

I. 7.5:工具接口、多返回值、工具链与并行

为什么强制统一接口?

  • Agent 调度工具时无需关心工具内部差异
  • 工具可替换、可组合、可测试
  • 方便 schema 化与 function calling

搜索工具返回多个值怎么办?

建议三种方案:

  1. 返回 JSON 字符串(结构化文本)
  2. 返回统一 Result 对象(但框架当前约定 string,需要扩展)
  3. Message.metadata 存结构化数据(对话层存引用)

工具链场景(至少 3 工具)

例:研究报告生成

  • search → summarize → cite_formatter
    输出流程图可用 Mermaid(见下一节建议)

并行执行何时提升性能?

  • 多个 I/O 工具可并行(网络请求、多个搜索源)
  • 工具之间无依赖(不需要上一步结果)
  • 注意外部 API 限流/配额/线程数

J. 框架扩展:流式输出、多轮对话管理、插件系统

1)流式输出(Agent 实时返回)

设计方案要点:

  • LLM 层提供 stream_invoke
  • Agent 增加 stream_run
  • Message 记录最终完整输出(流式过程中累计)
  • Tool calling 的流式更复杂:需要边生成边检测工具 call(可延后)

2)多轮对话管理:分支与回溯

需要新增:

  • ConversationManager:管理多个 session
  • Branch:保存分叉点(history snapshot)
  • Rewind:回退到某个 message id
    与 Message 集成:
  • Message 增加 id/parent_id/branch_id(或放 metadata)

3)插件系统(第三方扩展)

目标:不改 core 即可新增 Agent/Tool

关键接口:

  • Plugin 基类(name/version/register(registry))
  • Entry points / 动态加载(Python packaging)
  • PluginRegistry:发现、加载、隔离、冲突处理
    建议画 Mermaid 架构图(你写作时可用)

附:建议的"框架化复习清单"(自测)

  • 我能解释 HelloAgents 的分层结构与每层职责
  • 我能实现一个新的 provider(含自动检测)
  • 我能实现一个 Tool,并注册到 ToolRegistry
  • 我能实现一个新 Agent(继承 Agent 基类)
  • 我能把 ToolChain 串联 3 个工具完成任务
  • 我能解释 ReAct/Reflection/PlanSolve 的运行流程与差异

相关推荐
诗词在线2 小时前
中国古代诗词名句按主题分类有哪些?(爱国 / 思乡 / 送别)
人工智能·python·分类·数据挖掘
高锰酸钾_2 小时前
机器学习-L1正则化和L2正则化解决过拟合问题
人工智能·python·机器学习
${王小剑}2 小时前
深度学习损失函数
人工智能·深度学习
啊巴矲2 小时前
小白从零开始勇闯人工智能:机器学习初级篇(PCA数据降维)
人工智能·机器学习
北邮刘老师2 小时前
A3C Network:智能体互联网的层次化视图
运维·服务器·网络
天天睡大觉2 小时前
Python学习11
网络·python·学习
XRJ040618xrj2 小时前
如何在Linux中根据物理网卡建立虚拟网卡
linux·服务器·网络
geneculture2 小时前
融智学形式本体论:一种基于子全域与超子域的统一认知架构
大数据·人工智能·哲学与科学统一性·信息融智学·融智时代(杂志)
笔墨新城2 小时前
Agent Spring Ai 开发之 (一) 基础配置
人工智能·spring·agent