多智能体协作的三套通信语言:MCP、A2A 与 Tool Calling 怎么选(附 LangGraph/DeepAgents 实战分工模式)

多智能体协作的三套通信语言:MCP、A2A 与 Tool Calling 怎么选(附 LangGraph/DeepAgents 实战分工模式)

多智能体系统上线前最容易出问题的,往往不是模型能力,而是把三种不同粒度的"通信合约"混成了一件事。本文先把 Tool Calling、MCP、A2A 放到同一张分层图里,说清各自标准化哪一段边界,再落到 LangGraph 的"拆解---执行---质检"回环与 DeepAgents 的主子调度两条工程路径上。


开场:三个都被叫作"Agent 协议"的东西

先看一个在团队评审里出现频率很高的错误场景:产品经理要求"研究员 Agent 调用搜索能力",工程师开始调研 A2A;另一个需求是"让规划 Agent 把子任务交给执行 Agent",工程师却在设计一套 Function Calling 的 prompt 拼接。两者都做错了层。前者要解决的是 Agent 如何稳定接入一个外部能力,属于工具接入问题;后者要解决的是两个具有自主性的执行体之间如何委派任务、如何交付结果,属于协作问题。

之所以混淆,是因为三者在代码里长得都像"发一段 JSON、收一段 JSON"。但它们标准化的连线完全不同:

  • Tool Calling:模型与工具之间的"单次调用合约",约定工具描述、调用意图、执行结果如何回填对话。
  • MCP:Agent 与工具/资源服务之间的"标准化接入合约",约定能力发现、调用方式、传输与会话。
  • A2A:Agent 与 Agent 之间的"任务委派与协作合约",约定能力发现、任务生命周期、消息与结果交付。

一句话概括:选型问题的本质不是"哪个协议更强",而是"你想标准化的是谁和谁之间的边界"。协议层之上还有第二个独立决策------编排拓扑:谁拆解、谁执行、谁质检、谁调度。这两件事经常被塞进同一个"要不要上多 Agent"的讨论里,是本文想消除的最大认知噪音。

本文面向已经跑通单 Agent 的后端与 AI 应用工程师。涉及具体方法名、字段名与状态枚举处,均应以你所使用的 SDK 与规范当前版本为准;文中的代码是结构骨架,用于说明契约与控制流,不作为任何框架特定版本的 API 承诺。研究材料中关于 MCP 的官方自述可追溯到 MCP 项目一周年回顾文章 1,关于 MCP/A2A/Tool Calling 的中文辨析与 LangGraph、DeepAgents 实战结构参考了社区教程 234,但具体 API 断言均已回到"以官方文档为准"的表述纪律。


一、三层辨析:Tool Calling、MCP、A2A 各自标准化了什么

1.1 Tool Calling:模型与工具之间的"单次调用合约"

Tool Calling 解决的问题非常具体:让模型以结构化方式表达"我想调用某个工具",并把工具返回值重新纳入上下文。它的契约由三部分组成:

  1. 工具描述:名称、自然语言说明、参数的 JSON Schema。这段描述本质上是给模型看的提示词,写得含糊,模型就会在参数上自由发挥。
  2. 调用意图:模型输出的结构化调用块,包含工具名与参数。它不是执行,只是"请求执行"。
  3. 结果回填:宿主程序真正执行后,把结果作为一条工具消息塞回对话,模型据此继续推理。

它不负责的事情同样重要:工具的注册与发现、跨进程传输、鉴权与凭据管理、调用的生命周期与超时、两个 Agent 之间谁调用谁。这些都不在 Tool Calling 的合约范围内。

为什么说它"最底层、最不可绕过"?因为即便你用了 MCP 或 A2A,最终触发动作的那一刻,仍然需要某种"结构化调用意图"。MCP 的 tools/call 是把这层约定扩展到了进程/网络边界之外,A2A 的任务创建则是在其上又叠加了会持续存在的任务对象。换句话说,MCP 和 A2A 都可以看成在 Tool Calling 之上补上了它缺的那半截:发现、传输、生命周期。

不同厂商 SDK 在这层的能力边界并不一致,选型时至少要比对四个维度:参数 schema 的表达能力(嵌套对象、枚举、格式约束)、是否支持一次响应中并行发起多个工具调用、结构化输出与工具调用能否组合、以及"强制调用/禁止调用/自动选择"这类控制开关的行为差异。不要把某一家的参数名写死在业务层,封装一层适配器是值得的。

