Skip to main content
Glama
yhyu13
by yhyu13

CrossAgentMCP — 一个 A2A 池 MCP

这是对 A2A.md 愿景的最小实现:一个 A2A 池 MCP,在其中

  1. 任意 agent 都可以注册进共享的池子,

  2. 任意 agent 都可以绑定到一个多 agent 的会话

  3. agent 之间互相观察彼此的活动,在某位同伴完成后提出批判,自我改进,并在 无人工干预的情况下持续工作,直到共享目标被会话中的每一位 agent 认可。

这是一个面试 demo:重点不在于 URL 短链/代码评审那篇产出文档,而在于围绕它搭建 的这套系统——一层忠实于 A2A v1.0 的协议层、一个协调控制面、一条「批判到收敛」的闭环, 以及一条从「三个 agent」走向「三个达成一致并停下来的 agent」的可测试、可度量的路径。


1. 它是做什么的

它把彼此独立的 agent 变成一个能自我协调的团队。包含三种进程:

        ┌────────────────── POOL (:9100, FastAPI HTTP JSON-RPC) ──────────────────┐
        │  registry / sessions / activity / critique / goal  (内存态控制面      │
        │  —— 不路由任何工作消息)                                              │
        └──────────────────────────────────────────────────────────────────────────┘
            ▲ pool JSON-RPC (PoolClient)            ▲ pool JSON-RPC(每个 agent 的桥)
            │                                       │
      ┌─────┴──────┐    对等 A2A (SendMessage/GetTask)  ┌─────┴──────┐
      │ orchestrator│◄──────────────────────────────────►│ agent-N    │ … :9101..9103
      └────────────┘      每个 agent 运行各自的          └────────────┘
          无头驱动              v1.0 A2A HTTP 服务器
  • Poolcrossagent/pool.py)——控制面:agent 注册表、带共享目标的多 agent 会话、每个会话的只追加式活动日志批判线程,以及每位 agent 的满意度

  • Agents——每个 agent 是一个目录(agents/<role>/),内含一个 v1.0 A2A HTTP 服务器(对等数据面)、一份接线到 a2a stdio MCP 桥(crossagent/a2a_bridge.py)的 .mcp.json,以及一份 CLAUDE.md(角色 + 每轮契约)。

  • Orchestratorcrossagent/orchestrator.py)——唯一推进时间的组件。它注册 agent、创建会话,然后按轮询无头运行每个 agent(claude -p),把对方尚未见过的 活动/批判增量喂给它,直到每位成员都声明满意且没有残留的批判线程。

收敛规则是严格的:每位成员满意,且没有任何未关闭的批判线程。一次批判会自动撤销 被批判者的满意度,因此只有最后一条反对意见被它所指向的那位 agent 亲手解决,会话才能 结束。

2. 它解决什么问题

A2A(Google 的 Agent2Agent 协议)只定义了「两个 agent 之间如何交换任务」—— SendMessage / GetTask / 流式。它对「两个以上的 agent 如何协调」只字未提。而协调 恰恰是最难、最乱的那部分,也正是本仓库所解决的问题:

朴素多 agent 方案的痛点

CrossAgentMCP 如何解决

没有注册表:agent 不知道还有谁存在

