501 lines
24 KiB
Markdown
501 lines
24 KiB
Markdown
# 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"而非协作。
|
||
|
||
同时存在三个已知缺口:
|
||
1. `ExecutionMode.TEAM_COLLAB` 是死代码(`src/agentkit/chat/skill_routing.py:35`,全代码库无产生点)
|
||
2. CLI 完全没有多 Agent 入口(`src/agentkit/cli/chat.py` 不处理 `@team`/`@board` 前缀)
|
||
3. `@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)`:
|
||
1. 从 `phase.debate_config` 解析 topic/participants/max_rounds
|
||
2. Lead 开场(LLM 生成,陈述分歧点)→ emit `debate_started`
|
||
3. 循环 max_rounds 轮:
|
||
- 检查 `team.consume_user_interventions()`(/stop 提前结束)
|
||
- 参与专家并行发言(LLM 生成,基于历史 + 角色 prompt)→ emit `expert_argument`
|
||
- Lead 小结 → emit `debate_round_summary`
|
||
4. Lead 裁决(LLM 生成,JSON: `decision`, `rationale`, `conclusion`)→ emit `debate_resolved`
|
||
5. 结论写入 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):
|
||
```python
|
||
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 则动态插入一个 `DEBATE` phase(`depends_on` 指向该 phase),加入下一层
|
||
- 方案评审辩论(可选):`_decompose_task()` 返回 phases 后,Lead 判断"该任务是否需要方案评审",若需要则在 phases 头部插入一个 `DEBATE` phase(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`: 高亮裁决结果 Panel
|
||
- `team_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
|
||
|
||
### 风险
|
||
|
||
1. **分歧检测质量**:Lead LLM 判断失误(误报浪费 token,漏报错过辩论)。缓解:明确判断标准 prompt + `MAX_DEBATES` 上限 + 用户可关闭自动触发。
|
||
2. **辩论不收敛**:专家反复争论。缓解:硬上限 4 轮 + Lead 强制裁决权。
|
||
3. **成本上升**:辩论增加 token 消耗。缓解:逃生舱 + `MAX_DEBATES=3` + 简单任务跳过方案评审。
|
||
4. **CLI 交互复杂度**:终端展示多 Agent 辩论不如 Web 直观。缓解:Rich Panel + 颜色区分 + 轮次标记。
|
||
5. **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 行)
|