CrossAgentMCP
by yhyu13
README.md
# CrossAgentMCP — 一个 A2A 池 MCP
这是对 [A2A.md](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 服务器
```
- **Pool**(`crossagent/pool.py`)——控制面:agent **注册表**、带共享目标的多 agent
**会话**、每个会话的只追加式**活动日志**、**批判线程**,以及每位 agent 的**满意度**。
- **Agents**——每个 agent 是一个目录(`agents/<role>/`),内含一个 v1.0 A2A HTTP
服务器(对等数据面)、一份接线到 `a2a` stdio MCP 桥(`crossagent/a2a_bridge.py`)的
`.mcp.json`,以及一份 `CLAUDE.md`(角色 + 每轮契约)。
- **Orchestrator**(`crossagent/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.md` 与 `1/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.md`、`JOURNEY.md` 展示了完整弧线:计划 →
实现 → 代码评审揪出真实缺陷(一个死掉的 `revising` FSM 状态、一处 SSE 回放竞态、
`critique_resolve` 伪造线程)→ 修复 + 回归测试。系统施加在*自己的 agent* 身上的那条
批判闭环,同样被施加在了系统*自己的代码*上。
## 协议
忠实于 **A2A v1.0**(PascalCase JSON-RPC 方法、camelCase JSON、`SCREAMING_SNAKE_CASE`
枚举)。见 `crossagent/a2a.py`。
## 安装
```bash
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.json`(`mcp` 字段) | `a2a-writer`、`a2a-critic`、`a2a-lead` |
| Claude Code | `agents/<role>/.mcp.json` | `a2a`(从该 agent 目录运行 Claude 时加载) |
| Codex | `.codex/config.toml` | `a2a-writer`、`a2a-critic`、`a2a-lead` |
桥的工具只有在池和 agent A2A 服务器都起来后才能工作。启停脚本:
```powershell
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)**
```powershell
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 身份、无头编排器非一等公民;已冻结)**
```powershell
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/` 的关系」。
```bash
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——**writer**、**critic**、**lead**——共同撰写
`demo/output/design.md`(一个 URL 短链设计),直到三者都声明满意。
### 代码评审 demo(torchimpulse)
另有两条驱动针对一个真实代码库(`F:\XD\git-repo\torchimpulse`)跑同一套池:
```bash
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 / lead**(`claude -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`。
```bash
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`。
```bash
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_satisfaction`,`1/` 的 `satisfy()` 只能单向 `True`——不是评审质量
更差(`A2A_REVIEW_1.md` 同样有 `file:line` 的 Critical 发现)。详见
[JOURNEY.md](JOURNEY.md) 2026-08-21 节与 [1/README.md](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 的裸默认模型名会被该网关拒绝。
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues