# 09 - 分阶段落地路径

> 更新说明（2026-04-17）：
> Phase B 中的跨进程 IPC 方案已从 `UDS` 调整为跨平台的 `TCP loopback + 动态端口`。
> 文中历史上的 UDS 表述仅保留作演进背景，不再作为实现约束。

## 总体策略

遵循"最小可用 → 逐步增强"原则，每个阶段独立可交付、可验证。

存储引擎采用渐进引入策略：
- Phase A 引入 SQLite 元数据库
- Phase B 引入 Tantivy 全文检索
- Phase C 引入 Qdrant 向量检索 + 双引擎融合
- Phase D 完善反刍、Reranker、稀疏向量等增强能力

---

## Phase A: Injection 层 + 独立 crate 骨架 + SQLite 元数据库

**目标**：创建 `tiangong-memory` 独立 crate，实现 Actor 骨架 + 三级 Injection 读取 + SQLite 加密元数据库。

**前置条件**：无

**代码变更**：

| 文件 | 变更类型 | 描述 |
|------|---------|------|
| `crates/tiangong-memory/Cargo.toml` | 新增 | crate 配置（含 rusqlite + sha2 + hex） |
| `crates/tiangong-memory/src/lib.rs` | 新增 | crate 入口，导出公共 API |
| `crates/tiangong-memory/src/types.rs` | 新增 | 基础类型定义（MemoryScope 等） |
| `crates/tiangong-memory/src/command.rs` | 新增 | MemoryCommand 消息协议 |
| `crates/tiangong-memory/src/handle.rs` | 新增 | MemoryHandle（客户端句柄，支持自动重连） |
| `crates/tiangong-memory/src/actor.rs` | 新增 | MemoryActor（独立运行时） |
| `crates/tiangong-memory/src/store.rs` | 新增 | MemoryStore（三层存储协调器） |
| `crates/tiangong-memory/src/db/` | 新增 | SQLite 加密连接、schema 建表、CRUD |
| `crates/tiangong-memory/src/injection.rs` | 新增 | 三级 Injection 读取 |
| `crates/tiangong-memory/src/election/` | 新增 | Leader 选举骨架（进程内模式） |
| `Cargo.toml`（workspace） | 修改 | 添加 tiangong-memory 到 members |
| `crates/tiangong-core/Cargo.toml` | 修改 | 添加 tiangong-memory 依赖 |
| `prompt/sections.rs` | 修改 | `build_user_context()` 通过 Handle 查询 |
| `context/memory.rs` | 标记废弃 | `#[deprecated]` |

**新增外部依赖**：
```toml
rusqlite = { version = "0.32", features = ["bundled-sqlcipher"] }
sha2 = "0.10"
hex = "0.4"
```

**预计代码量**：~450 行新增，~30 行修改

**验证标准**：
1. 创建 `~/.tiangong/memory/profile/agent.md` 后，新会话能注入其内容
2. 不创建文件时，行为与现有一致（空注入）
3. Memory Actor 正常启动和关闭，无泄漏
4. SQLite 数据库文件在 `~/.tiangong/memory/metadata.db` 创建成功
5. 数据库已加密（直接用其他工具打开显示非法文件）
6. 所有入口（CLI、Server、GUI）都能通过 `start_or_connect_with_options()` 初始化或连接 Memory
7. 同一 workspace 多入口只产生一个 leader，其他入口通过 remote handle 访问
8. 不同 workspace 的 leader 运行文件相互隔离
9. GUI + CLI + Server 真实多进程组合验证通过
10. `cargo check --workspace` 通过

---

## Phase B: Episodic Memory 写入 + IPC + Tantivy 全文检索

**目标**：turn 执行完成后自动写入 Episode（SQLite + Tantivy），实现跨进程 IPC 和 Leader 选举。

**前置条件**：Phase A 完成

**代码变更**：

