多 Agent 之间如何通信?Supervisor 间接通信 直连 Handoff 全解析

配套代码:LangGraph Typescript,包含 Supervisor 间接通信(带轮次熔断兜底)+ LangGraph 实现 Handoff(类 Swarm 直连)两套完整 Demo

前言

做多智能体(Multi-Agent)开发时,90% 的开发者都会卡在同一个核心问题:多个子 Agent 之间到底怎么交互、传参、协作?

很多新手误区:

  • 以为子 Agent 可以像函数一样直接互相调用
  • 混淆 Supervisor 架构和 Swarm 架构的通信差异
  • 不知道什么场景需要 Agent 互通、什么场景禁止互通
  • 踩坑国产模型适配问题(Swarm 并非全模型通用)

本文基于 LangGraph(TS/JS)、OpenAI Swarm 生产实践,彻底讲透多 Agent 通信的所有范式、落地场景、优劣对比和工程最佳实践,并附带完整可运行代码。

一、核心定论:多 Agent 只有两种通信方式

所有多 Agent 框架,无论 LangGraph、OpenAI Swarm、AutoGen,底层只分为两类通信模型:

  1. 间接通信(中心调度模式)
    子 Agent 永远不能直接互相对话,所有交互经过中心节点转发,代表架构:Supervisor 主管架构。
  2. 直接通信(自主交接模式)
    子 Agent 可自主判断、主动将任务交接给其他 Agent,无需中心节点,代表架构:Swarm / Handoff 架构。

没有第三种模式,所有复杂多 Agent 协作都是这两种模式的组合。

二、模式一:Supervisor 间接通信(工业生产首选)

1. 通信原理

这是 LangGraph 默认的标准架构,也是企业级项目最常用的方案。

链路:用户 → Supervisor → 子 Agent → 写入共享 State → Supervisor 路由 → 下一个子 Agent

核心规则:

  • 所有子 Agent 互相隔离,无直接调用、无直接消息推送
  • 所有 Agent 的输出、中间结果,统一存入 全局共享 State
  • Supervisor(主管节点)统一读取状态、决策下一步路由、转发上下文
  • 子 Agent 通过读取共享 State,感知其他 Agent 的工作结果,实现「间接通信」

2. 典型落地场景(必须间接通信)

✅ 场景 1:多专家评审、迭代修改
起草 Agent 写方案 → 风控 Agent 评审 → 不通过再返回起草 Agent 修改,多轮迭代收口。

✅ 场景 2:RAG 多路召回融合
向量召回 Agent、关键词召回 Agent 并行执行,结果统一汇总到 Supervisor 做去重、打分、融合。

✅ 场景 3:分层任务拆解、流水线协作
需求拆解、内容生成、格式校验、结果润色等流水线节点串行协作。

3. 关键工程能力:轮次熔断与兜底(生产必备)

多轮迭代通信最大隐患:Agent 互相拉扯、无限循环、无法收敛。

标准解决方案:

  1. State 中增加 step 计数器、maxRound 最大轮次限制
  2. Supervisor 优先判断轮次,达到上限触发熔断
  3. 进入兜底节点,强制收口,三种兜底策略:
    • 折中输出(推荐):整合所有历史结果,生成最终内容,标注未解决风险
    • 失败终止:合规场景直接返回任务未完成,拒绝输出半成品
    • 主管仲裁:Supervisor 统一汇总结果、强行拍板收尾

4. 完整 TS 代码:Supervisor + 间接通信 + 轮次熔断兜底

业务示例:起草 Agent + 评审 Agent,互相读取对方产出,Supervisor 做调度,超过最大轮次触发兜底

安装依赖

npm install @langchain/langgraph @langchain/core @langchain/openai
// supervisor-multi-agent.ts
import {
  StateGraph,
  Annotation,
  START,
  END,
} from "@langchain/langgraph";
import { ChatOpenAI } from "@langchain/openai";
import { HumanMessage } from "@langchain/core/messages";

// ======================
// 1. 定义全局共享State(子Agent通信载体)
// ======================
const GraphAnnotation = Annotation.Root({
  messages: Annotation<Array<HumanMessage>>({
    reducer: (prev, next) => prev.concat(next),
  }),
  // 各个子agent产出,用来互相读取,实现间接通信
  agentOutputs: Annotation<Record<string, string>>({
    reducer: (prev, next) => ({ ...prev, ...next }),
  }),
  nextAgent: Annotation<string | null>(),
  // 迭代轮次计数器
  step: Annotation<number>({
    reducer: (_prev) => _prev + 1,
    default: () => 0
  }),
  maxRound: Annotation<number>({
    default: () => 4
  }),
});

