24 KiB
feat: Agent 间结构化辩论协作
日期: 2026-06-24
状态: active
范围: Deep — feature
Origin: docs/brainstorms/2026-06-24-agent-debate-collaboration-requirements.md
Summary
在 @team 多 Agent 协作模式中引入"Lead 主导的结构化辩论"能力。当前专家隔离执行、无互动,本计划让 Lead 能在关键决策点发起辩论(指定专家交锋→裁决),支持自动检测分歧触发 + 用户手动触发。同时修复 CLI 完全缺失多 Agent 入口的问题,并顺带补齐 @team 执行期间的用户干预通道(当前无 /stop)。
Problem Frame
当前 TeamOrchestrator(src/agentkit/experts/orchestrator.py)是 hub-and-spoke 模式:Lead 分解任务 → 专家隔离执行 → Lead 汇总。HandoffTransport 只做事件广播,专家间无通信通道。用户反馈"体现不出多 Agent 协同"——本质是"并行单 Agent"而非协作。
同时存在三个已知缺口:
ExecutionMode.TEAM_COLLAB是死代码(src/agentkit/chat/skill_routing.py:35,全代码库无产生点)- CLI 完全没有多 Agent 入口(
src/agentkit/cli/chat.py不处理@team/@board前缀) @team执行期间无用户干预通道(ExpertTeam.broadcast_user_message()方法存在但TeamOrchestrator.execute()从不检查)
Requirements
源自 docs/brainstorms/2026-06-24-agent-debate-collaboration-requirements.md:
- R1: 用户在
@team任务执行中,能看到专家间就某个分歧点来回辩论(不是各自独立发言) - R2: Lead 能自动检测专家产出间的冲突/分歧,并触发辩论
- R3: 用户能在执行期间手动请求就某个点发起辩论
- R4: 辩论有明确收敛:Lead 裁决,产出喂给下一阶段
- R5: CLI 用户能使用
@team/@board,且能触发辩论 - R6: 简单任务可以跳过辩论,不强制增加延迟
Key Technical Decisions
KTD1: 辩论作为 DEBATE 阶段类型,而非独立编排器
在 PlanPhase 上新增 phase_type 字段(EXECUTION | DEBATE),而非创建独立的 DebateOrchestrator。辩论阶段复用现有流水线的拓扑排序、依赖管理、SharedWorkspace 机制。
理由:最小架构改动。辩论阶段与其他阶段一样有 depends_on,只是执行逻辑不同。避免引入第二套编排引擎导致状态管理分裂。
代价:TeamOrchestrator._execute_phase() 需要按 phase_type 分派,增加一个分支。可接受。
KTD2: 辩论执行逻辑借鉴 BoardOrchestrator,但不复用其类
BoardOrchestrator(src/agentkit/experts/board_orchestrator.py)已实现"成员并行发言→主持人小结"的多轮循环。辩论阶段借鉴这个模式(Lead 开场→专家轮流发言→Lead 裁决),但作为 TeamOrchestrator._execute_debate_phase() 方法内联,不实例化 BoardOrchestrator。
理由:BoardOrchestrator 绑定 BoardTeam(独立容器、独立历史、独立状态机),强行复用会引入两套状态同步。内联一个方法比桥接两个编排器简单。
KTD3: 用户干预通道复用 ExpertTeam.broadcast_user_message() + 新增 WS 消息类型
ExpertTeam 已有 broadcast_user_message() 方法(src/agentkit/experts/team.py:253),但 TeamOrchestrator.execute() 从不检查。方案:
- WS 新增
team_intervention消息类型,chat.py收到后调用team.broadcast_user_message() TeamOrchestrator在阶段边界检查干预队列(与BoardOrchestrator检查consume_user_interventions()一致)- 干预消息可以是
/stop(停止团队)、/debate <topic>(触发辩论)、或普通文本(追加上下文)
理由:复用已有方法,不引入新队列。与 BoardOrchestrator 的干预检查模式一致,降低认知成本。
KTD4: 分歧检测作为 Lead 的 LLM 判断,带"是否值得辩论"的明确标准
自动触发不依赖复杂的一致性算法,而是 Lead 在阶段完成后用 LLM 判断"该阶段产出是否与其他阶段/约束冲突,是否值得辩论"。Prompt 给出明确判断标准(见 U3)。
理由:YAGNI——不引入冲突检测框架。LLM 判断够用,误报由"跳过辩论"逃生舱兜底。若不可靠,降级为纯手动触发(需求文档已记录此假设)。
KTD5: CLI 复用 ExpertTeamRouter/BoardRouter + Rich 渲染
CLI 在 chat.py 的 chat loop 中,于 skill routing 之前拦截 @team/@board 前缀,复用 Web 侧的 ExpertTeamRouter.resolve() 和 BoardRouter.resolve()。辩论过程用 Rich 的 Panel + 不同颜色渲染专家发言。
理由:路由逻辑已存在,CLI 只需接入。不重复实现前缀解析。
High-Level Technical Design
辩论阶段在流水线中的位置
Lead 分解任务 → phases[]
├── [可选] 方案评审辩论 (DEBATE phase, depends_on: 无, 在执行前)
│ Lead 开场 → 专家质疑方案 → Lead 修订 → 产出"确认的方案"
│
├── 执行阶段 A (EXECUTION phase)
├── 执行阶段 B (EXECUTION phase, depends_on: A)
│
├── [自动] 决策点辩论 (DEBATE phase, depends_on: B, Lead 检测分歧后动态插入)
│ Lead 陈述分歧 → 专家 A/B 交锋 → Lead 裁决 → 产出"辩论结论"
│
└── 执行阶段 C (EXECUTION phase, depends_on: 辩论结论)
辩论阶段执行流程(内联于 TeamOrchestrator)
_execute_debate_phase(phase, plan):
1. 解析 phase.debate_config: {topic, participants, max_rounds}
2. Lead 开场:陈述分歧点 + 上下文 → broadcast debate_started
3. for round in 1..max_rounds:
a. 检查用户干预(/stop 则提前结束)
b. 参与专家并行发言(基于历史 + 角色)→ broadcast expert_argument
c. Lead 小结本轮 → broadcast debate_round_summary
4. Lead 裁决:采纳/折中/搁置 → broadcast debate_resolved
5. 结论写入 SharedWorkspace ({plan_id}/phase/{phase_id}/output)
6. phase.status = COMPLETED
用户干预通道数据流
Web 用户 → WS message {type: "team_intervention", content: "/debate 前端框架选型"}
→ chat.py _handle_chat_message 检测团队执行中
→ team.broadcast_user_message(content)
→ TeamOrchestrator 在阶段边界检查 team.consume_user_interventions()
→ 识别 /debate 命令 → 动态插入 DEBATE phase
CLI 用户 → 输入 /debate 前端框架选型
→ cli/chat.py 检测团队执行中
→ team.broadcast_user_message(content)
→ 同上
Implementation Units
U1. 数据模型:PhaseType 枚举 + PlanPhase 扩展
Goal: 为 PlanPhase 增加 phase_type 字段和辩论配置,使流水线能区分执行阶段和辩论阶段。
Requirements: 支撑 R1, R4
Dependencies: 无
Files:
src/agentkit/experts/plan.py(修改)tests/unit/experts/test_plan.py(新建或修改)
Approach:
- 新增
PhaseType(str, enum.Enum):EXECUTION = "execution",DEBATE = "debate" PlanPhase新增字段:phase_type: PhaseType = PhaseType.EXECUTION(默认执行,向后兼容)debate_config: dict[str, Any] | None = None(辩论阶段专用:topic,participants: list[str],max_rounds: int = 2)
to_dict()/from_dict()序列化新字段topological_sort()无需改动(辩论阶段也有depends_on,与其他阶段一视同仁)
Patterns to follow: 现有 PlanPhase 的 dataclass + enum 模式(src/agentkit/experts/plan.py)
Test scenarios:
- Happy path: 创建
DEBATE类型 phase,序列化/反序列化后字段保留 - 向后兼容: 不带
phase_type的旧 dict 反序列化后默认为EXECUTION - 边界:
debate_config为 None 时不影响 EXECUTION 阶段 - 拓扑排序: 混合 EXECUTION + DEBATE 阶段的依赖图能正确分层
Verification: pytest tests/unit/experts/test_plan.py -x -q 通过
U2. 辩论阶段执行器(TeamOrchestrator)
Goal: 在 TeamOrchestrator 中实现辩论阶段的执行逻辑,借鉴 BoardOrchestrator 的多轮发言模式。
Requirements: R1, R4, R6
Dependencies: U1
Files:
src/agentkit/experts/orchestrator.py(修改)tests/unit/experts/test_orchestrator_debate.py(新建)
Approach:
_execute_phase()入口按phase.phase_type分派:EXECUTION→ 现有_execute_phase()逻辑(重命名为_execute_execution_phase())DEBATE→ 新增_execute_debate_phase()
_execute_debate_phase(phase, plan):- 从
phase.debate_config解析 topic/participants/max_rounds - Lead 开场(LLM 生成,陈述分歧点)→ emit
debate_started - 循环 max_rounds 轮:
- 检查
team.consume_user_interventions()(/stop 提前结束) - 参与专家并行发言(LLM 生成,基于历史 + 角色 prompt)→ emit
expert_argument - Lead 小结 → emit
debate_round_summary
- 检查
- Lead 裁决(LLM 生成,JSON:
decision,rationale,conclusion)→ emitdebate_resolved - 结论写入 SharedWorkspace,
phase.status = COMPLETED
- 从
- 辩论 prompt 借鉴
BoardOrchestrator._generate_expert_speech()的角色注入模式(persona + thinking_style + speaking_style + history) - 逃生舱:
debate_config可设skip: true,或 Lead 判断"无分歧"时直接跳过(phase.status = COMPLETED, result = "无需辩论")
Technical design (directional):
async def _execute_debate_phase(self, phase: PlanPhase, plan: TeamPlan) -> dict[str, Any]:
config = phase.debate_config or {}
topic = config.get("topic", phase.task_description)
participants = config.get("participants", [])
max_rounds = min(config.get("max_rounds", 2), 4) # 硬上限 4 轮
# Lead 开场
lead = self._team.lead_expert
opening = await self._generate_debate_opening(lead, topic, phase)
await self._broadcast_event("debate_started", {...})
history = [{"expert": lead.config.name, "content": opening, "round": 0}]
for round_num in range(1, max_rounds + 1):
# 检查用户干预
interventions = self._team.consume_user_interventions()
if self._has_stop_command(interventions):
break
# 参与专家并行发言
experts = [self._team.get_expert(name) for name in participants if self._team.get_expert(name)]
speeches = await asyncio.gather(
*[self._generate_debate_argument(e, topic, history, round_num) for e in experts],
return_exceptions=True,
)
for expert, speech in zip(experts, speeches):
if not isinstance(speech, Exception):
history.append({"expert": expert.config.name, "content": speech, "round": round_num})
await self._broadcast_event("expert_argument", {...})
# Lead 小结
summary = await self._generate_debate_summary(lead, topic, history, round_num)
history.append({"expert": lead.config.name, "content": summary, "round": round_num})
await self._broadcast_event("debate_round_summary", {...})
# Lead 裁决
verdict = await self._generate_debate_verdict(lead, topic, history)
await self._broadcast_event("debate_resolved", {...})
# 写入 SharedWorkspace
result = {"content": verdict.get("conclusion", ""), "verdict": verdict}
phase.status = PhaseStatus.COMPLETED
phase.result = result
return result
Patterns to follow:
BoardOrchestrator._generate_expert_speech()的角色 prompt 模式(src/agentkit/experts/board_orchestrator.py:268)BoardOrchestrator._has_stop_command()的停止命令检查(src/agentkit/experts/board_orchestrator.py:486)TeamOrchestrator._broadcast_event()的事件广播模式
Test scenarios:
- Happy path: 2 轮辩论,2 个专家参与,Lead 裁决产出结论,phase 状态变为 COMPLETED
- 边界: max_rounds=1 时只辩论一轮就裁决
- 边界: participants 为空时,Lead 直接给出结论(无辩论)
- 用户停止: 辩论中收到 /stop,提前结束并裁决
- 逃生舱:
debate_config.skip=true时直接跳过,phase 状态 COMPLETED,result="无需辩论" - 错误路径: LLM 不可用时,Lead 用模板文本裁决,不抛异常
- 集成: 辩论结论写入 SharedWorkspace,后续 EXECUTION 阶段能读取
Verification: pytest tests/unit/experts/test_orchestrator_debate.py -x -q 通过
U3. 分歧检测 + 方案评审辩论(自动触发)
Goal: Lead 在阶段完成后自动检测分歧,动态插入辩论阶段;在分解任务后可选发起方案评审辩论。
Requirements: R2, R6
Dependencies: U1, U2
Files:
src/agentkit/experts/orchestrator.py(修改)tests/unit/experts/test_divergence_detection.py(新建)
Approach:
- 新增
_detect_divergence(lead, completed_phase, plan) -> bool:- Lead 用 LLM 判断该阶段产出是否与其他已完成阶段冲突,或是否存在多个可行方案
- Prompt 给出明确标准:"以下情况值得辩论:1) 两个阶段产出矛盾 2) 阶段产出与任务约束冲突 3) 存在多个合理方案。其他情况返回 false。"
- LLM 不可用或判断失败时返回 false(宁可漏报不误报)
execute()主循环修改:每层执行完成后,对每个 completed phase 运行分歧检测,若 true 则动态插入一个DEBATEphase(depends_on指向该 phase),加入下一层- 方案评审辩论(可选):
_decompose_task()返回 phases 后,Lead 判断"该任务是否需要方案评审",若需要则在 phases 头部插入一个DEBATEphase(topic="方案评审", participants=所有成员, depends_on=[]) - 跳过逻辑:
MAX_DEBATES = 3限制单次执行最多插入 3 个辩论阶段(防止成本失控);简单任务(phases <= 2)默认跳过方案评审
Patterns to follow: TeamOrchestrator._decompose_task() 的 LLM prompt + JSON 解析模式
Test scenarios:
- Happy path: 两个阶段产出矛盾,分歧检测返回 true,自动插入辩论阶段
- Happy path: 阶段产出一致,分歧检测返回 false,不插入辩论
- 边界: phases <= 2 时跳过方案评审
- 边界: 已插入 3 个辩论后不再插入(MAX_DEBATES 上限)
- 错误路径: LLM 不可用时分歧检测返回 false
- 集成: 插入的辩论阶段能被
topological_sort()正确分层,后续阶段能依赖辩论结论
Verification: pytest tests/unit/experts/test_divergence_detection.py -x -q 通过
U4. 用户干预通道 + 手动辩论触发(WS + CLI 共用)
Goal: 建立 @team 执行期间的用户干预通道,支持 /stop、/debate <topic>、普通文本追加上下文。
Requirements: R3, R5
Dependencies: U1, U2
Files:
src/agentkit/experts/team.py(修改:补齐干预队列,参考 BoardTeam 模式)src/agentkit/server/routes/chat.py(修改:_execute_team_collab增加 WS 干预消息处理)src/agentkit/cli/chat.py(修改:团队执行期间拦截/debate、/stop命令)tests/unit/experts/test_team_intervention.py(新建)
Approach:
ExpertTeam补齐干预队列(参考BoardTeam的add_user_intervention()/consume_user_interventions(),src/agentkit/experts/board.py):_interventions: asyncio.Queue(bounded, maxsize=64)add_user_intervention(msg: str)/consume_user_interventions() -> list[str]broadcast_user_message()已存在,改为同时入队干预队列
- WS 侧(
chat.py _execute_team_collab):- 团队执行期间,
_handle_chat_message收到的消息若来自当前 session,识别为干预 - 新增 WS 消息类型
team_intervention,或复用message类型 + session 匹配 - 调用
team.add_user_intervention(content)
- 团队执行期间,
- CLI 侧(
cli/chat.py):- 团队执行期间,用户输入以
/开头时识别为命令:/stop、/debate <topic> - 调用
team.add_user_intervention(content)
- 团队执行期间,用户输入以
TeamOrchestrator在阶段边界(每层执行前 + 辩论每轮前)检查consume_user_interventions():/stop→ 终止执行,走 fallback/debate <topic>→ 动态插入 DEBATE phase- 其他文本 → 追加到 Lead 上下文(影响后续分解/裁决)
Patterns to follow:
BoardTeam.add_user_intervention()/consume_user_interventions()(src/agentkit/experts/board.py)BoardOrchestrator._has_stop_command()(src/agentkit/experts/board_orchestrator.py:486)
Test scenarios:
- Happy path: 用户发送
/debate 前端框架选型,团队在下一阶段边界插入辩论 - Happy path: 用户发送
/stop,团队终止执行并走 fallback - Happy path: 用户发送普通文本,Lead 在后续裁决中参考
- 边界: 干预队列为空时
consume_user_interventions()返回空列表 - 边界: 多条干预消息累积,一次性消费
- 集成: WS 干预消息能从
chat.py传到ExpertTeam再到TeamOrchestrator
Verification: pytest tests/unit/experts/test_team_intervention.py -x -q 通过
U5. 前端辩论可视化
Goal: 前端展示辩论过程,专家交锋有独立气泡样式,裁决结果清晰可见。
Requirements: R1
Dependencies: U1, U2, U4
Files:
src/agentkit/server/frontend/src/stores/chat.ts(修改:处理新事件)src/agentkit/server/frontend/src/components/chat/(修改:辩论气泡组件)src/agentkit/server/frontend/src/types/chat.ts(修改:新增辩论事件类型)
Approach:
- 新增 WS 事件类型声明:
debate_started、expert_argument、debate_round_summary、debate_resolved chat.ts事件处理(参考现有expert_step/expert_result处理,约第 870-1200 行):debate_started: 显示"辩论开始"分隔线 + 分歧主题expert_argument: 专家发言气泡,带"辩论中"标签和轮次标记debate_round_summary: Lead 小结,缩进显示debate_resolved: 裁决结果,高亮显示(采纳/折中/搁置 + 理由)
- 辩论气泡与普通专家发言气泡视觉区分:边框颜色/图标不同
- 用户干预入口:团队执行期间,ChatInput 显示"辩论"按钮(发送
/debate命令)
Patterns to follow:
- 现有
expert_step/expert_result事件处理模式(src/agentkit/server/frontend/src/stores/chat.ts) - 现有专家气泡组件样式(
src/agentkit/server/frontend/src/components/chat/)
Test scenarios:
- Happy path: 收到
debate_started后显示辩论分隔线和主题 - Happy path: 收到
expert_argument后显示带轮次标记的专家辩论气泡 - Happy path: 收到
debate_resolved后高亮显示裁决结果 - 边界: 辩论中 WebSocket 断开,已显示的辩论内容保留
- 集成: 团队执行期间点击"辩论"按钮,发送
/debate命令
Verification: npm run typecheck 通过;手动验证辩论过程可视化
U6. CLI 多 Agent 入口 + 辩论支持
Goal: CLI 支持 @team/@board 前缀触发多 Agent 协作,辩论过程用 Rich 渲染。
Requirements: R5
Dependencies: U1, U2, U4
Files:
src/agentkit/cli/chat.py(修改)tests/unit/cli/test_chat_multiagent.py(新建)
Approach:
- chat loop 中,在 skill routing 之前拦截
@team/@board前缀:- 复用
ExpertTeamRouter.resolve()/BoardRouter.resolve()解析前缀 - 构建
ExpertTeam/BoardTeam(复用 Web 侧逻辑,但不经过 WS) - 注册事件回调:用 Rich 渲染而非 WS 广播
- 复用
- 事件渲染(Rich):
team_formed: Panel 显示团队成员phase_started/expert_step: 带颜色的专家名 + 任务expert_result: Markdown 渲染专家产出debate_started: 分隔线 + "辩论: {topic}"expert_argument: 带轮次标记的专家发言 Panel(不同专家不同颜色)debate_resolved: 高亮裁决结果 Panelteam_synthesis: 最终结果 Markdown 渲染
- 团队执行期间,用户输入
/debate//stop走干预通道(U4) - 帮助文本(
_print_help)补充@team/@board说明
Patterns to follow:
- 现有 CLI chat loop 的 Rich 渲染模式(
src/agentkit/cli/chat.py) BoardOrchestrator的事件广播模式(改为回调而非 WS)
Test scenarios:
- Happy path: 输入
@team 开发登录功能,CLI 显示团队组建 + 阶段执行 + 最终结果 - Happy path: 输入
@board 讨论微服务 vs 单体,CLI 显示多轮讨论 + 总结 - Happy path: 团队执行中输入
/debate 前端框架,CLI 显示辩论过程 - Happy path: 团队执行中输入
/stop,CLI 显示终止 + fallback 结果 - 边界:
@team无任务描述时提示用法 - 边界: 专家名称不存在时提示错误
- 集成: CLI
@team流程能触发自动分歧检测和辩论(U3)
Verification: pytest tests/unit/cli/test_chat_multiagent.py -x -q 通过
Scope Boundaries
包含
DEBATE阶段类型及执行器- Lead 分歧检测(自动触发)
- 用户干预通道(手动触发 +
/stop) - 前端辩论可视化
- CLI
@team/@board入口 + 辩论支持 - "跳过辩论"逃生舱
不包含
- Agent 间点对点自由通信(保持 Lead 主导)
@board模式改造(它已是讨论模式)- 团队状态持久化(独立问题)
- 辩论成本优化(缓存、早停等,先验证价值)
ExecutionMode.TEAM_COLLAB死代码清理(顺手可做,非核心交付)
延后到后续工作
- 方向 C 全量(辩论优先作为默认模式):先验证 A+C 混合价值
- 自定义团队模板保存:用户选的专家组合无法存为模板
orchestrator/子系统与团队流程打通- 辩论成本预算阈值(token 上限触发跳过)
Risks & Dependencies
风险
- 分歧检测质量:Lead LLM 判断失误(误报浪费 token,漏报错过辩论)。缓解:明确判断标准 prompt +
MAX_DEBATES上限 + 用户可关闭自动触发。 - 辩论不收敛:专家反复争论。缓解:硬上限 4 轮 + Lead 强制裁决权。
- 成本上升:辩论增加 token 消耗。缓解:逃生舱 +
MAX_DEBATES=3+ 简单任务跳过方案评审。 - CLI 交互复杂度:终端展示多 Agent 辩论不如 Web 直观。缓解:Rich Panel + 颜色区分 + 轮次标记。
- WS 干预消息与正常消息混淆:团队执行期间用户消息可能被当新任务。缓解:session 匹配 +
team_intervention消息类型显式区分。
依赖
- U1 是所有后续单元的基础(数据模型)
- U2 依赖 U1(辩论执行器需要 DEBATE 阶段类型)
- U3 依赖 U1 + U2(分歧检测需要插入 DEBATE phase)
- U4 依赖 U1 + U2(手动触发需要干预通道 + 辩论执行器)
- U5 依赖 U1 + U2 + U4(前端需要新事件 + 干预入口)
- U6 依赖 U1 + U2 + U4(CLI 需要路由 + 辩论 + 干预)
Open Questions
以下问题留给实现阶段,不阻塞规划:
debate_config的确切 JSON schema(participants是专家名列表还是 Expert 对象?倾向名字列表,执行时解析)- WS
team_intervention消息的确切格式(是复用message类型 + flag,还是新类型?倾向新类型,显式优于隐式) - 前端辩论气泡的具体样式(边框颜色、轮次标记位置)——实现时对齐现有专家气泡风格
- CLI 辩论渲染是否用
Live动态更新还是逐条打印——倾向逐条打印(辩论是离散事件,不需要流式)
System-Wide Impact
- 后端:
experts/模块(plan.py, orchestrator.py, team.py)+server/routes/chat.py+cli/chat.py - 前端:
stores/chat.ts+components/chat/+types/chat.ts - 测试: 新增 4 个测试文件
- 配置: 无新配置项(辩论参数通过
debate_config在运行时传递) - 文档: AGENTS.md 的 ExecutionMode 描述需更新(TEAM_COLLAB 死代码清理可顺手做)
Sources & Research
- 需求文档:
docs/brainstorms/2026-06-24-agent-debate-collaboration-requirements.md - 现有团队流水线:
src/agentkit/experts/orchestrator.py - 现有私董会讨论引擎(借鉴模式):
src/agentkit/experts/board_orchestrator.py - 现有阶段/计划模型:
src/agentkit/experts/plan.py - WS 拦截入口:
src/agentkit/server/routes/chat.py(_execute_team_collab第 321 行) - CLI chat(当前无多 Agent):
src/agentkit/cli/chat.py - 前端事件处理:
src/agentkit/server/frontend/src/stores/chat.ts(第 870-1200 行)