| 文件 | 变更类型 | 描述 |
|------|---------|------|
| `tiangong-memory/src/store.rs` | 扩展 | 协调 SQLite + Tantivy 的写入 |
| `tiangong-memory/src/db/sqlite.rs` | 扩展 | Episode/Entity/Decision CRUD |
| `tiangong-memory/src/search/` | 新增 | 检索子模块骨架 |
| `tiangong-memory/src/search/tantivy.rs` | 新增 | Tantivy Schema 定义、文档索引、BM25 查询 |
| `tiangong-memory/src/writer.rs` | 新增 | EpisodeWriter（调用专用 Memory LLM 提取摘要，未配置时规则 fallback） |
| `tiangong-memory/examples/memory_llm_smoke.rs` | 新增 | 手动验证专用 Memory LLM 配置、JSON 标记、token 用量和耗时 |
| `tiangong-memory/src/rumination.rs` | 新增 | MicroRumination（仅 Episode 写入部分） |
| `tiangong-memory/src/actor.rs` | 扩展 | 处理 WriteEpisode / RunMicroRumination 命令 |
| `tiangong-memory/src/ipc/` | 新增 | UDS IPC 服务端/客户端 |
| `tiangong-memory/src/election/` | 扩展 | Leader 选举、心跳、Follower 监控 |
| runtime 集成点 | 修改 | turn 完成后通过 Handle 发送反刍命令 |

**新增外部依赖**：
```toml
tantivy = "0.22"
```

**预计代码量**：~700 行新增，~50 行修改

**验证标准**：
1. 执行一个包含工具调用的 turn 后：
   - SQLite `memory_nodes` 表中出现新记录
   - SQLite `episodes` 表中出现详细数据
   - Tantivy 索引目录 `~/.tiangong/memory/tantivy_index/` 生成索引文件
2. Tantivy 全文搜索关键词能命中已写入的 Episode
3. 纯对话 turn 不产生 Episode
4. 并发安全：Actor 串行处理，多个 turn 并发完成时不丢数据
5. 多进程场景：同时运行 GUI + CLI，只有一个 Leader，另一个通过 IPC 访问
6. Leader 进程退出后，剩余进程能自动选举新 Leader
7. Tantivy 索引可从 SQLite 数据重建

**关键设计决策**：
- Phase B 的 Episode 采用"写入 + Tantivy 可搜"策略，但主召回仍用 Tantivy BM25 单引擎
- 写入命令通过 Handle fire-and-forget，不阻塞主流程
- Actor 内部串行处理，天然无写入冲突
- IPC 和 Leader 选举是必要组件，确保多进程场景 Memory 不缺失

---

## Phase C: Qdrant 向量检索 + 双引擎召回 + Progressive Recall

**目标**：引入 Qdrant 语义检索，实现双引擎召回 + 融合重排 + 定向展开，Recall 结果注入 Prompt。

**前置条件**：Phase B 完成（有 Episode 数据 + Tantivy 索引可供召回）；`tiangong-llm` 已支持 `EmbeddingProvider` trait + OpenAI 兼容实现

**代码变更**：

| 文件 | 变更类型 | 描述 |
|------|---------|------|
| `tiangong-memory/src/search/qdrant.rs` | 新增 | Qdrant collection 管理、point upsert、语义查询 |
| `tiangong-memory/src/search/embedding.rs` | 新增 | 封装 `tiangong_llm::embedding::EmbeddingProvider` 调用，提供 Memory 特化便捷方法 |
| `tiangong-memory/src/search/reranker.rs` | 新增 | 分数归一化、时间衰减、重要度加权、双命中奖励 |
| `tiangong-memory/src/search/mod.rs` | 新增 | 检索统一入口（Query 分析 + 双引擎调度） |
| `tiangong-memory/src/recall.rs` | 新增 | RecallAnchors 提取 + 双引擎召回 + 定向展开 |
| `tiangong-memory/src/rumination.rs` | 扩展 | MesoRumination（Entity/Decision 提取） |
| `prompt/assembler.rs` | 修改 | 注入 Recall 结果到 Prompt |
| `context/organizer.rs` | 修改 | 压缩完成回调 Meso 反刍 |
| `workspace_index/` | 新增（可选） | 文件树索引 |

**新增外部依赖**：
```toml
qdrant-client = "1"
async-trait = "0.1"
```

**预计代码量**：~800 行新增，~80 行修改

**验证标准**：
1. 新会话提问历史任务相关内容时：
   - Tantivy 全文召回能命中包含精确关键词的 Episode
   - Qdrant 语义召回能命中语义相近但措辞不同的 Episode
2. 双引擎融合结果优于单引擎
3. Query 分析正确判断 Keyword / Semantic / Hybrid 意图
4. 锚点提取延迟 < 5ms
5. 双引擎召回延迟 < 50ms
6. 融合重排延迟 < 2ms
7. Recall 结果正确注入到 Prompt 的 UserContext 段
8. Meso 反刍正确提取 Entity 和 Decision 并同时更新三层存储

