Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
重构所有代码和文档中的项目名称,将OpenFang统一更新为ZCLAW。包括: - 配置文件中的项目名称 - 代码注释和文档引用 - 环境变量和路径 - 类型定义和接口名称 - 测试用例和模拟数据 同时优化部分代码结构,移除未使用的模块,并更新相关依赖项。
237 lines
10 KiB
Markdown
237 lines
10 KiB
Markdown
# 语义记忆 vs OpenViking 差距审计记录
|
||
|
||
**审计日期**: 2026-03-26
|
||
**审计范围**: ZCLAW 语义记忆子系统 vs OpenViking 原始设计
|
||
**审计结果**: 发现 2 个核心差距,已全部修复
|
||
|
||
---
|
||
|
||
## 一、审计背景与方法
|
||
|
||
### 1.1 审计动机
|
||
|
||
ZCLAW 的记忆系统基于 OpenViking 设计构建,但在实际落地过程中可能存在功能缺失或实现降级。本次审计目的是系统性比对 ZCLAW 实现与 OpenViking 设计规格之间的差距。
|
||
|
||
### 1.2 审计方法(可复用模板)
|
||
|
||
本次采用的五步审计流程可作为其他功能点的审计模板:
|
||
|
||
```
|
||
Step 1: 文档对齐 — 将 OpenViking 设计文档与 ZCLAW 实际代码逐一比对
|
||
Step 2: 追踪数据流 — 从前端 UI 到后端存储,确认每个环节是否连通
|
||
Step 3: 识别 dead_code — 搜索 #[allow(dead_code)]、#![allow(dead_code)]、未注册的命令
|
||
Step 4: 检查 trait 实现 — 确认 trait 方法是否被实际调用(而非仅定义)
|
||
Step 5: 验证端到端 — 从用户操作角度验证功能是否真正可用
|
||
```
|
||
|
||
### 1.3 关键发现
|
||
|
||
ZCLAW 存在**两套并行存储系统**,这是很多差距的根因:
|
||
|
||
| 存储系统 | 代码位置 | 使用场景 | 调用入口 |
|
||
|----------|----------|----------|----------|
|
||
| `SqliteStorage` | `crates/zclaw-growth/src/storage/sqlite.rs` | VikingPanel 记忆管理 | VikingCommands |
|
||
| `PersistentMemoryStore` | `desktop/src-tauri/src/memory/persistent.rs` | 聊天流程记忆 | MemoryCommands |
|
||
|
||
两套系统功能不对等,导致某些功能在一个路径可用但另一个不可用。
|
||
|
||
---
|
||
|
||
## 二、发现的差距与修复
|
||
|
||
### 差距 1: 向量嵌入搜索未启用
|
||
|
||
**严重程度**: 高
|
||
**差距描述**: OpenViking 设计中包含向量嵌入语义搜索,ZCLAW 代码中 `EmbeddingClient` trait、`index_entry_with_embedding()`、`score_similarity_with_embedding()` 已写好但从未被调用。搜索仅依赖 TF-IDF。
|
||
|
||
**根因分析**:
|
||
- `llm::EmbeddingClient` HTTP 客户端存在,Settings 页面有测试按钮
|
||
- 但前端保存 Embedding 配置后未调用 `viking_configure_embedding` 将配置传递到后端
|
||
- `SqliteStorage.store()` 未在存储时自动生成 embedding
|
||
- `SqliteStorage.find()` 未使用混合评分(embedding + TF-IDF)
|
||
|
||
**修复方案**:
|
||
1. 创建 `embedding_adapter.rs` — 将 `llm::EmbeddingClient` 适配为 `zclaw_growth::EmbeddingClient` trait
|
||
2. `SqliteStorage` 添加 `configure_embedding()` 方法
|
||
3. 修改 `store()` — embedding 可用时自动生成向量
|
||
4. 修改 `find()` — 混合评分(70% embedding + 30% TF-IDF),降级到纯 TF-IDF
|
||
5. 前端 `ModelsAPI.tsx` 保存后调用 `viking_configure_embedding`
|
||
6. `App.tsx` bootstrap 阶段自动恢复配置
|
||
|
||
**经验教训**:
|
||
> **"代码写好不等于功能可用"** — trait 实现、适配器、前端接入、启动恢复,任何一环缺失都会导致功能不可用。审计时不能只看代码是否存在,必须追踪完整调用链。
|
||
|
||
---
|
||
|
||
### 差距 2: L0/L1/L2 分层加载未接入
|
||
|
||
**严重程度**: 高
|
||
**差距描述**: OpenViking 设计了三层记忆加载策略以节省 token:
|
||
- L0(Quick Scan): ~100 tokens,3-5 个关键词
|
||
- L1(Standard): ~200 tokens,1-2 句话摘要
|
||
- L2(Deep): 完整内容
|
||
|
||
ZCLAW 中 `context_builder.rs` 已有完整 L0→L1→L2 加载逻辑,但整个模块标记为 `#![allow(dead_code)]`,从未接入实际聊天流程。
|
||
|
||
**根因分析**:
|
||
- `MemoryEntry` 缺少 `overview` 和 `abstract_summary` 字段
|
||
- 没有 LLM 驱动来生成摘要
|
||
- `ContextBuilder.build_context()` 未被任何 Tauri 命令调用
|
||
- `chatStore.ts` 使用简单的 `memory.search()` + 手动拼接,无分层概念
|
||
|
||
**修复方案**:
|
||
1. `MemoryEntry` 添加 `overview: Option<String>` 和 `abstract_summary: Option<String>`
|
||
2. 两套存储系统均做 schema migration(`ALTER TABLE ADD COLUMN`)
|
||
3. 新建 `summarizer.rs` — `SummaryLlmDriver` trait + prompt 模板
|
||
4. 新建 `summarizer_adapter.rs` — 用 OpenAI 兼容 API 实现摘要生成
|
||
5. 添加 `memory_build_context` Tauri 命令 — 优先使用 L1 overview,尊重 token 预算
|
||
6. `chatStore.ts` 替换为调用 `buildContext()` 获取分层上下文
|
||
7. `VikingPanel.tsx` 支持 L1→L2 展开
|
||
8. `extract_and_store_memories` 存储后异步生成 L0/L1
|
||
|
||
**经验教训**:
|
||
> **"#![allow(dead_code) 是最大的技术债信号"** — 完整的功能实现被标记为死代码,说明设计阶段考虑周全但集成阶段被跳过。审计时应优先搜索 `dead_code` 标记。
|
||
>
|
||
> **"后台异步生成 + 即时存储"模式** — L2 完整内容同步存储(不阻塞),L0/L1 摘要通过 `tokio::spawn` 后台异步生成并回写。这保证了用户体验不受影响。
|
||
|
||
---
|
||
|
||
## 三、集成审计中发现的 5 个 GAP
|
||
|
||
在修复核心差距后,进行了端到端集成审计,发现以下连通性问题:
|
||
|
||
| GAP | 描述 | 状态 |
|
||
|-----|------|------|
|
||
| GAP 1 | Settings 保存 Embedding 配置后未通知后端 | 已修复 |
|
||
| GAP 2 | Bootstrap 阶段未自动恢复 Embedding 配置 | 已修复 |
|
||
| GAP 3 | `extract_and_store_memories` 未触发 L0/L1 生成 | 已修复 |
|
||
| GAP 4 | Summary Driver 需要单独配置 | 不需要 — 已改为自动从活跃 LLM 配置 |
|
||
| GAP 5 | `context_builder.rs` 仍标记 dead_code | 已清理注释说明现状 |
|
||
|
||
---
|
||
|
||
## 四、遗留问题(后续工作)
|
||
|
||
### 4.1 双存储系统统一
|
||
|
||
当前 SqliteStorage 和 PersistentMemoryStore 功能不对等:
|
||
|
||
| 能力 | SqliteStorage | PersistentMemoryStore |
|
||
|------|--------------|----------------------|
|
||
| FTS5 全文搜索 | 有 | 无(仅 LIKE 查询) |
|
||
| TF-IDF 语义评分 | 有 | 无 |
|
||
| L0 abstract_summary | 有 | 无 |
|
||
| L0/L1 自动生成 | 有 | 无 |
|
||
| 导出/导入 | 无 | 有 |
|
||
| 记忆统计 | 无 | 有 |
|
||
|
||
**建议**: 长期应统一为一套存储系统,或在 PersistentMemoryStore 补齐缺失能力。
|
||
|
||
### 4.2 测试覆盖不足
|
||
|
||
| 模块 | 测试状态 |
|
||
|------|----------|
|
||
| `embedding_adapter.rs` | 无测试 |
|
||
| `memory_commands.rs` | 无测试 |
|
||
| `persistent.rs`(store/search/embedding) | 仅 1 个 ID 生成测试 |
|
||
| 端到端 embedding + 搜索流程 | 无集成测试 |
|
||
| 端到端 L0/L1 生成流程 | 无集成测试 |
|
||
|
||
### 4.3 ContextBuilder 完整版未启用
|
||
|
||
`context_builder.rs` 中的完整 L0→L1→L2 渐进加载逻辑仍是 dead_code。当前聊天流程使用简化的 `memory_build_context`。完整版预留了 retrieval trace、分阶段 token 预算等高级能力,待后续启用。
|
||
|
||
### 4.4 Intelligence 子系统大面积 dead_code
|
||
|
||
以下模块均为 `#![allow(dead_code)]`:
|
||
- `validation.rs` — 验证函数
|
||
- `identity.rs` — 身份管理
|
||
- `recommender.rs` — 推荐系统
|
||
- `heartbeat.rs` — 心跳引擎
|
||
- `pattern_detector.rs` — 模式检测
|
||
- `persona_evolver.rs` — 人格演化
|
||
- `compactor.rs` — 记忆压缩
|
||
- `trigger_evaluator.rs` — 触发评估
|
||
- `mesh.rs` — Agent 群体
|
||
- `reflection.rs` — 自我反思
|
||
|
||
---
|
||
|
||
## 五、审计方法论总结(供后续复用)
|
||
|
||
### 5.1 通用审计清单
|
||
|
||
对任何功能点进行审计时,按以下维度检查:
|
||
|
||
```
|
||
[ ] 代码存在性 — trait/struct/function 是否已定义
|
||
[ ] 实现完整性 — trait 方法是否有具体实现(非空/panic)
|
||
[ ] 调用链连通 — 从 UI 触发到后端执行的完整路径是否打通
|
||
[ ] 配置传递 — 前端配置是否能传递到后端生效
|
||
[ ] 启动恢复 — 应用重启后配置/状态是否能自动恢复
|
||
[ ] 降级策略 — 依赖不可用时是否有合理降级
|
||
[ ] 数据流闭环 — 写入的数据能否被正确读取和使用
|
||
[ ] dead_code 清理 — 无 dead_code 或有明确原因保留
|
||
[ ] 双系统一致性 — 多套实现是否功能对等
|
||
[ ] 测试覆盖 — 关键路径是否有测试
|
||
```
|
||
|
||
### 5.2 常见差距模式
|
||
|
||
本次审计中发现的差距模式可归纳为:
|
||
|
||
1. **"写了没接"** — 代码已实现但未接入实际流程(ContextBuilder、EmbeddingClient)
|
||
2. **"接了没传"** — 后端命令存在但前端未调用(viking_configure_embedding)
|
||
3. **"传了没存"** — 配置保存了但未持久化或恢复(Embedding 配置丢失)
|
||
4. **"存了没用"** — 数据已存储但读取时未使用(overview 字段未被搜索返回)
|
||
5. **"双系统不同步"** — 一套系统有功能另一套没有(SqliteStorage vs PersistentMemoryStore)
|
||
|
||
### 5.3 审计命令速查
|
||
|
||
```bash
|
||
# 搜索 dead_code 标记
|
||
rg "allow\(dead_code\)" --type rust
|
||
|
||
# 搜索未使用的函数
|
||
rg "#\[allow(dead_code)\]" crates/ desktop/src-tauri/src/
|
||
|
||
# 搜索未注册的 Tauri 命令
|
||
rg "#\[tauri::command\]" desktop/src-tauri/src/ -l
|
||
# 对比 lib.rs 中的 .invoke_handler() 注册列表
|
||
|
||
# 搜索 TODO/FIXME
|
||
rg "TODO|FIXME" --type rust --type ts
|
||
|
||
# 搜索前端 invoke 调用
|
||
rg "invoke\(" desktop/src/ --type ts -l
|
||
|
||
# 编译检查
|
||
cargo check 2>&1 | grep -i "warning\|error"
|
||
|
||
# 测试
|
||
cargo test -p zclaw-growth 2>&1 | tail -5
|
||
```
|
||
|
||
---
|
||
|
||
## 六、关键文件索引
|
||
|
||
| 文件 | 职责 | 审计阶段 |
|
||
|------|------|----------|
|
||
| `crates/zclaw-growth/src/types.rs` | MemoryEntry 数据模型 | Phase 2.1 |
|
||
| `crates/zclaw-growth/src/storage/sqlite.rs` | SqliteStorage 存储 | Phase 1.3, 2.1 |
|
||
| `crates/zclaw-growth/src/retrieval/semantic.rs` | TF-IDF + Embedding 评分 | Phase 1 |
|
||
| `crates/zclaw-growth/src/summarizer.rs` | L0/L1 摘要生成 trait | Phase 2.2 |
|
||
| `crates/zclaw-growth/src/injector.rs` | Prompt 注入器 | Phase 2.3 |
|
||
| `desktop/src-tauri/src/embedding_adapter.rs` | Embedding 适配器 | Phase 1.2 |
|
||
| `desktop/src-tauri/src/summarizer_adapter.rs` | 摘要 LLM 驱动 | Phase 2.2 |
|
||
| `desktop/src-tauri/src/viking_commands.rs` | Viking Tauri 命令 | Phase 1.4, 2.4 |
|
||
| `desktop/src-tauri/src/memory_commands.rs` | Memory Tauri 命令 | Phase 2.3 |
|
||
| `desktop/src-tauri/src/memory/persistent.rs` | PersistentMemoryStore | Phase 1.6, 2.1 |
|
||
| `desktop/src-tauri/src/memory/context_builder.rs` | L0/L1/L2 渐进加载 | Phase 2.3 |
|
||
| `desktop/src-tauri/src/memory/extractor.rs` | 会话记忆提取 | Phase 2.2 |
|
||
| `desktop/src/lib/intelligence-client.ts` | 前端记忆客户端 | Phase 2.3 |
|
||
| `desktop/src/store/chatStore.ts` | 聊天状态管理 | Phase 2.3 |
|
||
| `desktop/src/components/VikingPanel.tsx` | 记忆管理面板 | Phase 2.4 |
|
||
| `desktop/src/App.tsx` | 应用启动引导 | Phase 1.5, 2.2 |
|