第 36 章:架构全景与边界

个人公众号

难度:中等

我们已经看了 7 个具体的设计决策。这一章拉远视角,看整个框架的依赖图、模块边界、以及那些”存在但没展开”的角落。

上一章:第 35 章 为什么 Formatter 独立于 Model

依赖全景图

AgentScope 的 24 个顶层模块,按依赖关系分为四层:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
flowchart TD
subgraph "基础层"
MSG["message<br/>消息类型"]
MOD["module<br/>StateModule"]
TYP["types<br/>类型定义"]
UTL["_utils<br/>工具函数"]
end

subgraph "核心层"
MEM["memory<br/>记忆"]
MOD2["model<br/>模型"]
FMT["formatter<br/>格式转换"]
TOK["token<br/>Token 计数"]
TOL["tool<br/>工具"]
EMB["embedding<br/>向量嵌入"]
end

subgraph "Agent 层"
AGT["agent<br/>Agent 实现"]
PLN["plan<br/>规划"]
TTS["tts<br/>语音合成"]
end

subgraph "编排层"
PIP["pipeline<br/>Pipeline"]
RAG["rag<br/>RAG"]
SES["session<br/>会话"]
TRC["tracing<br/>追踪"]
A2A["a2a<br/>A2A 协议"]
RLT["realtime<br/>实时交互"]
MCP["mcp<br/>MCP 客户端"]
EVL["evaluate<br/>评估"]
end

MSG --> MOD2
MSG --> AGT
MSG --> TOL

MOD --> MEM
MOD --> AGT
MOD --> TOL

FMT --> MOD2
TOK --> FMT

AGT --> MEM
AGT --> MOD2
AGT --> FMT
AGT --> TOL
AGT --> PLN
AGT --> TTS

PIP --> AGT
RAG --> EMB
RAG --> MEM
TRC --> TOL
TRC --> MOD2
MCP --> TOL

依赖规则

  1. 基础层不依赖任何其他层——messagemoduletypes_utils 是独立的
  2. 核心层只依赖基础层——memory 依赖 modulemessage
  3. Agent 层依赖核心层——agent 依赖 memorymodelformattertool
  4. 编排层依赖 Agent 层——pipeline 依赖 agent

这个分层是自然形成的,不是人为规定的——如果你违反了层级(比如让 message 依赖 agent),会出现循环导入。


核心模块 vs 边缘模块

核心模块(卷一至卷三覆盖的)

模块行数职责成熟度
message~200消息类型稳定
module~120StateModule稳定
memory~1200记忆系统稳定
model~1500模型适配稳定
formatter~2000格式转换稳定
tool~1700工具系统稳定
agent~2000Agent 实现稳定
pipeline~300Pipeline 编排稳定

边缘模块(本书未深入展开的)

模块行数职责备注
rag~800RAG 检索依赖 embedding + vector store
embedding~300向量嵌入为 RAG 服务
token~200Token 计数为 Formatter 的截断服务
tracing~600OpenTelemetry生产环境可观测性
session~400会话管理跨请求状态持久化
plan~300规划子系统ReActAgent 的规划功能
tts~200语音合成RealtimeAgent 的语音输出

协议/集成模块

模块职责备注
a2aAgent-to-Agent 协议Google A2A 标准
mcpModel Context Protocol接入外部 MCP Server
realtime实时语音交互WebSocket + 流式音频
evaluate评估和基准测试Benchmark 工具

空壳/开发中模块

模块状态
tune模型微调——占位,功能未完整
tuner微调工具——与 tune 重叠?

边界模糊处

_utils/_common.py:工具箱还是垃圾桶?

_utils/_common.py 包含了各种工具函数:

  • _parse_tool_function:JSON Schema 生成(属于 tool 模块)
  • _get_timestamp:时间戳(通用)
  • _remove_title_field:Schema 处理(属于 tool 模块)

问题:_parse_tool_function 是工具系统的一部分,但它放在 _utils 里。这是因为它是”解析工具函数”的通用逻辑,被 _toolkit.py 和测试文件共同使用。

hooks/ vs agent/_agent_meta.py