---

## Phase D: Rumination + 增强检索 + Workspace Index

**目标**：完整反刍机制、过时检测、LLM Reranker、稀疏向量、符号索引。

**前置条件**：Phase C 完成；`tiangong-llm` 已支持 `RerankProvider` trait + OpenAI 兼容 rerank 实现

**代码变更**：

| 文件 | 变更类型 | 描述 |
|------|---------|------|
| `tiangong-memory/src/rumination.rs` | 扩展 | MetaRumination（过时检测、归档、索引维护） |
| `tiangong-memory/src/recall.rs` | 扩展 | 接入 `tiangong_llm::rerank::RerankProvider` 进行模型精排（Jina/Cohere/BAAI 等） |
| `tiangong-memory/src/search/qdrant.rs` | 扩展 | 稀疏向量、Hybrid Retrieval |
| `tiangong-memory/src/search/embedding.rs` | 扩展 | 在 tiangong-llm 中实现本地 ONNX EmbeddingProvider（离线可用） |
| `tiangong-memory/src/workspace_index.rs` | 新增 | 文件树扫描、Rust 符号扫描、查询与单文件增量更新 |

**新增依赖（可选）**：
```toml
ort = "2"                  # ONNX Runtime（本地 embedding）
```

**预计代码量**：~900 行新增，~100 行修改

**验证标准**：
1. 应用启动时自动执行 Meta 反刍
2. 过时 Episode 被正确标记并从 Tantivy/Qdrant 索引中移除
3. 通过 tiangong-llm `RerankProvider` 对 top-20 候选精排后质量提升
4. 本地 embedding（tiangong-llm ONNX EmbeddingProvider）可离线运行
5. 文件树索引在 turn 中可用
6. 符号索引准确（Rust 文件的 struct/fn/mod）

**当前状态**：Meta 过时检测、归档索引同步、embedded/Qdrant 删除、文件树索引、Rust `mod/fn/struct/enum/trait` 符号索引、workspace index 查询、单文件增量更新、`recall_memory` 线索补充和 `RerankProvider` 模型精排已完成首期实现。本地 ONNX embedding 仍按后续任务推进。

---

## 阶段依赖图

```
Phase A (Injection + SQLite)
    ↓
Phase B (Episode + IPC + Tantivy)
    ↓
Phase C (Qdrant + 双引擎 Recall + Meso)
    ↓
Phase D (Meta + Reranker + Sparse + Local Embedding + Index)
```

每个阶段可独立发布，不依赖后续阶段的实现。

### 存储引擎引入时序

| 阶段 | SQLite | Tantivy | Qdrant | 召回策略 |
|------|--------|---------|--------|---------|
| Phase A | ✅ 建库建表 | — | — | 仅 Injection |
| Phase B | ✅ CRUD | ✅ BM25 索引 | — | Tantivy 单引擎 |
| Phase C | ✅ | ✅ | ✅ Dense Vector | 双引擎 + 规则融合 |
| Phase D | ✅ | ✅ | ✅ Dense + Sparse | 双引擎 + RerankProvider 模型精排 |

---

## 风险与缓解

| 风险 | 影响 | 缓解措施 |
|------|------|---------|
| Episode 提取质量差 | 记忆数据噪声大 | Phase B 仅 Tantivy 可搜，后续人工审查后调优 prompt |
| SQLite 加密编译依赖 | 构建时间增长 | `bundled-sqlcipher` 自带编译，CI 缓存构建产物 |
| Tantivy 索引损坏 | 检索不可用 | 索引可从 SQLite 重建，启动时校验 |
| Qdrant 嵌入式内存占用 | 桌面应用资源消耗 | 控制 collection 大小 + 过时清理 |
| Embedding API 延迟/费用 | 写入变慢，费用增加 | Phase C 用 tiangong-llm EmbeddingProvider（API），Phase D 引入本地 ONNX |
| LLM 提取成本 | API 费用增加 | 使用专用 Memory LLM，不复用主 `chat` 模型，每次 < 1000 tokens |
| Memory 目录膨胀 | 磁盘空间 | Meta 反刍归档 + Evidence 定期清理 |
| Leader 选举复杂度 | 开发成本 | Phase A 先实现进程内模式，Phase B 完善跨进程选举 |