type GraphState = typeof GraphAnnotation.State;

// ======================
// 2. LLM实例,兼容国内模型(通义千问 / DeepSeek / GLM均可)
// ======================
const model = new ChatOpenAI({
  apiKey: process.env.LLM_API_KEY,
  model: "qwen-max",
  configuration: {
    baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
  },
});

// ======================
// 3. 子Agent节点
// draftAgent:方案撰写,可以读取reviewAgent上一轮评审意见
// ======================
async function draftAgent(state: GraphState): Promise<Partial<GraphState>> {
  const prevReview = state.agentOutputs.reviewAgent ?? "暂无评审意见";
  const prompt = `
你是方案撰写专家。
上一轮评审意见:${prevReview}
根据评审意见输出退款业务方案,只输出方案正文,不要多余描述。
`;
  const res = await model.invoke([new HumanMessage(prompt)]);
  console.log(`[DraftAgent] 本轮输出:`, res.content);
  return {
    agentOutputs: {
      draftAgent: res.content as string,
    },
    messages: [res],
  };
}

// reviewAgent:评审专家,读取draftAgent的方案输出评审意见
async function reviewAgent(state: GraphState): Promise<Partial<GraphState>> {
  const draft = state.agentOutputs.draftAgent ?? "暂无方案";
  const prompt = `
你是风控评审专家。
待评审方案:${draft}
给出评审意见。如果方案合格,直接输出【PASS】;不合格写明漏洞。
`;
  const res = await model.invoke([new HumanMessage(prompt)]);
  console.log(`[ReviewAgent] 本轮评审:`, res.content);
  return {
    agentOutputs: {
      reviewAgent: res.content as string,
    },
    messages: [res],
  };
}

// ======================
// 兜底熔断节点:达到最大轮次,强制收口
// ======================
async function fallbackTerminateAgent(state: GraphState): Promise<Partial<GraphState>> {
  const allOutput = JSON.stringify(state.agentOutputs, null, 2);
  const prompt = `
任务已达到最大迭代轮次,多方协商没有达成一致。
整合下面所有Agent历史产出,生成一份最终交付文档,**明确标记遗留风险和未解决争议**。
历史输出:
${allOutput}
`;
  const res = await model.invoke([new HumanMessage(prompt)]);
  console.log(`[Fallback] 轮次耗尽,兜底生成结果`);
  return {
    messages: [res],
    agentOutputs: {
      fallbackResult: res.content as string
    }
  }
}

// ======================
// 4. Supervisor主管节点:路由 + 熔断判断核心
// ======================
async function supervisor(state: GraphState): Promise<Partial<GraphState>> {
  const { step, maxRound } = state;
  const draft = state.agentOutputs.draftAgent;
  const review = state.agentOutputs.reviewAgent;

  // 熔断判断:达到最大迭代轮次,进入兜底
  if (step >= maxRound) {
    console.log(`[Supervisor] 已到达最大轮次${maxRound},触发熔断`);
    return { nextAgent: "fallback_terminate" }
  }

  let nextAgent: string;
  if (!draft) {
    nextAgent = "draftAgent";
  } else if (!review) {
    nextAgent = "reviewAgent";
  } else if (!review.includes("【PASS】")) {
    // 评审不通过,继续交给draftAgent修改,实现多轮间接通信
    nextAgent = "draftAgent";
  } else {
    nextAgent = END;
  }
  console.log(`[Supervisor] step=${step}, 路由到:${nextAgent}`);
  return { nextAgent };
}

// ======================
// 5. 构建LangGraph图
// ======================
const builder = new StateGraph(GraphAnnotation)
  .addNode("supervisor", supervisor)
  .addNode("draftAgent", draftAgent)
  .addNode("reviewAgent", reviewAgent)
  .addNode("fallback_terminate", fallbackTerminateAgent)
  // 条件路由:根据nextAgent跳转
  .addConditionalEdges("supervisor", (state) => state.nextAgent, {
    draftAgent: "draftAgent",
    reviewAgent: "reviewAgent",
    fallback_terminate: "fallback_terminate",
    [END]: END,
  })
  // 子Agent执行完成,全部回到主管节点
  .addEdge("draftAgent", "supervisor")
  .addEdge("reviewAgent", "supervisor")
  .addEdge("fallback_terminate", END)
  .addEdge(START, "supervisor");

export const app = builder.compile();

// ======================
// 6. 入口调用
// ======================
(async () => {
  const result = await app.invoke({
    messages: [new HumanMessage("写一份客户退款业务方案")],
    agentOutputs: {},
    nextAgent: null,
    step: 0,
    maxRound: 4
  });

  console.log("\n===== 最终全部Agent产出 =====");
  console.log(result.agentOutputs);
})();

