---
title: "feat: AgentKit Phase 9 — Integrated Next-Stage Plan"
status: active
created: 2026-06-12
plan-type: feat
depth: deep
origin: "整合 017/018/019/021 活跃计划剩余工作 + 本次会话发现的新问题"
---

# feat: AgentKit Phase 9 — Integrated Next-Stage Plan

## Summary

整合全部活跃计划的剩余工作，形成统一的下一阶段实施计划。核心目标：完成对话响应速度优化（sub-1s 首 Token）、补齐安全加固和劣势项改进的遗漏项、实现拍卖机制和智能并行工具执行。

**来源计划完成度：**

| 计划 | 完成度 | 剩余项 |
|------|--------|--------|
| 020 Pipeline 对抗闭环 | ~100% | 验证测试覆盖度 |
| 017 Multi-Agent Marketplace | ~90% | U9 拍卖机制 |
| 018 P2 安全加固 | ~90% | U6 配置热重载防御性修复 |
| 019 劣势项改进 | ~70% | U4 集成测试、U5 ReWOO 回退链配置化 |
| 021 响应速度优化 | ~60% | U2 合并路由 LLM 调用、U6 Chat 管线优化 |

**本次会话新增修复（已完成）：**
- 确认卡片死锁修复（`pending_confirmations or {}` → `if is not None`）
- Shell 白名单扩展（30 → 90+ 命令，管道智能检测）
- SkillInstallTool 新增（Agent 可正确安装技能）
- 前端技能列表自动刷新

## Problem Frame

当前 AgentKit 存在三个核心问题：

1. **对话响应仍不够快**：启发式分类器已消除路由层 LLM 调用，但当启发式不确定时仍走独立 IntentRouter LLM 调用；Chat 管线中每次消息新建 ReActEngine、串行 Session I/O 等仍有优化空间
2. **安全加固和测试覆盖有缺口**：配置热重载的线程安全问题、ReWOO 回退链不可配置、集成测试覆盖不足
3. **拍卖机制未实现**：Multi-Agent Marketplace 的核心经济模型缺失

## Scope Boundaries

### In Scope

- 021-U2: 合并路由 LLM 调用（complexity + intent 单次 LLM）
- 021-U6: Chat 管线优化（ReActEngine 复用、Session 操作并行化）
- 智能并行工具执行（LLM 标注可并行性，自动判断）
- 018-U6: 配置热重载防御性修复
- 019-U4: 集成测试补充
- 019-U5: ReWOO 回退链配置化
- 017-U9: 拍卖机制实现
- 流式首 Token 前端渲染优化

### Out of Scope

- 分布式消息总线（Redis 实现，后续按需）
- jieba 分词集成（可选依赖，后续按需）
- UI 可视化 trace（Jaeger/Zipkin 前端，运维配置）
- Headroom 检索优化（013，独立计划）
- 分层记忆系统（016，独立计划）

### Deferred to Follow-Up Work

- LLM Provider 级别 Prompt 缓存（需 LLM API 支持）
- 上下文压缩策略异步化（当前截断方案足够）
- 轻量模型自动降级（需 A/B 测试验证质量）

---

## Requirements

| ID | Requirement | Priority | Origin |
|----|-------------|----------|--------|
| R1 | 启发式分类器不确定时，complexity + intent 合并为单次 LLM 调用 | P0 | 021-U2 |
| R2 | Chat 管线中 ReActEngine 实例复用，避免每次消息重建 | P0 | 021-U6 |
| R3 | 多 tool_calls 时由 LLM 标注可并行性，自动并行执行独立工具 | P1 | 新需求 |
| R4 | 配置热重载线程安全，非 asyncio 线程调用不触发竞态 | P1 | 018-U6 |
| R5 | ReWOO 回退链可从 YAML 配置，不硬编码 | P1 | 019-U5 |
| R6 | 关键路径集成测试覆盖：路由链、ReWOO 回退、对抗闭环 | P1 | 019-U4 |
| R7 | 拍卖机制：Agent 竞标任务，基于能力+成本+历史质量评分 | P2 | 017-U9 |
| R8 | 前端流式首 Token 即渲染，不等 final_answer | P2 | 021-P1 |
| R9 | 所有改动有配置开关，可秒级回退 | P0 | 全局 |

---

## Key Technical Decisions

### KTD1: 合并路由 LLM 调用 — 单次 LLM 同时输出 complexity + intent

当 `HeuristicClassifier` 返回 `complexity=0.5`（不确定区间）时，不再分别调用 `quick_classify()` 和 `IntentRouter._classify_with_llm()`，而是发起一次 LLM 调用，prompt 要求同时输出：

```json
{"complexity": 0.7, "intent": "code_generation", "skill_hint": "react_agent"}
```

这比两次独立 LLM 调用节省 1-3s。LLM 的 structured output 能力确保格式可靠。

**Fallback**：若 LLM 返回格式异常，按 `complexity=0.5` 走默认 Agent。

### KTD2: 智能并行工具执行 — LLM 在 tool_calls 中标注 `parallelizable`

在 `ReActEngine` 的 system prompt 中指示 LLM：当返回多个 tool_calls 时，在每个 tool_call 的 `_metadata` 中标注 `"parallelizable": true/false`。ReActEngine 收集所有 `parallelizable=true` 的工具，用 `asyncio.gather` 并行执行；`parallelizable=false` 或未标注的串行执行。

**为什么不用纯规则判断**：工具间的依赖关系是语义级的（如"先搜索再分析"），规则无法可靠判断。让 LLM 标注是最准确的方案。

**安全网**：`parallel_tools` 配置仍保留，设为 `"auto"` 时启用智能判断，设为 `true` 时全部并行，设为 `false` 时全部串行。

### KTD3: ReActEngine 复用 — Agent 级别持有实例

在 `AgentPool.create_agent()` 中创建 `ReActEngine` 实例并绑定到 Agent 对象。`_handle_chat_message` 从 Agent 获取已有实例而非每次新建。每次调用 `execute_stream()` 前重置内部状态（对话历史、step count）。

**为什么不用全局单例**：不同 Agent 可能有不同的 `max_steps`、`parallel_tools` 配置，需要实例隔离。

### KTD4: 拍卖机制 — Vickrey 拍卖 + 能力匹配

采用 Vickrey（次价）拍卖模型：Agent 提交密封标价（bid = cost_estimate），出价最低者赢得任务，但支付第二低价。结合能力匹配过滤不合格竞标者。

**为什么选 Vickrey**：激励相容——Agent 的最优策略是如实报告成本，不需要策略性报价。比英式拍卖更简单，比固定分配更高效。

### KTD5: 配置热重载线程安全 — asyncio.run_coroutine_threadsafe

`_on_config_change` 从 `watchfiles` 线程调用时，通过 `asyncio.run_coroutine_threadsafe()` 将重载操作调度到事件循环，避免在非 asyncio 线程中直接操作 asyncio 对象。

---

## High-Level Technical Design

### 路由合并流程

```mermaid
flowchart TD
    A[用户消息] --> B{HeuristicClassifier}
    B -->|complexity < 0.3| C[Layer 0: 默认 Agent]
    B -->|0.3 <= complexity <= 0.7| D[合并 LLM 调用: complexity + intent]
    B -->|complexity > 0.7| E[Layer 2: 能力匹配]
    D -->|有 skill_hint| F[路由到指定 Skill]
    D -->|无 skill_hint| C
    D -->|LLM 格式异常| C
    E -->|匹配成功| G[路由到最佳 Agent]
    E -->|无匹配| F
```

### 智能并行工具执行

```mermaid
flowchart TD
    A[LLM 返回 tool_calls] --> B{parallel_tools 配置}
    B -->|false| C[全部串行执行]
    B -->|true| D[全部并行执行]
    B -->|auto| E[检查每个 tool_call 的 parallelizable 标注]
    E --> F[parallelizable=true 的工具 asyncio.gather 并行]
    E --> G[parallelizable=false 或未标注的串行执行]
    F --> H[合并结果，按 tool_call_id 排序]
    G --> H
```

### 拍卖机制

