Files
zclaw_openfang/docs/knowledge-base/semantic-memory-audit.md
iven 0d4fa96b82
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
refactor: 统一项目名称从OpenFang到ZCLAW
重构所有代码和文档中的项目名称,将OpenFang统一更新为ZCLAW。包括:
- 配置文件中的项目名称
- 代码注释和文档引用
- 环境变量和路径
- 类型定义和接口名称
- 测试用例和模拟数据

同时优化部分代码结构,移除未使用的模块,并更新相关依赖项。
2026-03-27 07:36:03 +08:00

237 lines
10 KiB
Markdown
Raw Permalink 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.

# 语义记忆 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
- L0Quick Scan: ~100 tokens3-5 个关键词
- L1Standard: ~200 tokens1-2 句话摘要
- L2Deep: 完整内容
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 |