hooks/ 目录有 Hook 类型定义,但 Hook 的核心逻辑在 agent/_agent_meta.py。为什么分开放?

  • hooks/ 定义了 Hook 的类型接口
  • _agent_meta.py 定义了 Hook 的注入机制

这是”接口”和”实现”的分离——合理但容易混淆。

types/ 的角色

types/ 目录定义了 ToolFunctionJSONSerializableObject 等跨模块使用的类型。它是最底层的依赖——几乎所有模块都导入它。但它不是 Python 标准的 typing——是 AgentScope 自定义的类型定义。


架构的演化方向

已有的扩展点

本书覆盖的扩展点:

  • 自定义 Memory(继承 MemoryBase
  • 自定义 Formatter(继承 FormatterBase
  • 自定义 Agent(继承 AgentBase
  • 自定义工具(register_tool_function
  • 自定义中间件(register_middleware
  • 自定义 Hook(register_*_hook

可能的演化方向

  1. 更多 Memory 后端:向量数据库 Memory、图数据库 Memory
  2. 更多 Model 适配:新模型 API(如 Grok、Mistral)
  3. A2A 生态:跨框架 Agent 协作
  4. MCP 集成:更多 MCP Server 接入
  5. 多模态 Agent:视觉、语音、视频输入

全书复盘

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
flowchart LR
subgraph "卷零:出发"
C1["ch01 什么是 LLM"]
C2["ch02 什么是 Agent"]
end

subgraph "卷一:旅程"
C3["ch03-ch12<br/>跟随一次 agent() 调用"]
end

subgraph "卷二:齿轮"
C13["ch13-ch20<br/>拆开设计模式"]
end

subgraph "卷三:造齿轮"
C21["ch21-ch28<br/>构建新模块"]
end

subgraph "卷四:为什么"
C29["ch29-ch36<br/>设计权衡"]
end

C2 --> C3 --> C13 --> C21 --> C29

从”什么是 LLM”到”为什么这样设计”,你走过了 36 章的完整旅程。

你现在能够:

  • 懂 AgentScope 的任意源码文件
  • 追踪一个请求从 agent() 到返回的完整路径
  • 构建新的工具、Memory、Formatter、Agent、Pipeline
  • 理解框架的设计决策及其权衡
  • 参与架构讨论和代码贡献

下一步?

  1. GitHub Issues 找一个 “good first issue”
  2. 尝试给框架添加一个新功能
  3. 在讨论区分享你的理解

AgentScope 官方文档覆盖了本书讨论的所有模块:Basic Concepts 介绍 Msg、Agent、Model 等核心概念,Building Blocks 展示各模块的用法和配置方法。本书从源码角度补充了这些设计决策背后的理由。

AgentScope 1.0 论文(arXiv:2508.16279)提供了框架的完整技术报告,涵盖 Foundational Components(Section 2.1)、Agent Infrastructure(Section 2.2)和 Multi-Agent Orchestration(Section 2.3)三大设计维度。

AgentScope 源码带读系列视频教程覆盖了以下核心内容:

  • StateModule 的序列化机制和子模块自动追踪
  • Memory 模块的工作记忆和长期记忆实现
  • ReAct Agent 的推理循环和工具调用流程
  • Toolkit 的注册、中间件和分组机制


验证性实验:绘制你自己的架构全景图

目标:基于源码实际依赖,验证或修改本章的四层全景图。

步骤

  1. grep -rn "from.*agentscope" src/agentscope/ 提取所有模块间的 import 关系。

  2. 绘制你自己的依赖图(可以用 Mermaid 或纸笔)。

  3. 找出所有”跨层依赖”——比如编排层的模块是否直接依赖了基础层?

  4. 特殊关注 _utils/_common.py:它被哪些层依赖?它的 500 行代码属于四层中的哪一层?这是一个架构边界模糊处——你认为应该怎么处理?


你的判断

贯穿全卷的开放性问题:

  1. 如果让你从零重写 AgentScope,你会保留哪些设计?改变哪些?
  2. 在”简单性”和”灵活性”之间,AgentScope 的平衡点在哪里?
  3. 哪个设计决策最让你惊讶?为什么?

下一章:附录 A:Python 进阶速查