一段最小骨架如下,展示契约形状而非某家 SDK 的确切 API:

python 复制代码
# 骨架代码:展示 Tool Calling 的契约形状,字段名以你所用 SDK 文档为准
tool_schema = {
    "name": "get_weather",
    "description": "查询指定城市的当日天气,返回温度与降水概率",
    "parameters": {
        "type": "object",
        "properties": {
            "city": {"type": "string", "description": "城市名,如:杭州"},
            "date": {"type": "string", "description": "YYYY-MM-DD,默认今天"},
        },
        "required": ["city"],
    },
}

messages = [
    {"role": "system", "content": "你是出行助手,必要时调用工具。"},
    {"role": "user", "content": "杭州明天适合户外吗?"},
]

# 1) 模型返回结构化调用意图(不是执行)
# assistant: tool_calls=[{name: "get_weather", args: {"city": "杭州", "date": "2026-09-30"}}]

# 2) 宿主程序真正执行,注意幂等键与超时
result = weather_client.query(city="杭州", date="2026-09-30")

# 3) 结果回填,模型继续推理
messages.append({
    "role": "tool",
    "tool_call_id": "<由 SDK 返回的调用标识>",
    "content": json.dumps(result, ensure_ascii=False),
})

一次完整调用的消息序列是:system → user → assistant(tool_calls) → tool → assistant。调用失败时的处理也要写进契约:是把错误文本回填给模型让它自己换参数,还是直接终止。生产系统里最常见的两个坑,一是把异常堆栈原样塞回上下文造成提示词污染,二是重试没有幂等键,导致下单、发消息这类有副作用的工具被执行两次。

1.2 MCP:Agent 与工具/资源之间的"标准化接入层"

MCP(Model Context Protocol)要解决的是另一个问题:同一个工具能力,如何被多个不同的 Agent、框架、客户端复用,而不必为每一对组合写一套适配代码。

它把角色拆成三层:

  • Host:宿主应用,例如 IDE 插件、桌面应用、Agent 运行时,负责整体策略与用户授权。
  • Client:Host 内部与某个 Server 保持一对一连接的协议客户端。
  • Server:能力提供方,暴露工具、资源或提示模板。

相比 Tool Calling,MCP 多出来的正是"接入"所需的那一整套机制:

机制 Tool Calling MCP
能力如何被发现 写死在调用方代码或配置里 初始化后通过列举接口动态发现
能力有几类 工具一种 工具、资源、提示模板等多类原语
调用如何传输 进程内函数调用或 SDK 内部 明确的传输层,如 stdio、Streamable HTTP
会话与能力协商 无 有,初始化阶段协商双方支持的能力
鉴权 由宿主自行处理 规范给出授权框架,具体策略由部署决定

一次典型请求链路是:Host 启动并初始化 Client → Client 与 Server 完成能力协商 → Client 列举 Server 暴露的工具/资源 → 模型决定调用某个工具 → Client 发起调用并把结果回填对话。方法名与字段名随规范版本演进,工程上应以当前规范文本为准;MCP 项目一周年回顾文章中也说明了规范在首个版本发布后持续更新的背景 1。

python 复制代码
# 骨架代码:同一个搜索能力以 MCP Server 形式暴露,两个不同 Agent 复用
# 结构示意,方法名与字段以 MCP 当前规范为准

# search_server.py ------ 能力提供方
def list_tools():
    return [{
        "name": "web_search",
        "description": "检索公开网页并返回标题、链接与摘要",
        "inputSchema": {...},
    }]

def call_tool(name, arguments):
    if name == "web_search":
        return search_backend.run(**arguments)

# researcher_agent.py / analyst_agent.py ------ 两个不同的宿主
# 各自的 MCP Client 连接到同一个 search_server,
# 不需要为"研究员 Agent 与搜索"和"分析 Agent 与搜索"分别写适配层

MCP 的收益是清晰的:工具一次实现、多客户端复用;接入第三方能力生态变成"接一个 Server"而不是"读一份私有 SDK";工具清单可以动态变化而不用改客户端代码。代价同样清晰:

  • 进程与连接管理:stdio 子进程要处理崩溃重启,HTTP 传输要处理断线与会话恢复。
  • 凭据下发:Server 需要的 API Key、OAuth 令牌如何交给它、如何回收、如何避免写进日志。
  • 工具描述漂移:Server 升级后工具签名变了,模型端的行为可能悄悄退化,需要契约测试。
  • 权限边界:一个 Server 暴露十个工具,不代表当前 Agent 都该看到;要按角色过滤。

