第 36 章:架构全景与边界

难度:中等
我们已经看了 7 个具体的设计决策。这一章拉远视角,看整个框架的依赖图、模块边界、以及那些”存在但没展开”的角落。
依赖全景图
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
58flowchart 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
依赖规则
- 基础层不依赖任何其他层——
message、module、types、_utils是独立的 - 核心层只依赖基础层——
memory依赖module和message - Agent 层依赖核心层——
agent依赖memory、model、formatter、tool - 编排层依赖 Agent 层——
pipeline依赖agent
这个分层是自然形成的,不是人为规定的——如果你违反了层级(比如让 message 依赖 agent),会出现循环导入。
核心模块 vs 边缘模块
核心模块(卷一至卷三覆盖的)
| 模块 | 行数 | 职责 | 成熟度 |
|---|---|---|---|
message | ~200 | 消息类型 | 稳定 |
module | ~120 | StateModule | 稳定 |
memory | ~1200 | 记忆系统 | 稳定 |
model | ~1500 | 模型适配 | 稳定 |
formatter | ~2000 | 格式转换 | 稳定 |
tool | ~1700 | 工具系统 | 稳定 |
agent | ~2000 | Agent 实现 | 稳定 |
pipeline | ~300 | Pipeline 编排 | 稳定 |
边缘模块(本书未深入展开的)
| 模块 | 行数 | 职责 | 备注 |
|---|---|---|---|
rag | ~800 | RAG 检索 | 依赖 embedding + vector store |
embedding | ~300 | 向量嵌入 | 为 RAG 服务 |
token | ~200 | Token 计数 | 为 Formatter 的截断服务 |
tracing | ~600 | OpenTelemetry | 生产环境可观测性 |
session | ~400 | 会话管理 | 跨请求状态持久化 |
plan | ~300 | 规划子系统 | ReActAgent 的规划功能 |
tts | ~200 | 语音合成 | RealtimeAgent 的语音输出 |
协议/集成模块
| 模块 | 职责 | 备注 |
|---|---|---|
a2a | Agent-to-Agent 协议 | Google A2A 标准 |
mcp | Model 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/ 目录定义了 ToolFunction、JSONSerializableObject 等跨模块使用的类型。它是最底层的依赖——几乎所有模块都导入它。但它不是 Python 标准的 typing——是 AgentScope 自定义的类型定义。
架构的演化方向
已有的扩展点
本书覆盖的扩展点:
- 自定义 Memory(继承
MemoryBase) - 自定义 Formatter(继承
FormatterBase) - 自定义 Agent(继承
AgentBase) - 自定义工具(
register_tool_function) - 自定义中间件(
register_middleware) - 自定义 Hook(
register_*_hook)
可能的演化方向
- 更多 Memory 后端:向量数据库 Memory、图数据库 Memory
- 更多 Model 适配:新模型 API(如 Grok、Mistral)
- A2A 生态:跨框架 Agent 协作
- MCP 集成:更多 MCP Server 接入
- 多模态 Agent:视觉、语音、视频输入
全书复盘
1 | flowchart LR |
从”什么是 LLM”到”为什么这样设计”,你走过了 36 章的完整旅程。
你现在能够:
- 读懂 AgentScope 的任意源码文件
- 追踪一个请求从
agent()到返回的完整路径 - 构建新的工具、Memory、Formatter、Agent、Pipeline
- 理解框架的设计决策及其权衡
- 参与架构讨论和代码贡献
下一步?
- 去 GitHub Issues 找一个 “good first issue”
- 尝试给框架添加一个新功能
- 在讨论区分享你的理解
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 的注册、中间件和分组机制
验证性实验:绘制你自己的架构全景图
目标:基于源码实际依赖,验证或修改本章的四层全景图。
步骤:
用
grep -rn "from.*agentscope" src/agentscope/提取所有模块间的 import 关系。绘制你自己的依赖图(可以用 Mermaid 或纸笔)。
找出所有”跨层依赖”——比如编排层的模块是否直接依赖了基础层?
特殊关注
_utils/_common.py:它被哪些层依赖?它的 500 行代码属于四层中的哪一层?这是一个架构边界模糊处——你认为应该怎么处理?
你的判断
贯穿全卷的开放性问题:
- 如果让你从零重写 AgentScope,你会保留哪些设计?改变哪些?
- 在”简单性”和”灵活性”之间,AgentScope 的平衡点在哪里?
- 哪个设计决策最让你惊讶?为什么?
下一章:附录 A:Python 进阶速查