```mermaid
sequenceDiagram
    participant Client
    participant Auctioneer
    participant Agent1
    participant Agent2

    Client->>Auctioneer: 提交任务
    Auctioneer->>Agent1: 广播任务需求
    Auctioneer->>Agent2: 广播任务需求
    Agent1->>Auctioneer: 提交标价 (bid=0.3)
    Agent2->>Auctioneer: 提交标价 (bid=0.5)
    Auctioneer->>Auctioneer: Vickrey 拍卖: 赢家=Agent1, 支付=0.5
    Auctioneer->>Agent1: 分配任务 (payment=0.5)
    Agent1->>Auctioneer: 返回结果
    Auctioneer->>Client: 返回结果
```

---

## Implementation Units

### U1. 合并路由 LLM 调用

**Goal:** 当 HeuristicClassifier 不确定时，将 complexity 评估和 intent 分类合并为单次 LLM 调用，消除路由层的第二次 LLM 调用。

**Requirements:** R1, R9

**Dependencies:** None

**Files:**
- `src/agentkit/chat/skill_routing.py` — 新增 `MergedRouter` 类
- `src/agentkit/chat/skill_routing.py` — 修改 `CostAwareRouter._route_layer1()` 使用合并调用
- `tests/unit/test_cost_aware_router.py` — 新增测试
- `configs/agentkit.yaml` — 新增 `router.merged_llm_classify: true` 配置

**Approach:**
1. 在 `CostAwareRouter` 中新增 `_classify_merged()` 方法，构建单次 LLM prompt 要求同时输出 complexity + intent + skill_hint
2. 修改 `_route_layer1()`：当 `HeuristicClassifier` 返回不确定区间（0.3-0.7）时，调用 `_classify_merged()` 而非分别调用 `quick_classify()` 和 `IntentRouter._classify_with_llm()`
3. LLM 返回格式：`{"complexity": float, "intent": str, "skill_hint": str|null}`，使用 JSON mode 确保格式可靠
4. Fallback：LLM 格式异常时按 `complexity=0.5` 走默认 Agent
5. 配置开关：`router.merged_llm_classify: true`（默认），设为 false 时回退到独立调用

**Patterns to follow:** `HeuristicClassifier` 的配置开关模式（`classifier` 参数），`IntentRouter._classify_with_llm()` 的 LLM 调用模式

**Test scenarios:**
- 合并调用返回有效 JSON，正确路由到指定 skill
- 合并调用返回格式异常，fallback 到默认 Agent
- 合并调用返回 complexity < 0.3，走 Layer 0
- 合并调用返回 complexity > 0.7，走 Layer 2
- 配置 `merged_llm_classify: false` 时回退到独立调用
- 合并调用超时，fallback 到默认 Agent

**Verification:** 启用 `merged_llm_classify` 后，不确定区间的路由只产生 1 次 LLM 调用（而非 2 次）

---

### U2. Chat 管线优化

**Goal:** ReActEngine 实例复用 + Session 操作并行化，减少每次消息的初始化和 I/O 开销。

**Requirements:** R2, R9

**Dependencies:** None

**Files:**
- `src/agentkit/core/agent_pool.py` — Agent 创建时绑定 ReActEngine 实例
- `src/agentkit/server/routes/chat.py` — 从 Agent 获取已有 ReActEngine
- `src/agentkit/core/react.py` — 新增 `reset()` 方法重置内部状态
- `tests/unit/test_chat_routes.py` — 新增测试
- `tests/unit/test_react_engine.py` — 新增 `test_reset` 测试

**Approach:**
1. 在 `ReActEngine` 中新增 `reset()` 方法，清空内部对话历史、step count、cancellation token
2. 在 `AgentPool.create_agent()` 中创建 `ReActEngine` 实例并绑定到 `agent._react_engine`
3. 修改 `_handle_chat_message()`：从 `agent._react_engine` 获取实例，调用 `reset()` 后执行
4. 若 Agent 无 `_react_engine`（向后兼容），仍新建实例
5. Session 操作：`append_message` 的 user message 和 assistant message 可并行写入（两者无依赖）

**Patterns to follow:** `AgentPool.create_agent()` 的 Agent 初始化模式

**Test scenarios:**
- ReActEngine.reset() 清空内部状态后可正常执行
- 连续两次 execute_stream() 调用互不干扰
- Agent 无 _react_engine 时向后兼容新建实例
- Session 并行写入后 get_messages() 返回完整消息列表

