Every thought leaves a trace — persistent memory MCP server with Ebbinghaus decay, vector search, and graph expansion
Project description
Engram
Every thought leaves a trace.
给 AI Agent 装一颗会遗忘的大脑。
Engram 是一个完全本地运行的 MCP 记忆服务。它不只是"存取"——它模拟人类记忆的遗忘、强化、联想机制,让 Agent 跨会话记住真正重要的事,自然忘掉不再需要的细节。
零云端依赖,数据永远在你的机器上。
为什么需要它
AI Agent 的每次对话都是一张白纸。你昨天告诉它的偏好、上周达成的架构决策、上个月踩过的坑——下次对话全部归零。
传统解决方案是"把什么都存下来"。但记忆不是仓库,是筛子。人类之所以高效,不是因为记住了所有事,而是因为遗忘了 90% 不重要的,强化了 10% 关键的。
Engram 把这套机制搬给 Agent:
- 重要的偏好和决策,衰减极慢,几乎永久保留
- 临时的调试上下文,11 天自然消退
- 反复被回忆起的知识,越用越牢固
- 矛盾的信息自动覆盖,不会左右互搏
核心机制
1. 艾宾浩斯遗忘曲线
每条记忆都有一个强度值(strength),随时间按指数曲线衰减:
effective_λ = base_λ × (1 - importance × 0.8)
strength = importance × e^(-λ × days) × (1 + recall_count × 0.2)
三个因子共同决定一条记忆能活多久:
| 因子 | 作用 | 机制 |
|---|---|---|
| 重要性(importance) | 越重要衰减越慢 | 最高可将衰减率降低 80% |
| 类别(category) | 不同类型不同半衰期 | 见下表 |
| 回忆次数(recall_count) | 越常用越牢固 | 每次召回 +20% 强度 |
四种记忆类别:
| 类别 | 衰减率 λ | 半衰期 | 适用场景 |
|---|---|---|---|
strategy |
0.10 | ~38 天 | 被验证有效的方法论、架构模式 |
fact |
0.16 | ~24 天 | 用户偏好、身份信息、技术选型 |
assumption |
0.20 | ~19 天 | 推断的上下文、不确定的信息 |
failure |
0.35 | ~11 天 | 踩过的坑、环境问题、临时 workaround |
设计意图:成功的策略要记最久(strategy ~38天),失败的教训记最短(failure ~11天)——因为环境会变,昨天的坑明天可能已经填上了。
2. 智能去重与矛盾消解
存入新记忆时,系统不是简单追加,而是先和已有记忆做语义比对:
相似度 ≥ 0.85 → REINFORCE 只增加回忆次数,不重复存储
相似度 0.65~0.84 → 检测矛盾
├── 语义矛盾 → REPLACE 用新内容覆盖旧内容
└── 语义兼容 → MERGE 合并为一条更完整的记忆
相似度 < 0.65 → NEW 存为新记忆
矛盾检测通过极性分析实现:提取正面词(prefer/love/adopt)和负面词(avoid/hate/reject),加上否定词(not/don't/never),判断两条记忆是否表达相反立场。
例:已有"用户偏好 TypeScript",再存入"用户决定放弃 TypeScript 改用 Go",系统识别为矛盾,自动用新记忆替换旧的。
3. 混合检索(向量 + BM25 + 图谱)
召回记忆时使用三路混合评分:
最终得分 = 0.4 × BM25关键词得分 + 0.6 × (语义相似度 × 衰减强度) + 图谱加成
为什么不只用向量搜索?
| 检索方式 | 擅长 | 不擅长 |
|---|---|---|
| 向量搜索 | "他上次提到的那个部署方式" → 语义理解 | 精确术语匹配 |
| BM25 | "DuckDB" → 精确关键词 | 语义相近但措辞不同 |
| 图谱扩展 | A→B→C 关联发现 | 独立的、无关联的记忆 |
三路融合的效果:用"数据库性能"查询,不仅能找到直接提到性能的记忆,还能通过图谱关联找到相关的索引策略、缓存决策等记忆。
4. 语义图谱
每条记忆在存入时自动和已有记忆建立语义关联:
- 计算与所有已有记忆的余弦相似度
- 相似度 ≥ 0.40 的建立双向边,权重 = 相似度 × 0.5
- 每条记忆最多连接 5 个最相似的邻居
图谱的两个关键作用:
联想发现:检索时从命中的记忆出发做 BFS(最大深度 2),沿边找到关联记忆,即使它们和查询词没有直接的语义相似度。就像人类"由此及彼"的联想。
链式保护:当一条记忆自身衰减到阈值以下,如果它的邻居中仍有强记忆,则保留它——因为它可能是连接两个重要知识点的桥梁。
5. 自动整合与淘汰
后台每 12 小时自动运行一次维护任务:
整合(Consolidation):
- 找出相似度 ≥ 0.70 的记忆簇
- 保留重要性最高的一条作为主记忆
- 将其余记忆的独有信息合并进来
- 重新计算向量和图谱关系
- 删除被合并的冗余记忆
淘汰(Pruning):
- 计算每条记忆的当前强度
- 强度 < 0.05 且 通过链式安全检查 → 删除
- 强度 < 0.05 但邻居仍强 → 保留(链式保护)
这意味着记忆库会自动保持精简——不需要手动清理,也不会无限膨胀。
技术架构
┌──────────────────────────────────────────────┐
│ MCP Client │
│ (Claude Code / Cursor / ...) │
└──────────────────┬───────────────────────────┘
│ stdio (JSON-RPC)
┌──────────────────▼───────────────────────────┐
│ server.py │
│ 5 MCP tools · APScheduler (12h 维护) │
├──────────────────────────────────────────────┤
│ │
│ ┌─ 写入路径 ──────┐ ┌─ 读取路径 ──────┐ │
│ │ resolve.py │ │ retrieve.py │ │
│ │ 去重/矛盾消解 │ │ 混合检索+评分 │ │
│ └─────────────────┘ └─────────────────┘ │
│ │
│ ┌─ 维护路径 ──────┐ ┌─ 统计路径 ──────┐ │
│ │ consolidator │ │ decay.py │ │
│ │ 聚类合并+剪枝 │ │ 遗忘曲线+强度 │ │
│ └─────────────────┘ └─────────────────┘ │
│ │
├──────────────────────────────────────────────┤
│ embedding.py │ graph.py │
│ 768d / 1024d 向量编码 │ NetworkX 语义图谱 │
├──────────────────────────────────────────────┤
│ db.py — DuckDB │
│ 向量存储 · BM25 全文索引 · CRUD │
└──────────────────────────────────────────────┘
数据文件(~/.engram/):
├── memories.duckdb # 向量数据库(单文件,零运维)
├── graph.pkl # 语义图谱(NetworkX 序列化)
└── model_cache/ # 嵌入模型缓存
MCP 工具接口
| 工具 | 参数 | 用途 |
|---|---|---|
recall_memory |
query, user_id?, top_k? |
语义检索记忆,每次任务开始时调用 |
store_memory |
content, importance, category?, user_id? |
存储新记忆(自动去重) |
update_memory |
memory_id, new_content, importance? |
更新已有记忆 |
consolidate_memory |
user_id? |
手动触发记忆整合 |
memory_stats |
user_id? |
记忆统计:总数、类别分布、平均强度、上次维护时间 |
重要性参考
| 值 | 使用场景 |
|---|---|
| 0.9–1.0 | 核心身份、永久事实("用户是后端工程师") |
| 0.7–0.8 | 强偏好、架构决策("项目用 Go + PostgreSQL") |
| 0.5 | 普通项目事实("最近在做登录模块重构") |
| 0.2–0.3 | 临时会话上下文("这次调试用的测试账号") |
对用户的收益
1. Agent 真正"认识"你
不再每次对话都要重新介绍自己的技术栈、编码习惯和项目背景。Agent 记住你偏好 Go 而不是 Java,知道你们项目用 monorepo,了解你上周做的架构决策。
2. 知识自然进化
矛盾消解意味着 Agent 的认知永远是最新的。你从 React 切到 Vue?一次对话自动更新。不需要手动维护一个"Agent 应该知道什么"的列表。
3. 零运维
- 不需要手动清理旧记忆——遗忘曲线自动淘汰
- 不需要手动合并重复——整合器自动处理
- 不需要担心数据膨胀——12 小时一次自动维护
- 不需要外部服务——DuckDB 单文件,开箱即用
4. 完全隐私
所有数据存在 ~/.engram/,不联网、不上传、不依赖任何云服务。嵌入模型也是本地运行。你的记忆就是你的。
5. 联想式发现
图谱扩展让 Agent 不只是"搜到什么返回什么",而是能沿着语义关联找到相关但不直接匹配的知识。就像你问一个老同事某个问题,他不光回答问题本身,还会提一嘴"对了,这个和上次那个事有关"。
6. 越用越聪明
回忆强化机制:被反复召回的记忆强度越来越高,衰减越来越慢。Agent 自动学会什么知识对你最有价值。
快速开始
# 安装
pip install mcp-engram
# 初始化(下载模型、创建数据库)
engram-setup
# 按照输出提示将配置块添加到 Claude Code 配置中
Claude Code 配置
{
"mcpServers": {
"engram": {
"command": "engram",
"env": {
"HF_ENDPOINT": "https://hf-mirror.com"
}
}
}
}
CLAUDE.md 集成
在项目 CLAUDE.md 中添加:
## Memory Rules
### Step 1 — 先回忆再行动
每次任务开始时,用请求中的关键词调用 `recall_memory`。
### Step 2 — 学到新东西就存
| 情况 | 操作 |
|------|------|
| 全新知识 | `store_memory(content, importance)` |
| 补充已有 | `update_memory(memory_id, merged_content)` |
| 推翻已有 | `update_memory(memory_id, new_content)` |
环境变量
| 变量 | 默认值 | 说明 |
|---|---|---|
HF_ENDPOINT |
https://hf-mirror.com |
HuggingFace 模型镜像 |
ENGRAM_MODEL |
all-mpnet-base-v2 |
嵌入模型名称 |
关键阈值速查
| 参数 | 值 | 含义 |
|---|---|---|
| 嵌入维度 | 768 | all-mpnet-base-v2 |
| 去重 REINFORCE | ≥ 0.85 | 几乎相同,只加回忆次数 |
| 去重 MERGE/REPLACE | 0.65~0.84 | 检测矛盾或合并 |
| 整合聚类 | ≥ 0.70 | 自动合并相似记忆 |
| 图谱建边 | ≥ 0.40 | 创建语义关联 |
| 淘汰阈值 | < 0.05 | 删除衰减殆尽的记忆 |
| 检索高阈值 | ≥ 0.50 | 主向量搜索 |
| 检索低阈值 | ≥ 0.20 | 降级搜索 |
| BM25 权重 | 40% | 关键词匹配贡献 |
| 向量权重 | 60% | 语义匹配贡献 |
| 图谱加成 | 30% | 关联记忆的额外加分 |
LoCoMo Benchmark 评测
基于 LoCoMo(Snap Research 长期对话记忆基准)的检索质量评测。LoCoMo 是 Mem0/Zep/Memobase/MemMachine 等产品统一使用的评测标准。
评测配置
- 数据集:locomo10.json(2/10 conversations, 233 QA, 排除 adversarial)
- 检索:recall() top-k=5
- LLM:DeepSeek-V3.2 / GLM-5.1(注:基线产品统一使用 GPT-4o-mini)
- 指标:Token-level F1(LoCoMo 官方指标)+ Hit@5(LLM 无关的检索命中率)
Turn Mode — 最佳配置(bge-m3 + bge-reranker-v2-m3, DeepSeek-V3.2)
两阶段检索:recall top-50 → CrossEncoder rerank to top-5,importance=1.0 修正权重比
| Category | Count | F1 | Hit@5 |
|---|---|---|---|
| Single-Hop | 114 | 0.5121 | 76.3% |
| Temporal | 63 | 0.4501 | 95.2% |
| Multi-Hop | 43 | 0.3181 | 60.5% |
| Open-Domain | 13 | 0.1324 | 61.5% |
| Overall | 233 | 0.4383 | 77.7% |
Turn Mode — 优化路径(DeepSeek-V3.2)
| 配置 | Overall F1 | Overall Hit@5 |
|---|---|---|
| bge-m3 + reranker + weight fix | 0.4383 | 77.7% |
| bge-m3 + reranker (r20) | 0.3913 | 69.1% |
| bge-m3 (API, 1024d) | 0.3514 | 61.8% |
| all-mpnet-base-v2 (local, 768d) | 0.2916 | 51.5% |
四轮优化累计 F1 +50.3%(0.29 → 0.44),Hit@5 +26.2pp(51.5% → 77.7%)。
Turn Mode — LLM 对比(all-mpnet-base-v2)
| LLM | Overall F1 | Single-Hop | Temporal | Multi-Hop | Open-Domain | 耗时 |
|---|---|---|---|---|---|---|
| DeepSeek-V3.2 | 0.2916 | 0.3470 | 0.3257 | 0.1772 | 0.0192 | 239s |
| GLM-5.1 | 0.2477 | 0.2672 | 0.3214 | 0.1430 | 0.0659 | 2011s |
Observation Mode(抽象 assertive facts)
| Category | Count | F1 |
|---|---|---|
| Single-Hop | 114 | 0.3000 |
| Multi-Hop | 43 | 0.1837 |
| Open-Domain | 13 | 0.0659 |
| Temporal | 63 | 0.0590 |
| Overall | 233 | 0.2003 |
与业界基线对比
| System | Overall F1 | LLM | Embedding |
|---|---|---|---|
| MemMachine | 0.8487 | GPT-4o-mini | — |
| Memobase | 0.7578 | GPT-4o-mini | — |
| Zep | 0.7514 | GPT-4o-mini | — |
| Mem0 | 0.6688 | GPT-4o-mini | — |
| Engram | 0.4383 | DeepSeek-V3.2 | bge-m3 + reranker |
结论:四轮优化 mpnet(0.29) → bge-m3(0.35) → +reranker(0.39) → +weight fix+r50(0.44)。Hit@5: 51.5% → 77.7%。与 Mem0(0.67) 的差距从 56% 缩小到 35%。
Best Config 速查
推荐配置:
bge-m3(1024d) +bge-reranker-v2-m3两阶段检索
指标 值 说明 Overall F1 0.4383 Token-level,DeepSeek-V3.2 Overall Hit@5 77.7% 纯检索命中率,LLM 无关 Temporal Hit@5 95.2% 时序类问题表现突出 优化幅度 F1 +50.3%, Hit +26.2pp 四轮累计(相对初始 mpnet) 关键参数:
recall top-50 → rerank to top-5,importance=1.0修正权重比。 本地部署零云端依赖,与使用 GPT-4o-mini 的 Mem0 差距缩小至 35%。
运行评测
# 纯检索命中率(不需要 LLM)
python benchmark/locomo_eval.py --mode turn --top-k 5
# 带 LLM 评分 + API embedding
python benchmark/locomo_eval.py --mode turn --top-k 5 \
--llm DeepSeek-V3.2 --base-url https://api.example.com/v1 \
--embed-model bge-m3
# 带 reranker(两阶段检索,最佳配置)
python benchmark/locomo_eval.py --mode turn --top-k 5 \
--llm DeepSeek-V3.2 --base-url https://api.example.com/v1 \
--embed-model bge-m3 --rerank
# 快速验证(前 10 题)
python benchmark/locomo_eval.py --mode turn --dry-run
开发
git clone https://github.com/hugfeature/engram.git
cd engram
pip install -e ".[dev]"
pytest tests/ -v
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcp_engram-0.2.0.tar.gz.
File metadata
- Download URL: mcp_engram-0.2.0.tar.gz
- Upload date:
- Size: 30.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bff5822b4d32d50da5d05fc57ca91da868f06d1a285d6d71a1488ca9c0b5136e
|
|
| MD5 |
c2c78babec825cd5dbd74c7e80d2d818
|
|
| BLAKE2b-256 |
7c2a692a0c886a0069eb95b0bdcd941a5a9a51e62317e106d0a9edeaaaae00da
|
File details
Details for the file mcp_engram-0.2.0-py3-none-any.whl.
File metadata
- Download URL: mcp_engram-0.2.0-py3-none-any.whl
- Upload date:
- Size: 23.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
286c071a53d6b361c63fcd092dbe94729c6fc6cb263036e751fe477e9d062fdb
|
|
| MD5 |
4c55ab07a266edad615929a2a225dbc5
|
|
| BLAKE2b-256 |
8851cd90c41f01a20bc5617e57b507c44752e036fb2955e886a35225de74d079
|