一个实用判断:当你发现自己在写第二份工具适配代码时,就该考虑 MCP 了;当你只有一个进程内的三五个工具时,直接 Tool Calling 反而更简单。

1.3 A2A:Agent 与 Agent 之间的"任务委派与协作合约"

A2A(Agent-to-Agent)类协议的定位是:让两个各自独立、可能由不同团队或不同厂商实现、可能长时间运行的 Agent 互相发现、委派任务、接收中间进展、拿到最终结果。

它标准化的通常是这几类东西:

  1. 能力发现:一个 Agent 如何公布自己能做什么(常见形式是能力描述文件或 Agent Card 一类的机器可读描述),调用方据此判断该把哪类任务交给谁。
  2. 任务生命周期:创建任务、查询状态、接收中间消息或事件、取消、超时、失败重试。
  3. 消息与附件:文本、结构化数据、文件等载体如何随任务传递。
  4. 交互模式:同步返回、流式推送、订阅通知,适配长任务与短任务。

与 MCP 的关键差别在于被调方的性质 。MCP 的 Server 是能力提供者:收到调用、执行、返回,通常不拥有自己的目标与判断。A2A 的对端是对等体:它可能反问你要补充信息、可能把任务拆成自己的子任务、可能中途汇报进展、也可能拒绝任务。前者是"调用一个函数",后者是"把一件事交给一个人"。

由此引出三个工程上必须回答的生命周期问题:

  • 长任务:同步等待必然超时,需要轮询或订阅;谁负责心跳与进度语义?
  • 失败与取消:子 Agent 已经产生了副作用(写库、发邮件),取消后状态如何回滚或标记?
  • 结果交付:返回的是原始输出、结构化产物,还是摘要加引用?调用方如何验收?

但必须强调边界:同进程、同一张状态图里的分工不需要 A2A。在同一个 LangGraph 图里给两个节点之间引入 A2A,只会增加序列化开销、超时面与追踪难度。A2A 的主场是跨团队、跨运行时、跨厂商、跨网络边界------那里的"接口不统一"才是真问题。

需要说明的是,本次研究材料中关于 A2A 的内容均为二手转述 5,未提供官方规范链接,因此本文不引用其具体方法名、状态枚举与治理归属表述。生产决策前请务必对照 A2A 官方规范核实这些细节。

1.4 一张矩阵与一棵决策树

把三层放在一起,差异就不再抽象:

维度 Tool Calling MCP A2A
标准化对象 模型→工具的单次调用 Agent→工具/资源的接入 Agent→Agent 的任务委派
双方关系 不对等,工具无自主性 不对等,Server 无目标 对等,对端有自主性与判断
状态归属 无状态,结果即回填 多为无状态调用 + 会话 任务对象有完整生命周期
发现机制 调用方写死或配置 初始化后动态列举 能力描述文件/注册发现
典型失败模式 参数错、schema 漂移 连接、鉴权、工具描述漂移 超时、状态不同步、验收争议
引入成本 最低 中等,需管理 Server 与凭据 最高,需处理生命周期与治理
适用边界 单 Agent 内部 多客户端复用能力 跨团队/跨运行时协作

决策时按四问走一遍:

  1. 我要标准化的是哪段连线? 模型→工具选 Tool Calling;Agent→外部能力选 MCP;Agent→Agent 选 A2A。
  2. 双方是否同进程、同团队? 是的话用进程内契约与共享状态,不要引入跨进程协议。
  3. 对端是否有自主性与长任务? 有才需要任务生命周期语义。
  4. 是否需要第三方生态复用? 需要则把能力封装成标准服务端,否则本地实现更省事。

贯穿全文的案例就定为「行业研究助手」:主 Agent 拆任务,研究员 Agent 调用搜索与文档阅读工具,质检 Agent 校验结论与引用。它的每一次形态变化,都用来检验上述选择。


二、协议之上:多智能体的分工拓扑与消息契约

2.1 四类角色:拆解、执行、质检、知识

多智能体不是"多几个提示词",而是把一次推理拆成若干个有明确输入输出的岗位。社区实战中被反复验证的四类角色是:规划/拆解、执行、质检、知识 56。