**Verification:** 连续发送 10 条消息，ReActEngine 实例 ID 保持不变

---

### U3. 智能并行工具执行

**Goal:** LLM 在 tool_calls 中标注可并行性，ReActEngine 自动判断并行/串行执行。

**Requirements:** R3, R9

**Dependencies:** None

**Files:**
- `src/agentkit/core/react.py` — 修改 `_execute_loop()` 中的工具执行逻辑
- `src/agentkit/core/react.py` — 修改 system prompt 指示 LLM 标注 parallelizable
- `tests/unit/test_react_engine.py` — 新增并行测试
- `configs/agentkit.yaml` — `parallel_tools` 支持 `"auto"` 值

**Approach:**
1. 修改 `parallel_tools` 参数类型为 `bool | str`，支持 `True`/`False`/`"auto"`
2. 在 ReActEngine 的 system prompt 中添加指引：当返回多个 tool_calls 时，在每个 tool_call 的 arguments 中包含 `_parallelizable: true/false`
3. `_execute_loop()` 中：
   - `parallel_tools=True` → 全部 `asyncio.gather`
   - `parallel_tools=False` → 全部串行
   - `parallel_tools="auto"` → 收集 `parallelizable=true` 的工具并行执行，其余串行
4. 执行顺序：先执行所有串行工具（按顺序），再并行执行所有可并行工具
5. 结果按 `tool_call_id` 顺序追加到对话历史

**Patterns to follow:** 现有 `asyncio.gather` 并行执行模式（`parallel_tools=True` 分支）

**Test scenarios:**
- `parallel_tools="auto"` + LLM 标注 2 个 parallelizable=true → 并行执行
- `parallel_tools="auto"` + LLM 标注 1 个 true 1 个 false → 串行先执行，再并行
- `parallel_tools="auto"` + LLM 未标注 parallelizable → 全部串行（安全默认）
- `parallel_tools=True` → 忽略标注，全部并行
- `parallel_tools=False` → 忽略标注，全部串行
- 并行执行结果按 tool_call_id 顺序追加

**Verification:** 发送需要多工具的消息，观察日志中的执行顺序和耗时

---

### U4. 配置热重载防御性修复

**Goal:** 修复配置热重载的线程安全问题，确保非 asyncio 线程调用不触发竞态。

**Requirements:** R4, R9

**Dependencies:** None

**Files:**
- `src/agentkit/server/app.py` — 修改 `_on_config_change()` 使用 `asyncio.run_coroutine_threadsafe()`
- `src/agentkit/server/app.py` — 添加 shell proc.kill() 错误处理
- `tests/unit/test_app_lifecycle.py` — 新增测试

**Approach:**
1. `_on_config_change()` 从 watchfiles 线程调用时，通过 `asyncio.run_coroutine_threadsafe(_async_reload_config(app, config), loop)` 调度到事件循环
2. 新增 `_async_reload_config()` 异步方法，包含原重载逻辑
3. 添加 `_config_reload_lock` 的线程安全版本（`threading.Lock` + `asyncio.Lock` 双锁）
4. shell proc.kill() 添加 try/except ProcessLookupError

**Patterns to follow:** `asyncio.run_coroutine_threadsafe()` 模式

**Test scenarios:**
- 从非 asyncio 线程触发配置变更，重载正常完成
- 并发配置变更，只有一个生效（锁保护）
- proc.kill() 时进程已退出，不抛异常
- 配置变更后 LLM Gateway 正确重建

**Verification:** 修改 agentkit.yaml 后观察日志，确认重载在事件循环中执行

---

### U5. ReWOO 回退链配置化

**Goal:** ReWOO 的 fallback 策略可从 YAML 配置，不硬编码。

**Requirements:** R5, R9

**Dependencies:** None

**Files:**
- `src/agentkit/core/rewoo.py` — `FALLBACK_STRATEGIES` 改为从配置读取
- `configs/skills/rewoo_agent.yaml` — 新增 `fallback_strategies` 字段
- `tests/unit/test_rewoo_engine.py` — 新增测试

