从 Function Call 到 MCP、A2A、Skills 与 Subagent:Agent 能力分层全解
上周三下午三点,我盯着屏幕上的五个术语发呆——function call、MCP、A2A、skills、subagent。每个词单独看我都认识,但它们之间的关系像一团乱麻。有人说 MCP 是 function call 的升级版,有人说 A2A 是 MCP 的竞品,还有人说 skills 就是个 fancy 的 prompt。我当时就想:卧槽,这东西到底能不能有个明白人讲清楚?
它们都和"让模型不只是聊天,而是真的去做事"有关,但它们并不是同一层概念——很多文章把它们混在一起讲,越看越乱。
这篇文章的目标很明确:把这五个概念放回它们各自出现的背景中,讲清楚它们分别解决什么问题、解决到什么程度,以及它们之间是怎么拼起来工作的。
先说结论:它们不是并列关系
如果你只想先抓住主线——先说清楚,这五个货根本不是并列关系,傻逼才把它们放在一张表里比参数——可以先记住一句话:
function call解决"模型如何调用一个明确的外部能力";MCP解决"外部能力如何用统一协议接入模型系统";A2A解决"不同 Agent 之间如何用统一协议互相通信和协作";skills解决"模型如何复用一套稳定的任务经验和工作方式";subagent解决"一个 agent 不够时,如何把复杂任务拆给多个 agent 协作完成"。
这五者更像是不同层次:
用户任务
↓
主 Agent 推理与规划
↓
如果任务复杂,需要分工
→ subagent(单系统内拆分)
→ A2A(跨系统 Agent 协作)
↓
执行时需要经验模板和工作方式
→ skills
↓
真正和外部世界交互
→ function call / tools
↓
而这些外部能力的接入方式
→ 可以通过 MCP 统一提供
换句话说:
function call更像"调用动作"MCP更像"工具接入协议"A2A更像"Agent 间通信协议"skills更像"可复用的操作知识包"subagent更像"任务组织方式"
理解了这个分层,后面很多概念就不会串线了。
一、为什么光靠聊天式 LLM 不够
最早的大模型应用,基本都是这种模式:
用户输入问题
↓
模型根据上下文生成文本
↓
返回答案
这个阶段的模型很强,但它有三个天然限制:
1. 它知道很多,但碰不到外部世界
比如你问:
- "帮我查一下今天订单总数"
- "帮我把这条工单指派给后端组"
- "把这个 PR 拉下来并跑一下测试"
模型本身并不能直接访问数据库、调用内部 API、执行 shell 命令。它最多只能"告诉你理论上怎么做"。
2. 它能生成步骤,但步骤不一定真的执行
比如用户说:
帮我分析这次线上故障,顺便看看最近 24 小时的错误日志。
纯聊天模型可以一本正经地写出排查流程:
- 查看日志
- 检查报警
- 分析错误类型
- 给出结论
问题在于:它没真的去看日志。 他妈的,它能生成排查流程,但生成完就完了——这跟给你一份菜谱然后说"我已经帮你做完饭了"有什么区别?
3. 它能临场发挥,但不擅长长期稳定重复执行
假设你要一个 AI 代码助手稳定遵守团队约定:
- 先读代码再改
- 优先用
rg - 修改文件必须走 patch
- 先跑最小验证
- review 时先报问题,再给总结
如果每次都靠 prompt 临时讲,这套行为不稳定,很容易漂。
于是,AI 工程逐渐开始分层演进。接下来这些概念,都是在这个过程中长出来的。
二、Function Call:先解决"怎么让模型动手"
2.1 它出现的背景
最早大家做"会干活"的 AI,通常是这样干的:
- 让模型输出一段 JSON
- 后端自己解析 JSON
- 判断里面是不是要调用某个 API
- 调完 API 再把结果喂回模型
例如:
{
"action": "get_weather",
"city": "Shanghai"
}
这个方法能用,但问题很明显:
- 输出格式不稳定
- 字段名经常漂
- 参数类型容易错
- 很难做标准化约束
- 不同模型之间兼容性差
所以,function call 或 tool calling 出现了。它本质上是在说:
不要让模型随便生成"像工具调用的文本",而是让模型在受约束的结构里选择要调用哪个函数,并给出符合 schema 的参数。
2.2 它解决什么问题
function call 解决的是:
1. 让模型能以结构化方式请求外部操作
例如给模型声明一个函数:
getWeather(city: string, date?: string)
当用户说:
帮我查一下上海明天的天气
模型不再返回一段模糊文本,而是可以返回类似:
{
"name": "getWeather",
"arguments": {
"city": "Shanghai",
"date": "2025-04-15"
}
}
2. 把"推理"和"执行"拆开
模型负责判断:
- 该不该调用工具
- 应该调用哪个工具
- 参数是什么
宿主程序负责:
- 真正执行函数
- 校验参数
- 权限控制
- 重试、超时、审计
这很关键。模型不是直接执行者,它只是提出调用请求。
3. 让 Agent 循环成为可能
典型循环是:
用户问题
↓
模型决定调用函数
↓
宿主程序执行函数
↓
把结果返回给模型
↓
模型继续推理
↓
给出最终答案,或继续调用下一个函数
没有 function call,Agent 很难进入稳定的"思考 -> 调工具 -> 看结果 -> 再思考"闭环。
2.3 它不解决什么问题
很多人第一次学到 function call,会误以为这就已经是完整 Agent 方案了——我当时也是,觉得卧槽牛逼,模型能调工具了这不就齐活了?其实不是。
它不解决:
- 工具如何发现和注册
- 工具来自本地还是远程
- 不同系统如何共享同一套工具
- 复杂任务的长期规划
- 团队经验如何复用
- 多个 agent 如何分工
- 不同 agent 之间如何通信
所以 function call 很重要,但它只是第一层。
2.4 一个最小例子
比如你在做一个运维助手,有两个函数:
getServiceStatus(serviceName: string)
restartService(serviceName: string)
用户说:
帮我看一下 payment-service 挂了没,如果挂了就重启。
可能的执行过程是:
1. 模型先调用 getServiceStatus("payment-service")
2. 系统返回:status = unhealthy
3. 模型再调用 restartService("payment-service")
4. 系统执行重启
5. 模型总结结果返回给用户
这里 function call 解决的是"模型如何发起这两次动作"。
三、MCP:再解决"工具怎么统一接进来"
3.1 它出现的背景
当 function call 普及之后,新的问题来了:
函数定义写在哪里?工具怎么发现?不同客户端怎么共享?
假设你有这些能力:
- 文件系统访问
- Git 操作
- 数据库查询
- 浏览器自动化
- 公司内部工单 API
- 文档搜索
最原始的做法是:每个 AI 客户端都自己手写一遍工具定义和对接代码。
于是你会遇到这些问题:
- A 应用接了数据库工具,B 应用还得重写一次
- 本地 IDE 助手和 Web Agent 用的是两套工具封装
- 工具描述文档不一致
- 权限模型各做各的
- 换个宿主程序,工具层要重做
这时候就需要一个统一的"工具接入协议"。MCP 就是在这样的背景下出现的。
3.2 MCP 到底是什么
你可以把 MCP 理解成:
模型宿主和外部能力提供方之间的一层标准协议。
它关心的是:
- 外部系统如何把能力暴露出来
- 宿主如何发现这些能力
- 工具的输入输出如何描述
- 资源、提示、工具等对象如何被统一读取
如果说 function call 解决的是"模型如何说出我要调用某个工具",那 MCP 解决的是"这个工具本身如何以标准化方式提供给模型系统"。
3.3 它解决什么问题
1. 工具接入标准化
以前你要在每个 agent 框架里重复写:
- 工具名
- 参数 schema
- 执行逻辑
- 描述文案
而 MCP 的思路是:由 MCP Server 统一暴露能力,MCP Client 统一消费能力。
比如一个 Git MCP Server 可以提供:
git_statusgit_diffgit_logcreate_branch
那不同宿主只要会说 MCP,就都能接这批能力。
2. 让工具和模型宿主解耦
这件事非常重要。
以前工具和应用常常是强绑定的:
某 IDE 插件
↔ 写死的工具实现
用了 MCP 之后,更像这样:
Agent 宿主
↔ MCP Client
↔ MCP Server
↔ 外部系统/能力
这样有几个直接收益:
- 工具可以独立演进
- 多个宿主可复用同一个 server
- 企业内能力更容易标准化封装
- 权限和审计可以集中治理
3. 让"资源"与"工具"一起被管理
很多人只盯着 tool,其实 MCP 还不止是工具调用。
在真实系统里,模型要接触的往往不只是"一个可执行函数",还有:
- 文件
- 文档
- 数据表
- 提示模板
- 运行上下文
MCP 的价值之一,就是给这些对象也提供更统一的接入方式,而不是所有东西都伪装成函数。
3.4 MCP 的演进:从 v1.0 到 v2.0
理解 MCP 的版本演进,有助于理解它到底在解决什么层次的问题。
阶段一:MCP 诞生(2024-11-05)
最初的 MCP 协议很简单,定义了两种传输方式:
- stdio:客户端把 MCP Server 作为子进程启动,通过标准输入/输出通信。适合本地工具。
- HTTP + SSE:服务器通过 HTTP POST 接收请求,通过 Server-Sent Events 推送响应和通知。适合远程工具。
这个版本的 MCP 解决了"工具可以跨宿主复用"的问题,很快就获得了广泛采用。但它在生产环境中暴露了几个问题:
- HTTP+SSE 对防火墙不友好:很多企业防火墙和代理对持续的长连接流不兼容
- 连接管理复杂:需要同时维护 POST 端点和 SSE 端点,状态管理脆弱
- 缺乏标准认证:远程 MCP Server 的访问控制完全靠实现者自己设计
- 没有工具元数据:host 无法区分一个工具是只读的还是破坏性的,导致权限控制只能一刀切
阶段二:MCP 2.0(2025-03-26)
2025 年 3 月发布的 MCP 规范修订版(常被社区称为"MCP 2.0")是一次重大更新,主要引入了四个关键能力:
① Streamable HTTP 替代 HTTP+SSE
这是最核心的变化。Streamable HTTP 用单一的 HTTP 端点同时支持 POST(客户端到服务器)和 GET(服务器到客户端推送),不再需要维护两套端点。它就像一个"双向 HTTP 通道"——你可以把它想象成一根管道,双方都能往里面扔消息,但走的都是标准的 HTTP 请求,这意味着:
- 任何支持 HTTP 的防火墙和代理都能正常工作
- 连接可以优雅地建立和恢复
- 支持会话管理(通过
Mcp-Session-Idheader) - 断线后可以通过
Last-Event-ID恢复流,不会丢消息
这个改变让 MCP 从"适合本地和开发环境"真正变成了"适合生产环境远程部署"的协议。
② OAuth 2.1 授权框架
有了标准化的认证之后,企业 MCP Server 可以有统一的权限体系,不再每个 server 自创一套。MCP Client 在连接时可以完成标准的 OAuth 授权流程,获取访问令牌。
③ 工具注释(Tool Annotations)
每个工具可以携带元数据,声明自己的属性:
readOnlyHint:是否只读destructiveHint:是否具有破坏性idempotentHint:是否幂等openWorldHint:是否访问开放网络
这样一来,host 在做权限控制时就不再是"要么全开要么全关",而可以基于工具的具体属性做细粒度审批。例如:只读工具可以自动放行,破坏性工具需要用户确认,访问外部网络的工具需要额外审查。
④ JSON-RPC 批处理
客户端可以一次 HTTP 请求携带多个 JSON-RPC 调用,减少网络往返。对于需要密集调用工具的 agent 场景,批处理能显著降低延迟。
演进的内在逻辑
回过头来看,MCP 的演进线其实非常清晰:
MCP v1.0 (2024-11)
- stdio: 解决"本地工具复用"
- HTTP+SSE: 解决"远程工具接入"
→ 核心问题:工具能跨宿主共享了
MCP v2.0 (2025-03)
- Streamable HTTP: 让远程接入真正生产化
- OAuth 2.1: 让权限管理标准化
- Tool Annotations: 让工具属性可描述
- JSON-RPC Batching: 让调用更高效
→ 核心问题:工具共享不仅要"能通",还要"可管、可控、可维护"
所以 MCP 不是一个静态的协议,而是在不断回答越来越具体的问题:"工具能共享了吗?→ 共享上生产了吗?→ 生产上安全可控了吗?"
3.5 它不解决什么问题
MCP 也很容易被神化。它不负责:
- 替你做任务规划
- 替你决定何时调用什么工具
- 替你写好高质量 prompt
- 替你把复杂任务拆给多个 agent
- 负责不同 Agent 之间的通信(那是 A2A 的事)
MCP 更像"标准化基础设施",不是"自动变聪明"。
3.6 一个直观类比
你可以这样理解:
function call像"拨打一个电话号码"MCP像"建立统一电话网络和通讯协议"- MCP 从 v1.0 到 v2.0,就像电话网络从"能打通"进化到"有来电显示、有通话加密、有套餐管理"
只有电话号码,没有通信协议,系统没法大规模互通。 只有通信协议,没有人去拨号,也不会自动解决业务问题。
3.7 一个例子:企业内部助手
假设公司内部有三套系统:
- Jira
- Confluence
- 内部发布平台
以前每个 AI 产品都要分别对接这三套 API。
现在团队可以做三个 MCP Server:
jira-mcpconfluence-mcpdeploy-mcp
然后让不同宿主去接:
- IDE 里的编码助手
- Slack 里的问答助手
- Web 后台里的运维助手
这样它们都能共享同一套企业能力,而不是每个产品重复造轮子。
更妙的是,用上 MCP 2.0 之后:
deploy-mcp的工具可以标上destructiveHint: true,这样助手在调用发布操作前会自动请求用户确认- 所有 MCP Server 统一走 OAuth 认证,权限管理员只需要在一个地方配置
- 即使助手在海外办公室,通过标准 HTTP 也能正常连接到内网的 Streamable HTTP 端点
四、Skills:解决"模型会不会做"而不只是"能不能做"
4.1 它出现的背景
当工具接入越来越丰富后,大家很快发现一个新问题:
有工具,不等于会用工具。 能调函数,不等于能稳定完成任务。
比如同样是"修一个 bug",两个 agent 的表现可能天差地别:
- 一个上来先改代码,结果改错模块
- 一个先读日志、查调用链、定位测试,再做最小修复
区别不在于它们有没有 shell、有没有 grep、有没有 git,而在于它们有没有稳定的工作方法。
这就是 skills 要解决的问题。
4.2 Skills 到底是什么:不止是 prompt,更是一种"上下文重载"
skills 可以理解为:
针对某类任务沉淀出来的可复用操作经验包。
这个"经验包"可能包括:
- 任务目标定义
- 适用场景
- 操作步骤
- 约束规则
- 示例
- 推荐工具
- 常见坑
但如果只理解到这里,你可能会觉得 skill 就是一个"写得比较详细的 prompt"。这种理解没有错,但它缺失了一个关键洞察。
Skills 的本质是一种"上下文重载(Context Override)"。
什么意思呢?LLM 在回复用户时,它的行为模式很大程度上是由"上下文窗口里的内容"决定的。正常情况下,它的上下文是:
系统提示词 + 用户消息 + 历史对话 + 工具定义
当 Agent 激活一个 skill 时,等于在上下文窗口里注入了一套完整的"专业认知框架"——不仅是"你要怎么做",还包括"你现在是谁"、"你应该优先考虑什么"、"你有哪些陷阱不能踩"、"你的输出应该长什么样"。
这套框架实际上"重载"了模型的默认行为方式,就像面向对象编程中,子类的方法重载(override)了父类的默认实现:
默认 LLM 行为(父类):
- 通用聊天模式
- 遇到编程问题,随便给个方案
- 输出格式自由
加载"代码修复" skill 后(子类重载):
- 先读代码,再动手
- 最小改动优先
- 必须有验证步骤
- 输出带文件位置和 diff
从这个角度,skill 和 RAG 有一个重要的区别:
- RAG 注入的是"知识"——它告诉模型"这个事实是什么"
- Skill 注入的是"方法"——它告诉模型"你现在应该怎么想、怎么做"
举个更具体的例子。假设你在做一个 code review 的 skill,它包含:
# Code Review Skill
## 身份
你现在是一个只关注代码质量的审查者。你不需要讲客气话,
也不需要评价代码风格以外的东西。
## 审查优先级
1. 逻辑错误和边界条件
2. 安全漏洞
3. 性能问题
4. 可维护性
## 输出格式
- 先按严重性列出问题
- 每个问题带文件路径和行号
- 没有问题就明确说"未发现问题"
- 不要在前面放"变更摘要"
当 agent 加载这个 skill 时,发生了几件事:
- 身份覆盖:从"通用助手"切换为"代码审查者"
- 优先级重塑:从"什么都可能提"聚焦到"按严重性排查"
- 输出约束:从"自由格式"锁定为"结构化的审查报告"
- 行为边界:明确"没问题就说没问题",避免"非要找出点什么"
这些都不是外部工具能做到的——工具只提供能力,不提供使用能力的方法论。skill 的价值,就是把这套方法论固化成上下文里的"行为程序"。
4.3 Skill 的上下文重载为什么重要
这一层的重要性经常被低估,但它解决了一个非常本质的问题:
LLM 是通用的,但任务是需要专业性的。
一个通用 LLM 的知识广度极大(读过人类历史上几乎所有的文本),但正因为它"什么都懂一点",它在具体任务上很容易表现出"什么都懂一点,但不够深"或者"知道怎么做但执行时不够稳"。
Skills 的上下文重载机制,就是在不改变模型参数的前提下,让模型在特定任务的上下文中表现出专家级的执行一致性。
这种一致性来自于 skill 在上下文中建立的"软约束系统":
- 先做什么,后做什么 → 防止步骤跳跃
- 什么能做,什么不能做 → 防止越界
- 遇到问题怎么处理 → 防止卡住
- 结果应该长什么样 → 防止输出漂移
这就是为什么一个好的 skill 文件往往比一个"同样意思的长 prompt"效果好得多——prompt 只是"说了一句",而 skill 是在上下文中系统性地"搭建了一个工作环境"。
4.4 它解决什么问题
1. 让高频任务的执行风格稳定下来
例如上面提到的代码评审 skill。每次做 code review,agent 的行为都不会飘得太厉害。
2. 降低复杂 prompt 的重复成本
如果每次都在对话里临时写一大段:
你现在是一个资深架构师,请先这样,再那样,遇到什么情况如何处理……
这很难维护,也不利于团队共享。
skill 的价值就在于把这套东西固化下来,变成可复用资产。
3. 把"领域知识"和"操作流程"绑定起来
举个例子,你做的是"生成 OpenAI API 使用建议"的 skill,它可以明确包含:
- 优先查官方文档
- 避免引用过时参数
- 推荐模型时区分延迟、成本、能力
- 给代码示例时优先官方 SDK 形式
这样它就不是一段抽象 prompt,而是有明确边界的专业工作流。
4.5 它不解决什么问题
skill 不直接解决:
- 外部系统怎么接入
- 工具实际怎么执行
- 多 agent 之间如何调度
- 跨系统 Agent 之间如何通信
所以 skill 不是 tool,也不是 protocol,更不是 scheduler。
4.6 一个例子:写博客 skill
假设你有一个"技术写作" skill,里面写着:
适用场景:
- 写工程实践文章
- 写原理解释文章
要求:
- 先讲问题背景,再讲方案
- 不只给定义,要讲为什么需要
- 必须给具体例子
- 避免把概念堆成术语表
- 默认输出中文
这时候,agent 在接到"写一篇讲解 MCP 的文章"时,会更像一个稳定的作者,而不是临场发挥的聊天机器人。
五、A2A:再解决"Agent 之间怎么互相通信"
5.1 它出现的背景
前面的 function call、MCP 和 skills 解决了一个核心问题:
单个 Agent 怎么使用工具、接入能力、稳定执行。
但当 Agent 系统越来越成熟,一个新的问题浮出水面:
不同 Agent 之间怎么协作?
想象一个企业的真实场景:
- 一个 Agent 专门负责代码审查(部署在公司 GitLab 旁边)
- 一个 Agent 专门负责工单管理(对接 Jira)
- 一个 Agent 专门负责文档检索(对接 Confluence)
- 一个 Agent 专门负责部署协调(对接 CI/CD)
这些 Agent 可能是不同团队、用不同框架、跑在不同服务器上构建的。现在用户提了一个需求:"帮我排查这个线上的 500 错误,看看最近的代码变更、相关工单和部署记录。"
单靠一个 Agent 很难完成——它没有 Jira 的权限,也不了解部署流程。你当然可以用 MCP 把所有工具接进来,但问题是:
- 你不想把所有敏感系统的访问权限都开给一个 Agent。安全上,让每个 Agent 只接触自己的领域更可控。
- 各团队的工具实现细节不应该被外部 Agent 直接调用。比如代码审查 Agent 可能内部使用了复杂的 AST 分析工具链,开发团队不希望外部直接调用这些底层工具。
- Agent 之间需要的不是"工具调用",而是"任务委托"。你说"帮我查一下这个 bug 关联的工单",这不是调用某个工具函数,而是把一个子任务委托给另一个 Agent 去思考、检索、总结。
这就是 A2A(Agent-to-Agent 协议)要解决的问题。
5.2 A2A 到底是什么
A2A(Agent-to-Agent Protocol)是由 Google 提出,后来贡献给 Linux Foundation 的开源协议。它的定义非常清晰:
一个开放协议,用于让不同框架、不同厂商、不同服务器上运行的 AI Agent 之间能够互相通信、发现能力、协作完成任务——而不需要暴露各自的内部状态。
如果说 MCP 解决的是 Agent 向下接入工具的问题,那 A2A 解决的就是 Agent 横向协作的问题。
5.3 几个核心概念
A2A 协议围绕几个关键设计展开:
1. Agent Card(Agent 名片)
每个 A2A Server 都暴露一张 Agent Card——一个 JSON 格式的能力声明,描述:
- 这个 Agent 是谁(名称、描述、提供商)
- 它能做什么(skills 列表,不是工具列表)
- 怎么连接它(URL、支持的传输协议)
- 认证要求(OAuth、API Key 等)
这有点像 DNS 之于互联网,或者 package.json 之于 npm 生态——它是一个标准化的"自描述文档",让其他 Agent 能够发现和理解它。
{
"name": "Code Review Agent",
"description": "Reviews pull requests for code quality and security issues",
"url": "https://code-review.internal.example.com",
"skills": [
{ "id": "code_review", "name": "Code Review", "description": "..." },
{ "id": "security_scan", "name": "Security Scan", "description": "..." }
],
"defaultInputModes": ["text", "file"],
"defaultOutputModes": ["text", "file"]
}
注意,它描述的是"skills"(能完成什么任务),而不是"tools"(有哪些函数)。这是刻意的设计——A2A 不关心对方内部怎么实现,只关心对方能交付什么结果。
2. Task(任务)
A2A 的核心工作单元不是"函数调用",而是"任务"。一个 Task 有自己的生命周期:
pending → working → input-required → working → completed
→ failed
→ canceled
这很重要,因为它意味着 A2A 天然支持长运行任务和多轮交互。一个 Agent 可以给另一个 Agent 派一个任务,过一段时间再来查看结果。甚至在任务进行中,被委托方可以反过来请求更多信息(input-required 状态),形成多轮对话。
3. 支持流式和推送
A2A 支持三种交互模式:
- 同步 request/response:简单的问答
- 流式 SSE:实时的进度更新(比如"代码审查已完成 60%")
- 异步推送通知:任务完成后通过 webhook 通知调用方
4. 不透明执行(Opaque Execution)
A2A 的一个核心设计原则是:Agent 之间协作时,不需要暴露内部状态。对方的 prompt、工具链、推理过程都是黑箱——你只需要知道"它能做什么"和"它产出了什么"。
这解决了企业级场景中的一个关键安全问题:你不需要让外部 Agent 看到你内部的工具实现、数据库 schema 或业务逻辑。
5.4 A2A 和 MCP 的关系
这两个协议经常被放在一起比较。关键在于理解它们的方向不同:
Agent ↔ Agent
↑
A2A
↑
┌─────────────────────────┐
│ Agent │
│ ┌───────────────────┐ │
│ │ LLM + Prompt │ │
│ │ + Skills │ │
│ └───────────────────┘ │
│ ↓ │
│ Function Call │
│ ↓ │
│ MCP │
│ ↓ │
│ Tools / Resources │
└─────────────────────────┘
- MCP 是纵向的:Agent 向下调用工具、访问资源、读取数据。它回答的是"这个 Agent 怎么接入外部能力"。
- A2A 是横向的:Agent 之间互相委托任务、交换信息。它回答的是"这些 Agent 怎么组成一个协作网络"。
MCP 和 A2A 不是竞争关系,而是互补关系。MCP 给了 Agent "手",让它能干具体的活;A2A 给了 Agent "嘴和耳朵",让它们能互相商量着把活分掉。
一个经典的比喻:
- MCP = 公司内部的工具标准(所有员工用同一套办公软件、同一套流程系统)
- A2A = 公司之间的合作标准(不同公司之间怎么发订单、签合同、交付成果)
5.5 它不解决什么问题
A2A 不解决:
- 单个 Agent 内部的任务规划
- 工具的具体调用和执行
- 单系统内的多 Agent 编排(那是 subagent 的事)
- Agent 该用什么方法论做任务(那是 skills 的事)
A2A 只解决一件事:让 Agent 在网络层面能够发现彼此、安全通信、协作完成任务。
5.6 一个例子:跨系统故障排查
回到开头的场景。用户说:
帮我排查这个线上 500 错误。
有了 A2A,系统可以这样工作:
主 Agent(用户对话界面)
↓ 通过 A2A 委托
├──→ 代码审查 Agent:查最近 24 小时的相关代码变更
├──→ 工单管理 Agent:查这个 bug 关联的 Jira 工单
└──→ 部署协调 Agent:查最近的部署记录和环境变更
每个被委托的 Agent 独立运行:
- 用 MCP 接入自己的专业工具
- 用 function call 执行具体操作
- 用 skills 保证工作方法稳定
最后各 Agent 通过 A2A 把结果传回主 Agent,主 Agent 汇总给用户。
关键是:每个 Agent 只暴露自己"能做什么"(通过 Agent Card),但不暴露"怎么做的"(内部工具和逻辑)。安全、可控、可审计。
六、Subagent:解决"一个 agent 忙不过来"
6.1 它出现的背景
当任务再复杂一点,单个 agent 即使会用工具、也有 skill,还是会遇到瓶颈。
比如这种任务:
帮我给这个仓库做一次全面改造: 先理解现有认证流程,再修复 3 个接口 bug,补测试,最后写迁移说明。
如果全靠一个 agent 顺着做,问题会很快暴露:
- 上下文太长
- 多条工作线互相打架
- 一个任务没做完,另一个信息又来了
- 局部细节挤占主线注意力
于是就有了 subagent 的需求。
6.2 Subagent 是什么
你可以把 subagent 理解为:
主 agent 为了完成复杂任务,派出去处理某个子问题的辅助 agent。
它不是普通函数,也不是普通工具。它更像是:
- 一个独立的推理单元
- 一个有自己上下文窗口的执行者
- 一个能自己读代码、调用工具、产出结果的"小代理"
6.3 Subagent 和 A2A 的区别
这是一个很容易混淆的点。
- Subagent 是单系统内部的任务拆分机制。它发生在同一个 Agent 框架内,由同一个宿主程序调度,共享同一套工具注册和上下文管理。subagent 之间不需要协议——宿主直接管理它们的生命周期。
- A2A 是跨系统之间的协作协议。它连接的是独立部署、独立运行的 Agent,可能用不同框架、不同语言、跑在不同服务器上。它们通过标准化的协议通信,互相之间是"黑箱"。
类比一下:
- Subagent 像是一个团队内部的分工(经理把任务分给组员,大家共享工具和上下文)
- A2A 像是跨公司的合作(你给外部供应商下单,对方在自己的系统里完成,你不需要知道他们怎么做的)
两者可以组合使用:主 Agent 可以通过 A2A 委托任务给外部的专业 Agent,而那个外部的 Agent 内部可能再用 subagent 来拆分工作。
6.4 它解决什么问题
1. 任务拆分
主 agent 不必亲自做所有事情,可以把一部分工作分出去。
例如:
- 主 agent 负责总体规划
- subagent A 调研认证模块
- subagent B 修复前端表单 bug
- subagent C 跑测试并整理失败项
2. 并行化
有些事情天然可以并行:
- 读不同模块代码
- 查询不同文档
- 修改不冲突的文件
- 做独立验证
subagent 可以显著减少总耗时。
3. 隔离上下文
这是最容易被低估的一点。
单 agent 很容易被海量细节污染上下文。subagent 能把局部问题封装掉,只把结果带回来。
比如主 agent 不需要看到测试日志的全部细节,它只需要知道:
- 哪些测试失败
- 失败原因是什么
- 需要不需要阻塞交付
6.5 它不解决什么问题
subagent 不是银弹。
它不能自动解决:
- 工具接入标准化
- 单个工具的 schema 设计
- 任务方法论沉淀
- 跨系统 Agent 之间的通信
换句话说,subagent 解决的是"组织问题",不是"能力定义问题"。
6.6 一个例子:代码库改造
主 agent 接到任务:
给支付系统加幂等保护,并补齐测试。
它可以这样拆:
主 Agent:
- 读整体架构
- 设计改造策略
Subagent A:
- 只看 API handler 和 service 层
- 找出幂等缺失点
Subagent B:
- 只看测试目录
- 评估现有测试缺口
Subagent C:
- 独立跑测试
- 汇总失败结果
最后主 agent 汇总这些结果,再决定下一步改哪些文件。
七、它们之间到底是什么关系
讲到这里,可以把它们串起来了。说实话,当我把这五个概念在纸上画出这五层的时候,我整个人是什么鬼——原来它们根本不是在同一个平面上竞争,而是像网络协议栈一样层层堆叠。
7.1 第一层:function call 是最基础的执行接口
它回答的是:
模型想调用外部能力时,怎么以结构化方式表达出来?
没有这层,模型只能"说自己会做",不能稳定请求执行。
7.2 第二层:MCP 是工具接入标准
它回答的是:
这些外部能力,如何统一暴露给模型系统?
function call 可以调用一个工具,但 MCP 让"工具生态"更容易被接入、发现和复用。从 v1.0 到 v2.0 的演进,让这个协议从"能通"走向了"可管可控"。
7.3 第三层:skills 是任务经验层
它回答的是:
即使有了工具,模型该按什么方法去完成某类任务?
skill 让 agent 不只是"有工具可用",而是"更像一个会干活的人"。通过上下文重载机制,skill 在模型的认知空间里搭建起一个专业的工作环境。
7.4 第四层:A2A 是 Agent 间协作协议
它回答的是:
不同 Agent 之间如何互相发现、安全通信、委托任务?
A2A 让 Agent 生态从"单打独斗"走向"网络化协作"。它不是替代 MCP 或 skills,而是在更高一层提供 Agent 间的"共同语言"。
7.5 第五层:subagent 是任务组织层
它回答的是:
当一个 agent 处理不过来时,任务怎么拆、怎么并行、怎么协作?
subagent 在单个系统内部组织任务,而 A2A 在跨系统层面组织协作。两者都解决"分工"问题,但作用域不同。
这五层的关系可以概括为:
用户任务
↓
规划层:subagent(拆任务)、A2A(跨 Agent 委托)
↓
经验层:skills(提供做事方法)
↓
执行层:function call(发起具体动作)
↓
接入层:MCP(标准化工具和资源的暴露与发现)
八、把它们放进一个完整场景里看
假设你要做一个"企业级研发助手",支持这些能力:
- 看代码
- 查文档
- 调工单
- 跑测试
- 生成变更说明
- 调用外部的专业 Agent(如安全审计 Agent)
这时五者可以这样协作。
8.1 MCP 提供接入层
你可能会有这些 MCP Server:
filesystem-mcpgit-mcpjira-mcpci-mcpdocs-mcp
它们负责把外部能力标准化暴露出来。如果用的是 MCP 2.0,这些 server 可以:
- 通过 Streamable HTTP 部署在生产环境
- 用 OAuth 统一认证
- 工具带上 annotations 让 agent 框架做细粒度权限控制
8.2 Function call 负责具体调用
主 agent 在推理过程中决定:
- 先调用
search_code - 再调用
get_ticket - 然后调用
run_tests
这里每一次动作,本质上都是 function call。
8.3 Skills 提供工作方法
例如一个"代码修复" skill 规定:
- 先读相关文件
- 不要直接大改
- 先做最小修复
- 修改后必须验证
- 如果测试跑不了,要明确说明
这个 skill 加载后,通过上下文重载,让 agent 从"能改代码的工具"变成了"会修 bug 的工程师"。它不是在给 agent 增加能力,而是在重新配置 agent 使用能力的方式。
8.4 A2A 负责调用外部专业 Agent
主 agent 发现这次修复涉及安全问题,需要额外的安全审计。但安全审计不是它自己的技能——公司有一个独立的"安全审计 Agent",由安全团队维护,跑在另一台服务器上。
主 agent 通过 A2A 协议:
- 发现安全审计 Agent 的 Agent Card(通过 URL 或注册中心)
- 理解它的能力:
security_auditskill - 发送任务:"请审计以下代码变更的安全性"
- 安全审计 Agent 在自己的环境中执行,用 MCP 接入自己的安全扫描工具
- 异步或流式返回审计结果
整个过程,主 agent 不需要知道安全审计 Agent 用了哪些工具、跑的什么模型、内部逻辑是什么——它只需要知道"它能做安全审计"和"结果是什么"。
8.5 Subagent 负责内部分工
对于在自己的 MCP 工具集和 skill 范围内能做的事情,主 agent 用 subagent 拆分:
- subagent A 去分析认证流程
- subagent B 去检查测试失败
- subagent C 去收集工单背景
8.6 这个系统的全链路大概长这样
用户说:修复支付回调重复入账的问题,进行安全审计,并写出修复说明
主 Agent:
1. 根据 skill 决定先读代码、找上下文
2. 通过 MCP 接入的代码工具执行搜索
3. 用 function call 调用具体工具
4. 发现任务复杂,派出 subagent 去并行分析测试和调用链
5. 通过 A2A 委托安全审计 Agent 进行独立的安全审查
6. 汇总所有结果后决定修改方案
7. 修改代码、跑验证、生成说明
这时候你会发现:
- 没有 MCP,工具接入会很散
- 没有 function call,工具调用不稳定
- 没有 A2A,无法安全地委托外部专业 Agent
- 没有 skills,执行风格会漂
- 没有 subagent,大任务效率低、上下文容易爆
九、最容易混淆的几个点
下面这几个坑我挨个摔过,傻逼如我当年,每一个都踩进去了,你大概率也会遇到。
9.1 "MCP 是不是 function call 的替代品?"
不是。
更准确地说,MCP 和 function call 关注点不同:
function call关心"调用动作如何表达"MCP关心"能力如何被标准接入"
很多基于 MCP 暴露出来的工具,最后依然是通过 function call 这类机制被模型选中和调用。
9.2 "A2A 是不是 MCP 的竞品?"
这是最常见的误解。实际上它们解决的是不同方向的问题:
MCP:Agent → 工具/资源(纵向)A2A:Agent ↔ Agent(横向)
两者不是二选一的关系,而是经常一起用。一个 Agent 可能同时是 MCP Client(连接各种工具)和 A2A Server(对外暴露自己的技能给其他 Agent 调用)。
9.3 "Skill 是不是 prompt 的别名?"
也不是。这是最容易踩的坑。
prompt 是"一段提示文本",而 skill 是"一套完整的任务执行系统"。区别在于:
- prompt 是一次性的、临时的
- skill 是结构化的、可复用的
- prompt 主要影响"单次回复"
- skill 通过上下文重载系统性地改变模型的执行模式
简单说:prompt 是"提醒",skill 是"培训"。
你可以把一段 prompt 塞进对话里说"请像资深架构师一样思考",也可以加载一个包含目标、步骤、约束和陷阱提示的 skill。后者的效果,通常远好于前者——因为它不是在模型原有的思维框架上"贴提示",而是直接在上下文中"换了一个思维框架"。
9.4 "Subagent 是不是 A2A 的一种实现?"
不是。
- Subagent 是单系统内部的机制,通常由宿主框架直接管理,不走协议
- A2A 是跨系统的开放标准,用于连接独立部署的 Agent
可以这样理解:subagent 是同一个进程中创建的辅助 Agent(共享工具注册、内存空间),而 A2A 连接的是不同进程、不同服务器、不同组织中的 Agent。
9.5 "只要有很多工具,Agent 就会变强吗?"
不一定,甚至经常会变差。
工具越多,越容易出现:
- 选择困难
- 错用工具
- 上下文污染
- 权限风险
所以成熟系统通常会同时做四件事:
- 用 MCP 管理工具接入
- 用 skill 约束任务方法
- 用 A2A 安全委托外部专业能力
- 用 subagent 管理复杂度
十、几个具体例子
10.1 例子一:客服助手查订单
用户说:
帮我查一下订单
A1024为什么还没发货。
系统可能这样工作:
- 模型根据 schema 发起
getOrder(orderId)function call - 工具来自公司内部订单 MCP Server
- 返回结果显示库存锁定异常
- 模型继续调用
getInventoryStatus(sku) - 最终总结成客服可读答案
这里:
- function call 负责"怎么调用"
- MCP 负责"订单和库存工具怎么接进来"
如果团队还有一个"客服沟通" skill,它还会约束输出风格:
- 先给结论
- 再给原因
- 不暴露内部字段名
10.2 例子二:写代码并修测试
用户说:
给这个接口加缓存,顺便修一下挂掉的测试。
系统可能这样工作:
- 主 agent 使用"代码修改" skill,先读代码再动手
- 通过代码搜索工具查依赖关系
- 任务变复杂,于是起一个 subagent 去专门分析测试失败
- 另一个 subagent 去看缓存层已有实现
- 主 agent 汇总后修改代码
- 再调用测试工具验证
这里 function call、MCP、skills、subagent 四者全出现。如果还需要安全审计,主 agent 还会通过 A2A 委托给独立的安全审计 Agent。
10.3 例子三:研究型 Agent
用户说:
帮我比较三种向量数据库的适用场景,并给出选型建议。
如果系统支持联网搜索和 A2A:
- 主 agent 先派 3 个 subagent,分别调研不同数据库
- 每个 subagent 调用搜索、打开网页、提取信息等工具
- 这些工具可能都通过某个 MCP Server 提供
- 如果主 agent 发现某个数据库的性能数据需要专门的基准测试,可以通过 A2A 委托给一个"基准测试 Agent"
- 最终主 agent 汇总,并按一个"技术选型分析" skill 输出结果
这时候五者的价值都体现出来了:subagent 拆解并行工作,A2A 委托外部专业能力,skills 约束输出质量,MCP 提供工具支持,function call 执行具体操作。
十一、工程上应该怎么设计这五层
如果你要自己做 Agent 系统,我建议按下面的思路分层设计。
11.1 把 function call 当成执行入口,不要让模型直接碰业务实现
也就是说:
- 模型只负责"请求调用"
- 真正执行一定放在宿主程序
- 参数必须校验
- 权限必须收口
- 超时、幂等、审计必须由系统保证
11.2 把 MCP 当成能力接入总线
凡是可能被多个宿主复用的外部能力,都适合往 MCP 方向收敛,比如:
- 文件系统
- Git
- 文档库
- 知识库
- 企业 API
建议尽量使用支持 Streamable HTTP 的 MCP 2.0 server,原因很简单:
- 你的 MCP Server 迟早需要支持远程访问(团队不一定都在本机跑)
- Tool annotations 让你能做更精细的权限控制
- OAuth 标准化减少了安全性方面的重复投入
这样未来无论换模型、换 IDE、换 Agent 框架,工具层都更稳。
11.3 当需要跨 Agent 协作时,引入 A2A
如果你的系统需要:
- 调用其他团队维护的 Agent(安全审计、合规检查、数据分析等)
- 让多个独立 Agent 协作完成一个复杂任务
- 保护各 Agent 内部的实现细节和敏感权限
那么引入 A2A 是很自然的选择。重要的设计决策:
- 什么通过 A2A,什么通过 MCP:如果你的 Agent 只需要"调用某个系统的函数"——用 MCP。如果你的 Agent 需要"委托另一个 Agent 去思考和决策"——用 A2A。
- Agent Card 的粒度:不要像 MCP 一样暴露工具函数列表。A2A 的 Agent Card 应该描述"skills"(能力),而不是"tools"(函数)。描述"能做安全审计",而不是描述"有 sqlmap、nmap、OWASP ZAP"。
11.4 把 skills 当成团队的"行为资产",而不只是提示词模板
不要把 skill 只当"提示词模板"。更好的做法是把它们做成:
- 有名称
- 有适用范围
- 有步骤说明
- 有示例
- 有约束
- 有引用文件
理解 skill 的本质是"上下文重载",能帮助你在设计 skill 时更有方向:你不是在写一段更好的 prompt,而是在搭建一个专业的工作环境。问问自己:
- 这个 skill 应该覆盖模型的哪些默认行为?
- 它的执行顺序够不够明确?
- 边界条件处理清楚了没有?
- 遇到异常状况时,skill 留下的空间够不够 agent 自主判断?
好的 skill 设计,是在"约束(决定怎么做)"和"自由(留出推理空间)"之间拿捏分寸——太松则退化回普通 prompt,太紧则变成死板的脚本。
11.5 把 subagent 用在真正值得拆分的任务上
不是所有任务都要多 agent。
适合上 subagent 的场景通常有:
- 多模块并行探索
- 多来源信息调研
- 写 scope 明确且互不冲突
- 独立验证任务
不适合的场景则是:
- 任务太小
- 下一步强依赖当前结果
- 子问题边界模糊
- 协作成本高于收益
十二、一个更实用的判断方法
以后再碰到新框架、新产品、新术语,你可以直接问五个问题:
1. 它是在解决"调用"问题,还是"接入"问题?
- 调用问题:偏 function call
- 接入问题:偏 MCP
2. 它是在解决"会不会做",还是"能不能做"?
- 能不能做:偏工具、function call、MCP
- 会不会做:偏 skills
3. 它是在解决"单点能力",还是"Agent 协作"?
- 单点能力:偏 tool / function call
- Agent 协作:偏 A2A(跨系统)或 subagent(单系统内)
4. 它是在增加自由度,还是在增加稳定性?
- MCP 和 function call 多半是在增加能力接入和执行自由度
- skills 多半是在增加任务执行稳定性——通过上下文重载,将"自由度"收束到专业的行为轨道上
- A2A 和 subagent 多半是在增加系统的规模处理能力
5. 它的作用范围是系统内部还是跨系统?
- 系统内部:function call、MCP、skills、subagent
- 跨系统:A2A
这样你就不容易被术语带跑偏。
十三、最后总结
妈的,回头看这五个概念,逆天的地方就在于——它们各自只解决一层问题,但拼在一起的时候,整个系统就活过来了。
把这五个概念压缩成最短版本,就是:
function call:让模型能结构化地请求调用外部能力MCP:让外部能力能被标准化地接入模型系统(从 v1.0 的工具共享发展到 v2.0 的生产级管控)A2A:让不同 Agent 之间能用统一协议互相发现、通信和协作——不暴露内部实现skills:让模型在某类任务上有更稳定的做事方法——通过上下文重载,在模型的认知空间里建立专业的工作框架subagent:让复杂任务可以在单个系统内被拆分、并行和协作完成
它们不是互斥关系,而是典型的分层协作关系。
一个成熟的 Agent 系统,往往会同时具备这五层能力:
- 用
MCP接入工具生态 - 用
function call发起具体动作 - 用
skills约束做事方法 - 用
subagent组织单系统内的复杂任务 - 用
A2A连接外部的专业 Agent
如果你把它们都混成"AI 能调用工具"这一句话,后面做系统设计时一定会乱。
真正靠谱的理解方式,是把它们看成:
- 有的解决"执行接口"
- 有的解决"能力接入"
- 有的解决"经验沉淀"
- 有的解决"Agent 互操作"
- 有的解决"协作组织"
而每一层都在不断演进:function call 在变得更细粒度(structured output、parallel calls),MCP 在从"能接入"走向"安全可控地接入",A2A 在从"Google 的提案"走向 Linux Foundation 的开放标准,skills 在从"复杂 prompt"走向"上下文工程",subagent 在从"一个辅助函数"走向"自主协作单元"。
当这五层拼起来,LLM 才会从"会聊天"慢慢进化成"能稳定干活的 Agent 网络"。
读者来信
暂无来信,期待你的分享。