运行命令:

# 设置环境变量
export LLM_API_KEY="sk-xxx"
tsx supervisor-multi-agent.ts

5. 优缺点总结

✅ 优点:

  • 极高可控性:路由、轮次、权限全可控,可防止死循环
  • 适配所有模型:对国产大模型友好,不依赖强 Function Call 能力
  • 可观测可审计:全链路 State 留存,日志、调试、复盘简单
  • 支持串行、并行、条件分支所有复杂流程

❌ 缺点:

  • 多轮协商场景路由逻辑稍重
  • 需要手动维护共享 State 数据结构

三、模式二:Swarm 直接通信(Handoff 自主交接)

1. 通信原理

代表框架:OpenAI Swarm(实验版)、新版 OpenAI Agents SDK。

核心逻辑:取消中心节点,子 Agent 自主判断,通过工具调用直接将任务交接给其他 Agent。

链路:AgentA → 自主调用转移工具 → 直接交给 AgentB 执行

无需中间人转发,Agent 之间可自由对话、多轮辩论、按需协作。

2. 适用场景

  • 多方 Agent 辩论、头脑风暴、协商共识
  • Agent 执行中按需主动查询其他 Agent 数据
  • 开放式对话、灵活任务接力,无固定流水线

3. 关键问题:Swarm 能不能用国内模型?

全网最大误区纠正:
Swarm 不强制绑定 OpenAI 模型,但极度依赖「稳定的 Function Call」。

详细结论:

  • ✅ 协议兼容即可接入:所有支持 OpenAI 兼容接口的国内模型(通义、DeepSeek、GLM 等)均可接入
  • ❌ 国内模型普遍适配翻车:Swarm 的 Handoff 完全靠模型主动输出工具调用,多数国产模型指令遵循弱,容易不触发转移、乱输出、直接自由对话
  • ❌ 无 TS 原生支持:原版 Swarm 只有 Python 版本,TS 项目无法直接使用
  • ⚠️ 项目已停止维护:OpenAI 已归档 Swarm,继任者为 OpenAI Agents SDK

4. Python 原版 Swarm 极简示例(仅用于演示,生产不推荐)

# swarm_demo.py
from swarm import Swarm, Agent
from openai import OpenAI

# 替换为国内兼容接口
client = OpenAI(
    api_key="你的通义千问api-key",
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)

# 评审Agent
review_agent = Agent(
    name="review_agent",
    instructions="你是风控评审专家,方案有问题就调用transfer_to_drafter返回修改,没问题直接输出PASS",
    model="qwen-max"
)

# 起草Agent
draft_agent = Agent(
    name="draft_agent",
    instructions="你是方案撰写专家,写完交给评审;收到评审意见就修改,调用transfer_to_reviewer交接",
    functions=[
        lambda: review_agent
    ],
    model="qwen-max"
)

swarm = Swarm(client=client)
resp = swarm.run(agent=draft_agent, messages=[{"role":"user","content":"写退款业务方案"}])
print(resp.messages[-1]["content"])

5. 优缺点总结

✅ 优点:

  • 多 Agent 自然对话、协商体验极佳
  • 无需复杂路由逻辑,代码简洁

❌ 缺点:

  • 不可控:极易出现无限循环、越权执行
  • 对模型能力要求极高,国产模型适配成本大
  • 链路追踪弱,生产调试困难
  • 无原生 TS 支持

四、两种通信架构全方位对比

表格

维度 Supervisor 间接通信 Swarm Handoff 直接通信
通信方式 中心转发、状态共享、无直连 Agent 自主交接、直接互传任务
模型适配性 所有大模型(国产友好) 依赖强 Function Call,国产模型易翻车
可控性 极强,支持熔断、限流、兜底 弱,易死循环、不可预测
可观测性 全 State 留存,易调试复盘 链路混乱,排查困难
技术栈 TS/Python 全支持 仅 Python,无 TS 原生版本
生产适用性 企业生产首选 仅适合 Demo、创意场景,不建议上生产

五、落地选型终极判断标准

1. 选 Supervisor 间接通信(90% 业务场景)

满足任意一条即可选择:

  • 需要稳定、可审计、可兜底的生产能力
  • 使用国产大模型部署
  • RAG、文档生成、任务拆解、流水线协作
  • 需要防死循环、轮次熔断、异常兜底
  • TS 技术栈项目

2. 选 Swarm 直连通信(仅小众场景)

同时满足所有条件再选择:

  • Python 项目、仅做体验 / 演示
  • 使用 GPT 系列强遵循模型
  • 需要多 Agent 自由辩论、多轮协商
  • 不要求严格可控、无强业务合规要求