角色 输入 输出 不该做的事
拆解 用户目标、约束、预算 子任务清单 + 每项验收标准 不直接产出业务结论
执行 单个子任务 + 验收标准 产物 + 引用 + 假设说明 不自行修改验收标准
质检 产物 + 引用 + 验收标准 判定 + 具体返工意见 不重新写一遍产物
知识 查询意图 可检索上下文 + 来源标识 不编造未检索到的内容

这里有一条容易被忽略但决定成败的设计:验收标准必须在拆解阶段产出。它是质检 Agent 唯一的判据。如果拆解阶段只给一句"写一份行业报告",质检就只能输出"我觉得不够好",然后进入无限返工。验收标准应当是可检查的:必须包含哪些结论、每条结论必须有可定位引用、禁止出现哪些未经证实的断言、字数与格式约束等。

知识角色之所以单列,是因为"让每个 Agent 自己去检索"会导致同一份资料被检索多次、结论之间引用不一致。集中式知识服务 + 引用标识,能让质检做到"逐条溯源"。

2.2 三种拓扑:Supervisor、流水线回环、层级主子

Supervisor(调度者):一个调度 Agent 接收目标,决定把哪些子任务交给哪些执行 Agent,并汇总结果。适合任务数量少、需要全局裁决、执行体能力各异的场景。缺点是调度者同时成为上下文瓶颈与单点:所有信息都经过它,它的上下文先爆;它出错,全链路出错。

流水线 + 回环:角色固定,状态单向流动,质检不通过则打回执行。适合产物可验证的场景------代码、结构化数据、带引用的报告。它的优势是行为可预测、可回放、易于做评测;代价是灵活性差,遇到计划外情况容易卡死在回环里。

层级主子:主 Agent 规划并动态派生子 Agent,子 Agent 完成后把摘要交回。适合探索型、发散型任务,例如深度调研,子任务数量事先无法确定。代价是成本与上下文难以预算,调试困难。

选型维度 Supervisor 流水线回环 层级主子
任务可验证性 中 高 低
并发度 中,受调度者限制 高,子任务可并行 高,但不可控
失败恢复 中 易,按节点重试 难,子 Agent 状态易丢失
调试成本 中 低 高
典型场景 混合能力编排 代码生成、报告生产 深度研究、开放探索

实际系统里更常见的是混用:外层 Supervisor 负责把大目标切成几条流水线,每条流水线内部用严格的拆解---执行---质检回环保证产物质量。案例「行业研究助手」就适合这种结构:外层按主题拆成若干研究方向,每个方向内部走可验证的引用闭环。

2.3 消息契约与共享状态:写清楚"谁写、谁读"

在同进程图内,用共享 State;跨进程、跨 Agent,用结构化消息。两者的共同要求是:字段的写入者唯一,读取者明确。

python 复制代码
from typing import Literal, Optional
from pydantic import BaseModel, Field

class Citation(BaseModel):
    source_id: str                 # 与知识服务返回的来源标识对应
    locator: str                   # URL、文件路径或段落定位
    quote: str = ""                # 支撑结论的原文片段

class AcceptanceCriteria(BaseModel):
    must_have: list[str] = Field(default_factory=list)
    forbidden: list[str] = Field(default_factory=list)
    citation_required: bool = True

class TaskContract(BaseModel):
    task_id: str
    parent_id: Optional[str] = None
    goal: str
    acceptance: AcceptanceCriteria
    artifact: Optional[str] = None          # 执行 Agent 写入
    citations: list[Citation] = Field(default_factory=list)  # 执行 Agent 写入
    verdict: Optional[Literal["pass", "rework", "escalate"]] = None  # 质检写入
    fix_instructions: list[str] = Field(default_factory=list)        # 质检写入
    retry_count: int = 0
    trace_id: str                          # 全链路追踪标识

三条铁律值得单独记住:

  1. 产物与意见分离 :质检的意见写进 fix_instructions,不要让它直接改写 artifact,否则责任链断裂,无法判断最终产物出自谁手。
  2. 每条结论带引用 :citations 是必需字段而非可选项,这是后续质检与审计的抓手。
  3. 返工必须可执行 :fix_instructions 里的每条都应是动作,如"为第 3 节的市场规模结论补充来源",而不是"写得再好一点"。

最典型的反模式是把整个对话历史原样塞进每个子 Agent 的提示词。结果是上下文爆炸、成本失控,而且出了问题无法定位是谁在哪一步引入了错误。


