关于 OMEM
OMEM 是面向 Agent 开发者的记忆服务,记录信念、证据及其变化过程。它保留矛盾信息和来源链,而非静默覆盖冲突事实。
主要功能
- 01随时间变化的信念状态
- 02显式追踪矛盾信息
- 03证据与来源链
- 04私有或共享的 Agent 记忆
- 05语义召回与学习
- 06受策略约束的修复流程
适用场景
- 01追溯 Agent 持有某项信念的原因
- 02审核相互冲突的客户信息
- 03在团队间共享选定记忆
- 04审批并审计 Agent 修复操作
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
uvx omem-infrastructureOMEM_API_KEY密钥API key from the OMEM server. It is printed on first run of `omem-server`.OMEM_PROJECTProject id to read and write memory in, also printed on first run.OMEM_BASE_URLURL of the OMEM server.OMEM_AGENTThe agent whose memory this process reads and writes. Fixed here rather than passed as a tool argument, so the model cannot act as a different agent.OMEM_USERThe end user this process is acting for. Also fixed here, not a tool argument. Leave unset and no user-scoped memory is visible.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
5收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| task | string | 否 | Agent 正在尝试完成什么 |
| limit | integer | 否 | |
| context | string | 否 | 当前对话/情境 |
详细介绍
OMEM
记录 AI Agent 所相信和所做之事的权威系统。 只追加不修改, 每条信念都有证据支撑,每个矛盾的双方都会保留,每项高风险操作背后都有一位具名的人类。 因此,当 Agent 采取行动后有人问“它为什么这么做”,你可以拿出记录作答,而不必展开调查。
OMEM 承担记忆层的职责,但做的是另一种工作。它不会把文本一股脑塞进向量存储并寄希望于结果,而是持续追踪每个 Agent 的信念,保存每条信念背后的证据,并明确处理矛盾,让 Agent 能够推理自己知道什么、何时得知,以及为何相信。
而且它并非从零开始。选择汇总一般人群相关认知的安装实例,会以无人可被识别的计数形式共享所得;新安装实例从第一天起就能借鉴这些直觉,而不必花六个月慢慢积累。你贡献的是计数,得到的是其他所有人的计数。借鉴而来的模式先天弱于自己学到的模式;一旦某个人自身的证据与之矛盾,它也会立刻失效,因此普遍模式永远不会凌驾于个体之上。
目前数据库还是空的。还没有任何安装实例作出贡献,这意味着最早参与的实例将决定它学到什么;同时也值得注意的是,关于人群规律的数据集可能会带有填充者的偏见。挖掘规则已重写,模式必须优于基准率,而不能仅仅依托基准率(工作论文第 1 号);贡献者群体是否具有代表性,则是另一个尚无定论的问题。
它可在本地运行,无需外部服务,也无需安装依赖项。
pip install omem-infrastructure && omem-server
或者,只需单击一次即可部署私有服务:
该蓝图会配置一个小型服务,附带持久化磁盘并启用密码身份验证(首个注册账户即为运营者账户),同时生成主密钥。Fly.io 也可使用:运行 fly launch --copy-config,并使用随附的 fly.toml。
文档:infrastructure.omem-cloud.com · 快速入门 · 安全 · 贡献指南
要向客户交付 Agent?审计跟踪和审批关卡正是关键:客户安全审查会询问什么,目前也开放少量深度参与的设计合作伙伴试点。
想在继续阅读前看看完整流程如何运行? refund-desk 是参考集成:一个能够转账并提供凭证的支持 Agent。 只有一个文件,一分钟即可运行,并会验证自己的每项声明。
这是 scripts/demo_reasoning.py 的节选。每一行都是在 CI 中运行的断言行为,因此这张图不会悄无声息地失去真实性。
两个来源说法不一致。两者都不会被覆盖。 查看完整运行效果。
有何不同
大多数 Agent 记忆都是事实列表。两个事实冲突时,其中一个会悄无声息地覆盖另一个,历史记录也随之消失。OMEM 会保留双方的信息,追踪当前相信哪一方,并说明原因。它有一些普通向量存储所不具备的功能:
- 随时间变化的信念状态。 每条事实都有一个状态(believed、contradicted、unknown),该状态由引擎根据证据计算得出,而不是存储在静态行中。
- 矛盾处理。 相互冲突的信息会被呈现出来,而不会丢失。名为
X和not:X的断言会自动视为对立;其他情况只需调用一次mem.contradict("prefers_annual", "prefers_monthly")来说明。OMEM 绝不会通过读取断言来判断它们是否相互矛盾,因为这种判断会导致同一个问题在一年后得到不同答案。 - 溯源。 询问某事为何被相信,即可获得得出这一结论的依据链。
- 跨 Agent 记忆。 默认情况下,记忆仅对单个 Agent 私有;你可以选择与团队或整个项目共享哪些内容。
- 语义召回。 即使措辞与存储时不同,也能找到相关记忆。使用无依赖的嵌入模型即可离线运行;设置
OMEM_EMBED_MODEL可使用你所用服务商的真实嵌入模型,并支持缓存向量,以及在服务商不可用时自动回退。 - 学习循环。 随着时间推移,证明有用的记忆会获得更高排名。
- 拒绝越权的自我修复。 OMEM 会记录故障,并依据策略执行修复;未经授权的修复不会执行。模型可以提出计划,但只有在代码中注册的操作才会执行;风险类别由 OMEM 的注册表决定,而不是由计划自行声明。参见自我修复。
快速开始
你需要 Python 3.9 或更高版本。没有其他依赖项。
选项 1:从 PyPI 安装(包含服务)。
pip install omem-infrastructure
omem-server
要从较早版本升级?运行 pip install --upgrade omem-infrastructure。
如果软件包已安装,直接运行 pip install 会提示“Requirement already
satisfied”并且不执行任何操作,这会让你悄悄继续使用原本打算弃用的版本。运行 python -c "import omem; print(omem.__version__)"
即可查看你实际安装的版本。
这会在 http://127.0.0.1:8787 启动服务,并在首次运行时打印项目 ID 和 API 密钥:无需调用注册接口、访问控制面板,也无需配置任何内容。直接粘贴即可:
from omem import Memory
mem = Memory(api_key="omem_sk_...", base_url="http://127.0.0.1:8787",
project="proj_...")
mem.remember(agent="support", about="customer:1", claim="prefers_annual_billing")
print(mem.believes(about="customer:1", claim="prefers_annual_billing"))
# -> BELIEVED_TRUE
QUICKSTART.md 会在大约 5 分钟内带你走过一个矛盾和一条溯源链,这时就能真正看出它与向量存储的区别。
选项 2:从此仓库运行。
cd server
python api.py # or: python api.py 9000 for a different port
相同的服务、相同的首次运行项目 ID 和密钥,只不过从源代码启动。无论哪种方式,设置都只需大约 1 分钟。需要了解的两个区别:
- 数据库位置不同。 从源代码运行时,数据库位于
server/data/omem.db;omem-server会在你运行它的目录中写入./omem-data/omem.db。OMEM_DB可以覆盖任一位置。 - 控制面板需要构建一次。 wheel 中包含已构建的版本;克隆仓库则不包含,因此在你运行
cd web && OMEM_STATIC=1 npm run build之前,服务会显示“dashboard not bundled”。无论哪种方式,API 都完全相同。
选项 3:Docker。
docker run -p 127.0.0.1:8787:8787 -p 127.0.0.1:3000:3000 \
-v omem-data:/app/server/data ghcr.io/troybrandonc-bit/omem
API 端口为 8787,控制面板端口为 3000,数据存储在命名卷中。端口特意只发布到回环地址:容器以本地模式运行,没有密码,因此可访问性就是访问控制。要将其放到网络上,必须先设置 OMEM_AUTH=password 和
OMEM_MASTER_KEY;此仓库中的 docker-compose.yml 展示了相应配置。
自愈
OMEM 会记录故障,并依据策略修复故障。这是为你的 Agent 提供的基础设施,而不是 OMEM 对自身执行的操作:你注册一个组件及其可用的修复钩子,OMEM 则负责管理记忆、安全边界和生命周期。
关键在于它会拒绝什么。模型可以提出修复计划;是否允许则由 OMEM 决定。只有在代码中注册的操作类型才能执行,风险等级来自该注册表,而绝不会来自计划;高风险操作需要明确批准;只有通过验证,修复才算成功。
mem.healing.report_health("vector-index", "healthy", "12,400 vectors")
result = mem.healing.handle(
error={"component": "vector-index", "error_type": "StaleShard"},
plan={"diagnosis": "replica fell behind after a partition",
"confidence": 0.8,
"actions": [{"type": "rebuild_index"}, {"type": "exec_shell"}]},
)
result["status"] # -> "denied"
result["decisions"] # rebuild_index: permitted (low risk)
# exec_shell: unknown action type (not registered)
没有任何操作执行。计划会保留每个操作被允许或拒绝的原因,因此拒绝会留下记录,而不是悄无声息。此处的错误文本和模型输出都只是数据,二者都无法凭空指定一个操作并使其生效。
你可能需要的其他保障也都已实施:故障会生成指纹,因此一千个相同错误只会形成一条记录;每个组件的修复风暴都有次数上限;数据库会强制确保每个组件同一时间只进行一次恢复;任何内容持久化之前都会移除机密信息;遇到内部错误时会升级处理,而不是盲目重试。
控制面板中的 自愈 页面会显示组件健康状况、故障记录,以及每项修复的进展情况,并标记停止步骤和所依据的诊断。如果你正在考虑是否信任它,值得读一读 server/healing.py,它包含了整个子系统。
控制面板
控制面板包含在软件包中。启动服务并打开同一地址:**http://127.0.0.1:8787**。所有内容都在这里:记忆、冲突、信念图谱、时间线、日志和审计记录。无需 Node、无需第二个进程,也无需另一个端口。
在本地模式(默认模式)下,无需登录;打开后会进入服务为你创建的项目。如果服务运行时设置了 OMEM_AUTH=password,则会显示登录表单。
它是从 web/ 静态导出的内容,也是此仓库中唯一的 UI,并会在构建时复制到 wheel 中。要在其上进行开发:
cd web
npm install
npm run dev # http://localhost:3000, proxying to the API on 8787
要重新构建随软件包提供的版本,请运行 OMEM_STATIC=1 npm run build。
身份验证
OMEM 以两种模式之一运行,在将它部署到自己的机器以外的任何地方之前,了解两者的区别很重要。
OMEM_AUTH=local:默认模式,也是快速入门能在一分钟内完成的原因。
无需登录:仪表板会针对它能访问的服务创建会话。但只有在没有其他设备能访问该服务时,这才安全,因此本地模式拒绝绑定非回环地址。如果你确实了解风险(例如,端口发布到 127.0.0.1 的容器、单用户 VM),请设置
OMEM_ALLOW_INSECURE_BIND=1。
OMEM_AUTH=password:其他人可以访问的服务必须使用此模式。
账户设有密码,密码使用 PBKDF2-SHA256 哈希。使用已有密码的地址注册会返回 409,而不是创建会话;已启用 TOTP 的账户必须通过 TOTP 验证;此外,除非将 OMEM_MASTER_KEY
设为非开发默认值,否则服务会拒绝启动。
export OMEM_AUTH=password
export OMEM_MASTER_KEY="$(python3 -c 'import secrets;print(secrets.token_urlsafe(32))')"
omem-server
TLS
将 OMEM_TLS_CERT 和 OMEM_TLS_KEY 指向证书,服务就会自行提供
HTTPS(最低支持 TLS 1.2)。只设置其中一个会导致启动错误,而不会悄悄
退回明文连接。大规模部署时,使用终止 TLS 的代理仍然更好,但现在不使用代理也不再意味着以明文运行。
静态加密记忆数据
pip install "omem-infrastructure[encryption]"
export OMEM_ENCRYPT_AT_REST=1
export OMEM_MASTER_KEY="$(python3 -c 'import secrets;print(secrets.token_urlsafe(32))')"
使用 AES-GCM 加密操作日志、摄取的源数据载荷,以及每条记忆背后的引用证据。现有明文记录仍可正常使用,因此可以为已有数据的数据库启用此功能。若使用开发用主密钥,服务会拒绝启动;若没有可用的真实 AEAD 库,服务也会拒绝运行,而不会退回到 OAuth 令牌所用的标准库密钥流。
密钥丢失,数据便无法找回:没有恢复途径,目前也没有密钥轮换工具。
当两个实体其实是同一个人时
Formation 根据可见信息生成实体 ID,因此同一个人可能出现两次:从消息正文中的一句话生成 person:sarah_chen,
从邮件署名生成 person:sarah_chen@acme。每个 ID 都只保存了关于此人的部分认知,两者既不能相互印证,也不能相互矛盾。
curl -X POST "$OMEM/v1/memory/resolve?project=$PROJECT" \
-H "Authorization: Bearer $KEY" -d '{}'
确凿证据会触发合并:同一组织中的同一全名。这也是 formation 在单一路径内已经采用的规则。合并会记录为由 agent:omem-resolution 执行的共指操作,并附上指向其锚点的推导,因此 /why 可以解释合并原因,拆分操作也可以撤销合并。提示性证据(例如,在 acme 中将“Sarah”与“Sarah Chen”对应起来)会成为 GET /v1/memory/merge-proposals 中的一条提案;在有人批准前不会产生任何变更,而且批准记录会署上批准者的姓名,而不是机器的名称。
拒绝合并正是这项功能的关键:绝不跨组织合并,绝不在未指定组织时合并,绝不在姓氏或职位词汇冲突时合并,绝不在存在歧义时合并,也绝不重新合并已通过拆分操作分开的实体。传入 {"apply": false} 可进行不记录任何内容的试运行。通过 SDK,可使用 mem.resolve()、
mem.merge_proposals() 和 mem.approve_merge(id, agent=...);仪表板中的 提案 页面使用的是同一个队列,并提供操作按钮。
得出结论,并将其撤回
矛盾需要显式声明,绝不会从文本中推断。推理也遵循相同的方式:规则是你声明的数据,机器只会组合你所说的内容,不会添加任何其他内容。
curl -X POST "$OMEM/v1/rules?project=$PROJECT" -H "Authorization: Bearer $KEY" \
-d '{"when": [{"rel": "works_at", "dir": "fwd"}, {"rel": "owns", "dir": "rev"}],
"then": {"rel": "involves", "dir": "rev"}}'
curl -X POST "$OMEM/v1/memory/infer?project=$PROJECT" \
-H "Authorization: Bearer $KEY" -d '{}'
Sarah 在 Beta 工作;Acme 拥有 Beta;OMEM 得出结论:Acme 的轨迹涉及 Sarah——这是一条根据其使用的精确前提推导出的普通断言,因此 /why 会从结论追溯到证据;同时它也是一条真实的图边,因此只需一跳即可检索到。
这项功能的意义,体现在撤回时。撤回所有权后,同一请求中就会撤回该结论;依赖该结论的结论也会随之撤回。每次撤回都是操作日志中的普通撤回操作。证据只使用一次——你关闭的结论永远不会基于相同前提重新裁定;停用规则得出的结论会在下一轮中撤回。
这一切都通过脚本实现,而非一段说明文字;与下方的拒绝演示遵循相同的约定——断言每种行为,任何行为不再成立时以非零状态退出,并在 CI 中运行:
python3 scripts/demo_reasoning.py
提出问题的规则形状
只有针对相同主体的两种信念才会冲突,这让信念状态具有可复现性——也就是说,“Sarah 在 Acme 工作”和“Sarah 在 Beta 工作”永远不会互相矛盾。是否应当如此,属于领域知识,因此需要由你声明:
mem.declare_constraint("works_at", "one_dst_per_src") # one employer at a time
mem.check()
违反规则会在“提议”队列中变成一项冲突。OMEM 不会选择较新的雇主:你可以指定保留哪一个(其余内容会以你的名义撤回,而规则引擎从中得出的任何结论也会在同一请求中撤回),也可以将其驳回;驳回只对这些证据永久生效。对于人已经回答过的问题,机器绝不会反复追问。
带有案例档案的猜想
人类会从一个例子中学习,并由此跳跃到结论。这种本能也是人类记忆会凭空编造的原因。OMEM 保留这种速度,摒弃凭空编造:它会做出跳跃式推断,然后比你更严厉地质疑这个推断。
mem.leap() # one similar case is enough
mem.expects(about="customer:gamma")
# -> wants_pdf_invoices, strength 0.35, "beta holds it; gamma resembles
# beta (both prefer annual billing, both use crm)", docket attached
mem.interrogate() # the skeptic works every open case
假设永远不会成为信念。它绝不会进入引擎,believes() 无论猜想多么可信,始终都会返回 UNKNOWN;只有关于目标本身的事实才能支持或反驳它,相似事物只会改变其强度。裁定结果会带来学习:推断屡屡得到证实的来源会产生更强的猜想,屡屡出错的来源会产生更弱的猜想;被证伪的推断也绝不会再根据相同证据得出。无法得到结论的案例会开始提问,问题会出现在控制面板上;回答是或否,就会以你的名义成为真实证据——裁定仍来自询问,绝非强行指定。
相似性遵循人类类比的方式:一个罕见的共同特征,比三个常见特征更能建立联系;配置了嵌入模型后,措辞不同的经历也会被视为同一经历;共同背景的权重低于共同特征。mem.calibration() 则体现了元认知:OMEM 知道自己擅长猜测哪些类型的说法,其大胆程度也会随记录而变化。
先验:它从一般人群中学到的内容
一次飞跃根据一个相似的人来推断。先验则根据从许多人身上学到的规律来推断:“持有 P 的人往往也持有 Q。”OMEM 从已有知识中挖掘这些规律,用极少的信息来解读新人。
只有在持有 P 能显著提高持有 Q 的概率,且这种概率高于 Q 本身的普遍程度时,才会保留一对关联;而且,这项检验针对的是发生率的下限,而不是发生率本身,因此,建立在少数人身上的模式必须比建立在数百人身上的模式可靠得多。
mem.learn_priors() # mine regularities across everyone
mem.priors()
# -> holds likes_dashboards -> holds wants_pdf_invoices
# in_population: 41 of 52 wants_pdf_invoices on its own: 0.29
# kept because the lower bound of that rate clears 0.29, not
# because wants_pdf_invoices happens to be common
# when_applied: supported 3, refuted 0
这条规则取代了旧规则。旧规则只问:持有 P 的人中,是否有 60% 也持有 Q?在对 19,668 名已知潜在结构的真实受访者进行测试时,旧规则恢复该结构的得分为 0.185,而随机结果为 0.184:它实际上是按结论的普遍程度来筛选结论。当前规则的恢复得分为 0.875,使用的先验减少了 94%,却覆盖了更多声明。研究报告见 Working Paper No. 1,测试框架位于 benchmarks/external/。
关键在于,先验绝不会凌驾于个人之上。它只会在信息空白处发挥作用:如果某人持有 P,却没有表明自己是否持有 Q,OMEM 就会将 Q 作为一种猜测推断到此人身上;但只要此人的自身证据出现,先验就会被拒绝;如果此人的证据后来与已接受的猜测相矛盾,interrogate 循环就会推翻该猜测,由先验承担错误。每条先验都附带两个可信的数字:它在学习时所依据的人群中的发生率,以及它在实际应用时单独记录的表现。基于人数过少的模式根本不会生效。
先验存储的是计数,而不是个人。它是关于一般人群的知识,不包含任何个人的事实,因此你可以查看整个集合,或将其交给他人,而不会泄露任何个人的信息。一般模式在设计上就会始终让位于个人,而非仅仅依赖政策规定。
日常行为也是记忆
值得记住的内容不全是合同。“我早上效率最高”“联系我最好发邮件”“我周五不上班”,这些都是日常往来中反复出现的小偏好。OMEM 会离线提取这些内容,无需 LLM。第一人称句子会关联到写下它的人,也就是根据其发件地址推断出其任职信息所关联的同一个节点;而“我们更喜欢异步沟通”则仍然是关于公司的事实。像 support@ 这样的职能地址不会凭空生成虚假个人,而且每种习惯都会附上作为证据的原句。这些恰恰是先验层会加以泛化的规律:“喜欢早上的人通常也喜欢用电子邮件”是学到的模式,而不是猜测。
执行被遗忘权
撤回不等于抹除:只追加日志会保留历史记录,而真正的抹除请求意味着个人数据必须消失。POST /v1/entities/{id}/forget 会真正重写操作日志:删除所有引用此人的记录、所有由这些记录级联产生的内容、仅承载其言论的事件,以及相关的证据引文、边、假设和原始来源消息。如果某人的句子被引用在仍保留的信念之下,也会进行删改,因为即使该信念属于公司,这句话仍然属于此人。精简后的日志会先通过临时引擎重放验证,之后才会执行任何更改;处理完成后,只留下一行哈希值、计数和日期:证明抹除已完成,但不保留任何内容。这是一项管理员操作,需要明确确认,且无法撤销。
公共资源库,以及它永远不会获取的内容
首次打开时,仪表板会问一个问题:是否向共享 OMEM 公共资源库贡献匿名模式?如果你同意,离开设备的只有计数,例如“5/7 人持有此观点”。绝不会包含姓名、公司、消息或任何来自你数据的数字;原始文件会保留在你自己的磁盘上,供你检查;你也可以在“设置”中随时撤回任一选择。保持沉默,就永远不会发送任何内容。 公共资源库会汇总所有同意参与的安装中的计数,以研究人类总体的工作行为。匿名性在两道关口都由机制保障:任何带有可识别信息的贡献都会在抵达时被拒绝,因此公共资源库不可能泄露它从未持有的信息。
教 AI 了解人是什么样的
公共资源库只有一个目标:通过让 AI 更好地理解我们的天性和行为,连接人类与 AI。如今的模型从抓取的文本中了解人类,而这些文本从未获准用于此目的,其中还给所有人都标上了姓名。公共资源库提供的则恰恰相反:关于人们实际如何工作的规律,由人们主动贡献,不包含任何人的信息。
它以训练语料库的形式发布。每种模式占一行 JSON,包含计数和通俗易懂的表述(“偏好上午开会的人通常也偏好通过电子邮件联系:在 31 个持有某种观点的人中有 24 人如此,占 77%”),并附有数据集说明卡,阐明数据来源、同意机制和许可协议:CC BY 4.0,须注明来源为 OMEM 公共资源库。基于这些数据训练的模型学到的是比例,而不是某个人;说明卡会明确写出这句关键的话:这些比例反映的是群体倾向,绝不是对个体的定论。真实的人完全可能与其中任何规律相悖;尊重人的系统会将每种模式视为先验,在遇到个体情况时让步,就像 OMEM 本身所做的那样。
你离开期间发生了什么
每个 Agent 在会话开始时都会询问的问题,使用每次查询都已采用的同一套 as_of 机制作答:
d = mem.changes(since=last_seen)
新出现的信念;已结束的信念,分别说明结束方式——被什么取代,或已撤回;新出现和已解决的冲突;合并或拆分的指代对象。只读、确定性且范围安全:你的差异仅包含你原本能够回忆起的内容。
看看它会拒绝什么
自愈边界这一部分很难仅凭描述让人相信,因此我们用脚本展示,而不是用一段文字说明:
python3 scripts/demo_refusal.py
脚本会通过修复计划实际出错的两种方式,驱动真实服务运行。模型提议 reload_config(已注册)以及 exec_shell(从未注册):前者按其自身条件获准,后者因名称不在注册表中而遭拒,整个计划也因此被拒绝。计划若自行声称风险类别,该类别会被忽略,因为风险类别由注册表决定。模型读到的错误消息中嵌入的指令不会执行任何操作。每项判定都会被保留,之后可以查阅;错误上下文中的秘密不会存入存储。
注册是在代码中完成的。没有任何 API 能添加可执行的操作类型,因此任何计划和提示词都无法扩大许可范围。
其中每次拒绝都有断言,如果有任何一次不再发生,脚本就会以非零状态退出,因此可以在 CI 中运行。一个可能悄然变得不真实的演示,还不如没有。
Witness 基准测试
记忆基准测试衡量回忆能力。Witness 衡量的是相反的职责:记忆系统是否会断言没人告诉过它的事、反复提起已撤回的信息、默默解决分歧、把两个同名的人合并,或保留前提已不成立的结论?
六个场景、十个维度、确定性评分,不使用 LLM 评审。已提供 OMEM、Mem0 和 Graphiti 的适配器;每个系统都通过各自的原生路径进行测试,而系统无法表达的探测项会报告为不支持,而非通过或失败。本仓库不会发布未经实际运行得出的数据:server/tests_witness_benchmark.py 会在每次提交时针对运行中的服务验证 OMEM 的结果卡,确保每个维度上的每项探测都通过。请使用你自己的密钥运行其他系统,并查看各自的结果卡。
声明台账
不会失败的营销宣传,与虚假宣传毫无区别。CLAIMS.md 将本项目每一条关键自述都对应到一项可执行的断言:一旦其不再属实,该断言就会失败。台账本身也由 CI 守护:如果某一行所引用的文件缺失,构建就会失败。
有两项值得特别指出,因为这个领域没人能写出这样的声明。它不会向任何人发送数据:tests_airgap.py 在 socket 层安装防护,然后通过运行中的服务测试每项主要功能;只要发生任何非回环的外连或 DNS 查询,就会失败。升级绝不会改写你的过往:一份冻结于 2026-08-29 的日志会在每次提交时重放,并生成逐字节一致的状态摘要,因此任何未来版本都无法悄悄重新解读你已记录的历史。
证明状态由日志推导而来
记忆通过重放只追加日志来重建。声称这一点很容易,但外部无法核查;对于一个核心主张是“你可以重建 Agent 曾相信什么以及为什么”的项目而言,这是个薄弱之处。
omem-verify
proj_a14ce3f94fab My first project
replayed 4 operations -> 2 assertions, 2 propositions
state digest cd95d761079a2388...
deterministic yes
它会将日志重放到两个相互独立的全新引擎中,并比较生成的状态。如果结果不同,就说明重放依赖于日志之外的信息,同一个问题无法得到相同答案。
该检查无法检测篡改,因为被改写的日志仍能与自身一致地重放。要检测这种情况,请记录摘要,并将其保存在 OMEM 无法写入的位置:
omem-verify --record # writes .omem-state.json
omem-verify --anchor kept-elsewhere.json
anchor DOES NOT MATCH cd95d761079a2388... the log has changed
audit chain org_f4f3bdfa7a82 MISMATCH
出于同样的原因,同一文件也锚定了审计链头。这条链只能证明篡改迹象,而非防止篡改:拥有写入权限的人可以从编辑处开始重写,且链在内部仍保持一致。只有将头部哈希保存在 OMEM 无法触及的地方,才能检测到这种情况。在两个地方设置两个锚点,意味着要养成两种习惯;而你跳过的那个,恰恰可能是最重要的。
这能证明状态由日志推导而来,也能证明日志和审计链自设置锚点以来都没有改变。但它不能证明这些信念是正确的,也不能证明在首次设置锚点之前没有内容被删除。
物料清单
python3 scripts/gen_sbom.py > sbom.json # CycloneDX
python3 scripts/gen_sbom.py --check # fails if a runtime dep appears
服务端和 SDK 没有运行时依赖项,因此 SBOM 只有一个组件,传递依赖范围也仅限于标准库。可选扩展也会列出并标记为可选,以免“没有依赖项”成为半真半假的说法。CI 会运行 --check,确保这一声明不会悄然失实。
拒绝无依据的写入
每条信念都带有一个依据判定结果:如果其来源链可追溯到已记录的事件,则为 GROUNDED;如果其依据始终只是其他主张,则为 UNGROUNDED。每次读取都会返回该判定结果,因此调用方可以据此筛选。
只有记得筛选的调用方才能从筛选中受益。设置
OMEM_REQUIRE_GROUNDED=1,OMEM 就会直接拒绝写入:
OMEM_REQUIRE_GROUNDED=1 omem-server
mem.remember(agent="support", about="customer:1", claim="prefers_annual")
# -> 422 R_UNGROUNDED: cite `because` evidence that reaches a recorded event
mem.remember(agent="support", about="customer:1", claim="prefers_annual",
because=["evt_call_2026_08_26"]) # accepted
已记录的事件,或本身有依据的断言,都算作证据。因此,以观察到的内容为根基的推理链会被接受,而没有根基的推理链则不会。
这适用于直接写入。取代和撤回操作会替换已通过准入的主张,并继承其来源;而且,摄取路径一直有自己的关卡:每个候选项都会在交由引擎处理前进行评级,DO_NOT_STORE 和 LOW 永远不会成为断言。
默认关闭,因为这确实会限制写入方式,而且现有调用方不应因升级而出问题。
此仓库包含什么
-
server/是 OMEM 服务:一个封装内存引擎的 HTTP API。引擎本身位于server/omem_engine/,是所有内存决策的事实来源。 -
sdk/python/是 Python SDK,以及omem-server/omem-mcp命令。它是已发布的版本:pip install omem-infrastructure。 -
sdk/typescript/是 TypeScript SDK,发布包为npm install @omem/sdk。它落后于 Python SDK,并会针对真实服务进行构建和测试:cd sdk/typescript npm install && npm test # builds, then runs test_parity.mjs against a live servertest_parity.mjs会启动 Python 服务,驱动构建好的 SDK 与其交互,并报告缺失的功能。弥合这一差距是目前最有价值的贡献。 -
web/是仪表板。
在 LangChain 中使用
OMEM 实现了 LangGraph 的 BaseStore,LangChain Agent 通过它保存长期记忆:
pip install "omem-infrastructure[langgraph]"
from omem import Memory
from omem.integrations.langgraph_store import OmemStore
store = OmemStore(Memory(api_key="omem_sk_...", project="proj_..."))
store.put(("memories", "alice"), "pref", {"text": "prefers annual billing"})
store.get(("memories", "alice"), "pref").value
# -> {"text": "prefers annual billing"}
将其传入 create_react_agent(..., store=store) 或任何 LangGraph 图中,用法与 InMemoryStore 相同。

