mcpField
O
OMEM

OMEM

本地服务
infrastructure.omem-cloud.com记忆与知识06 周前更新

关于 OMEM

OMEM 是面向 Agent 开发者的记忆服务,记录信念、证据及其变化过程。它保留矛盾信息和来源链,而非静默覆盖冲突事实。

主要功能

  1. 01随时间变化的信念状态
  2. 02显式追踪矛盾信息
  3. 03证据与来源链
  4. 04私有或共享的 Agent 记忆
  5. 05语义召回与学习
  6. 06受策略约束的修复流程

适用场景

  1. 01追溯 Agent 持有某项信念的原因
  2. 02审核相互冲突的客户信息
  3. 03在团队间共享选定记忆
  4. 04审批并审计 Agent 修复操作

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"troybrandonc-bit-omem": {
"command": "uvx",
"args": [
"omem-infrastructure"
],
"env": {
"OMEM_API_KEY": "<OMEM_API_KEY>",
"OMEM_PROJECT": "<OMEM_PROJECT>",
"OMEM_BASE_URL": "<OMEM_BASE_URL>",
"OMEM_AGENT": "<OMEM_AGENT>",
"OMEM_USER": "<OMEM_USER>"
}
}
}
}
启动命令uvx omem-infrastructure
需要配置的环境变量
OMEM_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+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypiomem-infrastructure0.3.15

工具

5

收录的工具列表 · 更新于 2 周前

参数类型必填说明
taskstring否Agent 正在尝试完成什么
limitinteger否
contextstring否当前对话/情境

详细介绍

OMEM

CI PyPI Python License: MIT

记录 AI Agent 所相信和所做之事的权威系统。 只追加不修改, 每条信念都有证据支撑,每个矛盾的双方都会保留,每项高风险操作背后都有一位具名的人类。 因此,当 Agent 采取行动后有人问“它为什么这么做”,你可以拿出记录作答,而不必展开调查。

OMEM 承担记忆层的职责,但做的是另一种工作。它不会把文本一股脑塞进向量存储并寄希望于结果,而是持续追踪每个 Agent 的信念,保存每条信念背后的证据,并明确处理矛盾,让 Agent 能够推理自己知道什么、何时得知,以及为何相信。

而且它并非从零开始。选择汇总一般人群相关认知的安装实例,会以无人可被识别的计数形式共享所得;新安装实例从第一天起就能借鉴这些直觉,而不必花六个月慢慢积累。你贡献的是计数,得到的是其他所有人的计数。借鉴而来的模式先天弱于自己学到的模式;一旦某个人自身的证据与之矛盾,它也会立刻失效,因此普遍模式永远不会凌驾于个体之上。

目前数据库还是空的。还没有任何安装实例作出贡献,这意味着最早参与的实例将决定它学到什么;同时也值得注意的是,关于人群规律的数据集可能会带有填充者的偏见。挖掘规则已重写,模式必须优于基准率,而不能仅仅依托基准率(工作论文第 1 号);贡献者群体是否具有代表性,则是另一个尚无定论的问题。

它可在本地运行,无需外部服务,也无需安装依赖项。

pip install omem-infrastructure && omem-server

或者,只需单击一次即可部署私有服务:

Deploy to Render

该蓝图会配置一个小型服务,附带持久化磁盘并启用密码身份验证(首个注册账户即为运营者账户),同时生成主密钥。Fly.io 也可使用:运行 fly launch --copy-config,并使用随附的 fly.toml。

文档:infrastructure.omem-cloud.com · 快速入门 · 安全 · 贡献指南

要向客户交付 Agent?审计跟踪和审批关卡正是关键:客户安全审查会询问什么,目前也开放少量深度参与的设计合作伙伴试点。

想在继续阅读前看看完整流程如何运行? refund-desk 是参考集成:一个能够转账并提供凭证的支持 Agent。 只有一个文件,一分钟即可运行,并会验证自己的每项声明。

重放 scripts/demo_reasoning.py:两条记录合并为一个人,已声明的规则得出结论,前提被撤回后,同一请求中的结论也随之撤销,而对于机器而言,分拆已成定局。

这是 scripts/demo_reasoning.py 的节选。每一行都是在 CI 中运行的断言行为,因此这张图不会悄无声息地失去真实性。

一次实际运行期间的仪表板:两个来源对客户的套餐说法不一致,OMEM 保留双方的信息并将该命题标记为 CONTRADICTED,每条信念都可以展开查看其依据链。

两个来源说法不一致。两者都不会被覆盖。 查看完整运行效果。

有何不同

大多数 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 server
    

    test_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 相同。

26 秒动画:在键值存储中,对同一个键调用两次 store.put 会擦除第一个值;通过 OmemStore 调用相同操作则会取代旧值,旧值仍保留在记录中,且 mem.why 会说明这段记忆的来源。

它与内置存储的区别在于第二次写入时的处理方式。内置存储会覆盖,而 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。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。