430 lines
16 KiB
Markdown
430 lines
16 KiB
Markdown
```yaml
|
||
title: "refactor: AgentKit 架构优化演进 — 对齐业界最佳实践"
|
||
status: active
|
||
plan_id: "2026-06-16-006"
|
||
created: 2026-06-16
|
||
depth: deep
|
||
origin: "基于对 Codex/Claude Code/Trae/Qoder 的深入分析,优化 AgentKit 架构"
|
||
```
|
||
|
||
# AgentKit 架构优化演进计划
|
||
|
||
## Summary
|
||
|
||
基于对 Codex CLI、Claude Code、Trae Agent 2.0、Qoder 的深入分析,对 AgentKit 进行架构优化演进。核心变更:(1) 消除"路由"概念改为请求预处理,(2) 专家团从去中心化协作简化为 hub-and-spoke,(3) PlanExec 简化为 Spec-Driven 模式,(4) 聊天记录 SQLite 持久化,(5) 删除旧路由层代码,(6) 新增可验证执行和工具描述精简。
|
||
|
||
## Problem Frame
|
||
|
||
AgentKit 当前架构存在三类问题:
|
||
|
||
1. **概念误导**:SimpleRouter 仍暗示"路由层"存在,但实际只做 @skill 前缀解析 + greeting fast-path,核心决策已交给 REACT agent loop 中的 LLM
|
||
2. **过度设计**:ExpertTeam 的去中心化协作(CollaborationPlan + HandoffTransport + SharedWorkspace + 3 种 MergeStrategy)远超业界实践,增加 ~1500 行代码但无对应价值
|
||
3. **能力缺口**:PlanExecEngine 默认使用 _LLMStepExecutor(纯 LLM 调用无工具),聊天记录不持久化,无自动验证循环
|
||
|
||
## Requirements
|
||
|
||
- R1: 消除"路由"概念,SimpleRouter 重命名为 RequestPreprocessor,语义从"路由决策"变为"请求预处理"
|
||
- R2: 专家团简化为 hub-and-spoke 模式(Lead Expert + 并行 Task,深度=1),删除 CollaborationPlan/HandoffTransport/SharedWorkspace 的 ExpertTeam 专用逻辑
|
||
- R3: PlanExecEngine 默认使用 ReActStepExecutor,删除 _LLMStepExecutor
|
||
- R4: 聊天记录 SQLite 持久化(参考 Codex 的 Thread 持久化)
|
||
- R5: 删除 CostAwareRouter 及相关代码(HeuristicClassifier、IntentRouter、QualityGate、SemanticRouter)
|
||
- R6: 新增可验证执行(Test-and-Verify 循环,参考 Codex Cloud)
|
||
- R7: 工具描述分层注入(核心工具全量 + 扩展工具一行描述 + tool_search 按需获取)
|
||
- R8: 默认启用上下文压缩
|
||
- R9: 新增 Spec 文档作为一等公民(参考 Qoder Quest Mode)
|
||
- R10: 统一事件模型(SQ/EQ 双队列,参考 Codex)
|
||
|
||
## Key Technical Decisions
|
||
|
||
### KTD1: SimpleRouter 重命名为 RequestPreprocessor
|
||
|
||
**决策**:将 SimpleRouter 重命名为 RequestPreprocessor,route() 方法重命名为 preprocess()
|
||
|
||
**依据**:
|
||
- Codex 无路由层,Claude Code 无路由层,Trae 移除了 Proposal 阶段——业界共识是没有路由层
|
||
- SimpleRouter 的 3 个功能(@skill 前缀、greeting regex、default REACT)都是预处理而非路由决策
|
||
- "路由"概念误导开发者认为存在意图预测层,实际上 LLM 在 agent loop 中自主决策
|
||
|
||
**替代方案**:完全删除 SimpleRouter,所有请求直接进入 REACT loop。被否决——greeting fast-path 每次请求节省 ~100 tokens + 500ms,@skill 前缀是用户显式指令需要代码级解析
|
||
|
||
### KTD2: 专家团 hub-and-spoke 模式
|
||
|
||
**决策**:ExpertTeam 从去中心化协作简化为 Lead Expert + 并行 Task(深度=1)
|
||
|
||
**依据**:
|
||
- Claude Code:Task 工具深度=1,子 Agent 不能再生子 Agent
|
||
- Codex:spawn_agent 层级式,结果返回父 Agent
|
||
- Qoder:多专家并行独立执行,主 Agent 汇总
|
||
- 去中心化协作的通信复杂度 O(N²),hub-and-spoke 为 O(N)
|
||
- 同一 LLM 扮演不同"专家"不产生真正的观点多样性,等价于多次采样+合并
|
||
|
||
**保留**:ExpertConfig/ExpertTemplate/Registry(定义专家 persona)、BEST 合并策略(Lead Agent 选择最佳结果)
|
||
|
||
**删除**:CollaborationPlan 的 phase 依赖图、HandoffTransport 的 Agent 间通信、SharedWorkspace 的跨阶段状态共享、VOTE/FUSION 合并策略
|
||
|
||
### KTD3: PlanExec 默认 ReActStepExecutor + Spec-Driven
|
||
|
||
**决策**:默认使用 ReActStepExecutor(已实现),删除 _LLMStepExecutor;新增 Spec 文档持久化
|
||
|
||
**依据**:
|
||
- _LLMStepExecutor 不支持工具调用 = 没有执行能力
|
||
- ReActStepExecutor 已实现并使用 ReActEngine,支持工具调用和多步推理
|
||
- Qoder Quest Mode:Spec First 是人和 AI 的契约,用户确认后再执行
|
||
- 当前 PlanExec 的计划对用户不可见,用户无法在执行前纠正方向
|
||
|
||
### KTD4: 聊天记录 SQLite 持久化
|
||
|
||
**决策**:使用 SQLite 做聊天记录持久化(参考 Codex 的 Thread 持久化)
|
||
|
||
**依据**:
|
||
- Codex 使用 SQLite(轻量、零配置、跨平台),支持 resume/fork/archive
|
||
- Claude Code 使用 append-only JSONL(更简单但搜索能力弱)
|
||
- 当前 ConversationStore 纯内存,服务重启后丢失
|
||
- SQLite 支持会话搜索、分页加载,且无需额外服务
|
||
|
||
---
|
||
|
||
## Implementation Units
|
||
|
||
### U1. SimpleRouter 重命名为 RequestPreprocessor
|
||
|
||
**Goal**: 消除"路由"概念,将 SimpleRouter 重命名为 RequestPreprocessor
|
||
|
||
**Dependencies**: 无
|
||
|
||
**Files**:
|
||
- `src/agentkit/chat/simple_router.py` → 重命名为 `src/agentkit/chat/request_preprocessor.py`
|
||
- `src/agentkit/chat/skill_routing.py` — 更新引用
|
||
- `src/agentkit/server/routes/portal.py` — 更新 import 和调用
|
||
- `src/agentkit/server/routes/chat.py` — 更新 import 和调用
|
||
- `src/agentkit/server/app.py` — 更新 import 和调用
|
||
- `tests/unit/chat/test_simple_router.py` → 重命名并更新
|
||
|
||
**Approach**:
|
||
1. 创建 `request_preprocessor.py`,类名 `RequestPreprocessor`,方法 `route()` → `preprocess()`
|
||
2. `_is_direct_chat()` 重命名为 `_is_trivial_input()`
|
||
3. `SkillRoutingResult` 保留(它是数据结构,不涉及路由概念)
|
||
4. 更新所有调用点
|
||
5. 删除旧文件
|
||
|
||
**Patterns to follow**: 现有 SimpleRouter 的代码结构
|
||
|
||
**Test scenarios**:
|
||
- @skill:xxx 前缀正确解析为 SKILL_REACT 模式
|
||
- Greeting regex 匹配返回 DIRECT_CHAT
|
||
- 默认输入返回 REACT 模式
|
||
- 未知 skill 回退到 REACT
|
||
- preprocess() 方法签名与 route() 兼容
|
||
|
||
**Verification**: `ruff check src/ && pytest tests/unit/chat/ -v`
|
||
|
||
---
|
||
|
||
### U2. 删除 CostAwareRouter 及相关代码
|
||
|
||
**Goal**: 删除已被 SimpleRouter 替代的旧路由层代码
|
||
|
||
**Dependencies**: U1
|
||
|
||
**Files**:
|
||
- `src/agentkit/router/` 目录下大部分文件(保留 __init__.py 和必要的导出)
|
||
- `src/agentkit/server/app.py` — 清理注释掉的引用
|
||
- `src/agentkit/chat/cost_aware_router.py` — 删除
|
||
|
||
**Approach**:
|
||
1. 确认 CostAwareRouter 在代码中无活跃引用(app.py 已注释)
|
||
2. 删除 `cost_aware_router.py`、`heuristic_classifier.py`、`intent.py`(IntentRouter)、`quality_gate.py`、`semantic_router.py`
|
||
3. 保留 `router/__init__.py` 导出必要的类型(如 ExecutionMode,如果前端依赖)
|
||
4. 清理 app.py 中的注释引用
|
||
5. 更新 `router/` 目录的 `__init__.py`
|
||
|
||
**Test scenarios**:
|
||
- 删除后 `ruff check` 无错误
|
||
- `pytest -m "not integration"` 全部通过
|
||
- 无 import 错误
|
||
|
||
**Verification**: `ruff check src/ && pytest -m "not integration" -x`
|
||
|
||
---
|
||
|
||
### U3. 专家团简化为 hub-and-spoke
|
||
|
||
**Goal**: 将 ExpertTeam 从去中心化协作简化为 Lead Expert + 并行 Task 模式
|
||
|
||
**Dependencies**: 无(可与 U1/U2 并行)
|
||
|
||
**Files**:
|
||
- `src/agentkit/experts/orchestrator.py` — 重写为 hub-and-spoke
|
||
- `src/agentkit/experts/team.py` — 简化,移除 CollaborationPlan 依赖
|
||
- `src/agentkit/experts/plan.py` — 简化,保留 MergeStrategy.BEST
|
||
- `src/agentkit/core/handoff_transport.py` — 移除 ExpertTeam 专用逻辑
|
||
- `src/agentkit/core/shared_workspace.py` — 移除 ExpertTeam 专用逻辑
|
||
- `src/agentkit/experts/router.py` — 简化为 @team 前缀 + RequestPreprocessor 集成
|
||
- `tests/unit/experts/test_orchestrator.py` — 更新
|
||
|
||
**Approach**:
|
||
1. 重写 TeamOrchestrator:Lead Expert 自主规划 + 并行 spawn Task
|
||
2. 删除 CollaborationPlan 的 phase 依赖图,Lead Expert 自主决定执行顺序
|
||
3. 删除 HandoffTransport 的 Agent 间通信,Task 结果直接返回 Lead Expert
|
||
4. 删除 SharedWorkspace 的跨阶段状态共享,Lead Expert 持有所有状态
|
||
5. 保留 MergeStrategy.BEST(Lead Agent 选择最佳结果),删除 VOTE/FUSION
|
||
6. 简化 ExpertTeamRouter 为 @team 前缀触发
|
||
7. 保留 ExpertConfig/ExpertTemplate/Registry 不变
|
||
|
||
**Technical design**:
|
||
|
||
```
|
||
新 TeamOrchestrator 流程:
|
||
1. 用户输入 → @team:xxx 前缀 → ExpertTeamMode
|
||
2. Lead Expert 接收任务,自主分解为子任务
|
||
3. 并行 spawn Task(每个 Task 是独立 ReActEngine 实例)
|
||
4. 等待所有 Task 完成
|
||
5. Lead Expert 汇总结果(BEST 策略)
|
||
6. 返回最终结果
|
||
|
||
约束:
|
||
- Task 深度=1(Task 不能再 spawn Task)
|
||
- Task 之间无通信
|
||
- Lead Expert 持有所有状态
|
||
```
|
||
|
||
**Test scenarios**:
|
||
- Lead Expert 正确分解任务为子任务
|
||
- 并行 Task 独立执行并返回结果
|
||
- Lead Expert 汇总结果
|
||
- 单个 Task 失败不影响其他 Task
|
||
- 所有 Task 失败时回退到 Lead Expert 单独执行
|
||
- @team 前缀正确触发 ExpertTeamMode
|
||
|
||
**Verification**: `ruff check src/ && pytest tests/unit/experts/ -v`
|
||
|
||
---
|
||
|
||
### U4. PlanExec 默认 ReActStepExecutor + 删除 _LLMStepExecutor
|
||
|
||
**Goal**: PlanExecEngine 默认使用 ReActStepExecutor,删除 _LLMStepExecutor
|
||
|
||
**Dependencies**: 无
|
||
|
||
**Files**:
|
||
- `src/agentkit/core/plan_exec_engine.py` — 删除 _LLMStepExecutor 和 _LLMStepAgent,默认 step_executor_type="react"
|
||
- `tests/unit/core/test_plan_exec_engine.py` — 更新
|
||
|
||
**Approach**:
|
||
1. 删除 `_LLMStepExecutor` 和 `_LLMStepAgent` 类
|
||
2. `_create_executor()` 方法移除 step_executor_type 参数,始终使用 ReActStepExecutor
|
||
3. 清理相关 import
|
||
|
||
**Test scenarios**:
|
||
- PlanExecEngine 默认创建 ReActStepExecutor
|
||
- ReActStepExecutor 正确执行带工具调用的步骤
|
||
- 步骤失败时触发重规划
|
||
|
||
**Verification**: `ruff check src/ && pytest tests/unit/core/test_plan_exec_engine.py -v`
|
||
|
||
---
|
||
|
||
### U5. 聊天记录 SQLite 持久化
|
||
|
||
**Goal**: 使用 SQLite 持久化聊天记录,服务重启后不丢失
|
||
|
||
**Dependencies**: U1(RequestPreprocessor 重命名完成后更新调用点)
|
||
|
||
**Files**:
|
||
- `src/agentkit/chat/sqlite_conversation_store.py` — 新建
|
||
- `src/agentkit/server/routes/portal.py` — 替换 ConversationStore
|
||
- `src/agentkit/chat/conversation_store.py` — 保留作为接口/内存实现
|
||
|
||
**Approach**:
|
||
1. 新建 `SqliteConversationStore`,实现与 `ConversationStore` 相同接口
|
||
2. SQLite 表结构:conversations(id, session_id, role, content, timestamp, metadata)
|
||
3. 支持按 session_id 查询、分页加载、搜索
|
||
4. 数据库文件路径:`~/.agentkit/conversations.db`
|
||
5. 在 portal.py 中替换 ConversationStore 为 SqliteConversationStore
|
||
6. 保留 ConversationStore 作为内存实现(测试用)
|
||
|
||
**Test scenarios**:
|
||
- 消息正确持久化到 SQLite
|
||
- 按 session_id 查询返回完整对话
|
||
- 分页加载正确
|
||
- 服务重启后数据不丢失
|
||
- SQLite 文件不存在时自动创建
|
||
|
||
**Verification**: `ruff check src/ && pytest tests/unit/chat/test_sqlite_conversation_store.py -v`
|
||
|
||
---
|
||
|
||
### U6. 可验证执行(Test-and-Verify 循环)
|
||
|
||
**Goal**: ReActEngine 执行后可选自动运行项目测试验证结果
|
||
|
||
**Dependencies**: U4
|
||
|
||
**Files**:
|
||
- `src/agentkit/core/verification_loop.py` — 新建
|
||
- `src/agentkit/core/react.py` — 集成验证循环
|
||
- `src/agentkit/tools/builtin.py` — 新增 run_tests 工具
|
||
|
||
**Approach**:
|
||
1. 新建 `VerificationLoop`:执行后运行 pytest/ruff/typecheck,失败则自动重试
|
||
2. 最大重试次数可配置(默认 2)
|
||
3. 验证结果附加到 ReActResult
|
||
4. 新增 `run_tests` 内置工具,LLM 可主动调用
|
||
5. 验证循环默认关闭,通过参数 `verification_enabled=True` 启用
|
||
|
||
**Test scenarios**:
|
||
- 验证循环关闭时行为不变
|
||
- 验证循环开启时,执行后自动运行测试
|
||
- 测试通过时返回成功
|
||
- 测试失败时自动重试
|
||
- 达到最大重试次数后返回失败结果
|
||
|
||
**Verification**: `ruff check src/ && pytest tests/unit/core/test_verification_loop.py -v`
|
||
|
||
---
|
||
|
||
### U7. 工具描述分层注入 + tool_search
|
||
|
||
**Goal**: 核心工具全量注入,扩展工具只注入名称+一行描述,LLM 可通过 tool_search 获取完整描述
|
||
|
||
**Dependencies**: 无
|
||
|
||
**Files**:
|
||
- `src/agentkit/core/react.py` — 修改 `_build_tool_use_prompt`
|
||
- `src/agentkit/tools/builtin.py` — 新增 tool_search 工具
|
||
- `src/agentkit/tools/search.py` — 新建,BM25 工具搜索
|
||
|
||
**Approach**:
|
||
1. 工具分为 core(read/write/bash/search)和 extended(其余)
|
||
2. core 工具全量注入 prompt
|
||
3. extended 工具只注入 name + one-line description
|
||
4. 新增 `tool_search` 工具:BM25 搜索工具描述,返回完整描述
|
||
5. LLM 在 agent loop 中按需调用 tool_search
|
||
|
||
**Test scenarios**:
|
||
- core 工具全量出现在 prompt 中
|
||
- extended 工具只出现名称和一行描述
|
||
- tool_search 正确返回工具完整描述
|
||
- BM25 搜索相关性排序
|
||
|
||
**Verification**: `ruff check src/ && pytest tests/unit/tools/test_tool_search.py -v`
|
||
|
||
---
|
||
|
||
### U8. 默认启用上下文压缩
|
||
|
||
**Goal**: ReActEngine 默认启用滑动窗口压缩
|
||
|
||
**Dependencies**: 无
|
||
|
||
**Files**:
|
||
- `src/agentkit/core/react.py` — 修改默认 compressor 参数
|
||
- `src/agentkit/core/compressor.py` — 确认滑动窗口实现
|
||
|
||
**Approach**:
|
||
1. ReActEngine 的 `__init__` 中 compressor 默认值从 None 改为 SlidingWindowCompressor
|
||
2. 保留最近 N 轮 + 系统提示 + 工具描述
|
||
3. N 可配置(默认 10)
|
||
|
||
**Test scenarios**:
|
||
- 长对话自动压缩
|
||
- 压缩后系统提示和工具描述保留
|
||
- 压缩不影响最近 N 轮对话
|
||
|
||
**Verification**: `ruff check src/ && pytest tests/unit/core/test_compressor.py -v`
|
||
|
||
---
|
||
|
||
### U9. Spec 文档作为一等公民
|
||
|
||
**Goal**: PlanExec 生成的计划持久化为 Spec 文档,用户可查看、编辑、确认后再执行
|
||
|
||
**Dependencies**: U4
|
||
|
||
**Files**:
|
||
- `src/agentkit/core/spec_manager.py` — 新建
|
||
- `src/agentkit/core/plan_exec_engine.py` — 集成 SpecManager
|
||
- `src/agentkit/server/routes/tasks.py` — 新增 Spec 相关 API
|
||
|
||
**Approach**:
|
||
1. 新建 `SpecManager`:管理 Spec 文档的 CRUD
|
||
2. Spec 文件路径:`.agentkit/specs/<plan_id>.yaml`
|
||
3. PlanExecEngine 生成计划后,先持久化为 Spec
|
||
4. 新增 API:`GET /api/v1/specs`、`GET /api/v1/specs/{id}`、`PUT /api/v1/specs/{id}`、`POST /api/v1/specs/{id}/confirm`
|
||
5. 用户确认后才开始执行
|
||
|
||
**Test scenarios**:
|
||
- 计划正确持久化为 Spec 文件
|
||
- Spec 文件可读取和编辑
|
||
- 未确认的 Spec 不会执行
|
||
- 确认后触发执行
|
||
|
||
**Verification**: `ruff check src/ && pytest tests/unit/core/test_spec_manager.py -v`
|
||
|
||
---
|
||
|
||
### U10. 统一事件模型(SQ/EQ 双队列)
|
||
|
||
**Goal**: 统一 CLI 和 WebSocket 的事件模型为 SQ/EQ 双队列
|
||
|
||
**Dependencies**: U3
|
||
|
||
**Files**:
|
||
- `src/agentkit/core/protocol.py` — 新增 SQ/EQ 事件类型
|
||
- `src/agentkit/server/routes/portal.py` — 对接 EQ
|
||
- `src/agentkit/cli/chat.py` — 对接 EQ
|
||
|
||
**Approach**:
|
||
1. 定义 SubmissionQueue(用户输入)和 EventQueue(Agent 输出)
|
||
2. 事件类型:Session/Task/Turn 三级模型
|
||
3. Portal WebSocket 和 CLI 共享同一事件流
|
||
4. 前端可以统一渲染
|
||
|
||
**Test scenarios**:
|
||
- SQ 正确接收用户输入
|
||
- EQ 正确推送 Agent 事件
|
||
- WebSocket 和 CLI 共享事件流
|
||
- 事件类型正确分类
|
||
|
||
**Verification**: `ruff check src/ && pytest tests/unit/core/test_protocol.py -v`
|
||
|
||
---
|
||
|
||
## Scope Boundaries
|
||
|
||
### In Scope
|
||
- 上述 10 个 Implementation Unit
|
||
- 单元测试覆盖
|
||
|
||
### Out of Scope
|
||
- DockerComputerUseSession 实现(P3,等用户需求验证)
|
||
- 前端组件更新(后续迭代)
|
||
- Agent 配置热重载(P4)
|
||
- 渐进式上下文加载(P4)
|
||
- Soul 演变多维度触发(关闭)
|
||
- OTel 埋点(延后)
|
||
|
||
### Deferred to Follow-Up Work
|
||
- 前端 ExpertTeamView 接入真实数据
|
||
- SWE-bench 端到端验证
|
||
- 性能监控和成本追踪
|
||
|
||
---
|
||
|
||
## Risks & Dependencies
|
||
|
||
| Risk | Impact | Mitigation |
|
||
|------|--------|------------|
|
||
| U3 专家团重写可能影响现有 @team 功能 | 中 | 保留 ExpertConfig/ExpertTemplate/Registry,只重写 Orchestrator |
|
||
| U5 SQLite 在高并发下可能有锁竞争 | 低 | 聊天场景写频率低,SQLite WAL 模式足够 |
|
||
| U7 tool_search 可能增加 LLM 调用轮次 | 中 | 核心工具全量注入,只有扩展工具需要搜索 |
|
||
| U9 Spec 文档可能增加用户操作步骤 | 低 | 默认自动确认(可配置),不阻塞自动化流程 |
|
||
|
||
---
|
||
|
||
## Phased Delivery
|
||
|
||
**Phase 1(清理收尾)**: U1 → U2 → U4 → U8
|
||
**Phase 2(核心能力)**: U5 → U6 → U9
|
||
**Phase 3(多 Agent)**: U3 → U7 → U10
|