联邦模式:去中心化 Agent 协商
概念速查
联邦模式(Federation Pattern)是一种无中央协调者的多 Agent 协作模式。Agent 之间通过点对点消息传递与协商达成共识,天然解除了单点依赖和单点瓶颈。联邦模式的核心思想借鉴了分布式系统领域:每个 Agent 是一个自治节点,遵循同一套通信协议,通过多轮"提案-反馈-修订-确认"循环收敛到一个双方(或多方)都接受的方案。
与投票模式的区别:投票模式有一个显式的中央聚合器,联邦模式中每个 Agent 都持有一份完整的上下文视图。与编排模式的区别:编排模式有明确的 Orchestrator 节点分配任务,联邦模式中 Agent 在地位上是平等的。
| 对比维度 | 投票模式 | 编排模式 | 联邦模式 |
|---|---|---|---|
| 协调方式 | 中央聚合器 | Orchestrator 节点 | 点对点协商 |
| 通信拓扑 | 星型 | 树型 | 全连接/网格 |
| 共识机制 | 加权/多数决 | 上级指令 | 消息协商 |
| 容错能力 | 聚合器单点 | 协调者单点 | 天然分散 |
| 一致性 | 最终一致 | 强一致 | 最终一致 |
联邦模式的核心思想借鉴了分布式系统领域:每个 Agent 是一个自治节点,遵循同一套通信协议,通过多轮"提案-反馈-修订-确认"循环收敛到一个双方(或多方)都接受的方案。
#mermaid-svg-Z84mUO7CgCFtKJiV{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Z84mUO7CgCFtKJiV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Z84mUO7CgCFtKJiV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Z84mUO7CgCFtKJiV .error-icon{fill:#552222;}#mermaid-svg-Z84mUO7CgCFtKJiV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Z84mUO7CgCFtKJiV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Z84mUO7CgCFtKJiV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Z84mUO7CgCFtKJiV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Z84mUO7CgCFtKJiV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Z84mUO7CgCFtKJiV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Z84mUO7CgCFtKJiV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Z84mUO7CgCFtKJiV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Z84mUO7CgCFtKJiV .marker.cross{stroke:#333333;}#mermaid-svg-Z84mUO7CgCFtKJiV svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Z84mUO7CgCFtKJiV p{margin:0;}#mermaid-svg-Z84mUO7CgCFtKJiV .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Z84mUO7CgCFtKJiV .cluster-label text{fill:#333;}#mermaid-svg-Z84mUO7CgCFtKJiV .cluster-label span{color:#333;}#mermaid-svg-Z84mUO7CgCFtKJiV .cluster-label span p{background-color:transparent;}#mermaid-svg-Z84mUO7CgCFtKJiV .label text,#mermaid-svg-Z84mUO7CgCFtKJiV span{fill:#333;color:#333;}#mermaid-svg-Z84mUO7CgCFtKJiV .node rect,#mermaid-svg-Z84mUO7CgCFtKJiV .node circle,#mermaid-svg-Z84mUO7CgCFtKJiV .node ellipse,#mermaid-svg-Z84mUO7CgCFtKJiV .node polygon,#mermaid-svg-Z84mUO7CgCFtKJiV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Z84mUO7CgCFtKJiV .rough-node .label text,#mermaid-svg-Z84mUO7CgCFtKJiV .node .label text,#mermaid-svg-Z84mUO7CgCFtKJiV .image-shape .label,#mermaid-svg-Z84mUO7CgCFtKJiV .icon-shape .label{text-anchor:middle;}#mermaid-svg-Z84mUO7CgCFtKJiV .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Z84mUO7CgCFtKJiV .rough-node .label,#mermaid-svg-Z84mUO7CgCFtKJiV .node .label,#mermaid-svg-Z84mUO7CgCFtKJiV .image-shape .label,#mermaid-svg-Z84mUO7CgCFtKJiV .icon-shape .label{text-align:center;}#mermaid-svg-Z84mUO7CgCFtKJiV .node.clickable{cursor:pointer;}#mermaid-svg-Z84mUO7CgCFtKJiV .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Z84mUO7CgCFtKJiV .arrowheadPath{fill:#333333;}#mermaid-svg-Z84mUO7CgCFtKJiV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Z84mUO7CgCFtKJiV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Z84mUO7CgCFtKJiV .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Z84mUO7CgCFtKJiV .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Z84mUO7CgCFtKJiV .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Z84mUO7CgCFtKJiV .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Z84mUO7CgCFtKJiV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Z84mUO7CgCFtKJiV .cluster text{fill:#333;}#mermaid-svg-Z84mUO7CgCFtKJiV .cluster span{color:#333;}#mermaid-svg-Z84mUO7CgCFtKJiV div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Z84mUO7CgCFtKJiV .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Z84mUO7CgCFtKJiV rect.text{fill:none;stroke-width:0;}#mermaid-svg-Z84mUO7CgCFtKJiV .icon-shape,#mermaid-svg-Z84mUO7CgCFtKJiV .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Z84mUO7CgCFtKJiV .icon-shape p,#mermaid-svg-Z84mUO7CgCFtKJiV .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Z84mUO7CgCFtKJiV .icon-shape .label rect,#mermaid-svg-Z84mUO7CgCFtKJiV .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Z84mUO7CgCFtKJiV .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Z84mUO7CgCFtKJiV .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Z84mUO7CgCFtKJiV :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 提案 P1
反馈 F1
修订版 P2
确认 ACK
提案 P3
同步提案
反馈 F2
修订 P4
确认 ACK
全域共识 D
全域共识 D
Agent A
Agent B
Agent C
底层原理
消息驱动型协商
联邦模式的通信单元是提案消息 ,每个消息包含四个字段:id(全局唯一提案 ID)、from(发起方)、payload(方案内容)、signature(数字签名或校验和)。Agent 收到提案后,评估是否接受、拒绝或提出修订,并将自己的立场广播给所有参与方。
#mermaid-svg-wUNscdGhUZwkPd1f{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-wUNscdGhUZwkPd1f .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-wUNscdGhUZwkPd1f .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-wUNscdGhUZwkPd1f .error-icon{fill:#552222;}#mermaid-svg-wUNscdGhUZwkPd1f .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-wUNscdGhUZwkPd1f .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-wUNscdGhUZwkPd1f .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-wUNscdGhUZwkPd1f .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-wUNscdGhUZwkPd1f .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-wUNscdGhUZwkPd1f .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-wUNscdGhUZwkPd1f .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-wUNscdGhUZwkPd1f .marker{fill:#333333;stroke:#333333;}#mermaid-svg-wUNscdGhUZwkPd1f .marker.cross{stroke:#333333;}#mermaid-svg-wUNscdGhUZwkPd1f svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-wUNscdGhUZwkPd1f p{margin:0;}#mermaid-svg-wUNscdGhUZwkPd1f .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-wUNscdGhUZwkPd1f .cluster-label text{fill:#333;}#mermaid-svg-wUNscdGhUZwkPd1f .cluster-label span{color:#333;}#mermaid-svg-wUNscdGhUZwkPd1f .cluster-label span p{background-color:transparent;}#mermaid-svg-wUNscdGhUZwkPd1f .label text,#mermaid-svg-wUNscdGhUZwkPd1f span{fill:#333;color:#333;}#mermaid-svg-wUNscdGhUZwkPd1f .node rect,#mermaid-svg-wUNscdGhUZwkPd1f .node circle,#mermaid-svg-wUNscdGhUZwkPd1f .node ellipse,#mermaid-svg-wUNscdGhUZwkPd1f .node polygon,#mermaid-svg-wUNscdGhUZwkPd1f .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-wUNscdGhUZwkPd1f .rough-node .label text,#mermaid-svg-wUNscdGhUZwkPd1f .node .label text,#mermaid-svg-wUNscdGhUZwkPd1f .image-shape .label,#mermaid-svg-wUNscdGhUZwkPd1f .icon-shape .label{text-anchor:middle;}#mermaid-svg-wUNscdGhUZwkPd1f .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-wUNscdGhUZwkPd1f .rough-node .label,#mermaid-svg-wUNscdGhUZwkPd1f .node .label,#mermaid-svg-wUNscdGhUZwkPd1f .image-shape .label,#mermaid-svg-wUNscdGhUZwkPd1f .icon-shape .label{text-align:center;}#mermaid-svg-wUNscdGhUZwkPd1f .node.clickable{cursor:pointer;}#mermaid-svg-wUNscdGhUZwkPd1f .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-wUNscdGhUZwkPd1f .arrowheadPath{fill:#333333;}#mermaid-svg-wUNscdGhUZwkPd1f .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-wUNscdGhUZwkPd1f .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-wUNscdGhUZwkPd1f .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wUNscdGhUZwkPd1f .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-wUNscdGhUZwkPd1f .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wUNscdGhUZwkPd1f .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-wUNscdGhUZwkPd1f .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-wUNscdGhUZwkPd1f .cluster text{fill:#333;}#mermaid-svg-wUNscdGhUZwkPd1f .cluster span{color:#333;}#mermaid-svg-wUNscdGhUZwkPd1f div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-wUNscdGhUZwkPd1f .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-wUNscdGhUZwkPd1f rect.text{fill:none;stroke-width:0;}#mermaid-svg-wUNscdGhUZwkPd1f .icon-shape,#mermaid-svg-wUNscdGhUZwkPd1f .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wUNscdGhUZwkPd1f .icon-shape p,#mermaid-svg-wUNscdGhUZwkPd1f .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-wUNscdGhUZwkPd1f .icon-shape .label rect,#mermaid-svg-wUNscdGhUZwkPd1f .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wUNscdGhUZwkPd1f .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-wUNscdGhUZwkPd1f .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-wUNscdGhUZwkPd1f :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 未收敛
已收敛
场景目标
Agent 1 生产初始提案
广播给所有 Peer
Agent 2 评估
Agent 3 评估
Agent N 评估
反馈:修订建议
反馈:条件接受
反馈:拒绝
提案方汇总反馈
生成修订版提案
再次广播
收敛判断
最终共识 + 执行
共识算法适配
Agent 联邦的共识本质上是分布式一致性问题。实践中会按场景选择收敛策略:
| 策略 | 适用场景 | 通信轮数 | 容错能力 |
|---|---|---|---|
| 全量握手(All-to-All) | 小规模(≤5 Agent) | O(n²) | 强 |
| 代表协商(Representative) | 中规模(6~20 Agent) | O(k·n) | 中 |
| 广播+最大重叠 | 大规模(>20 Agent) | O(n) | 弱(需 Gossip 协议) |
全量握手的收敛条件: 当所有 Agent 收到的提案集合的交集占某个 Agent 当前提案的 ≥ 阈值(通常 80%)时,取交集的最大分量作为最终方案。
交比(J) = |提案(i) ∩ 提案(j)| / |提案(i)| ∀ i, j ∈ Agents
收敛条件: min(J) ≥ θ (θ 通常取 0.8)
与 A2A 协议的关系
Google 的 Agent-to-Agent(A2A)协议为联邦模式提供了标准化的消息载体。A2A 的 Task 对象天然支持提案-响应模式:一个 Agent 发出 Task,其他 Agent 通过 Task 的状态转换(submitted → working → completed/ failed)来表达协商进度。联邦模式可以看作 A2A 协议在"多 Agent 平等协商"这一拓扑下的使用范式。
架构设计原则
原则一:消息格式必须版本化且向前兼容。 Agent 的生命周期不同,部署时间不同,如果 V2 版本的 Agent 发出的消息 V1 解析不了,联邦会分裂成两个孤岛。每个消息的 version 字段必须声明 schema 版本,接收方按自己能处理的最新版本解析,遇到未知字段跳过不报错。
原则二:共识超时必须伴随降级路线。 分布式协商天然有延迟不确定性。每当一个 Agent 发起提案,必须设定一个超时窗口(T1 = 预期响应时间 × 2 ~ 3)。超时未收到足够反馈时,Agent 应降级为"局部共识"------只与已响应的节点达成协议,并将部分共识结果告知沉默节点。
python
# agent_federation.py --- Python 3.12+
# 最小化联邦协商骨架
import uuid
import time
from dataclasses import dataclass, field
@dataclass
class Proposal:
id: str = field(default_factory=lambda: uuid.uuid4().hex[:12])
version: int = 2
payload: str = ""
timestamp: float = field(default_factory=time.time)
replies: list[str] = field(default_factory=list)
def add_reply(self, reply: str) -> None:
self.replies.append(reply)
class FederationAgent:
def __init__(self, peers: list[str], threshold: float = 0.8):
self.peers = peers # 已知对等节点列表
self.threshold = threshold # 收敛阈值
self.proposals: dict[str, Proposal] = {}
def propose(self, payload: str, timeout: float = 5.0) -> str | None:
p = Proposal(payload=payload)
self.proposals[p.id] = p
# 广播提案到所有 Peer(实际调用外部消息总线)
for peer in self.peers:
self._send(peer, p)
# 等待反馈,超时则只取已达成的部分
deadline = time.time() + timeout
while time.time() < deadline:
if self._convergence_check(p):
return p.payload
time.sleep(0.1)
# 超时降级:返回局部共识结果
return self._partial_consensus(p)
def _convergence_check(self, p: Proposal) -> bool:
agreed = [r for r in p.replies if r == p.payload]
return len(agreed) / max(len(self.peers), 1) >= self.threshold
def _partial_consensus(self, p: Proposal) -> str | None:
if not p.replies:
return None
from collections import Counter
return Counter(p.replies).most_common(1)[0][0]
def _send(self, peer: str, proposal: Proposal) -> None:
pass # ponytail: 接入实际消息总线(Redis PubSub / NATS / Kafka)
原则三:联邦拓扑必须允许 Agent 动态加入和退出。 生产环境中 Agent 因部署更新、扩缩容、故障而反复上下线是常态。引入一个轻量级的发现服务(不参与协商决策,仅维护存活列表),每个 Agent 启动时向发现服务注册心跳,联邦中的其他 Agent 通过发现服务获取最新拓扑。
原则四:可观测性要区分"协商过程"和"协商结果"。 联邦模式的黑盒特性比中心化模式更强------出了问题时,你不知道是哪个 Agent 的哪轮反馈导致了次优结果。应为每个提案单独追踪其协商轨迹(proposal_id → 每轮反馈列表 → 终局原因),输出到可观测性后端。
原则五:非对称能力场景下走"加权联邦"。 当 Agent 的能力不均衡时(一个基于 GPT-4 的 Agent 和三个基于小模型的 Agent 协商),等权投票会拉低整体质量。此时每个 Agent 带一个 capability 权重(历史精确率、领域匹配度等),对方的提案反馈按权重折算------这与投票模式的加权投票本质上相通,区别在于加权联邦没有中央聚合器,权重信息在消息中携带,由接收方自行折算。
何时不该用
联邦模式不适合:Agent 规模 > 50 的场景(通信复杂度 O(n²) 会拖垮延迟)、需要强一致性的场景(最终一致性意味着存在短暂分歧)、Agent 之间互信度低的场景(恶意 Agent 可发起 Sybil 攻击浪费协商轮次)。对小型团队(3~5 Agent),联邦模式是去中心化的优雅选择;对中型以上团队,建议联邦+代表选举的混合方案。