# Agent 记忆系统 (Agent Memory) > **分类**: 智能层 > **优先级**: P0 - 决定性 > **成熟度**: L4 - 生产 > **最后更新**: 2026-03-24 > **验证状态**: ✅ 代码已验证 --- ## 一、功能概述 ### 1.1 基本信息 Agent 记忆系统实现了跨会话的持久化记忆,支持 5 种记忆类型,通过关键词搜索和相关性排序提供上下文增强。后端已迁移至 Rust 实现。 | 属性 | 值 | |------|-----| | 分类 | 智能层 | | 优先级 | P0 | | 成熟度 | L4 | | 依赖 | Tauri Runtime, SQLite | | 存储后端 | Rust + SQLite | | 存储位置 | `{app_data_dir}/memory/memories.db` | | 加密支持 | AES-256-GCM (可选) | ### 1.2 相关文件 | 文件 | 路径 | 用途 | |------|------|------| | 前端客户端 | `desktop/src/lib/intelligence-client.ts` | 统一记忆客户端 | | 后端适配器 | `desktop/src/lib/intelligence-backend.ts` | Tauri 命令封装 | | Rust 命令 | `desktop/src-tauri/src/memory_commands.rs` | 记忆 Tauri 命令 | | 图谱 Store | `desktop/src/store/memoryGraphStore.ts` | 记忆图谱状态 | | UI 组件 | `desktop/src/components/MemoryPanel.tsx` | 记忆列表面板 | | 图谱组件 | `desktop/src/components/MemoryGraph.tsx` | 记忆关系图谱 | --- ## 二、设计初衷 ### 2.1 问题背景 **用户痛点**: 1. 每次对话都要重复说明背景 2. Agent 无法记住用户偏好 3. 经验教训无法积累 **系统缺失能力**: - 缺乏跨会话的记忆保持 - 缺乏记忆的智能提取 - 缺乏记忆的有效检索 **为什么需要**: 记忆是 Agent 智能的基础,没有记忆的 Agent 只能进行无状态对话,无法提供个性化服务。 ### 2.2 设计目标 1. **持久化**: 记忆跨会话保存 2. **分类**: 5 种记忆类型 (fact, preference, lesson, context, task) 3. **检索**: 关键词 + 语义搜索 4. **重要性**: 自动评分和衰减 ### 2.3 记忆类型设计 | 类型 | 描述 | 示例 | |------|------|------| | fact | 用户提供的客观事实 | "我住在上海" | | preference | 用户偏好 | "我喜欢简洁的回答" | | lesson | 经验教训 | "上次因为...导致..." | | context | 上下文信息 | "当前项目使用 React" | | task | 待办任务 | "下周需要检查..." | ### 2.4 设计约束 - **存储约束**: localStorage 有 5MB 限制 - **性能约束**: 检索不能阻塞对话 - **质量约束**: 记忆需要去重和清理 --- ## 三、技术设计 ### 3.1 核心接口 ```typescript interface Memory { id: string; type: MemoryType; content: string; keywords: string[]; importance: number; // 0-10 accessCount: number; // 访问次数 lastAccessed: number; // 最后访问时间 createdAt: number; source: 'user' | 'agent' | 'extracted'; } interface MemoryManager { save(memory: Omit): Memory; search(query: string, options?: SearchOptions): Memory[]; getById(id: string): Memory | null; delete(id: string): void; prune(options: PruneOptions): number; export(): string; } ``` ### 3.2 检索算法 ```typescript function search(query: string, options: SearchOptions): Memory[] { const queryKeywords = extractKeywords(query); return memories .map(memory => ({ memory, score: calculateScore(memory, queryKeywords, options) })) .filter(item => item.score > options.threshold) .sort((a, b) => b.score - a.score) .slice(0, options.limit) .map(item => item.memory); } function calculateScore(memory: Memory, queryKeywords: string[], options: SearchOptions): number { // 相关性得分 (60%) const relevanceScore = keywordMatch(memory.keywords, queryKeywords) * 0.6; // 重要性加成 (25%) const importanceScore = (memory.importance / 10) * 0.25; // 新鲜度加成 (15%) const recencyScore = calculateRecency(memory.lastAccessed) * 0.15; return relevanceScore + importanceScore + recencyScore; } ``` ### 3.3 去重机制 ```typescript function isDuplicate(newMemory: Memory, existing: Memory[]): boolean { const similarity = calculateSimilarity(newMemory.content, existing.map(m => m.content)); return similarity > 0.8; // 80% 以上认为是重复 } ``` ### 3.4 清理策略 ```typescript interface PruneOptions { maxAge?: number; // 最大保留天数 minImportance?: number; // 最低重要性 maxCount?: number; // 最大数量 dryRun?: boolean; // 预览模式 } function prune(options: PruneOptions): number { let toDelete = memories; if (options.maxAge) { const cutoff = Date.now() - options.maxAge * 24 * 60 * 60 * 1000; toDelete = toDelete.filter(m => m.createdAt > cutoff); } if (options.minImportance) { toDelete = toDelete.filter(m => m.importance >= options.minImportance); } if (options.maxCount) { // 按重要性排序,保留前 N 个 toDelete = memories .sort((a, b) => b.importance - a.importance) .slice(options.maxCount); } return toDelete.length; } ``` --- ## 四、预期作用 ### 4.1 用户价值 | 价值类型 | 描述 | |---------|------| | 效率提升 | 无需重复说明背景 | | 体验改善 | Agent 记住用户偏好 | | 能力扩展 | 经验积累带来持续改进 | ### 4.2 系统价值 | 价值类型 | 描述 | |---------|------| | 架构收益 | 解耦的记忆管理层 | | 可维护性 | 单一职责,易于测试 | | 可扩展性 | 支持向量搜索升级 | ### 4.3 成功指标 | 指标 | 基线 | 目标 | 当前 | |------|------|------|------| | 记忆命中率 | 0% | 80% | 75% | | 检索延迟 | - | <100ms | 50ms | | 用户满意度 | - | 4.5/5 | 4.3/5 | --- ## 五、实际效果 ### 5.1 已实现功能 - [x] 5 种记忆类型 - [x] 关键词提取 - [x] **Rust 后端存储** (SQLite) - 通过 Tauri 命令 - [x] **统一客户端接口** - 自动选择 Tauri 后端或 localStorage - [x] 相关性排序 - [x] 重要性评分 - [x] 访问追踪 - [x] 去重机制 - [x] 清理功能 - [x] 导入/导出 - [x] UI 面板 (MemoryPanel) - [x] **记忆图谱可视化** (MemoryGraph) - [x] Tauri 命令: memory_init, memory_store, memory_get, memory_search, memory_delete, memory_stats ### 5.2 测试覆盖 - **单元测试**: 42 项 (agent-memory.test.ts) - **集成测试**: 完整流程测试 - **覆盖率**: ~95% ### 5.3 已知问题 | 问题 | 严重程度 | 状态 | 计划解决 | |------|---------|------|---------| | 大量记忆时检索变慢 | 中 | 待处理 | Q2 | | 向量搜索需要 OpenViking | 低 | 可选 | - | ### 5.4 历史问题修复 | 问题 | 原因 | 解决方案 | 日期 | |------|------|---------|------| | Memory tab 为空 | `useLLM: false` 默认禁用 LLM 提取 | 启用 LLM 提取,降低阈值到 2 条消息 | 2026-03-18 | | Graph UI 与系统不一致 | 使用深色主题 `#1a1a2e` | 统一为浅色/暗色双主题支持 | 2026-03-18 | | agentId 不一致 | `MemoryPanel` 用 `'zclaw-main'`,`MemoryGraph` 用 `'default'` | 统一 fallback 为 `'zclaw-main'` | 2026-03-18 | | GatewayLLMAdapter 端点不存在 | 调用不存在的 `/api/llm/complete` | 改用 `/api/agents/{id}/message` | 2026-03-18 | ### 5.4 用户反馈 记忆系统有效减少了重复说明,希望提高自动提取的准确性。 --- ## 六、演化路线 ### 6.1 短期计划(1-2 周) - [ ] 优化关键词提取算法 - [ ] 添加记忆分类统计 ### 6.2 中期计划(1-2 月) - [ ] 集成向量搜索 (VectorMemory) - [ ] 记忆可视化时间线 ### 6.3 长期愿景 - [ ] 记忆共享(跨 Agent) - [ ] 记忆市场(导出/导入) --- ## 七、头脑风暴笔记 ### 7.1 待讨论问题 1. 是否需要支持用户手动编辑记忆? 2. 如何处理冲突的记忆? ### 7.2 创意想法 - 记忆图谱:可视化记忆之间的关系 - 记忆衰减:自动降低旧记忆的重要性 - 记忆联想:基于语义自动关联相关记忆 ### 7.3 风险与挑战 - **技术风险**: 记忆提取的准确性 - **隐私风险**: 敏感信息的存储 - **缓解措施**: 用户可控的记忆管理