池注册表(Register / ListAgents

无法分组:agent 无法围绕一个目标组队

带共享 goal 和动态成员的可会话

没有共享记忆:每个 agent 只看到自己的记录

只追加式会话 activityLog + activity_since(seq) 增量

没有异议通道:一个 agent 无法拦下另一个的劣质产出

critique_post 打开一个线程,撤销目标 agent 的满意度

没有收敛定义:什么才算「完成」

declare_satisfaction + 状态机(forming→working→revising→satisfied

没有终止机制:循环可能无限闲聊、烧 token

三道护栏:轮次上限 + 无进展检测 + 批判上限(maxCritiques)→ failed

没有身份:任何进程都能冒充另一个 agent

每个 agent 独立 bearer token;伪造动作被 403 拒绝

不可测试:证明循环有效要烧真金白银的 LLM token

可注入的 agent runner + 确定性 stub → pytest 零成本

让它保持清爽的关键设计决策:控制面集中(池),数据面点对点(A2A)。池只保存协调 状态;真正的产出和直接消息留在 agent 之间,所以池永远不会成为瓶颈或消息路由器。

3. 与其他方案的横向对比

方案

它是什么

CrossAgentMCP 的优势

claude-a2a(本仓库所扩展的参考实现)

固定的 2-agent P2P demo:一个硬编码对等方 + 一个本地 agent

泛化到 N 个 agent,补上注册表、会话、活动流、批判、共识与终止——正是 P2P 根本缺失的三件事

原生 A2A(Google)

仅传输:在两 agent 之间 send/get/stream 任务

在忠实 v1.0 线格式之上补上缺失的协调层,因此可与任何 A2A agent 组合

LangGraph / AutoGen / CrewAI

多 agent 框架:agent 跑在框架自身的运行时与图里

协议原生、不绑定框架。任何 agent——经 stdio MCP 桥接入的 Claude Code 会话,或任何会说 A2A over HTTP 的程序——都无需被重写进框架即可加入。agent 是独立 OS 进程;控制面就是一个普通的 HTTP JSON-RPC 服务

仅 MCP

agent↔工具上下文,单 agent

把 **MCP(工具)+ A2A(对等消息)+ 池(协调)**组合成一条 agent 循环:观察 → 批判 → 工作 → 汇报 → 声明

单 agent「全包」

一个模型、一个超长上下文、自我 review

角色分离(writer/critic/lead)并强制交叉校验:批判是一等公民,会阻断收敛,而非一句礼貌的建议

对一个 demo 而言,决定性优势在于:不花钱也能证明它成立。确定性 stub agent 在 pytest 下完整回放了整个生命周期(注册 → 会话 → 产出 → 批判 → 满意度撤销 → 认证 403 → 对等 A2A 往返 → 解决 → 全体收敛),而 benchmark 工具则对真实运行报告 token/耗时/成本。

4. 这证明了什么(AI vibe coding 能力)

每一条结论都落在代码里。

  1. 忠实阅读并实现一份真实的外部规范。 crossagent/a2a.py 对齐 A2A v1.0 proto 与 specification.md——camelCase JSON、PascalCase JSON-RPC 方法、SCREAMING_SNAKE_CASE 枚举、规范错误码(-32001..-32004)、终态任务状态。没有幻觉出的 API,线格式可对照 规范逐条核验。

  2. 歧义下的架构判断。 计划中明确选择了集中控制面 + P2P 数据面、为可测试性而设的 可注入 agent runner,以及在砍掉一个误触发的无进展检测器后保留三道终止护栏(轮次上限 + 无进展检测 + 批判上限)—— 推理过程记录在 1/plan.md1/REVIEW.md

  3. 零 LLM 成本的测试先行验证。 4 个文件 29 个测试覆盖协议、池、桥与 orchestrator; demo/review_demo_scripted.py 用确定性 stub 回放完整生命周期;benchmark.py 记录每轮/ 每会话的墙钟时间、token(含缓存命中)与美元成本(benchmark-results.json 显示一场 3-agent 共识对话:6 轮、$3.03)。

  4. 真实集成调试。 orchestrator.py 把 Windows 的 claude.cmd shim 解析到原生 .exe,杀掉整棵进程树(taskkill /T)以免 MCP 子进程变孤儿,而 JOURNEY.md 记录了 通过把 ANTHROPIC_MODEL 重新指向带限定的模型 id 来诊断网关 503/403——这类问题只有 真刀真枪跑无头 agent 时才会冒出来。

  5. 正确性与安全严谨,而非「能跑就行」。 每个 agent 独立 bearer 身份: test_cannot_spoof_another_agents_satisfaction 与脚本 demo 都展示了伪造的 declare_satisfaction 被 HTTP 403 拒绝。只有批判所指向的 agent 才能解决它; MarkFailed 需要 orchestrator token;已失败的会话永远不得报告收敛。

  6. 迭代式自审闭环。 1/ 目录加上 REVIEW.mdJOURNEY.md 展示了完整弧线:计划 → 实现 → 代码评审揪出真实缺陷(一个死掉的 revising FSM 状态、一处 SSE 回放竞态、 critique_resolve 伪造线程)→ 修复 + 回归测试。系统施加在自己的 agent 身上的那条 批判闭环,同样被施加在了系统自己的代码上。

协议

忠实于 A2A v1.0(PascalCase JSON-RPC 方法、camelCase JSON、SCREAMING_SNAKE_CASE 枚举)。见 crossagent/a2a.py

安装

uv sync          # Python 3.11+ venv + 依赖

为 Kilo / Claude Code / Codex 安装 a2a MCP 桥

每个 agent 角色(writer / critic / lead)都暴露同一个 stdio MCP 桥 (crossagent.a2a_bridge),只是身份、本地端口和对等映射不同。三个工具都已注册 (路径钉在 D:/GitRepo-AI/CrossAgentMCP;若再迁移请同步调整):

工具

配置文件

服务器名

Kilo

kilo.jsonmcp 字段)

a2a-writera2a-critica2a-lead

Claude Code

agents/<role>/.mcp.json

a2a(从该 agent 目录运行 Claude 时加载)

Codex

.codex/config.toml

a2a-writera2a-critica2a-lead

桥的工具只有在池和 agent A2A 服务器都起来后才能工作。启停脚本:

powershell -ExecutionPolicy Bypass -File scripts/start-servers.ps1
powershell -ExecutionPolicy Bypass -File scripts/stop-servers.ps1

start-servers.ps1 -WithDemoAuth 会镜像 demo/goal.json 里的 token;默认运行时池 关闭认证。)