它与内置存储的区别在于第二次写入时的处理方式。内置存储会覆盖,而 delete 会擦除。在这里,对已有键调用 put 会进行取代:先前的值仍保留在记录中,并注明它不再被认为可信的时间;delete 则会撤回而非销毁。每次写入都会记录归属,因此 mem.why(assertion_id) 可以说明一段记忆的来源。代价是每次操作都要进行一次网络往返。
存储目前尚未实现向量搜索。search() 会按命名空间和字段筛选;传入 query= 会引发错误,而不是悄悄返回伪装成语义搜索的子字符串匹配结果。
在 MCP 客户端中使用
安装软件包后会提供一个通过 stdio 使用 MCP 通信的 omem-mcp 命令,因此 Claude Desktop 等 MCP 客户端可以将 OMEM 用作记忆工具:
pip install omem-infrastructure
然后,在 MCP 客户端的配置中,完整条目如下:
{ "mcpServers": { "omem": { "command": "omem-mcp" } } }
无需密钥、URL,也无需单独启动服务。首次运行时,它会自行启动捆绑的服务、创建项目,并将其记在 ~/.omem 中。重启客户端后会继续使用同一份记忆。
共有十个工具。其中五个负责记录:omem_recall、omem_observe、
omem_remember、omem_why 和 omem_believes。另外五个属于直觉层,
全部为读取工具:omem_expects(OMEM 怀疑但不相信的内容,以及对应的
案例档案)、omem_priors(它从一般人群中学到的规律)、omem_brief(在任务
开始时调用一次,无需再从其他四个工具中拼凑出同一幅图景)、omem_ask(提出
一个问题,首先根据此安装实例自身见过的内容作答,其次参考共同知识库;每项依据
都会标明相关人员和安装实例),以及 omem_weigh(根据人群情况权衡一项你已经
持有的信念)。
如果支持某个答案的人太少,omem_ask 会拒绝回答,而不是返回空结果,因为
“没有这种模式”和“支持判断的人太少”是不同的答案,Agent 对这两种情况的处理
也不同。它从磁盘读取:共同知识库快照已在本地,因此即使无法连接共同知识库,或
从未联系过它,也能提问。
没有任何工具可以提升假设、回答其未解决的问题,或触发一次跃迁。直觉会在
审问过程中从现实中得出判断,模型也无法通过声称某项内容为真来将其标记为真。
omem_expects 列出的任何内容,通过 omem_believes 读取时仍会显示为
UNKNOWN,并且有测试会对此进行明确断言。
observe 会将原始对话交给 OMEM,让它判断哪些内容值得保留;处理对话记录时,
这正是你需要的方式。remember 则用于记录你已经识别出的事实:
{"about": "customer:acme", "claim": "prefers_dark_mode",
"because": "said on the 3 Nov call"}
确定事实时使用 remember。提取过程会运行一个针对决策和承诺的确定性词汇
匹配,因此不在该范围内的主张不会记录任何内容;模型指出某项主张,不代表模型
决定其真假:信念状态、矛盾和来源信息仍由 OMEM 管理。
记忆的作用范围由环境固定,绝不通过工具参数设定,涵盖记忆作用域的两个维度:
OMEM_AGENT 指定这是谁的记忆,OMEM_USER 指定它所服务的最终用户。通过 MCP
对话的模型无法指定其中任何一项,因此无法请求访问其他 Agent 或其他用户的私有
记忆。OMEM_USER 是可选项;不设置时,任何用户范围的记忆都不可见。对于尚未
获知自己代表谁行事的进程,这是正确的默认设置。
要将其接入 Claude Desktop,请先启动一次 omem-server 以获取项目 ID 和密钥,
然后将以下内容添加到 claude_desktop_config.json 并重启应用:
{
"mcpServers": {
"omem": {
"command": "omem-mcp",
"env": { "OMEM_AGENT": "claude", "OMEM_USER": "[email protected]" }
}
}
}
这两项都是可选的。OMEM_AGENT 指定这是谁的记忆,OMEM_USER 指定它所服务的
最终用户;二者都不是工具参数,因此模型无法指定其中任何一项。若要将其指向你
已运行的服务,可改为设置 OMEM_API_KEY、OMEM_BASE_URL 和
OMEM_PROJECT;显式配置始终优先于捆绑配置。
在 macOS 上,配置文件位于 ~/Library/Application Support/Claude/claude_desktop_config.json;
在 Windows 上,位于 %APPDATA%\Claude\claude_desktop_config.json。
状态和价格
免费,并且在测试阶段期间始终免费:无套餐、无需银行卡、无配额限制。
这是仍在积极开发的早期软件,目前旨在用于测试和收集反馈。 安全页面 列出了它能保护什么,以及同样重要的、目前还不能保护什么:不支持 SSO,无认证,无密钥轮换;审计链能够检测篡改,而非阻止篡改;目前强制只有一个进程持有权威状态,因此第二个进程会拒绝启动,而不会导致状态分歧。但这诚实地意味着它不具备高可用性,而不是具备高可用性。制定计划前请先阅读此页面。如果你试用后遇到问题或觉得哪里不妥,这些反馈正是当前阶段最有用的内容。
许可证
MIT。请参阅 LICENSE。
开发历史和引擎详细说明见 CHANGELOG-dev-notes.md、ENGINE.md 和 ENGINE_VALIDATION.md。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。