Add a new memory provider that delegates to a local Nowledge Mem instance for memory storage, retrieval, and knowledge graph building. Key design decisions: - User messages tagged as [DisplayName], bot messages as [我] - Per-message display name parsed from YAML front-matter headers - Let Nowledge Mem handle entity extraction and graph building - 6-way hybrid search (semantic + full-text + entity + community + label + graph) New files: - internal/memory/adapters/nowledgemem/client.go (REST API client) - internal/memory/adapters/nowledgemem/nowledgemem.go (Provider impl) - docs/nowledge-mem.md (design document with research and decisions) Modified: types.go, service.go, serve.go (provider registration), frontend (add-memory-provider.vue, types.gen.ts, i18n locales)
5.5 KiB
Nowledge Mem 集成设计文档
背景
Memoh 内置的 builtin memory provider 效果不佳。Nowledge Mem 是一个本地优先的 AI 记忆管理器,具备知识图谱、6 路混合搜索、后台智能(实体抽取、EVOLVES 关系检测、Crystal 合成、衰减评分)等能力,作为替代方案集成到 Memoh 的 memory provider 体系中。
调研:Nowledge Mem 能力概览
产品定位
- 本地优先的个人知识库,数据默认存储在用户设备
- 免费,支持 macOS / Windows / Linux
- 为 AI 工具(Claude Code、Cursor 等)提供统一的持久化记忆层
核心能力
| 能力 | 说明 |
|---|---|
| 记忆管理 | CRUD + 标签组织 + 重要性评分 |
| 语义搜索 | 6 路混合:semantic + full-text + entity + community + label + graph traversal |
| 知识图谱 | 自动实体抽取(Person/Concept/...)、关系可视化、遍历深度控制 |
| 蒸馏 (Distill) | 从对话线程中提取关键记忆 |
| Crystal 合成 | 三条以上独立记忆汇聚同一主题时自动合成统一摘要 |
| Decay + Confidence | 双分评分系统:新鲜度(指数衰减 + 频率提升)+ 可信度(只增不减) |
| Working Memory | 每日自动生成 daily briefing |
| 后台智能 | 定时任务:crystallization、community detection、KG extraction、decay refresh |
接入方式
- REST API:
http://127.0.0.1:14242,无认证 - MCP Server:
http://127.0.0.1:14242/mcp(streamableHttp) - CLI:
nmem命令行工具
方案选择
排除的方案
- 方案 B(双向同步):Memoh 和 Nowledge Mem 各自有完整的记忆 pipeline,双向同步没有意义
- 方案 C(MCP 接入):不够原生,Agent 不会主动调用 MCP 工具来记忆
最终方案:方案 A — 作为 Memory Provider
将 Nowledge Mem 作为 Memoh 的 memory provider 实现,通过 adapters.Provider 接口接入:
OnBeforeChat:搜索相关记忆注入上下文OnAfterChat:将对话写入 Nowledge Mem,由其 LLM 做实体抽取和知识图谱构建- 搜索、存储、CRUD 全部代理到 Nowledge Mem REST API
为什么不用方案 D(线程归档)
方案 D 只是事后归档,对 agent 在线对话质量无直接帮助。可作为 A 的补充,不做替代。
设计决策
多用户/群聊适配
Nowledge Mem 是单用户个人知识库,没有 user_id 或 group_id 概念。但在多用户维度上,现有的 Mem0 和 OpenViking provider 同样没做隔离(都只按 bot_id scope)。
关键改进:在存储文本中嵌入结构化的发言人标识,让 Nowledge Mem 的实体抽取和全文搜索能区分不同人。
存储文本格式
每条记忆对应一轮对话(用户消息 + bot 回复):
[张三] 我最近在用 Rust 重写后端
[我] 很好的选择,Rust 的性能和安全性都很出色
- 用户消息:
[{display-name}] {消息内容}- display-name 从 YAML front-matter header 中解析(Memoh 的 user_header.go 在每条用户消息中嵌入了
display-name字段) - 回退链:YAML header → AfterChatRequest.DisplayName →
"用户"
- display-name 从 YAML front-matter header 中解析(Memoh 的 user_header.go 在每条用户消息中嵌入了
- Bot 消息:
[我] {消息内容}- LLM 读到
[我]时自然理解为"这是我之前说过的话" 我不是命名实体,不会在知识图谱中产生误导节点
- LLM 读到
为什么不用 (@username) 双标识
AfterChatRequest 中只有 DisplayName(人类可读名)和内部 UUID(UserID、ChannelIdentityID),没有平台级 username。YAML header 中也只有 display-name 和 channel-identity-id(内部 ID)。因此只使用 display-name。
查询侧
直接使用用户消息原文查询 POST /memories/search。Nowledge Mem 的 6 路搜索会自动处理:
- 语义搜索命中话题相关记忆
- 全文搜索命中包含人名的记忆
- 实体搜索命中 Person 实体关联的记忆
不需要在查询时拼接发言人信息。
上下文注入格式
与现有 provider 一致的 <memory-context> XML 格式:
<memory-context>
Relevant memory context (use when helpful):
- [2025-01-15] [张三] 喜欢用 Rust,推荐过《The Rust Programming Language》
- [2025-01-10] [李四] 对 Rust 感兴趣但还没开始学习
</memory-context>
实现
新建文件
internal/memory/adapters/nowledgemem/client.go— HTTP 客户端internal/memory/adapters/nowledgemem/nowledgemem.go— Provider 实现
修改文件
internal/memory/adapters/types.go— 添加ProviderNowledgeMem常量internal/memory/adapters/service.go— 验证 + 元数据cmd/memoh/serve.go— 注册工厂apps/web/src/pages/memory/components/add-memory-provider.vue— UI 下拉选项packages/sdk/src/types.gen.ts— TypeScript 类型apps/web/src/i18n/locales/en.json/zh.json— 国际化
配置
创建 provider 时只需 base_url(可选,默认 http://127.0.0.1:14242):
{
"name": "nmem",
"provider": "nowledgemem",
"config": {}
}
局限性
- 本地依赖:Nowledge Mem 必须与 Memoh 在同一台机器上运行
- 无 GetAll:Nowledge Mem API 不提供列出所有记忆的端点(带分页的 GET /memories 不含语义排序),GetAll 返回 unsupported error
- 无 Compact:记忆整理由 Nowledge Mem 后台智能自动处理(decay refresh、crystallization),不暴露给 Memoh
- display-name 可变:用户改名后,旧记忆中的名字不会更新。但 Nowledge Mem 的 Entity aliases 机制可能缓解此问题