使用

快速上手(root vs 1/

本仓库有两套独立实现,都跑在同一组端口 :9100–9103,不要同时启动。1/ 已冻结,日常用 root。

root —— crossagent/(推荐,已接入 Kilo)

uv sync
powershell -ExecutionPolicy Bypass -File scripts/start-servers.ps1   # pool :9100 + writer/critic/lead :9101..9103
powershell -ExecutionPolicy Bypass -File scripts/stop-servers.ps1    # 停止

服务器起来后,Kilo 的 a2a-writer / a2a-critic / a2a-lead MCP 工具即可用;各角色 每轮契约见 agents/<role>/CLAUDE.md

子目录 1/ —— agentpool(早期实现,无 bearer 身份、无头编排器非一等公民;已冻结)

cd 1
uv sync
uv run pytest                                        # pool / session / consensus 测试
uv run python demo/run_session.py --num-agents 3     # 全自主闭环,无 LLM
uv run python demo/real_review.py --payload demo/real_review_payload.json
uv run python demo/compare_radiance.py               # 自动选端口,可与 root 并存
uv run python -m pool.server                         # 单跑 pool(:9100)

两套实现的差异(工具名 / 认证 / 收敛契约 / 编排器)见下方「与子目录 1/ 的关系」。

make test        # 单元测试(协议 / 池 / orchestrator,使用假 agent)
make smoke       # 拉起池 + 2 个 A2A 服务器;脚本化往返(无真实 Claude)
make demo        # 完整无头 3-agent demo(writer / critic / lead)——需要 `claude`

编排器支持 schedule: "serial"(默认)与 "parallel":并行模式每轮让所有 agent 在 同一 pre-round 快照上并发工作(bulk-synchronous),一轮计 len(agents) 次 run,与串行 模式的轮次预算可比。在 goal.json"schedule": "parallel" 即可切换。并行模式下 默认 "parallelCursor": "round"(下一轮看到同伴产出)。"finish" 是旧行为,不重喂,两轮并行会看起来很便宜——因为根本没 review。 "maxCritiques"(默认 200)限制批判总数,超限判 failed

Demo 目标

demo/goal.json 让三个 agent——writercriticlead——共同撰写 demo/output/design.md(一个 URL 短链设计),直到三者都声明满意。

代码评审 demo(torchimpulse)

另有两条驱动针对一个真实代码库(F:\XD\git-repo\torchimpulse)跑同一套池:

uv run python demo/review_demo_scripted.py   # 确定性 stub agent(无 claude,零成本)
uv run python demo/review_demo.py            # 完整自主 3-agent 评审——需要 `claude`
  • review_demo_scripted.py 回放完整生命周期——注册 → 会话 → 产出 → 批判(满意度撤销)→ 伪造动作被认证 403 → 对等 A2A 发送/应答 → 解决 → 全体收敛——以真实评审结论作为内容。

  • review_demo.py 无头运行 writer / critic / leadclaude -p)共同撰写 torchimpulse/A2A_REVIEW.md 并收敛(5 轮,全员满意,0 条未关闭批判)。

