- middleware.md: 集成契约+3不变量+执行流 (157→136行) - saas.md: 移除安全重复→引用security.md+Token Pool算法 (231→173行) - security.md: 吸收saas认证内容成为安全唯一真相源 (158→199行) - memory.md: 最大压缩363→147行+Hermes洞察提炼+4不变量 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
148 lines
6.8 KiB
Markdown
148 lines
6.8 KiB
Markdown
---
|
||
title: 记忆管道
|
||
updated: 2026-04-22
|
||
status: active
|
||
tags: [module, memory, fts5, growth]
|
||
---
|
||
|
||
# 记忆管道 (Memory Pipeline)
|
||
|
||
> 从 [[index]] 导航。关联: [[chat]] [[middleware]] [[butler]]
|
||
> 详细提取逻辑归档: [[archive/memory-extraction-details]]
|
||
|
||
## 1. 设计决策
|
||
|
||
**核心问题: LLM 无状态,每次对话从零开始。需要从历史对话中积累知识。**
|
||
|
||
| 决策 | WHY |
|
||
|------|-----|
|
||
| 闭环架构 | 对话→提取→索引→检索→注入,形成正向循环。每次聊天都积累,每次提问都利用 |
|
||
| 双数据库 | memories.db (FTS5 全文索引) + data.db (结构化画像)。前者处理模糊语义检索,后者处理精确字段查询 |
|
||
| FTS5+TF-IDF+Embedding 三层 | FTS5 粗筛 + TF-IDF 加权 + Embedding 精排(当前 NoOp,配置后激活)。不依赖外部服务即可工作 |
|
||
| 进化引擎 | 从对话中检测行为模式变化,生成进化候选项(技能建议/工作流优化),通过 EvolutionMiddleware@78 注入 system prompt |
|
||
| Token 预算控制 | 注入 system prompt 时有 token 上限,防止记忆注入挤占用户实际对话空间 |
|
||
|
||
**Hermes 核心借鉴** (详见 [[archive/hermes-analysis]]): 经验库 FTS5 全文检索 + 用户画像结构化建模 + 自然语言 cron 调度 + 轨迹记录压缩。4 Chunk 已交付: ExperienceStore(10 tests) + UserProfileStore(14 tests) + NlScheduleParser(16 tests) + TrajectoryRecorder(18 tests)。
|
||
|
||
## 2. 关键文件 + 数据流
|
||
|
||
### 核心文件
|
||
|
||
| 文件 | 职责 |
|
||
|------|------|
|
||
| `crates/zclaw-growth/src/extractor.rs` | LLM 记忆提取 (偏好/知识/经验) |
|
||
| `crates/zclaw-growth/src/retriever.rs` | 语义检索 (FTS5 + TF-IDF + 意图分类) |
|
||
| `crates/zclaw-growth/src/injector.rs` | Prompt 注入 (token 预算) |
|
||
| `crates/zclaw-growth/src/storage/sqlite.rs` | FTS5 + TF-IDF 核心 (memories.db) |
|
||
| `crates/zclaw-runtime/src/middleware/memory.rs` | 记忆中间件 (提取+注入编排) |
|
||
| `crates/zclaw-runtime/src/growth.rs` | GrowthIntegration 闭环编排 |
|
||
| `crates/zclaw-memory/src/user_profile_store.rs` | UserProfileStore (data.db) |
|
||
|
||
### 闭环数据流
|
||
|
||
```
|
||
[提取] 对话完成 → MemoryMiddleware.after_completion
|
||
→ MemoryExtractor.extract_combined() → LLM 单次调用
|
||
→ CombinedExtraction { memories, experiences, profile_signals }
|
||
→ VikingAdapter → SqliteStorage → memories.db (FTS5 索引)
|
||
→ UserProfileStore → data.db (结构化画像)
|
||
|
||
[检索] 新请求 → MemoryMiddleware.before_completion
|
||
→ MemoryRetriever.retrieve(agent_id, user_input)
|
||
→ QueryAnalyzer 意图分类 (5类: Preference/Knowledge/Experience/Code/General)
|
||
→ FTS5 全文搜索 + TF-IDF 评分 + IdentityRecall 43+ 模式
|
||
→ 弱身份 fallback: <3 结果 → 补充 broad retrieval
|
||
→ PromptInjector.inject_with_format(system_prompt, memories)
|
||
```
|
||
|
||
### 集成契约
|
||
|
||
| 方向 | 模块 | 触发点 |
|
||
|------|------|--------|
|
||
| Called by | middleware: Memory@150 | Every chat completion (after) + new request (before) |
|
||
| Calls | zclaw-memory: FTS5 store, TF-IDF scorer | Memory extraction + retrieval |
|
||
| Calls | zclaw-growth: GrowthIntegration, EvolutionEngine | Pattern detection + skill generation |
|
||
| Provides | loop_runner: Context injection into system prompt | Before LLM call |
|
||
|
||
### Tauri 命令
|
||
|
||
| 分类 | 命令数 | 关键命令 |
|
||
|------|--------|----------|
|
||
| Memory CRUD (`memory_commands.rs`) | 11 | `memory_store`, `memory_search`, `memory_build_context` |
|
||
| VikingStorage (`viking_commands.rs`) | 14 | `viking_add`, `viking_find`, `viking_inject_prompt` |
|
||
| Intelligence (`intelligence/`) | ~40 | identity(13), heartbeat(11), pain(5), reflection(6) |
|
||
| 提取+Embedding | 5 | `extract_session_memories`, `embedding_create` |
|
||
|
||
## 3. 代码逻辑
|
||
|
||
### 跨会话记忆完整链路
|
||
|
||
```
|
||
[初始化] kernel_init → init_storage(memories.db) → MemoryStore(data.db)
|
||
→ set_viking(SqliteStorage) → set_extraction_driver(LLM)
|
||
→ [首次聊天] create_middleware_chain() 重建 GrowthIntegration:
|
||
VikingAdapter + ExtractionDriver + UserProfileStore(data.db)
|
||
→ MemoryMiddleware@150 注册到中间件链
|
||
|
||
[写入] after_completion → 30秒去重 → extract_combined(LLM)
|
||
→ memories → memories.db | profile_signals → data.db
|
||
|
||
[读取] before_completion → retrieve(agent_id, query)
|
||
→ FTS5 + TF-IDF + IdentityRecall → inject_with_format()
|
||
|
||
[展示] 管家Tab → viking_ls/viking_read(memories.db) + agent_get(data.db)
|
||
```
|
||
|
||
### 不变量
|
||
|
||
- memories.db 和 data.db 是独立的 SQLite 数据库,跨库查询需使用正确连接
|
||
- 记忆注入在中间件@150,AFTER ButlerRouter@80,BEFORE SkillIndex@200
|
||
- Embedding 当前为 NoOpEmbeddingClient,用户配置 provider 后替换为真实实现
|
||
- 30 秒去重窗口:同一 agent 30 秒内跳过重复提取
|
||
- URI scheme: `agent://{agent_id}/{type}/{category}`
|
||
|
||
### 非显然逻辑
|
||
|
||
- TF-IDF 语义路由:70% embedding 权重 + 30% TF-IDF(embedding 未激活时退化为纯 TF-IDF)
|
||
- IdentityRecall: 43+ 模式匹配("你记得我"/"上次说的"/"我的偏好"等)触发记忆检索
|
||
- 弱身份 fallback: 检索结果 <3 且含弱身份关键词时,补充 broad retrieval 扩大搜索范围
|
||
|
||
## 4. 活跃问题 + 陷阱
|
||
|
||
### 活跃
|
||
|
||
| 问题 | 状态 | 说明 |
|
||
|------|------|------|
|
||
| Embedding 未激活 | 🚧 长期观察 | NoOpEmbeddingClient 是默认值,用户配置 provider 后替换 |
|
||
| SaaS pgvector | 🚧 deferred | HNSW 索引就绪 (knowledge_chunks, vector(1536)),生成逻辑未实现 |
|
||
|
||
### 历史陷阱 (已修复)
|
||
|
||
- 跨会话记忆断裂 (profile_store 未连接 + 双数据库不一致 + 缺日志) → 04-22 已修复 (adf0251)
|
||
- 记忆去重失败 (同 URI+content 重复添加) → 04-17 已修复 (a504a40)
|
||
- 记忆非 Agent 隔离 (viking_find 返回所有 Agent 记忆) → 04-17 已修复 (a504a40)
|
||
- 跨会话注入断裂 (新会话报 "no conversation history found") → 04-17 已修复 (a504a40)
|
||
|
||
### 警告
|
||
|
||
> memories.db / data.db 连接池隔离。修改存储层代码务必确认目标数据库。
|
||
> GrowthIntegration 缓存在 `set_viking()` / `set_extraction_driver()` 时会被清除,首次聊天时重建。
|
||
|
||
## 5. 变更日志
|
||
|
||
| 日期 | 变更 | 关联 |
|
||
|------|------|------|
|
||
| 2026-04-22 | 跨会话记忆断裂修复: profile_store 连接 + 双数据库统一 + 诊断日志 | commit adf0251 |
|
||
| 2026-04-22 | Wiki 5-section 重构: 363→~190 行,详细逻辑归档 | wiki/ |
|
||
| 2026-04-21 | Embedding 接通 + 自学习自动化 A线+B线 (SemanticScorer + EvolutionMiddleware) | 934 tests PASS |
|
||
| 2026-04-17 | E2E 全系统验证 129 链路: 记忆去重+注入+跨会话 修复 | 79.1% 通过率 |
|
||
| 2026-04-15 | Heartbeat 统一健康系统 (health_snapshot + 健康快照集成) | 183 commands |
|
||
|
||
## 测试概览
|
||
|
||
| Crate | 测试数 | 覆盖 |
|
||
|-------|--------|------|
|
||
| zclaw-growth | 181 (29 文件) | 全覆盖 |
|
||
| zclaw-memory | 54 (4 文件) | 全覆盖 |
|
||
| **合计** | **235** | |
|