# 开箱即用的上下文记忆库方案 (简化版) ## 一、背景与目标 ### 1.1 问题 当前 ZCLAW 的 OpenViking 集成需要用户独立安装 Python 包 (`pip install openviking`),不是开箱即用的。 ### 1.2 关键发现 ⚠️ 经过深入分析,发现 **zclaw-growth crate 已经实现了核心功能**: | 组件 | 文件 | 状态 | |------|------|------| | `VikingStorage` trait | `viking_adapter.rs` | ✅ 已实现 | | `SqliteStorage` | `storage/sqlite.rs` | ⚠️ 只用内存缓存 | | `SemanticScorer` (TF-IDF) | `retrieval/semantic.rs` | ✅ 已实现 | | `MemoryExtractor` | `extractor.rs` | ✅ 已实现 | | `MemoryRetriever` | `retriever.rs` | ✅ 已实现 | | `PromptInjector` | `injector.rs` | ✅ 已实现 | **问题**:`SqliteStorage` 虽然名字是 SQLite,但实际只用内存缓存(见 `storage/sqlite.rs:96-99`)。 ### 1.3 修订目标 - **完善现有实现**:让 `SqliteStorage` 真正持久化到 SQLite - **集成 TF-IDF**:使用已有的 `SemanticScorer` 提供语义搜索 - **替换外部依赖**:Tauri 命令使用 `SqliteStorage` 而非 Python 进程 - **无需 LanceDB**:现有 TF-IDF 方案已足够 ## 二、简化方案 ### 2.1 核心改动 | 改动 | 工作量 | 说明 | |------|--------|------| | 完善 `SqliteStorage` | 中 | 添加真正的 SQLite 持久化 | | 集成 `SemanticScorer` | 小 | 替换简单的相似度计算 | | 修改 `viking_commands.rs` | 中 | 使用 `SqliteStorage` 替代 Python 调用 | | 删除 `viking_server.rs` | 小 | 不再需要服务器管理 | ### 2.2 架构对比 **当前架构** (需要外部 Python): ``` 前端 → viking-client.ts → Tauri Commands → Python OpenViking 进程 ``` **目标架构** (纯 Rust): ``` 前端 → viking-client.ts → Tauri Commands → SqliteStorage (Rust) → SemanticScorer (TF-IDF) → ~/.zclaw/memories.db ``` ## 三、架构设计 ### 3.1 整体架构 ``` ┌─────────────────────────────────────────────────────────────────┐ │ ZCLAW Desktop (Tauri) │ │ │ │ ┌─────────────────┐ │ │ │ viking-client.ts│ (前端 API 保持不变) │ │ └────────┬────────┘ │ │ │ invoke() │ │ ┌────────▼────────────────────────────────────────────────────┐│ │ │ viking_commands.rs ││ │ │ (Tauri 命令层 - 接口不变,实现改为调用 zclaw-growth) ││ │ └────────┬────────────────────────────────────────────────────┘│ │ │ │ │ ┌────────▼────────────────────────────────────────────────────┐│ │ │ zclaw-growth (已存在) ││ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ ││ │ │ │SqliteStorage│ │SemanticScorer│ │ MemoryExtractor │ ││ │ │ │ (完善持久化)│ │ (TF-IDF) │ │ MemoryRetriever │ ││ │ │ └─────────────┘ └─────────────┘ │ PromptInjector │ ││ │ │ └─────────────────────┘ ││ │ └────────┬────────────────────────────────────────────────────┘│ │ │ │ │ ┌────────▼────────────────────────────────────────────────────┐│ │ │ 本地存储层 ││ │ │ ~/.zclaw/ ││ │ │ ├── memories.db (SQLite 持久化) ││ │ │ └── growth.json (成长指标) ││ │ └─────────────────────────────────────────────────────────────┘│ └─────────────────────────────────────────────────────────────────┘ ``` ### 3.2 模块变更 | 模块 | 位置 | 变更 | |------|------|------| | `SqliteStorage` | `crates/zclaw-growth/src/storage/sqlite.rs` | **完善**:添加真正的 SQLite 持久化 | | `viking_commands.rs` | `desktop/src-tauri/src/viking_commands.rs` | **修改**:使用 SqliteStorage | | `viking_server.rs` | `desktop/src-tauri/src/viking_server.rs` | **删除**:不再需要 | ### 3.3 数据模型 (已存在) ```rust // crates/zclaw-growth/src/types.rs pub struct MemoryEntry { pub uri: String, // agent://{agent_id}/{type}/{category} pub memory_type: MemoryType, pub content: String, pub keywords: Vec, pub importance: u8, // 1-10 pub access_count: u32, pub created_at: DateTime, pub last_accessed: DateTime, } pub enum MemoryType { Preference, // 用户偏好 Knowledge, // 知识积累 Experience, // 技能经验 Session, // 会话历史 } ``` ## 四、接口设计 ### 4.1 保持兼容的 Tauri 命令 | 命令 | 功能 | 变化 | |------|------|------| | `viking_status` | 检查状态 | 返回 `available: true` (始终可用) | | `viking_add` | 添加资源 | 内部使用 SqliteStorage | | `viking_find` | 语义搜索 | 使用 TF-IDF + SQLite FTS | | `viking_grep` | 模式搜索 | 使用 SQLite FTS | | `viking_ls` | 列出资源 | 从 SQLite 读取 | | `viking_read` | 读取内容 | 从 SQLite 读取 | | `viking_remove` | 删除资源 | 从 SQLite 删除 | | `viking_tree` | 资源树 | 从 SQLite 构建 | ### 4.2 移除的命令 | 命令 | 原因 | |------|------| | `viking_server_start` | 无需服务器 | | `viking_server_stop` | 无需服务器 | | `viking_server_status` | 无需服务器 | ## 五、实施计划 ### Phase 1: 完善 SqliteStorage (1-2 天) **任务 1.1: 添加 sqlx 依赖** ```toml # crates/zclaw-growth/Cargo.toml [dependencies] sqlx = { workspace = true, features = ["runtime-tokio", "sqlite"] } ``` **任务 1.2: 实现真正的 SQLite 持久化** - 文件: `crates/zclaw-growth/src/storage/sqlite.rs` - 改动: ```rust pub struct SqliteStorage { pool: SqlitePool, // 替换 RwLock scorer: SemanticScorer, // 添加语义评分器 } ``` - 功能: - `initialize_schema()` - 创建 memories 表和 FTS5 索引 - `store()` - 写入 SQLite - `get()` - 从 SQLite 读取 - `find()` - 使用 SemanticScorer + FTS **任务 1.3: 集成 SemanticScorer** - 替换 `compute_similarity()` 简单实现 - 使用已有的 TF-IDF 算法 ### Phase 2: 修改 Tauri 命令 (1 天) **任务 2.1: 修改 viking_commands.rs** ```rust // 替换 async fn viking_find(...) { let cli = get_viking_cli_path()?; let output = Command::new(&cli).arg("find")... } // 为 lazy_static! { static ref STORAGE: SqliteStorage = ...; } async fn viking_find(...) { STORAGE.find(query, options).await } ``` **任务 2.2: 删除 viking_server.rs** - 移除服务器管理相关命令 - 更新 `lib.rs` 移除模块引用 **任务 2.3: 初始化存储** - 在 `lib.rs` 的 `run()` 函数中初始化 `SqliteStorage` - 存储路径: `~/.zclaw/memories.db` ### Phase 3: 测试与验证 (1 天) **任务 3.1: 单元测试** - 完善 `SqliteStorage` 测试 - 测试持久化和恢复 **任务 3.2: 集成测试** - 端到端测试: 前端 → Tauri → SqliteStorage - 验证 `viking_find` 返回语义相关结果 **任务 3.3: 验收测试** - 启动 Tauri 后无需配置即可使用 - 打包体积无显著增加 ## 六、文件变更清单 ### 修改文件 | 文件 | 变更 | |------|------| | `crates/zclaw-growth/src/storage/sqlite.rs` | 添加真正的 SQLite 持久化 | | `crates/zclaw-growth/Cargo.toml` | 添加 sqlx 依赖 | | `desktop/src-tauri/src/viking_commands.rs` | 使用 SqliteStorage | | `desktop/src-tauri/src/lib.rs` | 移除 viking_server 模块,初始化存储 | ### 删除文件 | 文件 | 原因 | |------|------| | `desktop/src-tauri/src/viking_server.rs` | 不再需要服务器管理 | ### 保持不变 | 文件 | 原因 | |------|------| | `desktop/src/lib/viking-client.ts` | API 兼容 | | `desktop/src/components/VikingPanel.tsx` | UI 不变 | | `crates/zclaw-growth/src/viking_adapter.rs` | 接口不变 | | `crates/zclaw-growth/src/retrieval/semantic.rs` | TF-IDF 已实现 | ## 七、风险与缓解 | 风险 | 影响 | 缓解措施 | |------|------|----------| | SQLite FTS5 中文支持 | 搜索质量 | 使用 `unicode61` tokenizer | | TF-IDF 语义理解有限 | 搜索精度 | 可选:后续添加 embedding API | | 数据迁移 | 用户数据丢失 | localStorage 降级保留 | ## 八、验收标准 - [ ] 启动 Tauri 后无需任何配置即可使用记忆功能 - [ ] `viking_status` 返回 `available: true` - [ ] `viking_find` 返回语义相关结果(基于 TF-IDF) - [ ] 数据持久化到 `~/.zclaw/memories.db` - [ ] 打包体积无显著增加(< 1MB) - [ ] 所有现有测试通过 - [ ] 前端 API (`viking-client.ts`) 无需修改 ## 九、与现有设计文档的关系 本方案是对 `docs/superpowers/specs/2026-03-26-agent-growth-design.md` 的**简化实现**: | 设计文档要求 | 本方案实现 | |-------------|-----------| | OpenViking 作为完整记忆层 | SqliteStorage (实现 VikingStorage trait) | | 语义搜索 | TF-IDF (SemanticScorer) | | L0/L1/L2 分层 | 已有实现,保持不变 | | 记忆提取 | 已有 MemoryExtractor,保持不变 | **核心差异**:设计文档说用 OpenViking Python 包,本方案用纯 Rust 实现替代,保持接口兼容。 ## 十、对系统架构的影响分析 ### 10.1 正面影响 | 影响 | 说明 | |------|------| | **消除外部依赖** | 不再需要 Python 环境 | | **降低复杂度** | 移除进程管理代码 | | **提高可靠性** | 无进程启动失败风险 | | **减少打包体积** | 无需打包 Python | ### 10.2 潜在风险 | 风险 | 影响 | 缓解措施 | |------|------|----------| | TF-IDF 语义理解不如 embedding | 搜索精度降低 | 后续可选添加 embedding API | | 大量记忆时性能下降 | 查询变慢 | 添加分页、索引优化 | ### 10.3 功能完整性 | 功能 | 原方案 (OpenViking) | 新方案 (SqliteStorage) | |------|---------------------|------------------------| | 存储记忆 | ✅ | ✅ | | 语义搜索 | ✅ embedding | ⚠️ TF-IDF (可接受) | | URI 寻址 | ✅ | ✅ | | L0/L1/L2 分层 | ✅ | ✅ 已有实现 | | 记忆提取 | ✅ | ✅ 已有实现 | | 记忆检索 | ✅ | ✅ 已有实现 | | Prompt 注入 | ✅ | ✅ 已有实现 | ### 10.4 结论 **推荐采用简化方案**: 1. 工作量小(3-4 天 vs 7+ 天) 2. 风险低(复用现有代码) 3. 满足"开箱即用"核心需求 4. 后续可渐进增强(添加 embedding)