六、高阶补充:TS 基于 LangGraph 实现类 Swarm Handoff 直连通信

TS 没有原生 Swarm,我们可以自己在 LangGraph 上实现 Handoff,子 Agent 自主决定交接给谁,同时保留轮次熔断兜底,兼顾灵活性和稳定性。

核心逻辑:子 Agent 返回transferTo字段,图根据该字段自动路由,不需要固定 Supervisor 做业务判断。

// langgraph-handoff.ts
import {
  StateGraph,
  Annotation,
  START,
  END,
} from "@langchain/langgraph";
import { ChatOpenAI } from "@langchain/openai";
import { HumanMessage } from "@langchain/core/messages";

const GraphAnnotation = Annotation.Root({
  messages: Annotation<HumanMessage[]>({
    reducer: (prev, next) => prev.concat(next),
  }),
  transferTo: Annotation<string | null>(),
  step: Annotation<number>({
    reducer: (p) => p + 1,
    default: () => 0
  }),
  maxRound: Annotation<number>({
    default: () => 4
  })
});
type GraphState = typeof GraphAnnotation.State;

const model = new ChatOpenAI({
  apiKey: process.env.LLM_API_KEY,
  model: "qwen-max",
  configuration: {
    baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
  },
});

// 起草Agent,自主决定是否交接给评审
async function draftAgent(state: GraphState): Promise<Partial<GraphState>> {
  const prompt = `你是方案起草专家。
输出JSON,格式必须是:{"content":"方案内容","transferTo":"reviewAgent | null"}
transferTo如果需要交给评审专家就填reviewAgent,任务完成填null。
用户需求:${state.messages.at(-1)?.content}`;
  const res = await model.invoke([new HumanMessage(prompt)]);
  const json = JSON.parse(res.content as string);
  console.log("[DraftAgent] 输出,转移到:", json.transferTo);
  return {
    messages: [new HumanMessage(json.content)],
    transferTo: json.transferTo ?? null
  };
}

// 评审Agent,自主决定是否交回起草Agent修改
async function reviewAgent(state: GraphState): Promise<Partial<GraphState>> {
  const prompt = `你是风控评审专家。
输出JSON,格式必须是:{"content":"评审意见","transferTo":"draftAgent | null"}
方案不合格就transferTo=draftAgent;合格transferTo=null。
待评审内容:${state.messages.at(-1)?.content}`;
  const res = await model.invoke([new HumanMessage(prompt)]);
  const json = JSON.parse(res.content as string);
  console.log("[ReviewAgent] 输出,转移到:", json.transferTo);
  return {
    messages: [new HumanMessage(json.content)],
    transferTo: json.transferTo ?? null
  };
}

// 路由函数,增加最大轮次熔断
function routeNode(state: GraphState) {
  if (state.step >= state.maxRound) {
    console.log("[Handoff] 轮次超限,终止");
    return END;
  }
  return state.transferTo ?? END;
}

const builder = new StateGraph(GraphAnnotation)
  .addNode("draftAgent", draftAgent)
  .addNode("reviewAgent", reviewAgent)
  .addConditionalEdges("draftAgent", routeNode, {
    reviewAgent: "reviewAgent",
    [END]: END
  })
  .addConditionalEdges("reviewAgent", routeNode, {
    draftAgent: "draftAgent",
    [END]: END
  })
  .addEdge(START, "draftAgent");

export const handoffApp = builder.compile();

// 执行入口
(async () => {
  const result = await handoffApp.invoke({
    messages: [new HumanMessage("写退款业务方案")],
    transferTo: null,
    step:0,
    maxRound:4
  });
  console.log("==== Handoff最终消息 ====")
  console.log(result.messages);
})();

这个就是 TS 版的类 Swarm:Agent 自主决定交接对象,但是我们依然保留 step/maxRound 熔断,避免无限循环。
缺点:对模型 JSON 结构化输出能力有要求,国产模型需要调优 prompt 保证输出格式稳定。

七、总结

  • 多 Agent 通信只有 中心间接通信 和 自主直连通信 两种范式
  • 生产优先 Supervisor:稳定、可控、适配国产模型、支持熔断兜底、TS 友好
  • Swarm 仅适合 Demo:依赖强模型能力、国产适配差、无 TS 支持、不可控
  • 所有多轮 Agent 协作,必须配置 最大轮次熔断 + 兜底收口,杜绝无限循环
  • TS 项目无需纠结 Swarm,LangGraph 自定义路由可平替所有直连能力
posted @ 2026-09-28 11:47  当下是吾  阅读(27)  评论(0)    收藏  举报