Files
Agentswarm/docs/swarm/convergence-protocol.md
T
gongzhiyongandClaude Opus 4.8 1288fd19d7
CI / tests (push) Failing after 15m3s
CI / guardrails (push) Failing after 15m3s
feat(swarm): 协作聚合收敛取代蜂后选优 + sandbox 用 pytest 验证
按 juejin 协作聚合模型重构收敛(取代 best-of-N 选优):
- 删蜂后选优(queen.py/test-queen.py)
- 新增聚合节点 result_aggregator.py:共享池收集→同文件 LLM/AST 整合→沙箱验证→单次落 main
- 质量驱动闭环:不达标打回迭代(AGGREGATE_ACCEPTANCE_THRESHOLD + MAX_REVIEW_CYCLES)
- agent 停 git 工作分支,产出走 task.result.files 共享池(AGENT_GIT_PUSH_ENABLED 默认 false)
- sandbox_runner 改用 pytest(原生支持 pytest 风格 class),修 stdlib runner 收集失败
- 文档同步重写为协作聚合模型

本地验证:产物仓单分支 main + 三函数完整 + pytest 12/12 pass_rate=100 一次达标。
影响:Swarm 收敛/聚合层;Manager/客户端契约不变(artifact字段/sequence/状态机;契约测试全过)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 22:03:00 +08:00

17 KiB
Raw Blame History

蜂群收敛协议(共识 / 冲突消解 / 终止函数)

状态:已无条件接入 refresh_swarm_run_status(去中心化重构,无开关)。每次 run 终态都产 ConvergenceReport 存 run.metadata["convergence"],并把 termination_reason 附到 timeline.updated。当前为解释性——产出 termination_reason/共识/冲突,但不覆盖 run.status(今天 next_status 与报告对 completed/failed 一致);authoritative 状态覆盖为后续。

对应 Issue #12:「蜂群收敛机制缺失:缺少共识、冲突消解与终止函数,无法解释 Swarm 为什么结束」。

实现:orchestrator/convergence.py(纯计算,无 I/O)+ main.py: compute_convergence_report(装配 run_state,shadow 落库);单测 scripts/test-convergence.py + 集成测试 scripts/test-swarm-convergence.py。计划见 decentralized-rework-plan.md。

0. 问题:今天「为什么结束」是不可解释的

当前一次 run 走到终态,唯一判定在 orchestrator/main.py:refresh_swarm_run_status:

  • 所有已知任务到达终态后,next_status = "failed"(任一任务 FAILED)否则 "completed";
  • 可选地(仅 ENABLE_REVIEW_LOOP)先跑主控评审,被拒则重开任务再 finalize。

也就是说,今天的终止 = 「所有任务做完 + (可选)评审通过」,没有:

  • 共识模型:没有任何「多少产出处于一致状态」的度量;
  • 一等公民的冲突检测 / 消解:两个 Agent 对同一文件写出不同内容、依赖未满足却标记完成等,均无显式识别;
  • 可机读的终止原因:completed / failed 无法区分「质量达标」「预算耗尽」「轮次上限」「被风险阻断」。