**Approach:**
1. `ReWOOEngine.__init__()` 接受 `fallback_strategies: list[str]` 参数，默认 `["simplified_rewoo", "react", "direct"]`
2. Skill YAML 中新增 `fallback_strategies` 字段，覆盖默认值
3. `_plan_phase()` 失败时按配置的策略顺序尝试 fallback
4. 支持的策略名：`simplified_rewoo`、`react`、`direct`、`plan_exec`

**Patterns to follow:** `SkillConfig` 的字段扩展模式

**Test scenarios:**
- 默认 fallback 链：simplified_rewoo → react → direct
- 自定义 fallback 链：plan_exec → react → direct
- 空 fallback 链：直接抛异常
- 无效策略名：跳过并警告

**Verification:** 修改 rewoo_agent.yaml 的 fallback_strategies，重启后观察日志

---

### U6. 集成测试补充

**Goal:** 补充关键路径的集成测试，保障其他模块改动的回归安全。

**Requirements:** R6

**Dependencies:** U1, U2, U3

**Files:**
- `tests/integration/test_router_engine_chain.py` — 路由→引擎全链路测试
- `tests/integration/test_rewoo_fallback.py` — ReWOO 回退链测试
- `tests/integration/test_parallel_tools.py` — 并行工具执行测试
- `tests/integration/test_merged_router.py` — 合并路由测试

**Approach:**
1. 路由链测试：用户消息 → HeuristicClassifier → 合并 LLM 调用 → Skill 匹配 → ReActEngine 执行 → 结果
2. ReWOO 回退测试：Planning 失败 → simplified_rewoo → react → direct
3. 并行工具测试：LLM 返回多个 tool_calls + parallelizable 标注 → 验证执行顺序
4. 合并路由测试：不确定区间消息 → 单次 LLM 调用 → 正确路由

**Patterns to follow:** 现有 `tests/integration/test_react_loop.py` 模式

**Test scenarios:**
- 路由链：问候语 → Layer 0 直达；代码问题 → 合并 LLM → react_agent
- ReWOO 回退：mock LLM Planning 失败 → 验证 fallback 执行
- 并行工具：2 个 parallelizable=true 工具 → 验证并行执行（耗时 < 串行）
- 合并路由：不确定消息 → 验证只产生 1 次 LLM 调用

**Verification:** `pytest tests/integration/ -v` 全部通过

---

### U7. 拍卖机制实现

**Goal:** 实现 Vickrey 拍卖模型，Agent 竞标任务，基于能力+成本+历史质量评分。

**Requirements:** R7

**Dependencies:** None

**Files:**
- `src/agentkit/marketplace/auction.py` — 新增 `Auctioneer`、`Bid`、`AuctionResult` 类
- `src/agentkit/marketplace/wealth.py` — 新增 `WealthTracker` 类
- `src/agentkit/chat/skill_routing.py` — `CostAwareRouter._route_layer2()` 集成拍卖
- `configs/agentkit.yaml` — 新增 `router.auction_enabled: true` 配置
- `tests/unit/test_auction.py` — 新增测试

**Approach:**
1. `Bid` 数据类：agent_id、cost_estimate、capability_score、quality_history
2. `Auctioneer` 类：
   - `announce_task(task_desc, required_capabilities)` → 广播给合格 Agent
   - `submit_bid(bid)` → 收集标价
   - `resolve_auction()` → Vickrey 拍卖：最低价者赢，支付第二低价
   - 能力过滤：先按 `required_capabilities` 过滤不合格竞标者
3. `WealthTracker` 类：跟踪每个 Agent 的累计收入/支出，用于后续经济分析
4. 集成到 `CostAwareRouter._route_layer2()`：当 `auction_enabled=True` 且有多个候选 Agent 时，发起拍卖
5. 拍卖超时：默认 5s，超时后按最低价直接分配

**Patterns to follow:** `CostAwareRouter` 的三层路由模式，`org_context.find_best_agent()` 的能力匹配模式

**Test scenarios:**
- 单一竞标者 → 直接分配，支付 0
- 两个竞标者 → Vickrey 拍卖，低价者赢，支付第二低价
- 竞标者能力不匹配 → 过滤掉，不参与拍卖
- 拍卖超时 → 按已有标价分配
- 无竞标者 → fallback 到 IntentRouter
- WealthTracker 正确累计收入/支出

