当一家公司开始拥有多个 Agent,问题很快就不再是“如何做一个聊天机器人”。
产品团队会提出一个统一入口:用户只登录一次,在同一个会话中使用不同领域的能力。各个项目组则可能已经拥有自己的单页应用、HTTP 接口或 WebSocket Agent。平台还要统一用户身份、权限、模型选择、计费、日志和监控。更进一步,Agent 之间也要能够互相调用。
这类需求很容易把架构推向两个极端:
- 所有东西都做成 Agent,再用一个“总父 Agent”负责调度;
- 所有能力都拆成工具服务,Agent 只负责把工具串起来。
前一种方案会让简单能力变得昂贵而脆弱,后一种方案又可能把系统拆成一堆没有业务语义的微服务。更稳妥的答案不是二选一,而是先把“能力”“Agent”“平台治理”分清楚,再决定哪些东西需要独立部署。
一、先判断:手里拿到的到底是 Agent,还是一个调用适配器
现实中经常出现这样的交付物:一个 Skill 文件、一个 MCP Server,以及一段连接外部 WebSocket 的脚本。它在某个 Agent 宿主里可以工作,于是看起来像“已经接入了另一个 Agent”。
实际上,这通常只是下面这条链路:
宿主 Agent
-> Skill 提示
-> 本地 MCP 进程
-> WebSocket 客户端
-> 外部 Agent
这种方式很适合做验证:宿主 Agent 能否调用对方、协议是否能连通、会话标识能否续接。它甚至可以作为一个低成本的 PoC。
但它通常不能直接成为平台级能力,原因也很具体:
- 只返回最终文本,丢弃中间事件,无法提供真正的流式体验;
- 没有明确的取消、重连、幂等和运行状态;
- 只靠一个可提交的
sessionId维持上下文,没有用户和租户绑定; - 认证、计费和审计发生在平台之外;
- MCP SDK 版本变化就可能导致宿主无法发现工具;
- 一旦外部 Agent 和宿主 Agent 互相调用,还可能形成递归。
这说明一个重要事实:
Skill 和 MCP 可以是 Agent 使用能力的方式,但它们不等于平台的 Agent 互联架构。
二、为什么不应该把所有能力都包装成 Agent
Web 搜索、OCR、文件解析、向量检索、格式转换、数据库查询,这些能力当然可以各自配一个 Agent,但通常没有必要。
例如,搜索请求本质上更接近一个确定性接口:
web.search(query, filters, top_k)
如果先调用一个“搜索 Agent”,让它再理解一次“请搜索这个关键词”,系统就多了一次模型推理、多一层上下文和一套不可预测的输出格式。成本、延迟和故障点都会增加。
工具或能力服务更适合具有以下特征的功能:
- 输入和输出边界清晰;
- 结果可以结构化表达;
- 不需要长上下文推理;
- 需要统一限流、缓存、密钥和审计;
- 有独立的计算资源或安全边界;
- 会被多个 Agent 重复使用。
因此,下面这些通常应优先做成能力服务或工具:
| 能力 | 推荐形态 | 原因 |
|---|---|---|
| Web Search | 工具服务 | 参数明确,可统一限流和缓存 |
| OCR | 能力服务 | 计算密集,适合独立扩容和异步处理 |
| 文件解析 | 能力服务 | 多种文件格式,适合统一维护 |
| 知识检索 | 数据/能力服务 | 负责索引、权限和检索,不负责最终回答 |
| 记忆存取 | 平台服务 | 需要租户隔离、生命周期和权限控制 |
| 工作流执行 | 工作流服务 | 执行步骤应确定、可重试、可审计 |
| MCP | 接入协议 | 它描述“如何暴露工具”,不是一种业务能力 |
Agent 的价值则在另一侧:理解模糊目标、制定计划、选择工具、解释结果、处理领域规则,以及在必要时调用其他 Agent。
三、也不能把所有东西都拆成工具
如果所有能力都变成工具,另一个问题会出现:工具数量不断增长,但系统缺少业务语义。
一个合同审核过程可能需要:读取文件、提取条款、检索法规、识别风险、生成意见、触发审批。这不是简单地把六个工具平铺出来就结束了。谁来决定顺序?哪些风险必须人工确认?结果如何解释?这些问题需要领域 Agent 或工作流来承担。
可以用一个简单的判断方式:
确定性执行 -> 工具或服务
模糊目标理解 -> Agent
固定业务流程 -> Workflow
跨调用治理 -> Gateway / Control Plane
换句话说:
工具负责“做事”,Agent 负责“判断”,Workflow 负责“按规则执行”,平台负责“管住边界”。
四、推荐的分层架构
一个可扩展的多 Agent 平台,至少需要三层。
用户、外部系统、其他 Agent
|
v
+------------------------------------------------+
| Unified Invocation Gateway |
| 身份、授权、路由、计费、配额、审计、追踪、事件流 |
+----------------------+-------------------------+
|
+----------------+----------------+
| |
v v
+-------------+ +-------------+
| 能力与工具层 | | Agent Runtime |
| | | |
| 搜索 | | 通用 Agent |
| OCR | | 领域 Agent |
| 知识检索 | | 编排 Agent |
| 记忆 | | |
| 文件处理 | +-------------+
+-------------+
1. 能力与工具层
提供稳定、可复用、可结构化调用的能力。它可以是平台内的模块,也可以是独立服务,不必一开始就每个能力部署一个微服务。
例如,搜索、OCR、知识库检索和文件解析可以先由一个能力网关统一管理,内部根据负载再拆分。真正需要独立部署的依据应该是资源、故障域、团队所有权和安全边界,而不是“每个名词一个服务”。
2. Agent Runtime 层
承载通用对话 Agent 和领域 Agent。Agent 负责理解任务、组织上下文、调用能力以及生成解释性结果。
一个领域 Agent 可以调用工具,也可以调用其他 Agent。但它不应该直接知道其他 Agent 的真实网络地址,而应该通过统一调用入口按逻辑标识调用。
3. Unified Invocation Gateway
这是整个系统真正应该统一的地方。它同时处理两类调用:
Agent -> Tool
Agent -> Agent
两类调用都使用统一的调用记录、权限模型、事件格式、用量统计和追踪信息。这样就不需要为“工具计费”和“Agent 计费”设计两套体系。
五、是否需要一个“总的父 Agent”
不建议建立一个永久存在、所有请求都必须经过的总父 Agent。
原因不是中心化一定不好,而是“认知中心”和“治理中心”不应该是同一个东西。
一个总父 Agent 会带来:
- 所有请求都增加一层延迟和模型成本;
- 它成为推理和路由的单点故障;
- 所有领域 Agent 都退化成它的工具;
- 上下文越来越大,权限和费用越来越难归属;
- 发生循环调用时很难判断责任边界。
更好的方式是:每个具体任务都有一个 root run,它可以由不同的 Agent 或工作流担任根节点。
例如:
root run: general-assistant
+-- child: product-search
+-- child: financing-policy
+-- child: document-generator
另一个外部 Agent 也可以把通用 Agent 作为子节点调用:
root run: crm-agent
+-- child: general-assistant
+-- child: knowledge-search
这里的“父子关系”只属于某一次任务,而不是系统的永久层级。
如果确实需要动态拆解任务,可以提供一个可插拔的编排 Agent。但它应该是角色,不应该是全公司的唯一入口。能够用确定性工作流解决的问题,也不应该交给大模型临时规划。
六、统一调用协议比统一传输协议更重要
不同项目组可能使用 HTTP、WebSocket、SSE、MCP,甚至其他协议。强制所有团队使用同一种传输方式,通常会拖慢接入。
更值得统一的是调用语义。一次调用至少要有:
{
"invocationId": "inv-123",
"source": "general-assistant",
"target": "product-search",
"tenantId": "tenant-1",
"userId": "user-1",
"sessionId": "session-1",
"runId": "run-1",
"parentRunId": "run-parent-1",
"deadline": "2026-09-23T12:00:00Z",
"idempotencyKey": "idem-123",
"input": {}
}
事件则至少需要区分:
run.accepted
output.delta
output.snapshot
progress
run.completed
run.failed
run.cancelled
tool.started
tool.completed
approval.required
尤其不能把所有文本事件都当作字符串直接拼接。必须明确它是增量、快照还是替换,并提供序号或事件 ID,才能支持断线恢复和重复事件去重。
七、统一身份、计费和监控
Agent 和工具最终都要进入同一套治理体系。
身份与授权
用户身份在平台入口终止。平台向下游调用签发短期、最小权限的 delegation token,包含:
tenant_id
user_id
source
target
session_id
run_id
allowed_scopes
expires_at
不要把长期用户 JWT、数据库凭据或其他服务的密钥直接交给 Agent。
计费
计费账本应记录完整的调用树:
parent run
+-- Agent 模型用量
+-- 搜索调用费用
+-- OCR 处理费用
+-- 子 Agent 调用费用
外部 Agent 可以按照 Token、调用次数、耗时或任务单价上报用量,但最终账本只能有一个事实来源,否则很容易重复扣费。
监控
所有调用都应该共享 trace_id、correlation_id、run_id 和 parent_run_id。这样才能回答:
- 哪个 Agent 调用了哪个能力?
- 总耗时主要花在哪里?
- 哪个服务产生了费用?
- 是模型慢、工具慢,还是网络慢?
- 失败后是否发生了重复执行?
八、方案选择:平台适配器还是独立 Agent Gateway
这里常见的两个方案并不是完全互斥的。
方案 B:平台内置 Adapter
Platform Gateway
+-- Tool Adapter
+-- Agent Adapter
+-- WebSocket Adapter
+-- MCP Adapter
优点是上线快、运维简单,适合接入第一批能力。缺点是连接池、协议转换和外部故障会逐渐挤进平台主网关。
方案 C:独立 Agent Gateway
Platform Control Plane
-> Agent Gateway
-> Tool Services
-> Agent Runtimes
优点是连接层可以独立扩缩容和隔离故障,也更适合多团队、多协议和 Agent-to-Agent 调用。缺点是早期会增加部署、鉴权和运维成本。
更实际的选择
如果目标只是接入一两个 Agent,先做 B。
如果目标已经是公司级 Agent 平台,不应把 B 作为终态。比较稳妥的路线是:
先在平台内部实现 C 的接口和数据模型,运行时先采用 B;当连接规模和并发达到阈值后,再把同一套运行时抽成独立 Agent Gateway。
这比第一天就拆出大量服务更务实,也比把所有连接代码永久塞进主网关更有余地。
九、哪些东西应该独立部署
不要按“名字”决定服务边界,而要按以下因素决定:
- 是否有不同的资源需求;
- 是否需要独立扩容;
- 是否有独立的安全边界;
- 是否由不同团队负责;
- 故障是否需要隔离;
- 是否有不同的发布节奏;
- 是否需要独立计费或审计。
因此,OCR 可能很快需要独立的异步 Worker,但记忆服务未必需要单独部署;搜索可能使用统一网关和缓存,知识库索引则可能由独立任务系统处理。
“能力服务化”不等于“微服务化”。更准确的目标是能力边界清晰、调用协议稳定,部署方式可以随着规模演进。
十、建议的落地顺序
第一步:建立能力目录
先列出所有准备开放的能力,标记它们属于:
- Tool;
- Agent;
- Workflow;
- Data Service;
- Platform Service。
同时记录每项能力的输入、输出、权限、计费单位、延迟目标和数据分类。
第二步:建立统一调用记录
先不要急着拆服务,先让工具调用和 Agent 调用都拥有统一的 invocation/run 记录、状态和事件。
第三步:建设统一 Invocation Gateway
把认证、授权、路由、限流、计费、审计和协议适配集中到一个边界。第一阶段可以和平台主网关部署在一起,但代码边界要独立。
第四步:优先接入可复用能力
先建设 Web Search、知识检索、文件解析、OCR、记忆等公共能力,再接入真正需要独立推理的领域 Agent。
第五步:引入 Agent-to-Agent 调用
先支持显式目标 Agent、父子 Run、超时、预算和调用深度限制,再考虑自动路由和复杂编排。
第六步:根据真实负载决定是否拆分 Gateway
当连接处理影响主平台稳定性、多个团队需要独立发布,或 Agent-to-Agent 调用规模明显增长时,再把 Invocation Gateway 抽成独立服务。
结语
多 Agent 系统真正难的地方,不是“让 Agent 互相发消息”,而是让这些调用能够被授权、被追踪、被计费、被取消、被恢复,并且在失败时不会互相拖垮。
因此,架构的中心不应该是一个永远高高在上的总父 Agent,而应该是一个统一的能力与调用治理层。
最终可以用四句话概括:
工具负责执行确定性能力;
Agent 负责理解、判断和解释;
Workflow 负责固定流程;
Gateway 负责身份、权限、计费、观测和边界。
当这四个边界清楚之后,Agent 可以增加,工具可以替换,协议可以演进,平台也不会被某一个项目组的实现方式绑死。