重构所有代码和文档中的项目名称,将OpenFang统一更新为ZCLAW。包括: - 配置文件中的项目名称 - 代码注释和文档引用 - 环境变量和路径 - 类型定义和接口名称 - 测试用例和模拟数据 同时优化部分代码结构,移除未使用的模块,并更新相关依赖项。
10 KiB
语义记忆 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::EmbeddingClientHTTP 客户端存在,Settings 页面有测试按钮- 但前端保存 Embedding 配置后未调用
viking_configure_embedding将配置传递到后端 SqliteStorage.store()未在存储时自动生成 embeddingSqliteStorage.find()未使用混合评分(embedding + TF-IDF)
修复方案:
- 创建
embedding_adapter.rs— 将llm::EmbeddingClient适配为zclaw_growth::EmbeddingClienttrait SqliteStorage添加configure_embedding()方法- 修改
store()— embedding 可用时自动生成向量 - 修改
find()— 混合评分(70% embedding + 30% TF-IDF),降级到纯 TF-IDF - 前端
ModelsAPI.tsx保存后调用viking_configure_embedding App.tsxbootstrap 阶段自动恢复配置
经验教训:
"代码写好不等于功能可用" — 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()+ 手动拼接,无分层概念
修复方案:
MemoryEntry添加overview: Option<String>和abstract_summary: Option<String>- 两套存储系统均做 schema migration(
ALTER TABLE ADD COLUMN) - 新建
summarizer.rs—SummaryLlmDrivertrait + prompt 模板 - 新建
summarizer_adapter.rs— 用 OpenAI 兼容 API 实现摘要生成 - 添加
memory_build_contextTauri 命令 — 优先使用 L1 overview,尊重 token 预算 chatStore.ts替换为调用buildContext()获取分层上下文VikingPanel.tsx支持 L1→L2 展开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 常见差距模式
本次审计中发现的差距模式可归纳为:
- "写了没接" — 代码已实现但未接入实际流程(ContextBuilder、EmbeddingClient)
- "接了没传" — 后端命令存在但前端未调用(viking_configure_embedding)
- "传了没存" — 配置保存了但未持久化或恢复(Embedding 配置丢失)
- "存了没用" — 数据已存储但读取时未使用(overview 字段未被搜索返回)
- "双系统不同步" — 一套系统有功能另一套没有(SqliteStorage vs PersistentMemoryStore)
5.3 审计命令速查
# 搜索 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 |