**Verification:** 配置 `auction_enabled: true`，发送高复杂度消息，观察拍卖日志

---

### U8. 流式首 Token 前端渲染

**Goal:** 前端收到首个 token 即开始渲染，不等 final_answer，降低感知延迟。

**Requirements:** R8

**Dependencies:** U2

**Files:**
- `src/agentkit/server/static/index.html` — 修改 WebSocket 消息处理逻辑
- `src/agentkit/core/react.py` — 流式事件增加 `is_final` 标记

**Approach:**
1. 当前前端收到 `token` 事件时已经在渲染文本（`currentAgentBubble.textContent += msg.content`），但 LLM 决定调工具时需要"收回"已渲染的 token
2. 新增 `thinking` 事件类型：LLM 的思考过程（如 "Let me search for..."），前端渲染为灰色斜体
3. `token` 事件仅在 LLM 直接回答时发送（不调工具时）
4. 当 LLM 决定调工具时，发送 `tool_call` 事件，前端将 thinking 文本替换为工具调用卡片
5. `final_answer` 事件标记 `is_final: true`，前端完成渲染

**关键 UX 决策**：不在 LLM 可能调工具时渲染 token，避免"文字闪烁消失"问题。只在确认是最终回答时才渲染 token 流。

**Patterns to follow:** 现有 `token` / `final_answer` 事件处理模式

**Test scenarios:**
- LLM 直接回答 → token 流式渲染，无闪烁
- LLM 先思考再调工具 → thinking 渲染为灰色，工具调用显示为卡片
- LLM 思考后直接回答 → thinking 后接 token 流式渲染
- 多轮工具调用 → 每轮工具调用显示为步骤卡片

**Verification:** 发送需要工具调用的消息，观察前端渲染无闪烁

---

## Risks & Mitigations

| Risk | Impact | Mitigation |
|------|--------|------------|
| 合并 LLM 调用格式不稳定 | 路由失败，走 fallback | JSON mode + 严格 schema 校验 + fallback 到默认 Agent |
| 智能并行工具执行依赖误判 | 工具结果错误 | `parallel_tools="auto"` 默认保守（未标注=串行）；`true` 模式需显式启用 |
| 拍卖机制增加路由延迟 | 高复杂度任务响应更慢 | 拍卖超时 5s；单竞标者时跳过拍卖直接分配 |
| ReActEngine 复用状态泄漏 | 上下文串扰 | `reset()` 方法严格清空所有内部状态；每次执行前强制调用 |
| 流式渲染闪烁 | 用户体验差 | 只在确认不调工具时渲染 token；thinking 阶段渲染为灰色 |

---

## System-Wide Impact

- **路由层**：`skill_routing.py` 变更最大（合并 LLM + 拍卖集成）
- **引擎层**：`react.py` 变更（智能并行 + reset），`rewoo.py` 变更（配置化回退）
- **服务层**：`chat.py` 变更（ReActEngine 复用），`app.py` 变更（热重载修复）
- **前端**：`index.html` 变更（流式渲染优化）
- **新增模块**：`marketplace/auction.py`、`marketplace/wealth.py`

---

## Open Questions

- 拍卖机制的 `cost_estimate` 如何计算？当前 Agent 无自省能力，可能需要基于历史执行时间统计
- `parallel_tools="auto"` 的 LLM 标注格式是否需要与 OpenAI function calling 兼容？当前 `_parallelizable` 字段放在 arguments 中可能被 LLM 忽略
- 流式渲染的 thinking 文本是否需要持久化到 Session？当前不持久化，重载后丢失

---

## Acceptance Examples

- AE1: 发送一般问题，首 Token 在 1s 内出现（当前 3-5s）
- AE2: 发送需要多工具的消息，工具并行执行，总耗时 < 串行执行
- AE3: 修改 rewoo_agent.yaml 的 fallback_strategies，重启后生效
- AE4: 配置 auction_enabled: true，高复杂度任务触发拍卖日志
- AE5: 修改 agentkit.yaml 后服务自动重载，无异常日志