文档树评审 + 单 agent 对照(radiance 3d/doc

同一棵 ~589 文件的文档树、同一模型(deepseek/deepseek-v4-pro),demo/compare_radiance.py 对照 单 agent 融合一轮3-agent 编排器

模式

轮次

墙钟

成本

收敛

mono-agent

1

556 s

$2.29

是(MONO_REVIEW.md

3-agent(本仓库 crossagent/

5

855 s

$4.56

是(三方 true

相对 mono:墙钟 ×1.54、input token ×3.03、成本 ×2.00。产出篇幅相当(18.5 KB vs 19.2 KB)。 原始数字在 demo/output/radiance_comparison.json

uv run python demo/compare_radiance.py          # 需已运行 scripts/start-servers.ps1
uv run python demo/review_radiance.py           # 附着已运行栈评审;结束后导出完整活动/批判记录

单 agent vs 3-agent 效率 / 质量对照(payments ledger,盲评)

同一个问题、同一模型、同一运行栈,demo/compare_efficiency.py 对照单 agent 融合一轮3-agent 编排器的效率比值;demo/compare_quality.py 再跑三种模式(single-monolithic / single-iterative(N) / 3-agent),并由独立盲评按 5 项标准打分(满分 25):

模式

轮次

墙钟

成本

盲评 /25

single-monolithic

1

38 s

$0.24

25

single-iterative(6)

6

650 s

$2.01

25

3-agent

6

264 s

$2.13

10*

* 10/25 是度量产物:目标写了「不要写文件」,池的推理只留在活动日志里,盲评只看到 lead 的状态行——池保存的是协调状态,不是工作产出。原始数字在 demo/output/{efficiency,quality}_comparison.json

uv run python demo/compare_efficiency.py        # 需已运行 scripts/start-servers.ps1
uv run python demo/compare_quality.py           # 同上(含盲评)
uv run python demo/scale_n.py                   # 零 LLM:N=1..30 stub 缩放(串行/并行/两轮)

与子目录 1/ 的关系

1/另一套实现(从 claude-a2a 长出来的池:slash 方法名、SSE watch、无 bearer 身份、无头编排器不是一等公民)。同一棵 radiance 树的第一次真 claude -p 循环(1/demo/compare_radiance.py,自动选端口以免撞 :9100)跑满 9 轮仍停在 reviewing(lead 未声明满意),成本 $7.57。差距主要来自循环契约——根编排器每轮 强制 declare_satisfaction1/satisfy() 只能单向 True——不是评审质量 更差(A2A_REVIEW_1.md 同样有 file:line 的 Critical 发现)。详见 JOURNEY.md 2026-08-21 节与 1/README.md

1/ 已冻结(2026-08-22):不再作为竞争架构演进,仅保留作多进程测试夹具。 它唯一不可替代的发现——all-to-all 批判的 N(N−1) 组合爆炸——已固化为 root 的 maxCritiques 护栏(默认 200)。

注意事项

  • .mcp.json / kilo.json / .codex/config.toml 文件硬编码了仓库路径 D:/GitRepo-AI/CrossAgentMCP;若迁移仓库请同步更新。

  • 池与 agent 服务器都把状态保存在内存里;重启即重置。

  • 无头 agent 运行的是 claude -p,此处它指向一个网关(llm-proxy.tapsvc.com)。请在 ~/.claude/settings.json 中钉住模型(例如 ANTHROPIC_MODEL=deepseek/deepseek-v4-pro); Claude Code 的裸默认模型名会被该网关拒绝。