三、LangGraph 实战:把"拆解 / 执行 / 质检"画成一张可回环的图

LangGraph 的价值在于它把 Agent 之间的协作显式化为状态机:节点是处理函数,边是控制流,State 是唯一的通信载体 3。这恰好与上一节的契约思想一致。

3.1 状态契约先行:图里流转的到底是什么

先定 State 再画图,顺序不能反。否则很容易画出一个"看起来很合理"的图,跑起来发现三个节点都在改同一个字段。

python 复制代码
import operator
from typing import Annotated, TypedDict, Literal, Optional

class Subtask(TypedDict):
    task_id: str
    goal: str
    acceptance: dict      # AcceptanceCriteria 的序列化形式
    assignee: str

class TeamState(TypedDict):
    objective: str
    # 字段写入者约定(唯一写入者原则)
    # subtasks   ------ 拆解节点写入
    # artifacts  ------ 执行节点写入
    # reviews    ------ 质检节点写入
    # verdict    ------ 质检节点写入,其他节点只读
    subtasks: Annotated[list[Subtask], operator.add]
    artifacts: Annotated[list[dict], operator.add]
    reviews: Annotated[list[dict], operator.add]
    verdict: Optional[Literal["pass", "rework", "escalate"]]
    retry_count: int
    trace_id: str

用 Annotated[..., operator.add] 这类聚合方式声明列表字段的合并语义,是为了让并发执行的多个子任务结果可以安全追加,而不是互相覆盖。具体的 reducer 写法与内置聚合机制随 LangGraph 版本演进,实现时请对照当前版本文档核实。

3.2 图结构:START → 拆解 → 执行 → 质检 → 条件边

python 复制代码
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import InMemorySaver  # 类名以当前版本为准

builder = StateGraph(TeamState)

builder.add_node("decompose", decompose_node)   # 拆解 + 产出验收标准
builder.add_node("execute", execute_node)       # 执行单个子任务
builder.add_node("review", review_node)         # 结构化质检
builder.add_node("human_gate", human_gate_node) # 超限后的人工介入

builder.add_edge(START, "decompose")
builder.add_edge("decompose", "execute")
builder.add_edge("execute", "review")

builder.add_conditional_edges(
    "review",
    route_after_review,
    {"pass": END, "rework": "execute", "escalate": "human_gate"},
)

graph = builder.compile(checkpointer=InMemorySaver())

当子任务数量在拆解后才能确定时,用静态边会导致图结构僵化。LangGraph 提供运行时动态派发的机制(如 Send 一类的原语),把每个子任务作为一个独立工作单元发往执行节点:

python 复制代码
from langgraph.types import Send  # 机制示意,具体导入路径以当前版本为准

def fan_out(state: TeamState):
    return [
        Send("execute", {**state, "subtasks": [t]})
        for t in state["subtasks"]
    ]

选择原则很简单:拓扑固定用静态图,任务数运行时才知道用动态派发。动态派发能提高并发,但也意味着状态合并与错误聚合要自己设计清楚,不要两头都不做。

3.3 质检节点:把"人工偏好"变成可执行判据

质检节点是整张图里最容易退化的环节。要让它稳定,必须满足三个条件:

  1. 输入完整:验收标准 + 产物 + 引用,缺一不可。只给产物的质检等于盲评。
  2. 输出结构化:判定结果是 schema,不是一段自然语言。
  3. 尺度版本化:验收标准本身带版本号,避免"同一份产物在不同时间用不同尺子"的质检漂移。
python 复制代码
from typing import Literal
from pydantic import BaseModel, Field

class ReviewResult(BaseModel):
    verdict: Literal["pass", "rework", "escalate"]
    issues: list[str] = Field(default_factory=list)          # 问题定位,指向具体段落
    fix_instructions: list[str] = Field(default_factory=list)  # 可执行的修改动作
    evidence: list[str] = Field(default_factory=list)          # 判定依据,如缺失引用的位置

MAX_RETRY = 2

def route_after_review(state: TeamState) -> str:
    if state["verdict"] == "pass":
        return "pass"
    if state["retry_count"] >= MAX_RETRY:
        return "escalate"      # 人工队列,或交付"带已知问题"的产物 + 问题清单
    return "rework"

以「行业研究助手」走一遍状态变化:

轮次 执行产物 质检判定 状态变化
1 三条结论,其中市场规模无引用 rework:补来源 retry_count=1,打回执行
2 补齐引用,但一条引用与结论不匹配 rework:替换引用 retry_count=2,打回执行
3 引用完整且逐条匹配 pass 进入 END

超过上限时的降级策略必须事先定义,而不是让图无限循环。常见做法是把产物连同未解决问题清单一起交付,并标记需要人工确认,这样既不阻塞交付,也不掩盖缺陷。

3.4 可观测与持久化:多 Agent 调试的基本盘

多 Agent 系统的调试难度不在于单点逻辑,而在于跨节点、跨轮次、跨进程的因果链。一次返工循环里可能有十几个工具调用,如果不能回答"哪一轮、哪个节点、哪个子 Agent、调了哪个工具、花了多少 token",就无法定位成本与质量问题。

需要落实三件事:

  • 统一 trace 标识 :trace_id 贯穿协议层与编排层,子任务用 parent_id 关联父任务。跨进程时,trace 上下文要随消息一起传递。
  • 断点续跑:长任务中途崩溃是常态,checkpointer 一类的持久化机制让图能从最近的检查点恢复,而不是整体重跑。具体类名与配置项随版本变化,本文只写能力不写死 API。
  • 工具调用留痕:记录调用参数摘要、结果摘要、耗时与 token 消耗,敏感字段脱敏。这既是调试手段,也是安全审计的底线。

可观测平台在这里的作用是把多 Agent 的执行链可视化出来。社区实践中把"可视化管理智能体团队"作为框架核心能力之一的做法,也印证了这一点 7。


四、DeepAgents 主子智能体调度:什么时候比自写 Supervisor 更省事

4.1 定位与边界

DeepAgents 是面向深度研究与长任务场景的 Agent 构建框架,核心思路是主 Agent 负责规划与调度,通过内置的派生机制把子任务交给子 Agent 执行,并提供文件读写、规划清单一类的内置工具来支撑长任务 4。

它替你解决的通常是这几件事:

  • 子 Agent 生命周期:派生、执行、返回摘要的样板代码。
  • 上下文隔离:子 Agent 在自己的上下文里消化工具噪声,只把结论性摘要交回主 Agent。
  • 共享产物:通过文件类工具让多个子 Agent 围绕同一份资料协作。
  • 规划工具:让主 Agent 把计划显式写出来,而不是在对话里隐式推进。

它没有解决的也必须说清楚:跨运行时、跨团队的通信(那是 A2A 的领域)、你的业务鉴权与凭据管理、审计与合规留痕、以及评测口径。这些仍然是你的责任。

4.2 核心动作:规划 → 派生 → 汇总

主 Agent 的工作循环是三步:

  1. 规划:把目标拆成带验收标准的计划,写入规划类工具(todo/plan 一类的内置机制)。
  2. 派生 :按计划为不同子任务选择合适的子 Agent 角色,每个子 Agent 拿到的上下文是经过裁剪的任务描述 + 验收标准,而不是主 Agent 的完整对话历史。
  3. 汇总 :主 Agent 消费子 Agent 返回的结构化产物与引用,而不是原始输出流水。
python 复制代码
# 骨架代码:DeepAgents 主子调度结构示意
# 具体构造函数名、参数名、内置工具名以官方 README 与当前版本为准
from deepagents import create_deep_agent

RESEARCHER_PROMPT = """
你是子任务研究员。只完成交给你的单一问题,产出结构化摘要与逐条引用。
不要扩展任务范围,不要修改验收标准,不确定的内容明确标注为假设。
"""

researcher = {
    "name": "researcher",
    "description": "针对一个子问题检索资料并产出带引用的摘要",
    "prompt": RESEARCHER_PROMPT,
    "tools": [web_search, read_document],   # 最小权限:只给必要工具
}

reviewer = {
    "name": "reviewer",
    "description": "依据验收标准校验产物与引用的匹配度",
    "prompt": REVIEWER_PROMPT,
    "tools": [read_document],
}

agent = create_deep_agent(
    tools=[web_search, read_document],
    instructions=MAIN_PROMPT,
    subagents=[researcher, reviewer],
)

result = agent.invoke({"messages": [{"role": "user", "content": goal}]})

这里的关键取舍是上下文隔离带来的信息损失。子 Agent 不知道全局,能防止上下文被工具输出淹没,但也意味着它无法自行判断"这个问题已经被别的子 Agent 解决了"。所以主 Agent 在派发前要做的去重与依赖分析,比提示词里的"请你协作"重要得多。

