From eff1522ec34209dcbecc659ce8aae812d0469def Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BB=9D=E5=B0=98?= <237809796@qq.com> Date: Wed, 1 Jul 2026 15:18:02 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E:=20=E5=A4=9AAgent=E5=B9=B6?= =?UTF-8?q?=E8=A1=8C=E6=89=A7=E8=A1=8C=E4=B8=8E=E4=BB=B2=E8=A3=81=E5=90=88?= =?UTF-8?q?=E5=B9=B6=E8=AE=BE=E8=AE=A1=E6=96=87=E6=A1=A3(P0=20Batch=2037-3?= =?UTF-8?q?8=20=E5=AE=9E=E6=96=BD=E4=BE=9D=E6=8D=AE)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 数据模型:混合方案(messages加FK列 + Plan/SubTask/Conflict独立表) - 并行策略:层间串行+层内并行,写SubTask降级串行,token预算池 - 上下文隔离:子Agent独立ContextManager+fork快照,合并产出落回主对话 - 事件协议:4个新事件(AiPlanCreated/AiSubTaskStatusChanged/AiMergeCompleted/AiConflictResolved) - UI交互:PlanProgress发送即展示+工具卡分组+冲突徽章非阻塞 - 状态机:Plan/SubTask/Conflict各自状态流转图 - 前端类型:PlanRecord/SubTaskRecord/ConflictRecord TypeScript定义 - INDEX.md注册 + Batch.md同步批次明细 --- Batch.md | 38 +- docs/02-架构设计/INDEX.md | 1 + .../多Agent并行执行与仲裁合并设计-2026-07-01.md | 478 ++++++++++++++++++ 3 files changed, 509 insertions(+), 8 deletions(-) create mode 100644 docs/02-架构设计/专项设计/多Agent并行执行与仲裁合并设计-2026-07-01.md diff --git a/Batch.md b/Batch.md index 3bcd3a6..9860c42 100644 --- a/Batch.md +++ b/Batch.md @@ -433,15 +433,37 @@ ## 后续规划批次(待推进) -### Batch 37 — 多 Agent 并行执行 -1. PlanExecutor JoinSet 真并行:process_tool_calls 内并行执行同层工具 -2. 子 Agent 调用链路:SubTask → 独立 agentic loop → 产出 + 错误传播 -3. DAG 进度实时更新:PlanProgress.vue 接入真实状态 +> 设计文档:[多Agent并行执行与仲裁合并设计-2026-07-01.md](docs/02-架构设计/专项设计/多Agent并行执行与仲裁合并设计-2026-07-01.md) -### Batch 38 — 仲裁合并 + 技术债 -1. Reviewer 仲裁合并:并行 Agent 产出冲突检测 + 合并建议 -2. 交互式审批:冲突 diff 展示供用户裁决 -3. 扫尾技术债:SMELL-P1-6 / 编译警告 / 注释清理 +### Batch 37 — 数据层 + 并行执行 + +| # | 任务 | 文件 | +|---|------|------| +| 1 | V36 迁移(ai_plans/ai_subtasks/ai_conflicts 3 新表 + ai_messages/ai_tool_executions 加 subtask_id 列) | migrations.rs | +| 2 | PlanRepo / SubTaskRepo / ConflictRepo CRUD | 新 repo 文件 | +| 3 | Coordinator.dispatch 改 JoinSet 层内并行(写 SubTask 降级串行) | coordinator.rs | +| 4 | Token 预算池(超限拒绝新 SubTask) | coordinator.rs | +| 5 | 子 Agent 独立 ContextManager + fork 快照(隔离上下文) | coordinator.rs | +| 6 | 4 个新事件类型(AiPlanCreated/AiSubTaskStatusChanged/AiMergeCompleted/AiConflictResolved) | AiChatEvent | +| 7 | PlanProgress 接入真实状态 + 发送即展示 | PlanProgress.vue | +| 8 | 工具卡按 subtask_id 折叠归组(带 persona 徽章) | MessageList.vue | +| 9 | 前端 PlanRecord/SubTaskRecord/ConflictRecord 类型 | api/types.ts | + +### Batch 38 — 仲裁合并 + UI 完善 + +| # | 任务 | 文件 | +|---|------|------| +| 1 | Coordinator.merge 冲突检测(按文件路径) | coordinator.rs | +| 2 | Reviewer Agent 仲裁(persona.rs 扩展) | persona.rs + coordinator.rs | +| 3 | 冲突 diff 展示 + resolution 按钮 | 新 ConflictResolver.vue | +| 4 | AiConflictResolved 事件闭环 | AiChatEvent | +| 5 | 技术债扫尾(编译警告 / unused import) | 各文件 | + +### Batch 39-40 — P1 模板系统 + Git/CI(远期) + +1. YAML 模板加载器 + SubflowNode +2. GitNode(分支/PR/合并) + DockerNode(容器构建/测试) +3. 从模板加载工作流 → Git 分支 → 代码生成 → PR → CI 全链路 --- diff --git a/docs/02-架构设计/INDEX.md b/docs/02-架构设计/INDEX.md index 845680d..2f72793 100644 --- a/docs/02-架构设计/INDEX.md +++ b/docs/02-架构设计/INDEX.md @@ -87,6 +87,7 @@ | [项目知识图谱与任务队列系统-2026-06-26.md](./专项设计/项目知识图谱与任务队列系统-2026-06-26.md) | 📐 设计 | 项目级知识图谱 + 任务队列:依赖解析 / 优先级调度 | | [工程系统设计-2026-06-29.md](./专项设计/工程系统设计-2026-06-29.md) | ✅ 已落地 | 项目多工程(Module) + Git 状态查询 + 文件浏览器 + Git AI 工具(只读3+写3) | | [架构债迁移设计-2026-06-29.md](./专项设计/架构债迁移设计-2026-06-29.md) | 📐 设计草案 | #8/#15/#18/#19 架构债迁移路径(AI状态机抽离/IPC错误结构化/配置统一/连接池) | +| [多Agent并行执行与仲裁合并设计-2026-07-01.md](./专项设计/多Agent并行执行与仲裁合并设计-2026-07-01.md) | 📐 设计 | P0 Batch 37-38 实施依据:混合数据模型(messages加FK列+Plan/SubTask/Conflict独立表)、JoinSet层内并行、Reviewer仲裁、事件协议、UI交互(PlanProgress+工具卡分组+冲突徽章) | --- diff --git a/docs/02-架构设计/专项设计/多Agent并行执行与仲裁合并设计-2026-07-01.md b/docs/02-架构设计/专项设计/多Agent并行执行与仲裁合并设计-2026-07-01.md new file mode 100644 index 0000000..86c6b45 --- /dev/null +++ b/docs/02-架构设计/专项设计/多Agent并行执行与仲裁合并设计-2026-07-01.md @@ -0,0 +1,478 @@ +# 多 Agent 并行执行与仲裁合并设计 — 2026-07-01 + +> 性质:架构设计 / 数据模型 / 事件协议 / UI 交互 +> 关联: [AI-Native方向与路线图-2026-06-29.md](../构想审查/AI-Native方向与路线图-2026-06-29.md)(P0 智能体人设 + 多 Agent 协作) +> 关联: [单对话并行多轮-设计-2026-06-20.md](../单对话并行多轮-设计-2026-06-20.md)(Plan DAG 结构与分层调度) +> 关联: [Agent架构说明-2026-06-14.md](Agent架构说明-2026-06-14.md)(当前 Agent 能力边界) +> 关联: [三层模型-流程模板与人设体系-2026-06-28.md](三层模型-流程模板与人设体系-2026-06-28.md)(模板/工作流/人设三层抽象) +> 用途:Batch 37-38 的实施依据 + +--- + +## 一、设计目标 + +DevFlow 的定位是 AI Native——AI 是系统的主要操作者,人的角色是「决策者 + 政策制定者」。 + +多 Agent 并行执行要解决的核心问题: + +| 问题 | 现状(单 Agent) | 多 Agent 后 | +|------|-----------------|------------| +| 复杂任务拆解 | LLM 自行在单轮内拆,上下文窗口受限 | Coordinator 拆为 SubTask,各自独立上下文 | +| 并行产出 | 串行,无冲突 | 多 Agent 同时改文件 → 数据竞争 | +| 用户感知 | 单条流式输出 | 多 Agent 产出交织,用户分不清谁是谁 | +| 错误恢复 | 一个工具失败 → LLM 下一轮决策 | 一个 SubTask 失败 → Coordinator 决定是否继续 | + +--- + +## 二、数据模型(方案 C:混合) + +### 2.1 设计原则 + +1. **messages 不膨胀** — 只加 `subtask_id` 外键列,不把 Plan/Conflict 字段塞进去 +2. **重实体独立** — Plan / SubTask / Conflict 各自独立表,各自演进 +3. **历史兼容** — `subtask_id = NULL` 表示单 Agent 时期消息,零回归 +4. **FK 三层链路** — messages → SubTask → Plan 可追溯完整生命周期 + +### 2.2 ER 图 + +```mermaid +erDiagram + ai_conversations ||--o{ ai_plans : "1:N 触发" + ai_plans ||--o{ ai_subtasks : "1:N 拆解" + ai_plans ||--o{ ai_conflicts : "1:N 冲突" + ai_subtasks ||--o{ ai_messages : "1:N 产出(subtask_id FK)" + ai_subtasks ||--o{ ai_tool_executions : "1:N 工具调用(subtask_id FK)" + ai_conflicts }o--|| ai_subtasks : "subtask_a" + ai_conflicts }o--|| ai_subtasks : "subtask_b" + + ai_plans { + TEXT id PK + TEXT conversation_id FK + TEXT user_message_id "触发 Plan 的用户消息" + TEXT status "planning/executing/merging/done/error" + INTEGER subtask_count + TEXT created_at + TEXT completed_at "可空" + } + + ai_subtasks { + TEXT id PK + TEXT plan_id FK + TEXT persona_id "coder/reviewer/architect/..." + TEXT intent "子任务意图描述" + TEXT status "pending/running/done/error" + INTEGER layer "DAG 层级(0起)" + TEXT deps "JSON 数组: 依赖的 SubTask id 列表" + TEXT created_at + TEXT completed_at "可空" + } + + ai_conflicts { + TEXT id PK + TEXT plan_id FK + TEXT file_path "冲突文件路径" + TEXT subtask_a FK + TEXT subtask_b FK + TEXT diff_a "Agent A 对该文件的改动摘要" + TEXT diff_b "Agent B 对该文件的改动摘要" + TEXT resolution "pending/a/b/merged/manual" + TEXT resolved_by "reviewer/user" + TEXT created_at + TEXT resolved_at "可空" + } +``` + +### 2.3 现有表改动 + +```sql +-- V36 迁移 +ALTER TABLE ai_messages ADD COLUMN subtask_id TEXT; +ALTER TABLE ai_tool_executions ADD COLUMN subtask_id TEXT; + +-- 新建 3 张表(见 ER 图字段) +CREATE TABLE ai_plans (...); +CREATE TABLE ai_subtasks (...); +CREATE TABLE ai_conflicts (...); +``` + +### 2.4 三层关联查询示例 + +```sql +-- 查某 Plan 的全部产出(消息 + 工具) +SELECT m.* FROM ai_messages m +JOIN ai_subtasks s ON m.subtask_id = s.id +WHERE s.plan_id = ?; + +-- 查某 Plan 的所有冲突 +SELECT c.* FROM ai_conflicts c WHERE c.plan_id = ? AND c.resolution = 'pending'; + +-- 查某对话的全部 Plan 历史 +SELECT p.* FROM ai_plans p WHERE p.conversation_id = ? ORDER BY created_at DESC; +``` + +--- + +## 三、事件协议 + +### 3.1 新增事件 + +| 事件 | 时机 | 载荷 | 前端响应 | +|------|------|------|---------| +| `AiPlanCreated` | Coordinator.decompose 完成后 | `{ plan_id, layers: [[{id, persona, intent, status}],...] }` | PlanProgress 展示 DAG | +| `AiSubTaskStatusChanged` | SubTask 状态变更(pending→running→done/error) | `{ subtask_id, plan_id, status, persona_id }` | PlanProgress 更新节点状态 + 工具卡分组徽章 | +| `AiMergeCompleted` | Coordinator.merge 完成后 | `{ plan_id, merged_output, conflicts: [{id, file, subtask_a, subtask_b}] }` | 展示合并结果 + 冲突徽章 | +| `AiConflictResolved` | 用户/reviewer 解决冲突后 | `{ conflict_id, resolution, resolved_by }` | 冲突徽章消失 + 最终输出更新 | + +### 3.2 事件流时序 + +``` +用户发送消息 + ↓ +AiPlanCreated { plan_id, layers } + ↓ (PlanProgress 立即展示) +Layer 0 启动 + ↓ +AiSubTaskStatusChanged { subtask_0, running } +AiSubTaskStatusChanged { subtask_1, running } ← 层内并行 + ↓ (工具卡片按 subtask_id 分组,带 persona 徽章) +AiSubTaskStatusChanged { subtask_0, done } +AiSubTaskStatusChanged { subtask_1, done } + ↓ +Layer 1 启动 ... + ↓ +AiMergeCompleted { plan_id, merged_output, conflicts } + ↓ (有冲突 → 冲突徽章;无冲突 → 直接展示合并输出) +用户点击冲突 → 展示 diff_a/diff_b → 选择 + ↓ +AiConflictResolved { conflict_id, resolution } + ↓ +最终输出展示 +``` + +--- + +## 四、并行执行策略 + +### 4.1 调度规则 + +``` +Plan.to_layers() → [[subtask_0, subtask_1], [subtask_2], [subtask_3, subtask_4]] + Layer 0(并行) Layer 1(串行) Layer 2(并行) +``` + +| 规则 | 说明 | +|------|------| +| 层间串行 | 上层全部 done 才进下一层(DAG 依赖保证) | +| 层内并行 | 同层 SubTask 用 JoinSet 并发执行 | +| **写 SubTask 降级串行** | 同层内如有 `write_file`/`patch_file` 工具的 SubTask,降级为串行执行,防 concurrent write | +| 只读 SubTask 并行 | `read_file`/`search_files`/`list_directory` 等只读工具的 SubTask 可安全并行 | + +### 4.2 Token 预算管控 + +```rust +struct TokenBudgetPool { + total: AtomicU64, // 全局预算(来自设置项) + consumed: AtomicU64, // 已消耗 +} + +impl TokenBudgetPool { + fn try_reserve(&self, estimate: u64) -> bool { + // CAS 循环:consumed + estimate <= total + } +} +``` + +- 每个 SubTask 启动前向预算池申请估算额度 +- 超限时 Coordinator 拒绝启动新 SubTask(降级为串行顺序执行剩余任务) +- 预算来源:设置项 `df-ai-plan-token-budget`(默认 100k tokens) + +### 4.3 错误传播 + +| 场景 | 策略 | +|------|------| +| SubTask 执行失败 | 记录 error 状态,**不中断其他同层 SubTask**(容错) | +| 全部 SubTask 失败 | Coordinator 标记 Plan 状态为 error,前端展示错误 | +| 部分 SubTask 失败 | merge 时跳过失败 SubTask 的产出,只合并成功的 | +| 子 Agent 超时 | 单 SubTask 超时(默认 120s)→ 标记 error,不影响其他 | + +--- + +## 五、UI 交互设计 + +### 5.1 PlanProgress 组件(发送即展示) + +``` +┌─────────────────────────────────────────┐ +│ 📋 执行计划 2/4 │ +├─────────────────────────────────────────┤ +│ Layer 1 │ +│ ▶ 🔵 [coder] 重构代码 running │ +│ 🟢 [architect] 分析结构 done │ +│ ↓ │ +│ Layer 2 │ +│ ⏸ [tester] 补测试 pending │ +│ ↓ │ +│ Layer 3 │ +│ ⏸ [reviewer] 审查 pending │ +└─────────────────────────────────────────┘ +``` + +- **发送即展示**:用户发消息后 Coordinator 分解完成立即展示 +- **实时更新**:AiSubTaskStatusChanged 驱动节点状态变化 +- **折叠工具卡**:每个 SubTask 下的工具卡片折叠归组(点击展开) +- **层间箭头**:DAG 层级关系可视化 + +### 5.2 工具卡片分组(subtask_id 归组) + +``` +┌─ 🔵 [coder·重构代码] ──────────────┐ +│ ▸ read_file main.rs ✓ done │ +│ ▸ patch_file utils.rs ✓ done │ +└────────────────────────────────────┘ +┌─ 🟢 [architect·分析结构] ──────────┐ +│ ▸ list_directory ✓ done │ +│ ▸ 分析结论: 模块耦合度偏高... │ +└────────────────────────────────────┘ +``` + +- 每个 SubTask 一个折叠容器,带 persona 颜色徽章 +- 工具卡片归入对应 SubTask 容器 +- 默认折叠,有审批/错误时自动展开 + +### 5.3 冲突展示(徽章非阻塞) + +``` +┌─────────────────────────────────────────┐ +│ ✅ 执行完成 ⚠ 2 处冲突待处理 │ +├─────────────────────────────────────────┤ +│ 合并输出: │ +│ ... │ +├─────────────────────────────────────────┤ +│ ⚠ main.rs — Agent A vs Agent B │ +│ [查看 diff] [接受 A] [接受 B] [手动] │ +│ ⚠ utils.rs — Agent A vs Agent B │ +│ [查看 diff] [接受 A] [接受 B] [手动] │ +└─────────────────────────────────────────┘ +``` + +- 冲突用**徽章**提示,不打断阅读流 +- 点击展开 diff 对比 + resolution 按钮 +- reviewer Agent 可自动给出推荐(`resolved_by=reviewer`),用户确认即可 + +--- + +## 六、取消与中断 + +| 操作 | 行为 | +|------|------| +| 用户点停止 | 停止所有并行 SubTask(整体取消) | +| 单 SubTask 超时 | 只标记该 SubTask error,不影响其他 | +| 会话切换 | 后台 SubTask 继续执行(F-09 并发语义一致) | +| 会话删除 | 所有关联 SubTask 停止 + Plan 标记 error | + +--- + +## 七、实施分批 + +### Batch 37 — 数据层 + 并行执行 + +| # | 任务 | 文件 | +|---|------|------| +| 1 | V36 迁移(3 新表 + 2 ALTER) | migrations.rs | +| 2 | PlanRepo / SubTaskRepo / ConflictRepo CRUD | 新 repo 文件 | +| 3 | Coordinator.dispatch JoinSet 层内并行 | coordinator.rs | +| 4 | 写 SubTask 降级串行 + token 预算池 | coordinator.rs | +| 5 | 4 个新事件类型 | AiChatEvent | +| 6 | PlanProgress 接入真实状态 | PlanProgress.vue | +| 7 | 工具卡按 subtask_id 分组 | MessageList.vue | + +### Batch 38 — 仲裁合并 + UI 完善 + +| # | 任务 | 文件 | +|---|------|------| +| 1 | Coordinator.merge 冲突检测(按文件路径) | coordinator.rs | +| 2 | Reviewer Agent 仲裁(persona.rs 扩展) | persona.rs + coordinator.rs | +| 3 | 冲突 diff 展示 + resolution 按钮 | 新 ConflictResolver.vue | +| 4 | AiConflictResolved 事件闭环 | AiChatEvent | +| 5 | 技术债扫尾(编译警告 / unused import) | 各文件 | + +--- + +## 八、子 Agent 上下文隔离 + +### 8.1 问题 + +多 Agent 并行执行时,每个 SubTask 需要独立的上下文(messages / currentText / tool_results)。 +如果共享主对话的 ContextManager,多个 SubTask 的产出会交织污染。 + +### 8.2 方案:子对话快照 + 独立 ContextManager + +```rust +struct SubTaskContext { + /// 从主对话 fork 的快照(只读父上下文 + 用户原始消息) + parent_snapshot: Vec, + /// 独立的 ContextManager(不写回主对话) + messages: ContextManager, + /// 分配的人设 + persona: AgentPersona, + /// 子任务 id(产出消息标记 subtask_id) + subtask_id: String, +} +``` + +**隔离规则**: + +| 维度 | 主对话 | 子 Agent | +|------|--------|---------| +| messages | 用户消息 + 合并产出 | fork 快照 + 独立执行轨迹 | +| ContextManager | 主对话的 | 每个 SubTask 独立实例 | +| pending_approvals | 主对话的 | 各 SubTask 独立(无并发写竞争) | +| tool_results | 写入子 Agent 的 messages | 合并时提取摘要写入主对话 | + +### 8.3 合并产出落回主对话 + +``` +SubTask 完成 → ExecutionResult { output, success } + ↓ +Coordinator.merge(results) → MergeResult { merged_output, conflicts } + ↓ +主对话 push 一条 assistant 消息(merged_output) + N 条冲突消息(conflicts[i]) +``` + +- **合并输出 = 单条 assistant 消息** — 不是把所有子 Agent 的消息都堆进主对话 +- **冲突 = 单独消息** — 每个冲突一条,带 `conflict_id` 供前端定位 +- **子 Agent 执行轨迹不落主对话** — 只在 ai_messages 表中保留(带 subtask_id),前端按需展开查看 + +--- + +## 九、前端类型定义 + +```typescript +// api/types.ts 新增 + +/** Plan 执行状态 */ +export type PlanStatus = 'planning' | 'executing' | 'merging' | 'done' | 'error' + +/** SubTask 执行状态 */ +export type SubTaskStatus = 'pending' | 'running' | 'done' | 'error' + +/** 冲突解决状态 */ +export type ConflictResolution = 'pending' | 'a' | 'b' | 'merged' | 'manual' + +/** Plan 记录 */ +export interface PlanRecord { + id: string + conversation_id: ConvId + user_message_id: MessageId + status: PlanStatus + subtask_count: number + created_at: string + completed_at: string | null +} + +/** SubTask 记录 */ +export interface SubTaskRecord { + id: string + plan_id: string + persona_id: string + intent: string + status: SubTaskStatus + layer: number + deps: string[] // JSON 解析后的数组 + created_at: string + completed_at: string | null +} + +/** 冲突记录 */ +export interface ConflictRecord { + id: string + plan_id: string + file_path: string + subtask_a: string + subtask_b: string + diff_a: string + diff_b: string + resolution: ConflictResolution + resolved_by: 'reviewer' | 'user' | null + created_at: string + resolved_at: string | null +} + +/** PlanProgress 展示用 DAG 层结构 */ +export interface PlanLayer { + items: Array<{ + id: string + persona: string + intent: string + status: SubTaskStatus + }> +} +``` + +--- + +## 十、状态机 + +### 10.1 Plan 状态流转 + +```mermaid +stateDiagram-v2 + [*] --> planning: Coordinator.decompose() + planning --> executing: Plan 写入 DB + emit AiPlanCreated + executing --> merging: 所有 SubTask done/error + merging --> done: merge 完成 + 无冲突 + merging --> done: 所有冲突已解决 + merging --> error: merge 失败 + executing --> error: 全部 SubTask 失败 + done --> [*] + error --> [*] +``` + +### 10.2 SubTask 状态流转 + +```mermaid +stateDiagram-v2 + [*] --> pending: Plan.decompose 创建 + pending --> running: dispatch 分配 + JoinSet 启动 + running --> done: agentic loop 收敛(无 tool_calls) + running --> error: 超时 / 全部工具失败 + done --> [*] + error --> [*] +``` + +### 10.3 Conflict 状态流转 + +```mermaid +stateDiagram-v2 + [*] --> pending: merge 检测到冲突 + pending --> resolved: reviewer 推荐 + 用户确认 + pending --> resolved: 用户手动选择 a/b/merged + resolved --> [*] +``` + +--- + +## 十一、事件总线集成 + +4 个新事件均走现有双写机制(`app_handle.emit` + `ai_event_bus.publish_event`), +与 AiToolCallStarted/AiCompleted 等关键状态变更事件一致: + +```rust +let ev = AiChatEvent::AiPlanCreated { ... }; +let _ = app_handle.emit("ai-chat-event", ev.clone()); +let _ = app_handle.state::().ai_event_bus.publish_event(ev); +``` + +- `emit`:桌面端前端监听 +- `publish_event`:tunnel subscriber 透传小程序 + +--- + +## 十二、不做的方向 + +| 方向 | 放弃理由 | 可能的时机 | +|------|---------|-----------| +| 工具级并行(同轮多 tool_call JoinSet) | 并发写 pending_approvals + LLM 对乱序 tool_result 行为不可预测 | 永不(LLM 已能单轮多 tool_call) | +| 单 SubTask 取消 | MVP 简化,整体取消即可 | P1 以后按需 | +| 双栏 diff 对比 UI | 违背 AI Native 定位(让用户做 AI 该做的合并) | 永不(reviewer Agent 仲裁替代) | +| SubTask 级审批门控 | 审批在工具级(RiskLevel)已足够 | P2 审批政策配置 |