Files
agcore/design/roadmap/roadmap-v0.3.0.md
T
徐涛 28ca43ccb2 chore(docs): 将设计文档从 docs 移至 design 目录
将 note、pdd、prd、roadmap 四类文档分别归入 `design/` 下对应子目录中,并新增 `.gitkeep` 占位文件
2026-07-23 05:45:53 +08:00

368 lines
31 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AG Core Roadmap — v0.3.0
> 本文件聚焦 **v0.3.0 版本** 的规划与交付(Phase 1319)。Phase 13-19 全部完成,v0.3.0 交付完毕。
> 返回总入口:[`roadmap.md`](./roadmap.md)
## v0.3.0 愿景
从"LLM 调用工具箱"升级为"能构建多 Agent 协作、RAG、长记忆 Agent 产品的基础系统"。补齐 LangChain 7 大组件中缺失的 Document 和 VectorStore 能力,落地笔记设计中的 ContextSlot fork/merge、摘要自动生成、知识图谱,建立 engine 引擎层(会话树 + time-travel Checkpointer + SubAgent Dispatch + Agent Switch),为即将开发的多 Agent 产品提供完整基础。
## v0.3.0 总体范围
**总体规模**7 个增量 PhasePhase 1319),总新增代码约 2600 行,测试从 277 → 427。7 个 Phase 全部完成(M9-M15 已达成),v0.3.0 交付完毕。
---
## v0.3.0 — 多 Agent 基础系统(Multi-Agent Foundation
**目标**:从"LLM 调用工具箱"升级为"能构建多 Agent 协作、RAG、长记忆 Agent 产品的基础系统"。补齐 LangChain 7 大组件中缺失的 Document 和 VectorStore 能力,落地笔记设计中的 ContextSlot fork/merge、摘要自动生成、知识图谱,建立 engine 引擎层(会话树 + time-travel Checkpointer + SubAgent Dispatch + Agent Switch),为即将开发的多 Agent 产品提供完整基础。
**总体规模**7 个增量 PhasePhase 13-19),总新增代码约 2600 行,测试从 277 → 427。
### 功能清单
#### P0 — 必须交付
| # | 功能 | 模块 | 方案要点 |
|---|------|------|---------|
| 1 | 技术债清理(旧 types 文件) | `llm/types` | `request.rs` / `response.rs` / `old_stream.rs` 三个 Phase 0 旧文件删除;内部类型移入 `provider/openai.rs` |
| 2 | ContextSlot fork/merge | `agent/context` | `fork(child_id, strategy)` 别名 + `merge(child, MergeStrategy)` 三种策略(Append/Replace/Summarize |
| 3 | Document 系统 | `document/`(新模块) | `Document` 核心类型 + `RecursiveCharacterSplitter`(递归字符分割,支持 chunk_size/chunk_overlap/separators |
| 4 | Embedding 抽象 | `llm/embedding` | `Embedding` trait`embed` / `dim`+ `MockEmbedding` 测试实现 |
| 5 | 向量存储持久化 | `vector/`(新模块) | `VectorStore` trait + `InMemoryVectorStore`(读写)+ `PersistentVectorStore`SqliteStore 后端)+ `RagPipeline` 组合器 |
| 6 | 摘要自动生成 | `agent` / `llm/hooks` | `SummaryConfig` 配置 + `OnTurnEnd` Hook 自动检测 token 水位 → 调 LLM 生成摘要 → `SessionMemory::set("conversation_summary", ...)` |
| 7 | SessionManager + 会话树 | `engine/`(新模块) | Session 工厂(`create`/`create_child`+ 按 ID 恢复(`get`+ 子树管理(`children`/`parent`/`destroy_subtree`+ 元数据持久化(MemoryStore |
| 8 | Time-travel Checkpointer | `engine/checkpointer` | `checkpoint(session)` 全量序列化 + `rollback(session_id, ckpt_id)` 回滚 + `fork(session_id, ckpt_id, new_id)` 分支 + `list_checkpoints` |
| 9 | Agent Switch | `engine/switch` | 热切换 `session.agent`(替换 `Arc<dyn Agent>`),slot 历史 / turn_index / session_memory 全保留 |
| 10 | SubAgent Dispatch | `engine/sub_agent` | `dispatch(parent, sub_agent, task, config)` 单任务 + `dispatch_all(parent, tasks, config)` 并行派发(Semaphore 并发控制)+ 子 SessionMemory 继承 + `SubTaskResult` 结构化回传 |
| 11 | 知识图谱 | `memory/graph` | `KnowledgeGraph` trait`add_entity` / `add_relation` / `get_related` / `find_by_keywords`+ `InMemoryGraph` 实现 + `tag_index` 标签管理 |
| 12 | 双通道检索 | `memory/retriever` | `MemoryRetriever` 扩展为双通道(`KnowledgeStore` + `KnowledgeGraph`+ `RetrievalStrategy::Hybrid` |
### 实施计划 — 7 个增量 Phase
> **编号说明**Phase 13-19 接续 v0.2 的 Phase 5-12,按开发顺序排列。
#### Phase 13: 热身清理 + ContextSlot fork/merge
**目标**:清除 Phase 0 遗留的旧 types 文件,交付超低价功能建立节奏。
| Step | 内容 | 文件范围 | 验证标准 |
|------|------|---------|---------|
| **13.1** | `OpenaiChatRequest` 移入 `provider/openai.rs``types/request.rs` 删除 | `llm/types/request.rs` + `llm/provider/openai.rs` | `cargo build --all-targets` |
| **13.2** | `OpenaiChatResponse/Chunk` 移入 `provider/openai.rs``types/response.rs` 删除 | `llm/types/response.rs` + `llm/provider/openai.rs` | `cargo build --all-targets` |
| **13.3** | `old_stream.rs` 删除 + `types/mod.rs``ChatResponse` 删除 | `llm/types/old_stream.rs` + `llm/types/mod.rs` | `cargo build` + 确认 3 个旧文件不存在 |
| **13.4** | `ToolChoice``request.rs` 搬到 `tool.rs` | `llm/types/tool.rs` + `llm/types/request_v2.rs` | `cargo test --all-targets` 全绿 |
| **13.5** | `ContextSlot::fork(child_id, strategy)` 别名 + `merge(child, MergeStrategy)` | `agent/context.rs` | 单元测试:fork → 子 slot 消息 = 父 slot 副本;merge(Append) → 消息按序追加 |
**依赖**:无
**优先级**P0
**预估规模**:约 200 行
**状态**:✅ Phase 13 全部交付物已完成(2026-07-08
---
#### Phase 14: Document 系统 + Embedding 抽象
**目标**:补齐 LangChain 7 大组件中最明显的缺口——Document 类型和分割器。不搞 Loader 框架,用户用 `fs::read_to_string` 自行加载。
**交付物**
1. `src/document.rs` 新模块(`Document` 类型 + `RecursiveCharacterSplitter`
2. `src/llm/embedding.rs``Embedding` trait + `MockEmbedding`
**设计要点**
- `Document`id / content / metadataHashMap<String, String>/ mime_type
- `RecursiveCharacterSplitter`chunk_size(默认 1000/ chunk_overlap(默认 200/ separators`["\n\n", "\n", "。", "", "", ".", " ", ""]`,含 CJK 标点)
- 两阶段算法:按 separator 优先级递归分割(Phase 1+ 贪心合并 + overlap 滑动窗口(Phase 2
- 所有长度比较以 Unicode 字符数为单位(`chars_len()`),非字节数
- `Embedding` trait`async fn embed(&self, input: &[String]) -> Result<Vec<Vec<f32>>, LlmError>` + `fn dim()`
- 复用 `LlmError` 而非新错误类型
- `MockEmbedding`:sin-hash 零依赖伪随机向量 + L2 归一化
- 不引入 `DocumentLoader` trait(应用层职责)
**实际新增**2026-07-09 commit `d4c4d8f`,详见 `docs/20-phase14-document-and-embedding.md`):
- 新增文件 3 个:
- `src/document.rs`580 行)— `Document` 类型(4 字段 + `new`/`from_raw` 构造器,2 个 `new` 接受 `impl Into<String>` + `RecursiveCharacterSplitter`(两阶段算法:按 separator 优先级递归分割 + 贪心合并 overlap,所有长度比较 `chars_len()` 字符级,overlap 提取 `chars().rev().take().rev()` 字符级安全)+ 19 个内联测试
- `src/llm/embedding.rs`183 行)— `Embedding` traitasync + `LlmError`+ `MockEmbedding`(sin-hash:字节和+长度做种子,`f32::sin(seed + i) * 10000`,L2 归一化到单位长度,零向量防除零)+ 6 个内联测试
- `examples/document_demo.rs`(74 行)— 端到端演示 Document → RecursiveCharacterSplitter → MockEmbedding → InMemoryVectorRetriever → search
- 修改文件 2 个:
- `src/lib.rs`+3 行:`pub mod document` + `pub use document::Document` + 空行)
- `src/llm.rs`+1 行:`pub mod embedding`
- 关键设计:
- **早返回守卫**`split_text``chars_len(text) <= self.chunk_size` 时直接返回 `[text]`,避免短文本在 Phase 2 `join("")` 中丢失 separator 边界
- **`Document::new` 使用 `impl Into<String>`**:接受 `&str``String`,比规范示例的 `String` 更灵活
- **`new()` panic + `try_new()` Result 双路径**:与 Rust 库惯例一致
- **CJK 分隔符扩展**`DEFAULT_SEPARATORS` 包含 `"。"`/`""`/`""`,避免中文文本跳过句子级退化为空格分割
- **chunk_size = 0 校验**:构造器拒绝零值,避免字符级兜底死循环
- **tracing 埋点**`split()` 入口 `tracing::debug!` + 每文档/每 chunk `tracing::trace!`
- **debug_assert 溢出保护**:单文档 chunk 数 < 10000 时 `debug_assert!`
- **Metadata 键覆盖文档化**`HashMap::insert()` 静默覆盖 source_id/chunk_index/chunk_count 在 `split()` doc comment 注明
- 测试:19 个 Document 测试(含 1 个 split_multibyte_utf8_boundary CJK 边界测试)+ 6 个 Embedding 测试,全量 286 → 313(+27 新测试,但部分测试覆盖范围重叠计算约 25 个净增)
- 方案文档:`docs/20-phase14-document-and-embedding.md`(1417 行,含背景/调研/方案对比/实施计划(详细版)/3 轮审查修复记录),经过 3 轮 PM/SA 审查 + 1 轮实施后修复
- clippy 0 警告,doc 0 warning
- 无新增外部依赖(`Cargo.toml` 未修改)
**实施后调整**
- 实施发现方案算法中 Phase 1 累加器设计与测试期望冲突("para1\n\npara2" 在 chunk_size=100 时 1 chunk 更合理),简化为"按 separator 切分 + Phase 2 合并"两阶段分工
- 二次审查发现 `split_text` 缺少早返回守卫 + `current_sep_count` 虚增计数,全部已修复
**依赖**:无(纯数据结构 + 零新 crate 依赖)
**优先级**P0
**预估规模**:约 350 行
**状态**:✅ Phase 14 全部交付物已完成(2026-07-09
---
#### Phase 15: 向量存储持久化(SqliteStore 后端)
**目标**:实现 VectorStore 持久化,让语义检索支持进程重启后数据恢复。
**设计决策**:不用 pgvector。基于已有 SqliteStore`rusqlite`)做持久化包装——运行时全量加载到 InMemory 索引做余弦搜索,写时同步到 SqliteStore。
**交付物**
1. 新增 `src/memory/vector_store.rs`937 行)—— `VectorStore` trait + `InMemoryVectorStore` + `PersistentVectorStore` + `RagPipeline`
2. `VectorStore` trait`add(&[Document], &[Vec<f32>])` 批量 / `search(query, k)` 返回 `(Document, f32)` / `remove(ids)` 幂等
3. `PersistentVectorStore`:构造时从 `MemoryStore` 全量加载已有索引;`add` 先写持久化后写内存(持久化失败时内存不污染,重启自动恢复);`search` 纯内存余弦搜索(快照 clone + 锁外计算)
4. `RagPipeline`:组合器封装 `split → embed → store.add`ingest)和 `embed → store.search`retrieve)两条管线
5. 存储格式:`vec:{namespace}:{doc_id}` → JSON `{doc_id, content, metadata, embedding, created_at}`,通过 `MemoryStore` 通用接口读写
6. `src/memory/vector.rs``VectorRetriever` trait + `InMemoryVectorRetriever` 标注 `#[deprecated(since = "0.3.0")]`,迁移路径指向 `VectorStore` / `InMemoryVectorStore`
**实际新增**2026-07-09 commit `32d886f`):
- 新增文件 1 个:`src/memory/vector_store.rs`937 行,含 19 个内联测试)
- 修改文件 3 个:`src/memory/vector.rs`+4 行 deprecated 标注);`src/memory.rs`+pub mod vector_store + 4 个 pub use re-export);`examples/document_demo.rs`(迁移到 RagPipeline ingest+retrieve
- 零新外部依赖(`Cargo.toml` 未修改)
- 全量测试 313 → 335+22Phase 15 新增 19 测试 + 部分重叠计数 22 净增);clippy 0 警告,doc 0 warning
- 设计文档:`docs/21-phase15-vector-store-persistence.md`(1570 行,经 3 轮审查 + 文档-代码不一致修复:`search_orthogonal_vectors` 返回 1 条 score≈0 而非空列表)
**依赖**Phase 14Document 类型 + Embedding trait
**优先级**P0
**预估规模**:约 400 行(实际约 937 行纯实现 + 测试)
**状态**:✅ Phase 15 全部交付物已完成
---
#### Phase 16: 摘要自动生成
**目标**:闭环长对话能力。v0.2 的 `inject_summary` 消费端(`FocusedConfig.summary_override`)已就绪,缺的是生产端。
**交付物**
1. `SummaryConfig` 结构体:`trigger_token_ratio`(默认 0.75 / `max_context_tokens`(默认 32_000/ `summary_prompt`(默认中文 `DEFAULT_SUMMARY_PROMPT``{messages}` / `debounce_turns`(默认 3 / `summary_model`(默认 `None` 沿用主模型) / `max_tool_result_chars`(默认 500
2.`submit_turn` / `finalize_turn` 中 OnTurnEnd 之后插入**内联检查点**(非 Hook 扩展):`should_summarize`(水位 + 防抖,首次不受防抖约束)→ `generate_summary` 关联函数(新 `LlmCycle` + `submit_messages` 无工具调用)→ 更新 `FocusedConfig.summary_override` + `slot.save()` 持久化 + `SessionMemory::set("conversation_summary", summary)` 全局快照
3. `AgentBuilder` 扩展:`.summary_config(cfg)` 方法(不覆盖整个 `AgentConfig`
4. 公开 API`get_conversation_summary() -> Result<Option<String>, AgentError>`
5. `format_messages_as_text()` 简洁版消息格式化(System/User/Assistant + `[Tool: name]` + `Tool Result [id]:` 截断到 `max_tool_result_chars` 字符)
**设计决策**:内联于 `submit_turn` 流程而非 Hook 扩展(因为 HookContext 无法携带 `&mut self` 引用更新 slot config,且流式路径的 `finalize_turn``cycle` 已销毁)。`Option<SummaryConfig>` 的 opt-in 机制已足够提供可插拔性,不改变 Hook 系统签名。流式路径中 `submit_turn_stream` 已将 `turn_index` 提前 ++1,检查点使用 `saturating_sub(1)` 修正。
**依赖**:无(`submit_turn` 流程 + `CostTracker` + `SessionMemory` + `LlmProvider` 均已就绪)
**优先级**P0
**预估规模**:约 220 行(实际约 250 行,含 11 个内联测试)
**方案文档**`docs/22-phase16-summary-auto-generation.md`471 行,经 PM/SA 审查 11 项修复 + 实施后第二轮审查 9 项修复全部完成)
**状态**:✅ Phase 16 全部交付物已完成(含实施后 PM/SA/Code Reviewer 第二轮审查 PASS
**实施后审查修复记录**(共 9 项):
- 🔴 B1`generate_summary` 调用 `submit_messages(Vec::new(), vec![])` 发送空消息列表 → 移除 `with_messages()`,直接 `submit_messages(vec![Message::user_text(prompt)], vec![])`
- 🟡 W4`should_summarize` 使用 `self.turn_index` 而非 `current_turn` 参数 → 改签名接收 `current_turn`,流式路径防抖准确
- 🟡 W2`summary_model` 硬编码 `unwrap_or("gpt-4o")` → 改为条件赋值,`None` 时沿用 `CycleConfig::default()`
- 🟡 W5Full 模式 `slot.save()` 无谓调用 → 移入 `SlotMode::Focused` 分支内
- 🟡 W3`format_messages_as_text` 缺 30K 整体截断 → 新增 `MAX_TOTAL_CHARS=30_000` + `truncate_total_chars`,优先保留最新
- 🟡 W6:摘要成功无日志 → 添加 `tracing::info!(turn, summary_len, "摘要自动生成成功")`
- 🟡 W1/W7:缺 3 个测试 → 新增 `format_total_charset_truncation_keeps_recent` / `summary_written_to_focused_slot_config` / `summary_skipped_for_empty_messages` / `summary_not_generated_if_max_context_unreachable`
- 💭 `context.rs:78` 过时注释("v0.3 将支持 Hook 驱动")→ 更新为"v0.3 Phase 16 起 AgentBuilder 内联检查点自动生成摘要"
**第二轮审查门禁**PASS0 🔴 阻塞)。`cargo test --all-targets` **353 passed / 0 failed**clippy 0 警告,doc 0 warning。
---
#### Phase 17: Agent 执行引擎(会话树 + Time-travel Checkpointer
**目标**:建立 `engine/` 模块。解决 v0.2 中"session 在变量里、无法通过 ID 恢复、不支持父子关系"的空白。
**方案文档**`docs/23-phase17-agent-execution-engine.md`
**交付物**
1. `src/engine/` 新模块(`session_manager.rs` + `checkpointer.rs` + `snapshot.rs` + `error.rs`
2. `SessionManager`
- `create(agent, bundle) -> Result<String, EngineError>` — 创建根 sessionUUID v4 自动生成 ID
- `create_child(parent_id, agent) -> Result<String, EngineError>` — 创建子 session(继承父 `RuntimeBundle``Arc::clone` 共享引用)
- `get(session_id) -> Result<Arc<Mutex<AgentSession>>, EngineError>` — 按 ID 查找(仅查内存,不自动从存储恢复)
- `recover(session_id, agent, bundle) -> Result<Arc<Mutex<AgentSession>>, EngineError>` — 从存储恢复 session
- `replace(session_id, session) -> Result<(), EngineError>` — 替换已有 session 实例(用于 rollback 后切换)
- `children(parent_id)` / `parent(child_id)` — 树形查询
- `destroy(id)` — 生命周期管理(允许孤儿 session 存在,不递归删除子 session)
3. `Checkpointer`
- `checkpoint(session)` — 每个 `submit_turn` 末尾自动保存全量状态快照
- `rollback_load(session_id, ckpt_id) -> SessionSnapshot` — 读取 checkpoint JSON 为 snapshot(不重建 AgentSession
- `list_checkpoints(session_id)` — 列出 checkpoint 列表
- `delete_all(session_id)` — 清理某 session 所有 checkpoint
- `fork()` 推迟(底层可拆解为 `rollback` + `create_child`,作为高层 API 等价于约 30 行组合代码,已具备原始能力)
4. `SessionSnapshot` 独立 struct(位于 `engine/snapshot.rs`)—— 避开 `Arc<dyn Agent>` 不可序列化的限制,通过 `to_snapshot()` / `from_snapshot()` 双向转换实现 AgentSession 快照持久化
- `to_snapshot()`async,从 `SessionMemory` 读取完整数据)+ `from_snapshot()`(纯同步构造)+ `restore_memory()`async 写回持久层)
5. `EngineError` 枚举(含 `MemoryError` 透传变体 与项目既有 `AgentError` 风格一致)
**Checkpoint 存储格式**`ckpt:{session_id}:{ckpt_id}``SessionSnapshot` JSON(全量 session 状态,含所有 slot 消息列表)。Ponytail:全量 JSON 够用,等遇到存储效率问题时再改增量模式。
**会话树持久化**`session:{session_id}:meta``SessionMeta` JSON`{agent_name, parent_id, created_at, turn_count}`
**依赖**Phase 10ContextSlot 持久化 — 消息由 slot 自己管,Checkpointer 管执行状态)
**优先级**P0
**预估规模**:约 700 行(5 新增文件 + 5 修改文件)
**状态**:✅ Phase 17 全部交付物已完成
---
**实际新增**2026-07-153 commits + 实施审查修复一轮):
- **新增 5 文件(`src/engine/`**`mod.rs`19 行)+ `error.rs`43 行)+ `snapshot.rs`35 行)+ `checkpointer.rs`373 行)+ `session_manager.rs`910 行含测试)
- **修改 5 文件**
- `src/llm/types/usage.rs``CostTracker``Clone, Serialize, Deserialize`3 行)
- `src/agent/context.rs``ContextSlot` + `MergeStrategy``Serialize, Deserialize`4 行)
- `src/agent/session_memory.rs` — 新增 `list_entries()` + `set_with_meta()` 方法
- `src/agent/session.rs` — 新增 `to_snapshot()` (async) / `from_snapshot()` (sync) / `restore_memory()` (&mut self, async) / `has_pending_memory_restore()` + 公开 `bundle()` accessor
- `src/lib.rs``pub mod engine`
- **新增 1 示例**`examples/engine_demo.rs`~210 行,端到端演示 create → submit_turn → checkpoint → list → rollback_load → from_snapshot → restore_memory → replace → destroy 全链路,含 rollback 一致性 assert
- **依赖**:零新外部依赖(ponytail:ckpt_id 用纳秒+计数器生成,session_id 同理)
- **测试**353 → **374**+21 引擎内联测试:Checkpointer 6 个 + SessionManager 15 个)
- **质量基线**`cargo test --all-targets` 374 passed / 0 failed`cargo clippy --all-targets -- -D warnings` 0 警告;`cargo doc --no-deps` 0 warning`cargo run --example engine_demo` exit 0
- **关键设计决策落地**
- `SessionSnapshot` 独立 struct(避开 `Arc<dyn Agent>` 不可序列化)
- `to_snapshot` async + `from_snapshot` 纯同步 + `restore_memory` async 三段式分离
- `session_memory_data` 改用 `HashMap<String, SessionMemoryEntry>`(保留 metadata/created_at
- `EngineError::Memory(#[from] MemoryError)` 透传变体
- `EngineManager` 锁契约:所有写操作先 HashMap 再 I/O(或反之,destroy 反向)
- 自动 checkpoint 失败 `tracing::error!` 不阻断主流程(不提供强持久化保证)
- ckpt_id 时间戳+纳秒+计数器无外部依赖(`created_at_nanos` 字段确保同秒内精确排序)
- 孤儿策略:`destroy()` 不递归删除子 session;父被销毁后 `parent()` 返回 `Ok(None)`
- **实施审查通过**:经过 PM + SA + Code Reviewer 三方联合审查 → 1 轮修复 → 全部 🟡 警告关闭
- **M13 里程碑达成** — Phase 17 rc.1 标签可打(v0.3.0 第二个 Phase
---
#### Phase 18: Agent Switch + SubAgent Dispatch + Agent 间交互
**目标**:在 SessionManager 基础上,提供 Agent 角色热切换和子代理调度能力。
**交付物**
1. `engine/switch.rs``switch_agent(session_id, new_agent)`:替换 `Arc<dyn Agent>`slot 历史 / turn_index / session_memory 全保留
2. `engine/sub_agent.rs` — SubAgent Dispatch 核心:
- `DispatchConfig``max_concurrency`(默认 10/ `inherit_session_memory`(默认 true/ `bridge_keys`
- `dispatch(parent_id, sub_agent, task, config) -> SubTaskResult`:创建子 session → 继承父 SessionMemory → `submit_turn` → 返回结构化结果
- `dispatch_stream(parent_id, sub_agent, task, config) -> SubTaskStream`:流式版
- `dispatch_all(parent_id, tasks, config) -> Vec<SubTaskResult>`:并行派发,`tokio::sync::Semaphore` 控制并发数
3. `SubTaskResult``child_id` / `response` / `usage` / `summary` + `child_memory(sm)` 读取子 SessionMemory
**Agent 间交互三层级**
- 父→子:继承 SessionMemory 快照 + `bridge_keys` 指定 key 强制注入 system prompt
- 子→父:`SubTaskResult` 结构化回传 + `SessionMemory["result_summary"]` 结论摘要
- 子↔子(间接):通过公共 `MemoryStore` namespace`shared:{parent_session_id}`)共享数据
**依赖**Phase 17SessionManager + 会话树)
**优先级**P0
**预估规模**:约 500 行
**实际新增**2026-07-15 commit `46de111`,详见 `docs/24-phase18-agent-switch-and-dispatch.md`):
- 方案文档:`docs/24-phase18-agent-switch-and-dispatch.md`700 行,含 Agent Switch 与 SubAgent Dispatch 的设计推演)
- 新增文件 2 个:
- `src/engine/switch.rs`222 行)— `SessionManager::switch_agent()` 热切换:替换 `Arc<dyn Agent>`slot 历史 / turn_index / session_memory / cost_so_far 全部保留,同步更新 `SessionMeta.agent_name` 到持久层
- `src/engine/sub_agent.rs`1071 行)— SubAgent 调度完整实现:4 个公开方法 + 3 个公开类型
- 修改文件 4 个:
- `src/engine/mod.rs`+5 行:`pub mod switch; pub mod sub_agent;` + `pub use sub_agent::{DispatchConfig, SubTaskResult, SubTaskStreamEvent};`
- `src/engine/error.rs`+1 变体:`DispatchFailed(#[source] String)`
- `src/engine/session_manager.rs`+2 处可见性:`save_session_meta` / `load_session_meta``pub(crate)``switch.rs` 使用)
- `src/llm/types/usage.rs`+`From<Usage>` 实现供 `SubTaskResult.usage` 字段构造)
- 新增 4 个示例:
- `examples/agent_switch_demo.rs`(115 行)— Agent 热切换演示
- `examples/sub_agent_dispatch_demo.rs`141 行)— dispatch / dispatch_all 并行派发演示
- `examples/bridge_keys_demo.rs`197 行)— bridge_keys 过滤的 SessionMemory 继承演示
- `examples/dispatch_stream_demo.rs`121 行)— dispatch_stream 流式派发演示
- 关键设计:
- **`switch_agent` 锁契约**:先 `get` session → 锁 `Mutex` 替换 agent 并读取 turn_index → 释放 Mutex → 读/写 `SessionMeta`(无锁 IO),最大限度减少锁竞争
- **`SessionMeta` 保留原则**:切换 `agent_name` 字段,但 `created_at` / `parent_id` 保留原始(血缘不可变)
- **`switch_agent` 不自动 checkpoint**:与 `auto_checkpoint` 语义一致(仅 `submit_turn` / `finalize_turn` 触发),避免每次角色切换产生冗余 checkpoint
- **`inherit_session_memory` 快照语义**:捕获调用时刻的父 session_memory 快照,子 session 写回后即使父被并发写入也不传播(防止非确定性结果)
- **`bridge_keys` 三态语义**`None` = 不继承任何(安全默认)/ `Some(vec![])` = 继承全部 / `Some(keys)` = 仅继承指定 key
- **`shared_namespace` 约定式共享**:纯约定字段,不触发自动注入逻辑,子 agent 显式 `session.set_session_data("shared:{prefix}:{key}", value)` 写入
- **`dispatch_all` 部分成功语义**`Vec<Result<SubTaskResult, EngineError>>` 按输入顺序 indexed 收集,task panic 通过 `DispatchFailed` 哨兵占位(不破坏顺序一致性)
- **`dispatch_stream` 后台 finalize**spawn task 内部调 `finalize_turn()` 落库,明确不参与 `auto_checkpoint`(避免与流式 checkpoint 重复)
- **`SubTaskStreamEvent` 事件序列**`ChildCreated { child_id }``Stream(StreamEvent) × N``Completed(SubTaskResult)``Error { child_id, error }`
- **`SUBTASK_NAMESPACE` 防误注入**:子 session 注入到 SessionManager 时使用 `subtask:` prefix 避免与 SessionMeta 的 `session:{id}:meta` 冲突
- 测试:+17 内联测试(4 switch + 5 dispatch + 4 dispatch_all + 4 dispatch_stream),全量 374 → **391 passed / 0 failed**+170 失败)
- 质量基线:`cargo test --all-targets` 391 passed / 0 failed`cargo clippy --all-targets -- -D warnings` 0 警告;`cargo doc --no-deps` 0 warning4 个示例全部 exit 0
- 零新外部依赖(ponytail:与 Phase 17 一致)
**状态**:✅ Phase 18 全部交付物已完成
---
#### Phase 19: 知识图谱 + 双通道检索
**目标**:落地 `docs/note-knowledge-graph-design.md` 中记录的知识图谱设计,提供实体-关系图检索能力。扩展 `MemoryRetriever` 为双通道。
**交付物**
1. `src/memory/graph.rs`(新文件):
- `GraphEntity` / `GraphRelation` / `ScoredEntity` 核心类型
- `RelationDirection` 枚举(Outgoing / Incoming / Both
- `KnowledgeGraph` trait`add_entity` / `get_entity` / `remove_entity` / `add_relation` / `remove_relation` / `get_related` / `find_by_keywords` / `find_tags` / `set_entity_tags`
- `InMemoryGraph` 实现:`HashMap<String, GraphEntity>` + `Vec<GraphRelation>` + BFS 图遍历
- `TagConstraints``max_tags_per_entity` 默认 8
2. `src/memory/retriever.rs` 扩展:
- `MemoryRetriever` 增加 `knowledge_graph` 可选字段
- `RetrievalStrategy` 枚举:`Hybrid`(默认)/ `KnowledgeOnly` / `GraphOnly`
**与 Document 系统的关系**:知识图谱提供实体级检索("这个实体和什么相关"),VectorStore 提供语义相似度检索("哪些文档最相似"),两者互补。
**依赖**MemoryStore 持久化(v0.1 Phase 3
**优先级**P0
**预估规模**:约 400 行(实际约 720 行核心 + 200 行测试)
**方案文档**`docs/25-phase19-knowledge-graph-and-retrieval.md`(652 行,经 PM/SA 双轮审查 PASS
**状态**:✅ Phase 19 全部交付物已完成(2026-07-17
**实际新增**2026-07-17):
- 新增文件 2 个:
- `src/memory/graph.rs`~580 行)- `GraphEntity`id/name/entity_type/description/tags/properties+ `GraphRelation`(无 id 字段,`composite_key()` 派生)+ `RelationDirection``#[derive(Default)]` + `#[default]` Outgoing+ `ScoredEntity`(含 path 路径)+ `TagConstraints`max_tags_per_entity 默认 8+ `KnowledgeGraph` trait10 个 async 方法)+ `InMemoryGraph``Mutex<GraphInner>` 单一锁结构,避免嵌套锁死锁)+ BFS 图遍历(visited 防环 + 权重乘积衰减 + 多路径先到先得 + depth=0 返回空)+ 标签管理(tag_index 反向索引)+ 23 个内联测试
- `examples/knowledge_graph_demo.rs`(~140 行)- 端到端演示:构建图谱 -> BFS 遍历 -> 标签管理 -> Hybrid/GraphOnly 双通道检索
- 修改文件 3 个:
- `src/memory/retriever.rs` - `RetrievalStrategy` 枚举(Hybrid 默认 / KnowledgeOnly / GraphOnly+ `RetrievalItem` enum(统一列表,`score()` 方法)+ `RetrievalResult` 新增 `strategy` 字段(反映实际执行策略)+ `MemoryRetriever` 双通道(`with_knowledge_graph` / `with_strategy` 链式构造)+ `search_knowledge_store` / `search_graph` 私有方法 + `tokio::join!` 并行 + 旧 `ScoredItem` 标注 `#[deprecated]` + `RetrieverConfig` 新增 `graph_depth`(默认 2+ 13 个内联测试
- `src/memory.rs` - `pub mod graph` + 重导出 7 个图类型 + 更新 retriever 重导出
- `examples/knowledge_search_demo.rs` - 适配新 API`RetrievalItem` enum match + `RetrieverConfig.graph_depth`
- 关键设计:
- **`Mutex<GraphInner>` 单一锁结构** - 避免 `set_entity_tags` 嵌套锁死锁风险(审查修复)
- **`RetrievalResult.strategy` 反映实际执行策略** - graph 未注入时退化为 `KnowledgeOnly`(审查修复)
- **`GraphRelation` 无 id 字段** + `composite_key()` 派生方法
- **BFS**`visited` 防环 + 权重乘积衰减 + 多路径先到先得 + `depth=0` 返回空
- **零新外部依赖**ponytail 风格)
- 测试:391 -> **427 passed / 0 failed**+36 新测试:23 graph + 13 retriever
- 质量基线:`cargo test --all-targets` 427 passed / 0 failed`cargo clippy --all-targets -- -D warnings` 0 警告;`cargo doc --no-deps` 0 warning`cargo run --example knowledge_graph_demo` exit 0
---
### v0.3.0 Phase 依赖关系图
```mermaid
graph BT
P13["<b>Phase 13: 热身清理</b><br/>旧 types 文件删除<br/>ContextSlot fork/merge"]:::done
P14["<b>Phase 14: Document + Embedding</b><br/>Document 类型<br/>RecursiveCharacterSplitter<br/>Embedding trait"]:::done
P15["<b>Phase 15: 向量存储持久化</b><br/>VectorStore trait<br/>PersistentVectorStore<br/>RagPipeline<br/>19 新测试"]:::done
P16["<b>Phase 16: 摘要自动生成</b><br/>SummaryConfig<br/>内联检查点<br/>首次防抖跳过<br/>18 新测试"]:::done
P17["<b>Phase 17: 执行引擎</b><br/>SessionManager<br/>会话树<br/>Time-travel Checkpointer<br/>21 新测试"]:::done
P18["<b>Phase 18: 切换与调度</b><br/>Agent Switch<br/>SubAgent Dispatch<br/>dispatch_all 并发控制<br/>17 新测试"]:::done
P19["<b>Phase 19: 知识图谱</b><br/>KnowledgeGraph trait<br/>InMemoryGraph<br/>双通道检索"]:::done
P15 --> P14
P18 --> P17
classDef done fill:#4ade80,stroke:#16a34a,color:#1a1a1a
classDef pending fill:#fbbf24,stroke:#d97706,color:#1a1a1a
```
### 关键里程碑
| 里程碑 | Phase 完成条件 | 可验证指标 | 状态 |
|--------|---------------|-----------|------|
| **M9** | Phase 13 | 旧 types 文件删除、`cargo test --all-targets` 全绿、`fork`/`merge` 测试通过 | ✅ 2026-07-08 |
| **M10** | Phase 14 | `Document` + `RecursiveCharacterSplitter` 分割结果验证、`MockEmbedding` 测试通过 | ✅ 2026-07-09 |
| **M11** | Phase 15 | `PersistentVectorStore` 持久化 roundtrip、`RagPipeline::ingest → retrieve` 端到端验证 | ✅ 2026-07-09 |
| **M12** | Phase 16 | 多轮对话后摘要自动写入 SessionMemory、派生 slot 时摘要正确注入 + 第二轮实施审查 PASS | ✅ 2026-07-10 |
| **M13** | **Phase 17 (rc.1)** | `SessionManager` 创建/recover/replace/子树/销毁集成测试通过、`Checkpointer` checkpoint/rollback/list_checkpoints 验证(`fork` 推迟,按需时引入)| ✅ 2026-07-15 |
| **M14** | Phase 18 | `switch_agent` 热切换验证(slot / turn_index / session_memory 保留)、`dispatch` / `dispatch_all` 并行派发 + Semaphore 顺序、`dispatch_stream` 流事件序列验证 | ✅ 2026-07-15 |
| **M15** | Phase 19 | `KnowledgeGraph` 实体-关系 CRUD + `get_related` BFS 验证、双通道检索 Hybrid 策略验证 | ✅ 2026-07-17 |