4.3 DeepAgents 与自写 LangGraph Supervisor 的取舍

维度 DeepAgents 主子调度 自写 LangGraph Supervisor
编排自由度 中,遵循框架的派生模型 高,图结构完全自定义
样板代码量 少,生命周期与文件工具内置 多,需自建派生与汇总
状态可控性 中,依赖框架约定 高,State schema 自己定义
可审计性 需额外补 trace 与留痕 易与 checkpointer、trace 打通
适用场景 发散型探索、子任务数不确定 拓扑固定、验收标准严格、强监管

选择规则可以很直接:

  • 选 DeepAgents:任务发散、子 Agent 数量事先不知道、需要围绕共享文件做研究型协作、希望少写编排样板。
  • 选自写 LangGraph:拓扑固定、需要严格的质检回环、状态 schema 要接受审计或合规检查、需要精确的成本与重试控制。

两者并非互斥。一种务实的组合是:外层用 DeepAgents 承担探索与广度搜索,其中某个产物要求严格、可验证的子流程(例如代码生成与自检)单独用 LangGraph 的回环实现。是否能在一个运行时内嵌套,取决于框架当前版本的支持情况,实现前请核实;不支持时,就把它们定位为分别承担外层与内层的两个独立服务,通过结构化消息契约衔接------这本身也是更清晰的架构边界。

回到「行业研究助手」:同一套 Tool Calling 调用与 MCP 工具接入完全不变,DeepAgents 版本把"主题发散---资料收集"交给主子调度,LangGraph 版本把"报告生成---引用质检"做成回环。协议层不变、编排层可换,这正是分层设计的意义。


五、工程化收口:协议选对了也可能翻车的地方

安全与权限。 子 Agent 应遵循最小权限:研究员不需要写库权限,执行写操作的 Agent 不需要管理类工具。凭据下发要短时效、可回收、不落日志。高风险动作(发消息、扣款、删除)保留人工确认环节。能力端应运行在沙箱内,限制网络与文件系统访问范围。近期公开报道中出现过智能体脱离测试环境尝试越权访问的案例 89,这些报道的具体细节未经独立核实,本文只用于说明一个定性结论:Agent 的自主性越高,沙箱与审计就越不能事后补。从架构第一天就把权限边界与操作留痕设计进去,成本远低于事后补救。

成本与上下文预算。 多 Agent 的成本不是线性而是超线性的:每个子 Agent 都有自己的上下文,主 Agent 还要汇总。三条控制手段:子 Agent 数量上限、摘要回传而非全文回传、端到端 token 预算熔断。把预算写进 State,让节点在超限时明确失败而不是悄悄降质。

幂等与重试。 每个有副作用的工具调用都要有幂等键,网络重试不能导致重复下单或重复发信。retry_count 与指数退避要写进契约,而不是散落在各个节点的 try/except 里。

评测。 要回答"多 Agent 是否真的比单 Agent 好",需要固定任务集与可验证指标:引用完整率、返工次数、端到端成本、人工采纳率、超时率。没有这组数据,多 Agent 架构很容易变成"看起来更智能、实际更贵"的复杂度投资。

可观测。 跨协议、跨进程的统一 trace_id 是底线。没有它,MCP 调用、A2A 任务、图节点三类事件无法拼成一条因果链,故障定位只能靠猜。

一份上线前检查清单:

类别 检查项
安全 子 Agent 最小权限与工具白名单
安全 凭据短时效下发、可回收、日志脱敏
安全 高风险操作的人工确认与沙箱隔离
成本 子任务数量与 token 预算上限
成本 摘要回传而非全文回传
成本 端到端预算熔断与降级策略
可靠性 工具调用幂等键与副作用防护
可靠性 重试上限、退避与失败降级路径
可靠性 检查点持久化与断点续跑验证
可观测/评测 跨层统一 trace_id 与父子关系
可观测/评测 固定任务集与可量化指标
可观测/评测 验收标准版本化与质检漂移监控

六、五个常见反模式

一、把 Tool Calling 当成多 Agent 通信。 让两个 Agent 通过互相"调用工具"传消息,tool_result 里塞满对话内容。短期能跑,长期一定在追踪、重试和责任归属上出问题。工具调用是能力触发,不是人际对话。

二、为同进程分工引入 A2A。 序列化、超时、状态同步的成本全部白付。同进程用共享 State 与函数调用,跨边界才用协议。

三、质检 Agent 没有验收标准。 于是返工循环围绕"我觉得不够好"展开,既烧 token 又消磨团队信任。验收标准必须在拆解阶段产出并版本化。

四、子 Agent 无上下文隔离、无重试上限。 前者导致上下文爆炸,后者导致循环卡死。这两项都应在框架层强制,而不是依赖提示词自觉。

五、用 prompt 拼接代替契约。 字段靠自然语言约定,漂移是必然的。task_id / acceptance / artifact / citations / verdict / retry_count / trace_id 这组字段用 schema 固定下来,成本很低,收益贯穿调试、审计与评测。


回到主线:先选对层,再选拓扑,最后才选框架。Tool Calling 回答"模型如何触发动作",MCP 回答"能力如何被多个 Agent 复用",A2A 回答"两个自主体如何委派与交付任务";在这三层之上,Supervisor、流水线回环、层级主子决定信息如何流动;LangGraph 适合把可验证的流程显式化为状态机,DeepAgents 适合承担发散型的主子调度。框架会持续更替,但"把边界画清楚、把契约写下来"这件事不会过时。

参考资料

1 One Year of MCP: November 2025 Spec Release,modelcontextprotocol 官方博客(GitHub 仓库),https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/blog/content/posts/2025-11-25-first-mcp-anniversary.md

2 2026年,AI Agent 开发实战指南:从 MCP 协议到多智能体协作,掘金,https://juejin.cn/post/7671966587106689043

3 AI Agent 第十五篇:多智能体 Agent 协同实战(分工拆解、自主协作、任务互评),CSDN 博客,https://blog.csdn.net/weixin_44661794/article/details/162009795

4 DeepAgents 多智能体研究系统实战:ai-agents-from-zero 深度研搜项目从 0 到 1 拆解,CSDN 博客,https://blog.csdn.net/gitblog_00764/article/details/166568619

5 智能体-343 智能体的最新技术(2026),CSDN 博客,https://blog.csdn.net/HiWangWenBing/article/details/161870790

6 从零构建 AI Agent:工具调用、记忆系统与多智能体协作实战指南,CSDN 博客,https://blog.csdn.net/weixin_27038701/article/details/166292400

7 如何用 AgentScope 2.0 快速构建可观测、可信任的智能体应用,CSDN 博客,https://blog.csdn.net/gitblog_00249/article/details/161865534

8 2026年9月5日 AI 重要新闻:OpenAI Agent 公开密谋越狱沙箱等,掘金,https://juejin.cn/post/7681874398225661979

9 AI 快讯日报 2026-09-09 · Issue #77 · sikm-lqs/agents-radar,GitHub,https://github.com/sikm-lqs/agents-radar/issues/77

说明:A2A 的官方规范链接未在本次研究材料中提供,正文涉及 A2A 的描述为通用机制层面的整理,具体方法名、字段与状态枚举请以 A2A 官方规范为准。LangGraph 与 DeepAgents 的代码片段为结构骨架,构造函数、类名与参数请以各自官方文档与仓库当前版本为准。参考资料 89 中关于智能体越权行为的报道细节未经独立核实,正文仅作定性风险提示使用。

相关推荐
漂着的圆木2 小时前
Agent执行安全:Taskflow无容器架构风险边界核对
github·安全架构·ai agent·部署边界
光依旧3 小时前
RSA杀入Agent 身份安全:MCP网关成了新战场
rsa·身份安全·ai安全·mcp·agent安全·mcp网关
10年前端老司机3 小时前
MCP 技术分享:从协议握手到 LangGraph 多 Server 调用
人工智能·agent·mcp
鲸能云18 小时前
【AI Agent】光储运维从 “展示数据“ 到 “自主决策“:运维 AI Agent 落地实践拆解
大数据·人工智能·ai agent·智能运维·光伏储能
code2cat20 小时前
【随笔】Agent Skills如何按需加载:把技能说明放进分层目录
人工智能·ai agent·agent skills
Alice-YUE1 天前
A2A 协议详解:Agent 间通信标准、四大核心机制与 MCP 互补
大模型·多智能体·ai agent·mcp·a2a协议
光依旧1 天前
MCP实战手记(九):生产化MCP Server的6层安全防护
java·人工智能·spring boot·安全·网络安全·ai agent·mcp
ZDGJ60992 天前
新手小白了解国际期货先了解哪一步
区块链