关于 memharness
memharness 是面向 AI Agent 的 SQLite 长期记忆存储层,以双时态事实和来源记录保留信念变化及其依据。它通过 MCP 提供记忆操作,不在存储层调用 LLM 或网络。
主要功能
- 01按事实存储双时态记忆
- 02记录每条事实的来源
- 03修订时保留旧信念链
- 04按时间查询与比较变化
- 05支持按来源撤销记忆
- 06可选本地语义检索
适用场景
- 01追溯 Agent 某时点的信念
- 02检查记忆变化及其来源
- 03清除指定会话或来源的记忆
- 04管理超出上下文窗口的长期事实
MCP 相关
MCP 服务通过 stdio 向 MCP 客户端提供七种工具,用于记忆、检索、修订、比较、溯源、撤销和统计。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
memharness
面向 AI Agent 的双时态、携带来源信息的记忆原语。 一个 SQLite 文件。存储层不调用大模型或网络。可通过 MCP 提供给任何 Agent。
大多数 Agent 的记忆只是一堆字符串。memharness 存储的是事实,并结合了现有方案往往各自拆分处理的三种语义:
- 双时态:每条事实分别记录它在现实中开始成立的时间(
valid_from/valid_to)和Agent 得知它的时间(tx_at)。因此,你可以询问:“你在 3 月 1 日时相信什么?” - 只取代,不删除:更正会关闭旧事实,并将它链接到后续事实。*“你在我更正你之前是怎么想的?”*这个问题有答案。
- 每条事实都有来源信息:每条记忆都会注明是谁、在何处、何时说的。*“你为什么相信这个?”有答案。“忘掉那个会话里的所有内容。”*也有答案。
存储层是确定性的:没有大模型、没有网络、没有后台守护进程。 它就是普通的 SQLite,因此你可以用任何客户端打开该文件。
亲自运行:cd examples && npm install && npm run demo
适用场景(以及不适用的场景)
memharness 不是提升准确率的灵丹妙药,也对此坦诚以待。如果 Agent 的记忆量很小、内容固定,而且能轻松放进上下文窗口,那么使用 CLAUDE.md 文件(或者直接把历史记录塞进提示词)会更简单;对于较短的历史记录,完整上下文的表现也会胜过任何外部记忆系统,或至少与之相当。
以下情况可以考虑使用 memharness:
- 历史记录超出窗口容量:数月的事实、众多主题,内容多到你不想(或无法)在每个提示词里都粘贴一遍。
- 需要审计线索:“Agent 做出这项决策时相信什么?”(
as_of)、“自周一以来有什么变化?”(diff)、“它为什么相信这个?”(why)。这些问题不是一堆字符串能回答的。 - 需要按来源范围删除:一次调用即可*“忘掉那个会话/文件/来源中的所有内容”*(契合 GDPR 式需求,而不是字符串搜索)。
- 信念会随时间变化:更正应该取代旧内容,而不是悄然覆盖,这样旧的推理过程仍然可以解释。
对比
坦诚而言,memharness 的独特之处在于它是一个确定性、可审计的存储层,而不是提取服务。
| 存储方式 | 写入时的大模型调用 | as_of / diff / why | 可嵌入 / 可自托管 | |
|---|---|---|---|---|
| memharness | 一个 SQLite 文件 | 无 | 支持:双时态 + 来源信息 | 支持,它是一个库 |
| mem0 | 托管 / OSS 服务 | 有(提取流水线) | 部分支持 / 不支持 | 部分支持 |
| Zep / Graphiti | 托管图数据库 | 有(大模型摄取) | 支持双时态,但由大模型构建 | 部分支持 |
| Letta / MemGPT | Agent 框架 + DB | 有(由 Agent 管理) | 不支持 | 支持 |
| Anthropic memory tool | 客户端文件 | 模型编辑文件 | 不支持(由模型决定) | 支持 |
普通 CLAUDE.md / 文件 | 文本文件 | 无 | 不支持 | 支持 |
坦率地说,其他方案的优势在于:mem0 和 Zep 能够从原始对话中自动提取事实,而 memharness 有意不这样做(写入路径不依赖模型;由客户端或技能决定哪些内容值得记忆)。普通的 CLAUDE.md 完全不需要安装。只有在你需要其他方案不提供的时序和来源查询时,memharness 才能体现其价值。
软件包
| 软件包 | 内容 |
|---|---|
@memharness/core | TypeScript 库:架构、迁移、写入路径、回忆排序。不使用模型,不访问网络。 |
@memharness/mcp | MCP 服务(stdio),向任何 MCP 客户端提供七种工具。 |
@memharness/embed | 可选。本地嵌入模型,用于混合式(语义)回忆。默认不安装。 |
快速开始(MCP)
默认安装内容精简(SQLite 加 MCP SDK);嵌入模型为可选项,参见混合检索。
Claude Code:
claude mcp add memharness -- npx -y @memharness/mcp
Claude Desktop(~/Library/Application Support/Claude/claude_desktop_config.json)
和 Cursor(~/.cursor/mcp.json)使用相同的 JSON 格式:
{
"mcpServers": {
"memharness": { "command": "npx", "args": ["-y", "@memharness/mcp"] }
}
}
Codex(~/.codex/config.toml)使用 TOML,而不是 JSON:
[mcp_servers.memharness]
command = "npx"
args = ["-y", "@memharness/mcp"]
数据库位于 ~/.memharness/memory.db(可通过 MEMHARNESS_DB 覆盖;
在 Linux 上会遵循 XDG_DATA_HOME)。除非启用可选的调试日志,否则不会写入其他内容。
首次运行
- 使用上述任一命令添加服务,然后重启客户端,使其加载新的 MCP 服务。
- 在对话中向 Agent 提供一条持久事实,例如 “记住,我用 Fly.io 部署这个项目。” 它会调用
remember。 - 稍后(或在新会话中)询问 “你知道我是如何部署的吗?” 它会调用
recall并根据记忆作答。纠正它后,它会调用revise;旧信念会成为历史记录,可通过as_of/why/diff查询。
无需 API 密钥,无需注册,无需联网。首次调用 remember 时会创建 SQLite 文件,设置就全部完成了。如需在没有 Agent 的情况下端到端查看工具运行情况,请运行演示:cd examples && npm install && npm run demo。
可选:让检索自动进行
默认情况下,由 Agent 决定何时调用 recall。若要在每个会话开始时主动注入相关记忆(比寄希望于模型记得去查更可靠),请添加一个 Claude Code SessionStart hook,运行随附的 memharness-context 工具,该工具的标准输出会注入上下文:
{
"hooks": {
"SessionStart": [
{ "hooks": [ { "type": "command",
"command": "npx -y -p @memharness/mcp memharness-context --subject user" } ] }
]
}
}
它会输出最相关的当前信念的精简内容(如果尚无内容,则会静默退出),让 Agent 在每个会话开始时就已了解持久事实。多次传入 --subject 可注入多个实体。
七个工具
| 工具 | 功能 | 验证的论点 |
|---|---|---|
remember | 存储带有置信度和来源信息的原子事实 | 事实 > 大块内容 |
recall | 按排名返回当前信念;as_of 返回过去某个时刻的信念 | 双时态 |
revise | 替代某条信念,并保留历史记录 | 替代 > 删除 |
diff | 查看自某日期以来的变更(学习/修订/撤回) | 审计演示 |
why | 查看某条事实的来源信息和完整修订链 | 信任/审计 |
forget | 按 ID 或来源(基于来源信息删除)添加墓碑 | 符合 GDPR 要求 |
stats | 计数、主体、架构版本 | — |
库的使用
import { Memharness } from "@memharness/core";
const mem = Memharness.open(); // ~/.memharness/memory.db
// Learn something now, then learn it was actually true earlier.
const { id } = mem.remember({
subject: "user",
fact: "lives in Osaka",
sourceRef: "session-2026-06-09",
});
mem.revise({ oldFactId: id, newFact: "lives in Tokyo", validFrom: "2026-05-01" });
mem.recall({ query: "lives" }).facts[0].fact; // "lives in Tokyo" (current belief)
mem.diff({ since: "2026-06-01" }); // { learned, revised, retracted }
mem.why(id); // { fact, ancestors, descendants }
recall 返回的是 RecallResult({ facts: ScoredFact[]; asOf; truncated; usedFallback }),而不是普通字符串。asOf 支持时间回溯:mem.recall({ query: "lives", asOf: "2026-04-15" }) 会返回在该日期当时被视为真实的内容。
这会遵循事务时间,因此今天学到的事实不会出现在对过去的查询中。
检索排名通过对 FTS5 BM25(以及启用混合检索时的向量排名)进行倒数排名融合,再乘以置信度和近期性衰减(半衰期为 90 天,可配置),并在 SQL 中评分。可选的 maxTokens 预算会限制输出,以适应上下文窗口。FTS-only 和混合模式均会使用子串回退,以匹配部分词语和拼写错误。
可选:混合召回
默认情况下,召回使用 FTS5 关键词搜索,并按近期程度和置信度排序:不需要模型,完全离线。混合召回通过本地嵌入模型(BGE-small,约 130MB)增加语义检索:从 HuggingFace Hub 下载一次后即可完全离线运行,不需要 API 密钥,也不会在每次查询时联网。分两步启用:
-
在服务旁安装可选的嵌入包。使用
npx:npx -y -p @memharness/mcp -p @memharness/embed memharness-mcp(也可以使用
npm i -g @memharness/embed进行全局安装)。 -
在服务的环境中设置
MEMHARNESS_HYBRID=1。
此后,服务会自动为已存储的事实生成嵌入:你通过 remember 记录的事实会在下一次 recall 时支持语义搜索,无需单独执行回填。如果尚未加载模型,首次混合召回时会将下载进度输出到 stderr。如果未安装该包,服务会提示这一点并继续仅使用 FTS;它绝不会因无法使用混合召回而直接失败。
在库层面,召回与嵌入提供方无关:可以将自己的查询向量传给 recall({ queryVector }),并使用 setEmbedding(...) 添加文档向量,模型不限。
一个完整示例
两个相隔数周的会话。Agent 学到一项偏好,用户之后又对其进行更正,下游问题则询问 Agent 当时相信的是什么:
// June 9: the agent learns a deploy target and acts on it.
const { id } = mem.remember({
subject: "project:acme",
fact: "deploys via Heroku",
sourceRef: "session-2026-06-09",
});
// June 16: turns out the team moved to Fly back on June 1.
mem.revise({
oldFactId: id,
newFact: "deploys via Fly.io",
validFrom: "2026-06-01",
sourceRef: "session-2026-06-16",
});
mem.recall({ subject: "project:acme" }).facts[0].fact; // "deploys via Fly.io"
// "Why did the CI config you wrote on June 9 target Heroku?"
mem.recall({ subject: "project:acme", asOf: "2026-06-09" }).facts[0].fact;
// "deploys via Heroku": what the agent honestly believed that day.
mem.why(id); // the full chain: Heroku, superseded by Fly.io, with sources.
mem.diff({ since: "2026-06-15" }); // surfaces the Heroku -> Fly.io revision.
基于字符串集合的记忆无法回答 as_of 问题,因为它在得知 Fly.io 后就覆盖了 Heroku。
正确性
属性测试套件是本项目的核心:对于随机生成的 remember/revise/forget 序列,recall({asOf: T}) 必须与不使用 SQL 对事件日志进行朴素重放所得的信念集合一致,并在每个事件时间戳的 ±1ms 处进行探测。每次推送到 main 时都会运行 10,000 个测试用例。
在一台开发笔记本电脑(Apple Silicon)上,以 100k 条事实(10% 修订链、2% 撤回)进行基准测试:四种查询形式(双词关键词、关键词 + 主体、仅主体,以及 as_of + 关键词)的整体召回 p95 约为 1.3ms,低于 10ms 的预算。pnpm bench 会填充数据库并验证预算,因此这个数值可复现,而非仅作宣称。
与最初原型的一项刻意差异:撤回会存储时间戳(retracted_at),而不是标志,因此在撤回之前进行的 as_of 查询仍能看到历史记录。这正是原型文档承诺的行为,但其 SQL 并未实现。
开发
pnpm install
pnpm test # unit + behavior suites (property tests at 200 runs)
pnpm test:property # 10k randomized property cases
pnpm bench # seed 100k facts, assert recall p95 < 10ms
Schema 迁移只向前进行,由 PRAGMA user_version 驱动。行永不删除(forget 使用墓碑标记),因此 facts.id 同时充当插入顺序。所有时间戳均为规范的定宽 UTC ISO 8601 格式,因此可以按字典顺序进行时间比较。
可选:本地使用日志
如需调试或衡量自己的使用情况,可设置 MEMHARNESS_DEBUG=1。服务会在数据库旁的 usage.log 中追加操作名称和时间戳(绝不记录事实内容)。此功能默认关闭,完全在本地运行,绝不会联网。
许可证
Apache-2.0
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。