本协议补齐上述三者。已无条件接入(无开关),但当前作为解释层:产出报告 + termination_reason 存 run,不覆盖 run 的终态语义(规则 #9:authoritative 覆盖为后续)。

1. 设计原则

  • 纯函数、可测:evaluate_convergence(run_state) 不做任何 I/O,不修改 run;调用方(main.py: compute_convergence_report)负责持久化。
  • 无条件(无开关):refresh_swarm_run_status 每次终态都计算报告——本仓即 swarm 运行时,无 ENABLE_* 门控。
  • 不伪造信号(规则 #9):无质量评分 ≠ 通过;无测试信号 ≠ 失败;无预算 ≠ 充足。缺信号一律退出判定,不补 0、不补 100。
  • 解释优先于干预:本版只解释「为什么结束」,不自动改写终态、不自动 merge 冲突产物。

2. 数据结构(orchestrator/convergence.py)

@dataclass
class ConvergenceReport:
    status: ConvergenceStatus              # running / converged / failed / blocked
    termination_reason: TerminationReason | None  # 终态必有,running 时为 None
    consensus_score: float                 # [0,100],无冲突牵连的已完成产出占比
    conflicts: list[Conflict]              # 全部检出冲突
    resolved_conflicts: list[Conflict]     # 已消解
    unresolved_risks: list[dict]           # 阻断性风险 + 未消解硬冲突
    budget_state: dict                     # 预算限额 / 消耗 / exhausted
    quality_state: dict                    # fixture 评分 / 阈值 / reached

2.1 终止原因枚举(TerminationReason)

值 含义 触发输入
quality_reached 质量 / 验收门达标 quality.test_pass_rate ≥ acceptance_threshold(默认 1.0)
budget_exhausted token / 成本 / 时长预算耗尽 usage ≥ budget 任一限额
max_rounds_reached 评审 / 重做轮次达上限 review_cycles ≥ max_review_cycles
risk_blocked 被未消解阻断性风险终止 输入阻断风险或未消解硬冲突
tasks_completed 诚实回退:仅「所有任务做完」 以上均不适用——即今天唯一真实信号

tasks_completed 明确对应「现状」:当没有质量评分、预算、轮次或风险信号时,我们能说的只有「任务都做完了」,不冒充更强的解释。

2.2 冲突类型(ConflictType)

类型 检测器 判据
artifact_mismatch detect_artifact_mismatch 两个已完成任务对同一 files_modified 路径记录了不同 file_hashes/file_contents 指纹
test_failure detect_test_failures 任务结果 tests_passed is False 或 test_pass_rate < 1
review_disagreement detect_review_disagreement 主控评审 accepted=False(沿用 master_agent.review_and_decide 的 verdict 形状)
dependency_inconsistency detect_dependency_inconsistency 任务已完成,但其 depends_on 依赖在同 run 内未完成

3. 终止函数判定顺序

evaluate_convergence(run_state) 依次判断,先匹配先返回:

  1. 无任务 / 任一任务处于 pending|assigned|in_progress → RUNNING(无 reason)。
  2. 存在阻断风险或未消解硬冲突 → BLOCKED + risk_blocked。
  3. 仅有 blocked 任务(无阻断风险) → RUNNING(与 refresh_swarm_run_status 中「blocked 但有活跃子任务保持 running」对齐)。
  4. 任一任务 failed → FAILED,原因取(预算耗尽→budget_exhausted;否则轮次到顶→max_rounds_reached;否则 tasks_completed)。
  5. 全部完成且预算耗尽 → CONVERGED + budget_exhausted。
  6. 全部完成且轮次到顶 → CONVERGED + max_rounds_reached。
  7. 全部完成且质量达标 → CONVERGED + quality_reached。
  8. 其余(全部完成) → CONVERGED + tasks_completed(诚实回退)。

不变式:任何终态(converged/failed/blocked)必带且仅带一个 termination_reason;running 必为 None。单测逐条断言。

3.1 共识分(compute_consensus_score)

consensus = 100 × (未被任何冲突牵连的已完成任务数 / 已完成任务总数)

无已完成任务 → 0.0。这是一个可解释的真实代理量(仅来自任务状态 + 检出冲突),不是模型主观打分。

3.2 消解(resolve_conflicts)——保守首版

  • artifact_mismatch:仅当评审 accepted=True(评审隐式选定了胜出版本)才标记 resolved;否则 unresolved。
  • review_disagreement:verdict 给出可操作 retry_tasks 时标记 resolved(蜂群可通过重开任务行动);空泛拒绝无可操作项 → unresolved。
  • test_failure / dependency_inconsistency:视为硬阻断,本版不自动消解,留给重做循环或人工。

每个冲突就地写回 resolved 与 resolution(消解方式或无法消解的原因)。

4. 事件载荷构造器

按 SwarmRuntime.emit_event(run, event_type, payload=...) 约定,每个构造器返回 (event_type, payload),payload 为 JSON 安全 dict:

函数 event_type 用途
event_convergence_started convergence.started 收敛评估开始
event_conflict_detected conflict.detected 每检出一个冲突
event_conflict_resolved conflict.resolved 每消解一个冲突
event_consensus_updated consensus.updated 当前共识分与冲突计数
event_convergence_reached convergence.reached 终态成功,附 termination_reason
event_convergence_failed convergence.failed 终态失败/阻断,附 termination_reason

⚠️ 上述六个 event_type 尚未登记进 Manager 事件契约(heicode agent_callback.go)。在订阅或回调消费前,必须先按下方集成说明走 Manager 侧契约登记,否则属于未登记事件。

5. 测试

..\.venv\Scripts\python.exe scripts\test-convergence.py

模块级、无 WS/Redis/模型。覆盖:两个冲突产物 → 检出 artifact_mismatch + review_disagreement;review_disagreement 可消解、artifact_mismatch 未消解;产出带具体 termination_reason 的 ConvergenceReport;断言每个终态都带 termination_reason;断言至少一个冲突「检出 + 消解」闭环;以及五个终止原因各自的终态用例。全部 PASS。

6. 接入现状与诚实差距(规则 #9)

已接入(main.py: compute_convergence_report + refresh_swarm_run_status,无开关):每次 run 终态装配 run_state(tasks/budget/usage/quality/review_cycles)→ evaluate_convergence → 报告存 run.metadata["convergence"],termination_reason 附到 timeline.updated 载荷。

诚实差距:

  • 解释性,非权威:报告不覆盖 run.status(今天 next_status 与报告对 completed/failed 一致)。authoritative 模式(如 BLOCKED→置 run blocked)改变 Manager 面终态语义,须先过 scripts/test-runtime-contract.py + 契约评审——列为后续。
  • 质量/预算/风险输入有条件:quality 依赖 Group B fixture 评分(绑定 fixture 时);budget/usage 需 run 提供;risks 需上游注入。缺失时相应原因不触发,回退 tasks_completed(不伪造)。
  • 消解为保守首版:convergence.py 的冲突消解层不做自动选胜,硬冲突留待重做或人工。注意这与 §7 的协作聚合是不同层次:聚合节点(§7.2)对互补子产物做 LLM 合并属正常收口,不是「冲突消解」;冲突消解针对的是同路径不一致/测试失败等异常。互补聚合不依赖「选胜」。
  • 收敛事件不进 Manager 流:六个 convergence.*/conflict.*/consensus.* 事件构建器已实现但不经 emit_event 外发(未在 Manager agent_callback.go 注册;与 swarm.health 同策略,避免向订阅全部的回调投递未登记事件)。登记后方可启用 Manager 侧发送。termination_reason 以新增可选字段附在 timeline.updated,对旧消费方向后兼容。

7. 收敛 = 协作聚合(不是 best-of-N 选优)

理念来源:去中心化蜂群范式(掘金《蜂群智能多 Agent 框架》理念,舆情分析案例)——「个体简单、群体智能」。涌现来自分工协作 + stigmergy 间接协调,不是多个独立解相互竞争后选一个最优。本节据此把旧的「蜂后 best-of-N 选最优」收敛模型重写为协作聚合模型。

7.0 两种收敛语义(先区分,再选默认)

蜂群里「收口」有两种本质不同的语义,必须分开处理:

语义 何时产生 收敛方式 是否本仓默认
互补聚合(complementary aggregation) 一个种子任务经自主分解(#7)铺成多个互补子任务(各做一块,产出不重叠) 聚合合并:从共享池读所有子任务产出 → 整合成一份完整产物 ✅ 主路径
多解选优(best-of-N selection) 同一个原子任务被多 Agent 竞争(#8)各自给出可互换的完整解 选优:按质量排序取胜出解 仅竞争原子任务时的次要路径

文章主推前者:舆情案例里「情感分析 Agent」「趋势分析 Agent」产出互补,由「报告生成 Agent」汇总所有分析结果成一份报告——这是合并,不是选优。本仓 fan-out 的产物来自自主分解的互补子任务,因此默认走聚合合并。选优只在「同一原子任务有多个可互换完整解」时才适用,属次要路径。

7.1 共享结果池:中间产物不进交付仓

对齐文章 SwarmEnvironment.results(agent 把产出 append 进共享池):

  • 每个子任务完成时,产物以 task.result.files 写入共享结果池(Redis run 状态里的任务结果,对应文章的 environment.results),而不是直接提交进交付(git)仓库。
  • 共享池是聚合节点的唯一输入源:聚合前没有任何子任务分支落到产物仓。
  • 产物仓永远只有 main 一份,无 per-agent 工作分支——子任务产出停留在共享池(运行时状态)里,落仓是聚合之后的单次动作(§7.3)。这也消除了「artifact 碎在各结果分支、需要事后 merge」的旧问题。

7.2 聚合节点(ResultAggregator,扮演「报告生成 Agent」)

对齐文章的专门聚合节点 + ResultAggregator(合并结果 / 按质量排序 / 格式转换)+ DAG mode=wait_all:

  • wait_all 栅栏:聚合节点是 DAG 的汇聚点,等所有上游互补子任务到达终态后才触发——即文章舆情案例里报告节点 mode=wait_all 等情感/趋势分析全部完成。本仓以「该种子下所有互补子任务均完成」作为 wait_all 条件(无活跃 pending|assigned|in_progress 互补子任务)。
  • 从共享池读取:聚合节点从 SwarmEnvironment.results(共享结果池)取出该种子下所有子任务的 task.result.files,不重新执行子任务。
  • LLM 整合成完整产物:把互补产出(各子任务的文件/片段)交 LLM 整合为一份完整、自洽的产物(代码:合并到一致的文件树并消解接口/依赖;文档:汇总成一篇)。这是「报告生成 Agent」职责的实现——master_agent.synthesize 作为汇总工具在此复用(仅文字汇总能力;代码整合的边界见 §7.5)。
  • 跑测试验证:整合后的完整产物跑 held-out / 共享测试(沙箱见下方门控)做验收,而不是对每个候选解分别打分选优。
  • 单次落 main:验证通过后,聚合产物一次性提交到产物仓 main,并发单一 artifact.created(见 §7.4 契约一致性)。

ResultAggregator 三职责映射:合并 = LLM 整合互补产出;按质量排序 = 仅在 §7.0「多解选优」次要路径下对可互换解排序;格式转换 = 把异构子产物归一为交付格式。主路径用「合并」,不用「排序选优」。

7.3 落 main 的单次提交

  • 聚合 + 验证通过 → orchestrator 把整合后的完整产物一次 push 到产物仓 main。
  • 全程无 per-agent 工作分支、无多分支后置 merge:子任务产出活在共享池,分支层面只有 main。
  • 失败隔离仍适用:个别互补子任务失败不必拖垮整个 run;聚合节点对已到达共享池的产出做整合,缺失部分按 tasks_completed / 冲突语义如实反映(不伪造,规则 #9)。

7.4 与冻结契约的一致性(FROZEN v1,不得违背)

聚合收敛流程完全落在现有冻结契约内,不新增/不改字段、类型、状态机:

  • 单一 artifact:聚合后只发一个 artifact.created(整合产物),扁平字段 {uri, checksum, task_id, size_bytes?, created_at} 不变。子任务中间产物不各发 artifact.created(它们在共享池里,不是交付物)。
  • sequence 递增:聚合相关回调沿用 per-swarm 严格递增 sequence,无空洞。
  • 状态机不变:聚合是 run 收敛前的内部步骤,不引入新 run/task 状态;终态仍由 §3 终止函数判定(completed/failed 语义不变)。
  • 13 类客户端事件冻结:聚合不新增客户端可见事件类型;wait_all/合并属内部编排,对客户端仅体现为既有 task.* 与最终 artifact.created + swarm.completed。

7.5 诚实差距(规则 #9,不主张未实现的)

  • 本节为目标模型:上述聚合收敛是按文章理念重写的协作聚合设计;与之相对,旧的 best-of-N 选优(queen.aggregate_run → score_candidates → select_best,winner 标 deliverable.selected)已废弃为主路径,仅在 §7.0「多解选优」次要语义下保留(同一原子任务多个可互换解时排序取胜出)。文档以聚合为主路径,不再把选优当作默认收口。
  • 代码整合非纯文字汇总:master_agent.synthesize 当前仅文字汇总;把互补代码子产物整合成一致文件树(消解接口/import/依赖冲突)是更强能力,列为后续实现,不冒充已完成。
  • 落 main 待端到端:聚合产物 push 到 main 需 orchestrator 的 git CLI + 凭据持久化打通,端到端待验证。
  • 测试沙箱门控:聚合后跑验证测试依赖沙箱隔离双门控(ENABLE_QUALITY_EVAL + HEICODE_SANDBOX_ISOLATED);未确认隔离则不执行测试、不伪造分数(unscored ≠ 0/100,规则 #9)。
  • convergence 全 authoritative(后续):让 ConvergenceReport.status 完全覆盖 run.status 动 Manager 终态语义,仍列为后续(同 §6)。
  • 防跨 run 抢夺(P0 / #8,保留):extract_swarm_from_agent / _agent_belongs_to_run——agent 只能竞争/认领自己 run 的 task;swarm_dispatch 过滤、handle_task_bid/yield/takeover 拒绝跨 run(cross_run_denied)。此为竞争路径的隔离保证,与聚合主路径并存。