服务内部的 Agent2Agent 怎么交互?AgentScope vs LangChain 实战对比
Google 在 2025 年 4 月把 A2A(Agent2Agent)协议推成了开放标准,很多人就开始用「A2A」这个词代指所有 多 Agent 协作。 但实际上 —— A2A 协议解决的是一个特定问题,而「服务内部多 Agent 怎么协作」是另一个完全不同的问题 。 这篇文章把这两件事拆开讲清楚。
⚠️ 代码声明 :本文所有代码示例按公开文档写法,不能保证在最新版本下能直接跑通 。两个框架都在快速迭代,API 路径和函数签名可能已变。建议把代码当伪代码 / 设计参考 ,实际落地以官方最新文档为准。跑不通时不要慌,对照报错查文档改 1-2 行就行 。
读完你应该能:
区分网络级 的 A2A 协议和进程内 的多 Agent 协作
说出服务内部 Agent2Agent 的三种主流模式
用 AgentScope 或 LangGraph 写一个能跑的多 Agent 系统
理解 A2A 协议是怎么把不同框架 的 Agent 串起来的
一、先澄清:A2A 协议 ≠ 多 Agent 协作 1.1 A2A 协议是什么 A2A(Agent2Agent)是 Google 在 2025 年 4 月联合 50 多家公司推出的网络级开放协议 ,目的是让 不同厂商、不同语言、不同进程 写的 Agent 能互相调用。
类比一下理解:
协议
解决什么
对应网络层
HTTP
浏览器和服务端怎么对话
应用层
SMTP
不同邮件服务商怎么互发邮件
应用层
A2A
不同 Agent 服务怎么互相调用
应用层
A2A 的核心机制:
1 2 3 4 5 6 7 8 9 10 GET https: { "name" : "Research Agent" , "skills" : [ { "id" : "web-search" , "description" : "联网检索资料" } , { "id" : "summarize" , "description" : "长文摘要" } ] , "auth" : "bearer" }
调用方发 tasks/send,服务端通过 SSE(Server-Sent Events)流式返回进度和结果。完整流程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 Client A2A Server (Agent B) │ │ │─── GET /.well-known/agent.json ──────▶│ 1. 拿 Agent Card │◀──── 200 OK {name, skills...} ────────│ │ │ │─── POST /tasks/send ────────────────▶│ 2. 提交任务 │ { "skill": "web-search", │ │ "input": "A2A 协议" } │ │ │ │◀─── SSE: data: {state: working} ─────│ 3. 流式进度 │◀─── SSE: data: {state: working} ─────│ │◀─── SSE: data: {state: completed, │ │ artifacts: [...]} ────│ 4. 最终结果 │ │
1.2 服务内部的 Agent2Agent 是另一回事 同一个进程、同一份代码里,多个 Agent 之间怎么协作 —— 这不是协议问题 ,是架构模式问题 。
为什么需要拆开讲?因为你搜「A2A」搜到的内容,90% 是讲上面那个网络协议,但真正写代码时遇到的 90% 问题,是进程内多 Agent 怎么组织 。
本文主角 :服务内部的 Agent2Agent(多 Agent 协作模式)次要话题 :A2A 协议(只在最后一节用来串联两个框架的 Agent)
二、服务内多 Agent 协作的三种主流模式 不管用 AgentScope、LangGraph 还是自研框架,多 Agent 协作逃不出这三种模式:
2.1 Orchestrator 编排(最常见) 1 2 3 4 5 6 7 8 9 10 ┌─────────────────┐ │ Orchestrator │ ← 主管 Agent(往往是 LLM 驱动的 ReAct) │ (主管) │ └────────┬────────┘ │ 调用 ┌─────────┼─────────┐ ▼ ▼ ▼ ┌───────┐ ┌───────┐ ┌───────┐ │Agent A│ │Agent B│ │Agent C│ ← 下属 Agent(也可能是 LLM,也可能是函数) └───────┘ └───────┘ └───────┘
主管 Agent 通过 LLM 决策「下一步让谁干」
下属 Agent 对主管来说就是「一个 Tool」
典型代表:AutoGPT、MetaGPT、LangGraph Supervisor
2.2 Pipeline 串行(流水线) 1 Input → Agent A → Agent B → Agent C → Output
每个 Agent 是确定性的处理节点
上游输出直接喂下游,不需要 LLM 决策
适合结构化数据处理 :解析 → 分析 → 写报告
2.3 Peer-to-Peer(消息总线) 1 2 3 4 5 6 7 ┌──────┐ ↔ ┌──────┐ ↔ ┌──────┐ │Agent A│ │Agent B│ │Agent C│ └──────┘ └──────┘ └──────┘ ↘ ↓ ↙ ┌─────────┐ │ MsgHub │ ← 共享消息池 └─────────┘
Agent 之间对等通信 ,无中心
通过消息总线(如 AgentScope 的 MsgHub)广播或点对点
适合多 Agent 共同决策 的场景:协商、辩论、投票
三、AgentScope 实战:消息驱动的多 Agent AgentScope (阿里达摩院出品)走的是消息驱动 路线 —— Agent 之间靠 Msg 对象通信,对等且解耦。
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 from agentscope.agent import ReActAgentfrom agentscope.tool import Toolkitfrom agentscope.model import DashScopeChatModelresearcher = ReActAgent( name="researcher" , sys_prompt="你是一个研究员,擅长联网调研和资料整理。" , model=DashScopeChatModel("qwen-max" ), ) coder = ReActAgent( name="coder" , sys_prompt="你是一个工程师,擅长写 Python 代码。" , model=DashScopeChatModel("qwen-max" ), ) toolkit = Toolkit() toolkit.register_agent_tool(researcher) toolkit.register_agent_tool(coder) orchestrator = ReActAgent( name="orchestrator" , sys_prompt=( "你是项目主管。复杂问题先调研(researcher)," "再让 coder 实现,最后整合输出。" ), model=DashScopeChatModel("qwen-max" ), toolkit=toolkit, ) msg = Msg("user" , "调研 A2A 协议并写一个最小示例" , role="user" ) result = await orchestrator(msg) print (result.content)
关键 API :toolkit.register_agent_tool(agent) —— 这一行把整个 Agent 包成了一个可调用的 Tool。
3.2 模式 2:Pipeline(流水线) 1 2 3 4 5 6 7 8 from agentscope.pipeline import sequential_pipelineresult = await sequential_pipeline( agents=[parser_agent, analyst_agent, writer_agent], msg=Msg("user" , "分析上季度销售数据并写报告" , role="user" ), )
sequential_pipeline 把上游输出直接喂下游,不经过 LLM 决策 —— 适合流程固定 的场景。
3.3 模式 3:MsgHub(对等多 Agent 协作) 这是 AgentScope 最独特的设计 —— 多个 Agent 进同一个聊天室,共享上下文:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from agentscope.hub import MsgHubfrom agentscope.pipeline import fanout_pipelinehub = MsgHub( participants=[planner_agent, critic_agent, executor_agent], announcement=Msg( "system" , "用户需求:设计一个分布式任务调度系统。" , role="system" , ), ) await fanout_pipeline( agents=[planner_agent, critic_agent, executor_agent], msg=Msg("user" , "请各自给出方案" , role="user" ), hub=hub, )
MsgHub 的妙处在于:每个 Agent 看到的对话历史是共享的 (其他 Agent 说的话它也能看到),这天然适合辩论、协商 场景:
1 2 3 4 5 6 async with MsgHub(participants=[debater_a, debater_b]) as hub: for round in range (3 ): await debater_a(hub.last_msg) await debater_b(hub.last_msg)
四、LangChain/LangGraph 实战:图编排 LangGraph 是 LangChain 团队对多 Agent 协作 的官方解法 —— 把协作建模成有向状态图 。
4.1 核心抽象:StateGraph 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 from langgraph.graph import StateGraph, ENDfrom typing import TypedDict, Annotatedimport operatorclass State (TypedDict ): messages: Annotated[list , operator.add] draft: str revision_count: int def researcher_node (state: State ): """节点 1:研究员""" research = do_research(state["messages" ][-1 ].content) return { "messages" : [("ai" , f"调研结果:{research} " )], "revision_count" : state.get("revision_count" , 0 ) + 1 , } def writer_node (state: State ): """节点 2:写作者""" draft = write_article(state["messages" ]) return {"draft" : draft} def should_continue (state: State ) -> str : """条件边:决定下一步走哪个节点""" if state["revision_count" ] >= 2 : return "end" return "writer" graph = StateGraph(State) graph.add_node("researcher" , researcher_node) graph.add_node("writer" , writer_node) graph.add_edge("researcher" , "writer" ) graph.add_conditional_edges( "writer" , should_continue, {"end" : END, "writer" : "writer" }, ) graph.set_entry_point("researcher" ) app = graph.compile () result = app.invoke({"messages" : [("user" , "写一篇 A2A 文章" )]})
核心概念 :
State :所有节点共享的字典(带类型注解,LangGraph 自动合并)
Node :一个函数,接收 State、返回 State 的部分字段
Edge :节点之间的连接,可以是固定边 也可以是条件边
4.2 LangGraph 的杀手锏:可视化 + Checkpoint 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from langgraph.visualization import draw_mermaidprint (draw_mermaid(app.get_graph()))from langgraph.checkpoint.memory import MemorySaverapp = graph.compile ( checkpointer=MemorySaver(), interrupt_before=["writer" ], ) config = {"configurable" : {"thread_id" : "1" }} result = app.invoke({"messages" : [("user" , "写" )]}, config=config) app.invoke(None , config=config)
4.3 Supervisor 模式(一行起手式) 如果你就想用主管模式,不想手画图:
1 2 3 4 5 6 7 8 9 from langgraph.prebuilt import create_supervisorsupervisor = create_supervisor( agents=[research_agent, code_agent], model=llm, prompt="你是主管,分派任务给 researcher 或 coder" , ) app = supervisor.compile () result = app.invoke({"messages" : [("user" , "调研 A2A 并写 demo" )]})
create_supervisor 内部就是个有向图:supervisor 节点 + N 个 worker 节点 + 条件边。
五、横向对比
维度
AgentScope
LangGraph
核心抽象
Agent + Msg + MsgHub
Node + Edge + State
多 Agent 通信方式
直接传 Msg 对象;MsgHub 共享上下文
共享 State dict(自动合并)
编排方式
Pipeline / ReAct / A2A 服务
StateGraph(图)
可视化
内置 log 打印
LangGraph Studio(强)
Human-in-the-loop
自己实现
一行配置 interrupt_before
长任务 / 异步
原生 A2A 协议支持 task 生命周期
需要 checkpoint + 外部存储自己接
跨服务 / 跨进程
内置 A2A Server / Client
自己实现;LangGraph Platform 提供托管
中文友好度
高(阿里达摩院 + 中文文档)
一般(英文为主)
学习曲线
平(API 直观)
陡(图 + State 设计需要经验)
适合场景
中文业务、多 Agent 协商、想快速上手
复杂工作流、需要可视化、需要 HITL
我的选型经验 :
场景简单 / 想快跑通 :AgentScope,MsgHub 写起来真的很爽
流程复杂 / 要可视化 / 要人工介入 :LangGraph,图的表达力强很多
跨语言 / 跨团队 / 跨厂商 :A2A 协议(两个框架都支持或可以接入)
六、进阶:跨框架互操作 最后讲一个真实场景 —— 怎么把 LangChain Agent 接进 AgentScope 系统(或反过来) 。
答案就是 A2A 协议:把其中一个框架的 Agent 暴露成 A2A 服务,另一个框架当 A2A 客户端调用 。
6.1 AgentScope 暴露 A2A 服务 1 2 3 4 5 6 7 8 9 10 11 12 from agentscope.a2a import A2AServerserver = A2AServer( agent=researcher, port=8001 , agent_card={ "name" : "Researcher Agent" , "description" : "调研专家" , "skills" : [{"id" : "web-search" , "description" : "联网调研" }], }, ) await server.start()
6.2 LangGraph 当 A2A 客户端调用 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 import httpximport jsonasync def call_researcher_agent (query: str ) -> str : """通过 A2A 协议调用 AgentScope 的 researcher""" async with httpx.AsyncClient() as client: card = await client.get("http://localhost:8001/.well-known/agent.json" ) resp = await client.post( "http://localhost:8001/tasks/send" , json={ "skill" : "web-search" , "input" : query, }, ) task_id = resp.json()["task_id" ] async with client.stream( "GET" , f"http://localhost:8001/tasks/{task_id} /events" ) as stream: final = "" async for line in stream.aiter_lines(): if line.startswith("data: " ): event = json.loads(line[6 :]) if event["state" ] == "completed" : final = event["artifacts" ][0 ]["text" ] return final def researcher_node (state ): result = asyncio.run(call_researcher_agent(state["query" ])) return {"research" : result}
这样 LangGraph 的工作流就能无缝 调用 AgentScope 的 Agent,反之亦然。
七、几个反直觉的提醒 最后是几个容易踩的坑 :
7.1 多 Agent ≠ 更好的结果
多数情况下,一个强 Agent + 好工具,比 3 个弱 Agent 协作更靠谱。
多 Agent 引入额外的 LLM 调用 (主管决策 + 通信开销),token 成本可能涨 2-3 倍,但结果质量往往提升不到 10%。只有当任务天然可拆 (调研 vs 写代码),多 Agent 才有意义。
7.2 MsgHub 不是银弹 MsgHub 的「共享上下文」听起来很美,但所有 Agent 都要把整段历史塞进 prompt 。3 个 Agent 还行,10 个 Agent 就爆 token 了。生产环境要么做上下文摘要 ,要么用 LangGraph 的显式 State 传递 。
7.3 StateGraph 的 State 设计是核心 LangGraph 看上去是画图,实际上难点在State schema 设计 。State 字段太多 → 每次 LLM 调用都浪费;State 字段太少 → 节点之间传不动。建议从 3-5 个字段开始,按需演进 。
7.4 不要为了 A2A 而 A2A A2A 协议适合跨组织、跨语言、跨厂商 的 Agent 互操作。如果你的所有 Agent 都是同一团队、同一技术栈、同一进程 写的,上 A2A 反而增加复杂度(多一层网络调用、多一份序列化成本)。先评估是否真的需要跨进程 。
八、总结
层级
问题
解法
跨服务 / 跨语言
不同团队写的 Agent 怎么互相调用
A2A 协议(HTTP + JSON-RPC + SSE)
进程内多 Agent 协作
同一份代码里多个 Agent 怎么组织
三种模式:Orchestrator / Pipeline / Peer-to-Peer
特定框架落地
用哪个框架
AgentScope(消息驱动)/ LangGraph(图编排)
一句话总结 :A2A 是网络层 的协议,服务内部 Agent 协作是架构层 的模式。两者正交 —— 一个项目可以同时用 LangGraph 编排内部流程,又把 LangGraph 暴露成 A2A 服务给其他团队用。
参考
评论区聊聊你的多 Agent 实践 —— 你用哪个框架?踩过什么坑?