mcpField
M
mnemo

mnemo

本地服务
pypi.org记忆与知识8今天更新

关于 mnemo

mnemo 是面向 AI Agent 的长期记忆库及 MCP 服务,支持更正、撤销和审查记忆,并提供主体删除证明与操作审计。它适合需要管理变化事实和追溯记忆操作的 Agent 开发者。

主要功能

  1. 01按键更正并退役旧值
  2. 02恢复更正并记录决策
  3. 03主体删除及可验证证明
  4. 04签名哈希链操作日志
  5. 05适配多种 Agent 框架

适用场景

  1. 01避免已更正事实重新成为当前值
  2. 02回应主体删除请求并提供证明
  3. 03核查 Agent 行动时保存的记忆
  4. 04为 Agent 集成持久记忆

MCP 相关

MCP 服务向 Claude Code、Cursor、Windsurf、Codex 和 Cline 等客户端提供记忆能力。README 也列出 LangChain、LangGraph、ADK 等框架的适配器。

配置

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

mcp.json · 通用配置
{
"mcpServers": {
"dancenitra-mnemo": {
"command": "uvx",
"args": [
"agora-mnemo"
],
"env": {
"MNEMO_PATH": "<MNEMO_PATH>",
"MNEMO_ECHO_GUARD": "<MNEMO_ECHO_GUARD>",
"MNEMO_EMBED_URL": "<MNEMO_EMBED_URL>",
"MNEMO_EMBED_MODEL": "<MNEMO_EMBED_MODEL>"
}
}
}
}
启动命令uvx agora-mnemo
需要配置的环境变量
MNEMO_PATHPath to the JSON memory file the server persists to (defaults to ./mnemo_memory.json).
MNEMO_ECHO_GUARD1 (default) blocks a restated retired value from resurrecting a corrected fact; 0 = legacy keyed supersession.
MNEMO_EMBED_URLOptional OpenAI-compatible /embeddings endpoint for SEMANTIC recall (e.g. http://localhost:11434/v1/embeddings for local Ollama). Unset = deterministic lexical recall.
MNEMO_EMBED_MODELEmbedding model id used with MNEMO_EMBED_URL (default: text-embedding-3-small; for Ollama use e.g. nomic-embed-text).

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypiagora-mnemo1.24.2

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

inspeximus

一座昏暗的档案大厅,悬挂的玻璃记录面板向雾霭深处延伸。一道琥珀色光线划过其中一块面板,并向前弯曲,延伸至更远处的面板。一张封口的纸质收据放在下方的地板上。

为 AI Agent 提供防篡改的长期记忆。只需更正一次事实,旧值就会永久停用;删除某个人并提供证明;向审计员展示 Agent 采取行动时掌握的信息。仅需一个零依赖的 Python 文件,另附 MCP 服务。

删除证明仅适用于此存储,不涵盖向量索引、提示词日志或备份;它是一种完整性原语,并非合规认证。

快速入门 · 文档 · 与 mem0 和 Graphiti 对比 · 从 mem0 迁移 · 欧盟《人工智能法案》与 GDPR 证据 · Claude Code,一行命令 · 透明度日志 · PyPI

PyPI 下载量 CI 声明审计 Python 零依赖 测试 许可证 DOI

pip install "inspeximus[crypto]"
inspeximus demo          # a first result: offline, touches nothing of yours
from inspeximus import Inspeximus

m = Inspeximus("memory.json")
m.remember("The staging database is db-3.internal", key="staging-db")
m.remember("The staging database is db-7.internal", key="staging-db")   # a correction
m.recall("which staging database")[0]["text"]   # 'The staging database is db-7.internal'
m.revert("staging-db")                            # and it is reversible, on purpose

memory.json 只是一个名称,并非文件格式:新建的存储是一个 SQLite 文件。请通过 inspeximus 或 sqlite3 模块读取,切勿使用 json.load 或 cat。

更正一条事实后,旧值再次出现的频率是多少?inspeximus 为 0%,Graphiti 0.x 为 13.3%,mem0 2.0.11 为 46.7%,禁用防护机制的 inspeximus 为 100%——每个系统均在其原生配置下测试,n=30。 | | 你将获得 | |---|---| | **持久生效的更正** | `remember(key=...)` 会按键废弃旧值。重述过时文本不会让它重新生效;`revert()` 会将其作为一项记录在案的决定恢复。 | | **可验证的删除** | `forget_subject()` 会删除关于某个人的所有记录,留下经过签名且不含内容的墓碑;`erasure_certificate()` 让第三方无需私钥即可验证。若要验证作者身份,第三方会固定你的公钥(`expected_pubkey`)并见证锚点。它仅涵盖此存储。 | | **Agent 采取行动时掌握的信息** | 经过签名、由哈希链连接的行动账本;`matches()` 会将保留的对话记录与其条目绑定。 | | **事件发生的时间** | RFC 3161 时间戳,并可检查该日期时颁发机构是否在欧盟信任列表上。 | | **审计员可读的证据** | `inspeximus compliance` 会按条款标注证据;可导出为 draft-sharif-agent-audit-trail-04 文件。 | | **适用于任何 Agent,一行配置** | 适用于 Claude Code、Cursor、Windsurf、Codex 和 Cline 的 MCP 服务;还提供适用于 LangChain、LangGraph、ADK 等的适配器。 |

为什么选择 inspeximus

当 Agent 会连续运行数天,而它持有的事实可能在运行过程中发生变化,并且日后有人可能会询问它当时掌握了什么、删除了什么,就可以使用它。这就是全部的设计目标。

你的情况可使用
Agent 一直信誓旦旦地重复你已经更正过的值remember(key=...):更正优先生效,重述不会让旧值重新生效,revert() 是一项记录在案的决定
收到删除权请求,或审计员询问 Agent 采取行动时掌握了什么使用 forget_subject() 和 erasure_certificate();以及带有 matches() 的签名行动账本
使用 Claude Code、Cursor、Windsurf、Codex 或 Cline,且会话之间无法保留记忆MCP 服务,只需一行配置
使用某个框架(LangChain、LangGraph、ADK、Hermes、Haystack),但无法证明记忆写入确实发生过适配器和回执链

agno 并非我们开发。 它在自己的指南中提供了官方集成示例:cookbook/11_memory/integrations/inspeximus_integration.py,该示例于 2026-09-20 合并至 agno#10146,与 mem0、zep、memori 和 dakera 并列。他们自己的 README 将其描述为 “让更正持续生效的 inspeximus”。该文件所在的仓库并非由我们编写或维护,这正是值得列出它的原因:读者无需相信我们的话,就能自行核实这项集成。agmi 也同样如此。这是一份 Agent 记忆完整性评分卡,其维护者在亲自复现后,将我们的三行适配器 agmi/adapters/inspeximus_rows.py 合并到了 agmi#1。

如果你需要带控制面板的托管服务、针对文档的知识图谱,或在对话回忆基准测试中取得最高分,那它就不是合适的工具。mem0、Zep 和 cognee 在这些方面表现出色,比较页面 说明了各自的优势与不足。

实测结果

我们测量了其他系统没有公布的一项指标:更正后的事实再次出现的频率。

每个系统都使用各自的原生配置运行,执行相同任务,共进行 30 次试验:

系统保留更正旧值再次出现
inspeximus100%0%
Graphiti 0.x (Neo4j + OpenAI)86.7%13.3%  95% CI [3.3, 26.7]
mem0 2.0.11 (OpenAI 原生)53.3%46.7%  95% CI [30.0, 63.3]
inspeximus,已禁用防护机制0%— 对照组:这就是防护机制的作用

每个系统 n = 30。mem0 测试版本为 2.0.11(2026-07);mem0 目前已更新至 2.0.18,我们尚未重新测试——这里注明具体版本,而非将结论重述为当前结论。完整方法、原始数组和可重新运行的测试工具: RAMR · echo_resistance_backends_result.json

请正确解读 Graphiti 这一行——它的回声防护并未失效。 我们自己的原始输出记录显示,在回声运行前正确提取的 26 条更正中,echo_attributable_flips: 0。Graphiti 的双时态失效机制保住了每一条。上面的 13.3% 是四条回声出现前的提取遗漏——更正根本没有进入图中——这与本表关注的故障类型不同。若以机制而非标题来表述:在可归因于回声的旧值复现方面,Graphiti 得分为 0%,与我们相同,因为它在写入时保留了取代关系链接。这里真正的发现是:这些系统的区别在于是否记录了该链接,而不在于由谁记录。

三秒内即可核验的两个数字,无需 API 密钥

于 2026-08-25 对 Hindsight 0.9.2(vectorize-io,21k stars)和 mem0 进行测试,各自使用原生配置,n=20。这两项测试完全不需要评判模型——它们直接读取原始召回载荷,因此结果不受模型阅读能力影响:

inspeximus 2.21.0Hindsight 0.9.2mem0
更正后,召回返回新值而不是旧值20 / 200 / 201 / 20
相同内容写入两次——存储状态是否相同?逐字节相同20 / 20 不同—
完成此测试所需的模型调用次数06060

两个竞品都会返回更正后的值和已废弃的值,并将选择权留给调用方。这是一种合理的设计——双时态存储通过有效性标记同时返回旧值和新值,确实做到了坦诚——但这与我们的承诺不同,差别在于由谁负责消除歧义。

第一行可以免费验证。无需密钥、服务或网络:

git clone https://github.com/DanceNitra/inspeximus && cd inspeximus
python probes/integrity_bench_store_resolves.py --systems inspeximus

测试会在几毫秒内完成,并打印 store-resolved=1.00 (resolved=20 both=0 stale=0 neither=0, n=20)。 添加 ,mem0 或 ,hindsight 即可复现它们对应的列,并产生它们各自的提取器调用成本。 方法、注意事项,以及我们未胜出的项目。

最重要的是最后一行。关闭我们的防护机制后,得分就是 零——这说明这个数字反映的是机制本身,而不是基准测试对我们手下留情。



内置符合《欧盟人工智能法案》和 GDPR 的证据记录

每次写入、修正、删除和 Agent 操作都会留下带签名、哈希链式记录。第三方无需 API 密钥,即可离线验证。只有当读取者固定运营方的公钥并见证锚点时,签名才能证明签署者身份。证据现在即可导出;《欧盟人工智能法案》的高风险义务将于 2027 年 12 月 2 日(附件 III 系统)和 2028 年 8 月 2 日(嵌入受监管产品的系统)起适用,而 GDPR 第 17 条自 2018 年 5 月 25 日起已适用。

义务inspeximus 保存的内容读取者如何检查
《欧盟人工智能法案》第 12 条,自动事件记录带签名的操作账本,记录 Agent 执行操作时记忆存储中的内容;matches() 将保留的转录与其条目绑定inspeximus actions verify,离线验证
第 19 条,日志保留仅追加的回执链,其链头存放在存储之外,因此会报告尾部截断verify_writes()
GDPR 第 17 条,删除权forget_subject() 会删除此存储中可归因于某个人的所有记录,包括继承了该信息的摘要,并留下不含内容且带签名的墓碑。事件日志中已删除记录的租户和 Agent ID,以及墓碑上的租户标记,均使用加盐 HMAC 进行假名化。盐值位于密钥目录中,因此可根据已知 ID 重新导出假名。一个标识符会保留:异议记录会在 <store>.objections.json 中保留主体的 ID,以便继续阻止新记录erasure_certificate(),无需私钥即可检查;固定 expected_pubkey 并见证锚点以确认作者身份
GDPR 第 15 条和第 16 条,访问权和更正权export_subject()、rectify(),并附有注明操作者和原因的回执导出的清单哈希存放在账本中
第 26 条,部署者义务deployer_report,默认仅提供计数,报告中不含个人数据
发生时间来自第三方的 RFC 3161 时间戳;inspeximus timestamp qualified 会说明该机构在对应日期是否列入欧盟可信列表(eIDAS 第 41 条)离线可信列表缓存
提交给审计员导出为 draft-sharif-agent-audit-trail-04 文件,并通过 action_detail 携带 Ed25519 签名任何符合规范的验证器

inspeximus compliance 会按条款打印证据。完整映射及每一行的适用边界见**《欧盟人工智能法案》证据页面**和 docs/AI_ACT.md。范围一句话概括:在全新存储(3.12.0)上,inspeximus coverage 会逐条列出已覆盖的 36 项适用提供者和部署者义务;认证是由其他方单独执行的行为。

对于评估人员要审阅的文档,intake_form() 会请你一次性填写仅运营方能够填写的 66 个字段,之后 assessor_pack()(3.7.0)会生成附件 IV、附有 DPIA 和 FRIA 附录的部署者报告、附件 VIII 导出文件以及审计包。只要还有字段未答复,它就不会声称内容已完整。

至关重要的 30 秒

每个记忆库都能存储和检索。没人回答的问题是:存储的事实被证明错误时,会发生什么?

from inspeximus import Inspeximus

m = Inspeximus("correction.json")

m.remember("The staging database is db-3.internal", key="staging-db")
m.remember("The staging database is db-7.internal", key="staging-db")   # a correction

m.recall("which staging database")[0]["text"]
# 'The staging database is db-7.internal'          <- the correction wins, every time

m.revert("staging-db")                              # and it is reversible
m.recall("which staging database")[0]["text"]
# 'The staging database is db-3.internal'

没有嵌入漂移,也没有“LLM 通常会选更新的那个”。旧值会按键退役,而退役本身是一条可审计、可撤销、可验证的记录。

再说一次旧值,它也不会回来。 这是近期优先规则做不到的事:在同一个键下,第三次写入 db-3,当前值仍然是 db-7。回退是你有意做出的决定,要使用 remember(..., reaffirm=True)——防护机制不会自行撤销取代关系。 按键写入后,读取 m.last_write["blocked"];或者传入 raise_on_block=True,这样防护机制保留旧值时会抛出 WriteBlocked 错误,而不是返回 ID。

这个限制源于按键机制: 未指定键的语句是一个新事实,而不是更正,因此不受防护机制约束。如果你的流水线在重新摄取过时文档时不使用键,那么这段文本就会凭自身价值参与竞争。这两种行为都在 probes/does_a_restatement_take_the_key_back.py 中进行了测量,该脚本可在一秒内离线运行。

选择启用权威度,较弱的来源就无法覆盖较强的来源。 默认情况下,较晚的按键写入会胜出。使用 Inspeximus(path, supersession="authority") 时,如果按键写入的 source={"doc": ..., "authority": 0.3} 权威度低于当前值,该写入会在到达时退役,当前值保持不变;判定结果会记录在记录中,也会写入 m.last_write。摘要会通过 derived_from 继承其最弱父项的权威度,因此以完整权威度重述谣言也无法洗白它。只有双方都声明了权威度时,权威度才会参与判定;因此,在现有存储上启用此功能不会带来任何变化,直到写入方开始声明权威度。在 MemTX 语料库上重放存储数据时,默认模式在 318 个案例中有 278 个提供了带标签的信念,而权威度模式在 318 个案例中有 307 个提供了带标签的信念,没有任何案例出现反向结果。大多数过时写入案例已被回声防护机制捕获;它会让重述的旧值退役,无论其权威度如何。权威度机制新增的作用是阻止较弱来源写入该键从未持有过的值。它仍未捕获的 11 个案例是权威度相同的写入方之间的更新丢失,这不是任何权威度规则所能裁定的;而且有一种情况值得了解:系统以完整权威度写入的事实,永远无法由权威度较低的 Agent 更正。这两点都写在 _supersede_by_key 的文档字符串中。 在一项我们未编写的基准测试上(MemTX,318 个可重放案例),默认模式在 318 个案例中有 278 个提供了带标签的信念,而 supersession="authority" 在 318 个案例中有 307 个。 第一个数字已经包含回声防护机制;该机制在 1.87.0 版本发布时就已上线,早于任何人在此语料库上对它进行测量。


当有人要求你证明时

启用收据后,每次写入都会加入哈希链。仅凭值本身,无法判断是否有人在库背后修改了文件。哈希链可以。

from inspeximus import Inspeximus

m = Inspeximus("receipts.json", receipts=True)
m.remember("The staging database is db-3.internal", key="staging-db")
m.remember("The staging database is db-7.internal", key="staging-db")

m.verify_writes()[0]        # nothing has been touched yet
# True

# now somebody edits the store directly, turning db-7 into db-9
from inspeximus import sqlite_store
items = sqlite_store.load("receipts.json")
before = sqlite_store.snapshot(items)
edited = next(r for r in items if "db-7" in r["text"])
edited["text"] = edited["text"].replace("db-7", "db-9")
sqlite_store.save("receipts.json", items, before)

Inspeximus("receipts.json", receipts=True).verify_writes()[1][0].split(": ", 1)[1]
# 'its TEXT or KEY no longer matches its write receipt (edited after write)'

如果存储中已有不带哈希链的记录,或者哈希链是从中途开始的,一次调用即可处理。哈希链未涵盖的每条记录,都会根据其当前状态生成一份收据;收据的哈希中会标记 backfill,并包含该批次的 Merkle 根。从这次调用开始,任何编辑都会像其他编辑一样导致 verify_writes() 失败;此前发生的情况,之后生成的收据都无法追溯。

from inspeximus import Inspeximus

m = Inspeximus("older.json")            # a store written with receipts off
m.remember("The on-call rota is in the wiki", key="on-call")
m.verify_writes()[1][0].split(":", 1)[0]
# 'write receipts are DISABLED'

m.enable_receipts()["anchored_records"]
# 1
m.verify_writes()[0]
# True

也可以在 shell 中运行:inspeximus receipts enable --backfill。3.0.0 版本的 CHANGELOG 条目包含了我们对自有存储进行的测量结果。

不再适用的键应该用 retire 结束,而不是写入占位值:按键写入会替换当前值,因此占位值会成为该键新的活动值。retire 不会留下活动值,会在 history(key) 中保留所有值及其原因,并在收据链中声明自身。

from inspeximus import Inspeximus

m = Inspeximus("rota.json")
m.remember("The on-call rota is in the wiki", key="on-call")
m.retire("on-call", "the rota moved to the pager tool")
m.current("on-call")
# None
m.history("on-call")[0]["reason"]
# 'the rota moved to the pager tool'
多个进程,一个存储库

行写入器会在写入行的同一事务中,向 memory_events 追加一条不含内容的行,因此另一个进程可以按 seq 追踪该表,并在下一次调用时看到一次提交,无需重新加载,也无需消息代理。current(key) 会通过以(租户、Agent、key)为键的 L1 缓存响应重复读取,因此,一个 Agent 预热的缓存命中绝不会被提供给另一个 Agent。

擦除记录时,会在执行删除的同一事务中,从其日志行中移除记录的 key(这些行会保留,并标记为 key_redacted),因此,以某个人命名的键不会在擦除后继续留存。

from inspeximus import Inspeximus

lead = Inspeximus("crew.json")
worker = Inspeximus("crew.json")
tip = worker.events_tip()

lead.remember("The plan is: ship on Friday", key="plan")
lead.publish_event("plan.updated", {"to": "worker"}, agent_id="lead")

[e["type"] for e in worker.poll_events(since_seq=tip)]
# ['record.added', 'plan.updated']
worker.current("plan")["text"]
# 'The plan is: ship on Friday'
Agent 的操作与其当时掌握的信息绑定

审计追踪工具会为 Agent 的操作签名。操作账本也会这样做,并将每项操作与 Agent 在当时持有的记忆绑定:存储库的状态摘要,以及上次召回返回的 ID。如果某条事实在两次操作之间被更正,这两次操作就会有不同的摘要,因此读者可以从链中看出,第一次操作基于旧值执行,第二次基于新值执行,而不必依赖任何人的说法。

from inspeximus import Inspeximus
from inspeximus.actions import ActionLedger

m = Inspeximus("deploys.json", receipts=True)
m.remember("The staging database is db-3.internal", key="staging-db")
led = ActionLedger(m, actor="deploy-agent")

target = m.recall("staging database")[0]["text"]
with led.action("tool:deploy", inputs={"target": target}) as a:
    a.output({"deployed_to": target})

m.remember("The staging database is db-7.internal", key="staging-db")   # the correction
target = m.recall("staging database")[0]["text"]
with led.action("tool:deploy", inputs={"target": target}) as a:
    a.output({"deployed_to": target})

led.what_it_knew(0)["recalled_now"][0]["current"]["status"]   # 'superseded'
led.what_it_knew(1)["recalled_now"][0]["current"]["status"]   # 'active'
led.verify()                                                   # (True, [])

默认不含内容:输入和输出会以加盐的 SHA-256 摘要形式存储。保留了对话记录的操作员仍可调用 led.matches(seq, inputs=prompt, output=answer),确认模型收到的内容和返回的内容是否与之相符;只要有一个字符不同,结果就是否,而且此项检查需要盐文件,因此其他人无法运行。若存储库有收据密钥,则会使用该密钥签名。inspeximus actions verify 可离线检查文件;若存储库存在,它还会检查每个条目的 last_receipt 是否仍存在于记忆链中,从而从操作侧发现被改写的记忆历史。设置 INSPEXIMUS_ACTIONS=1 后,MCP 服务会记录每次工具调用;inspeximus.integrations.langchain.InspeximusActionCallback 会记录 LangChain 工具调用和模型调用。探针:probes/what_the_agent_knew_when_it_acted.py,三个篡改控制,均未通过。

另外两种事件类型也会共用这条链。led.oversight("override", "ops-lead", refers_to=3, reason=...) 会记录针对某项操作的人类决策,并注明作出决策的人或角色(《法案》第 14 条和 GDPR 第 22 条所要求的记录);引用必须能够解析,验证器会重新检查。led.disclosure("s1", "You are chatting with an AI assistant.", channel="web") 会按会话记录一条第 50 条披露。inspeximus.subject_rights.export_subject(m, "crm/alice", ledger=led) 会响应 GDPR 第 15 条访问请求,导出来源可解析至该主体的所有记录,其解析方式与 forget_subject 完全相同;rectify(m, key=..., text=..., actor=..., reason=..., ledger=led) 则是第 16 条更正,并生成注明请求者身份的收据。led.incident("...", "serious", "dpo", refers_to=[3, 4]) 会创建一条第 73 条记录,并从知悉事件时开始计算 15 天时限;incident_report(seq) 会生成报告框架。inspeximus compliance 会通过其验证器读取账本中的所有内容,并生成 22 项按条款标注的控制措施。

根据同一组证据会生成两份文档。inspeximus technical-documentation --out annex_iv.md 会生成第 IV 附件框架(第 11 条),依据存储库和账本中的证据填写可填充的章节,其中包含第 13(3)(f) 条使用说明,并将 24 个提供方字段标记为 OPERATOR INPUT REQUIRED。inspeximus deployer-report --out deployer.md 则生成部署方报告(第 26 条):已记录的监督、事件及第 73 条时限、最早保留日志条目的时长与六个月最低期限的对比(在日志达到该时长之前,会报告为尚无法测试)、披露内容,以及 GDPR 第 35(7) 条 DPIA 附录和引用该附录的第 27(1) 条 FRIA 附录。两份文档都会列出所有无法填写的字段。inspeximus registration-export --section A 会以相同方式写入欧盟数据库所需的第 VIII 附件字段(第 49 条)。 保存多年的账本会进行轮换,而不是截断。inspeximus actions archive --keep-days 400 会将较早的条目移入账本旁边的归档文件,并以一条带签名的检查点作为当前文件的开头,其中注明归档文件、其哈希值和归档的尾部;链条不会中断,actions verify 会沿检查点继续验证归档文件,而仅验证当前文件时,会将归档范围报告为未验证,而不是跳过它。inspeximus actions attest --policy-days 183 --actor dpo 会追加一条带签名的声明,说明账本所涵盖的最早条目,以及是否遵守了 Art. 19 和 Art. 26(6) 规定的六个月底线。inspeximus actions timestamp --url https://freetsa.org/tsr 会请求 RFC 3161 机构为尾部加盖时间戳,并将令牌链接进账本链,这样审计员就能获得第三方对其之前所有内容的时间证明,并使用 openssl ts -verify 进行验证。

inspeximus actions timeline --session s1 会从链中重建一个工作流,不包含内容:每个步骤都列出 Agent 持有的记忆摘要、模型、参与者,以及与之相关的监督或事件。inspeximus actions export-trail 会以 IETF draft-sharif-agent-audit-trail-04 格式写出账本,按 RFC 8785 进行哈希链式链接,供读取该格式的工具使用;--verify 会验证任何此类文件。inspeximus actions lifecycle substantial_modification --actor cto --note "..." 会记录 Art. 3(23) 所指的变更,该变更会终止系统依据 Art. 111(2) 享有的祖父条款豁免;lifecycle decommission --disposition erased 则会记录系统生命周期结束时如何处置记忆。

记忆可以按 Agent 和流程进行分区,这正是 CNIL 2026 年关于智能体 AI 的说明所要求的形式:inspeximus partitions open triage-2026-09-16 --kind context --max-age-days 1 --max-records 200 会打开一个范围,其写入内容都会带上标签;partitions sweep 会为每个打开的分区应用过期时间和容量上限,并添加墓碑;partitions close NAME --actor 会结束流程(context 分区会在关闭时擦除其记录)。partitions report 会显示当前已过期的内容,以及分区外存放了多少记忆。

写入存储的位置

你无需选择存储格式。新存储会以行的形式写入 SQLite 文件,无论文件名是什么:memory.json 并不是 JSON,json.load 无法读取它。此版本首次打开现有 JSON 存储时会将其转换:转换过程会重新读取写入的数据,并且只有在记录数和 ID 顺序都保持不变时才会继续;原文件会作为 memory.json.pre-rows.bak 保留在存储旁边。加密存储仍然是单个加密数据块,因为静态数据加密覆盖整个文件。

采用行存储,是因为过去每次写入都会重写整个文件,而且重写无法像行写入那样合并并发写入者的记录。

一次持久化写入,两种格式,每种进行三次独立试验,每次写入 30 条记录 (probes/one_write_two_formats_across_store_sizes.py):

存储中的记录数整个文件单行
1,0000.0075 s0.0071 s行写入快约 1.1 倍
10,0000.0818 s0.0422 s行写入快约 1.9 倍
30,0000.2334 s0.1292 s行写入快约 1.8 倍

差距取决于文件大小:随着文件增大,重写文件的成本会增加,而写入一行的成本不会,因此记录越多,收益越明显。应将最小的一行视为最不可靠的结果。在 1,000 条记录时,两者足够接近,以至于该探针的不同运行结果各有胜负;而在生成此表的那次运行中,三次试验里仍有一次结果相反。因此,探针会报告每次试验的结果,而不是平均值,并在趋势不稳定时明确说明。上表由探针写入的回执生成(tools/sync_store_format_table.py),因此它反映的是某次运行的测量结果,而不是我们的记忆。 在并发写入者的情况下,调用方如果丢弃存储自身抛出的 StoreChangedOnDisk 错误,而不是重试,那么在 48 个进程的最差试验中,只写入了 384 条记录中的 199 条;而行存储在测试的每种并发规模下,4 次试验均写入了所有记录。差距源于调用方,而非格式:按照错误提示进行重试后,整文件存储可以跟上(probes/what_a_concurrent_writer_is_told_against_what_the_store_keeps.py)。 请参阅 probes/twelve_writers_and_the_one_that_stopped_writing.py。这两个探测都会在运行它们的机器上重新测量整文件基线,而不是引用我们的数据,因此较慢的机器会报告较小的差距,而非给出虚假的结果。

升级前有两件事需要了解:

  • **使用此版本写入的存储无法由 2.26.1 或更早版本读取。**这些版本会将文件解码为 UTF-8,并抛出 UnicodeDecodeError。如需回退,请将 memory.json.pre-rows.bak 重命名并覆盖存储,然后固定使用较早版本。
  • 首次擦除时会删除回滚副本。forget、forget_subject 和 forget_pii 都会将其移除,因为未经请求由此库创建的副本,不应成为个人数据在收到删除请求后仍得以留存的地方。erasure_certificate() 会按文件名报告该文件的处理结果,因此回滚窗口的结束会留下记录,而非悄无声息。如需保留该副本,请在 <key home>/inspeximus/config.json 中设置 {"store": {"keep_conversion_backup": true}}(而非设置环境变量):此时证书会声明该备份未被擦除操作触及,这就是你需要接受的取舍。

INSPEXIMUS_STORE_FORMAT=json 会保留旧格式,供其他工具直接读取存储使用。自 3.17.0 起,它适用于新存储和已经是 JSON 格式的存储;对于行存储,该设置会被忽略,并在标准错误输出中打印一行提示。在 <key home>/inspeximus/config.json 中设置 {"store": {"format": "json"}},则会固定任何存储的格式。

provenance(key=...) 一次调用即可提供其余信息:该键曾持有的每个值及使其失效的策略、当前值的来源(包括通过摘要继承的污染)、记录是否仍与其回执承诺的内容相符,以及一个说明这些信息均无法证明什么的 limits 字段。擦除也以相同方式运作。forget_subject() 会硬删除可归因于某个人的所有记忆,包括通过谱系继承了这些记忆的摘要,并留下一个经过签名且不含内容的墓碑,让后续读取者能够分辨这是有意擦除,而非篡改。erasure_certificate() 可让第三方在没有私钥的情况下验证这一点。为证书签名的密钥属于操作者,因此要验证作者身份,第三方需固定 expected_pubkey 并见证锚点;verify_erasure_certificate(..., require_signed=True) 会拒绝未签名的证书。它只涵盖此存储,不包括向量索引、提示词日志或备份。

inspeximus compliance 会按条款标注并打印相同的证据,同时附上其自身的范围说明:列出的义务是 inspeximus coverage 所涵盖的义务,而非认证。

证明时钟的时间,以及它是否归任何人所有

系统中的每个时钟都归被审计的运营方所有,因此 timestamp.py 会改为从第三方获取 RFC 3161 令牌。根据 eIDAS 第 41 条,合格时间戳对其显示的时间具有可反驳的推定效力,而普通时间戳则没有。令牌本身不会说明你拿到的是哪一种。

inspeximus timestamp trusted-lists 会构建欧盟可信列表的离线缓存,而 inspeximus timestamp qualified <token> --trusted-list <cache> --when <the date it was made> 则会针对单个令牌给出判断。退出代码会区分合格、不合格和无法判定。

传入令牌生成时的日期,而不是今天的日期。合格状态会随时间授予和撤销: 在 25 个地区公布的 1477 项合格时间戳服务中,有 570 项(39%)曾同时处于合格和不合格状态。某项真实的奥地利服务仅因日期不同,就会根据同一张证书返回四种不同的答案。

它只报告成员资格,不做其他检查。它不会检查可信列表上的签名,不会说明令牌是否真实(verify_with_openssl 会进行此项检查,而且两项检查都必须通过),并且对于列表中最早记录之前的日期,它会回答 UNKNOWN,而不是“否”。

范围。 上述各行是 inspeximus coverage 按条款列出的职责。该法案对独立 Annex III 系统的高风险义务自 2027 年 12 月 2 日起适用,对嵌入受监管产品的系统则自 2028 年 8 月 2 日起适用;相关义务要求提供的证据(第 12 条的事件日志、第 19 条的留存、第 15 条的准确性和稳健性),正是存储目前已保留并可导出的内容。 docs/AI_ACT.md 将各项职责映射到存储,并标明映射的边界。

读者无需向你索取任何内容,就能自行检查的日志

只要你诚实,上述内容就都成立。但这些内容无法阻止你保留两份历史记录,并向不同读者展示各自合意的那一份,因为答案由你提供,记录也是你写的。

因此,tools/publish_static_log.py 会将日志写成普通文件:头部、COSE 密钥集、每个叶子哈希、每份收据、每条记录的文本,以及一个仅依赖标准库运行的 verify.py。读者下载四个文件,就能根据叶子本身检查 Merkle 根。这正是证书透明度的发展方向,而非绕过它的捷径:C2SP 的 static-ct-api 将日志作为可缓存文件提供,因为这种方式运行成本更低,也比 API 更难作假。

我们的日志位于 dancenitra.github.io/inspeximus/transparency。 每条记录都是本项目发布的一个数字,并附有它出现的句子以及可复现该数字的命令。

日志是否涵盖所有内容,是由你来检查的事,而不是我们声称的事;而这一段过去曾声称它涵盖所有内容。python tools/seed_claims_log.py --log transparency/claims.log --check 会将登记表与日志进行对比,并指出尚未记录的内容;它不需要密钥,CI 会在每次推送时运行它,因此一旦出现缺漏,你和我们就会同时看到。现在确实存在缺漏:四项声明已登记但尚未写入日志,因为追加记录需要签名密钥,而密钥并不在执行登记的地方。日志落后且如实说明这一点,正是此项工作的意义;日志落后却被描述为完整,正是它要防止的失败。

这里先说明静态日志无法做到的事,以免日后才发现:没有任何端点会通过 HTTP 接受登记。记录只能在签名密钥所在之处写入。如需实时端点,scrapi.py 提供 draft-ietf-scitt-scrapi-11,而 deploy/ 中包含容器映像。

见证者是你无法亲自运行的那一方

日志只能告诉你它内部一致。它无法告诉你别人看到的是否是同一份日志,运营者签多少次名也无法解决这个问题。只有记得先前某个头部的参与方才能发现日志被改写,而且只有当这份记忆存放在运营者无法触及的地方时才行。

inspeximus witness watch 就是这样的参与方。它获取一份自己并不运营的日志,从叶子节点重新计算根,而不是直接读取头部中的根;然后通过根据当前发布的叶子节点重建上次接受的头部,与之进行比较。判定结果包括 EXTENDS、FIRST_CONTACT(会明确说明它目前还不能证明任何事情)、FORK、ROLLBACK,以及表示日志自相矛盾的 MALFORMED。拒绝接受时不会更新记忆,因为如果见证者忘了刚刚发现的问题,下次面对改写后的日志就会报告 EXTENDS。

整个设置只需两个命令,而且首次运行不会让你作出任何承诺:

pip install inspeximus
inspeximus witness watch --url https://dancenitra.github.io/inspeximus-log/log --state witness.json

deploy/witness-template.yml 会在任意公开仓库中每天免费运行同一条命令。外部人士在这里最有帮助的做法,就是针对我们的日志运行一次;这不会让你作出任何承诺:你并非为任何条目的真实性背书,只是在记录今天展示给你的历史是否延续了之前展示给你的历史。

离线检查 Bitcoin 锚定

每个已发布的头部都用 OpenTimestamps 加盖时间戳,回执是一个 .ots 文件。通常可以用 ots 命令进行检查,但它会引入 python-bitcoinlib;在 Windows 上,该导入会通过 ctypes 查找 libssl,并在读取证明的任何字节之前崩溃。因此,检查功能已内置。

inspeximus ots upgrade <the .ots receipt>          # which block covers it? asks the calendars
inspeximus ots verify <the stamped file> --upgrade     --block-header <the 80-byte header as hex>     # ANCHORED, or MISMATCH

你需要提供区块头,可以来自你自己的节点,也可以来自任意区块浏览器。这就是离线检查的关键:区块来源由你选择,你的数据不会离开这台机器。只有 --upgrade 会使用网络,而且它只是向日历询问一个日历已经持有的摘要。

退出代码:0 表示 ANCHORED,1 表示 MISMATCH,3 表示 PENDING 或 INCOMPLETE。只有日历承诺的证明属于 PENDING,既不是错误,也不算通过,所以它有自己的代码,而不会被归入这两者之一。已锚定的证明表示这些确切的字节在该区块被挖出之前就已存在。它并不表示其中任何内容属实。

如果判定结果是 MISMATCH,且你的文件来自 Windows 上的 git 检出,请查看验证程序打印的关于行尾的提示:回执是针对 LF 字节加盖时间戳的,转换后的副本与回执不同,但这并不意味着有人篡改了任何内容。

你用来核验日志的密钥,发布了两份

要核验我们托管的日志,你需要我们的验证密钥。从你正在核验的主机获取密钥,等于让主机告诉你如何核验它自己:能够重写日志的运营者,也能重写旁边的密钥,而每个签名仍然都会通过验证。因此,这里也发布了该密钥。

现在,两份副本都托管在同一个 GitHub 账户下:这份 README,以及日志的公开镜像。只有在工作流使用固定在该仓库中的密钥验证快照后,镜像才会发布快照。这让这两份副本能够检查是否发生了隐蔽分叉,但无法防范 GitHub 或我们。独立于两者的参考是原始公钥: 9fb780dd72894867c6dac8e140cc78d755617147d20cfd26bfe557190f65ac49,它也以纸质形式离线保存。

92.5.74.17.sslip.io/log+41dfe27a+AZ+3gN1yiUhnxtrI4UDMeNdVYXFH0gz9Jr/lVxkPZaxJ

该行的 SHA-256:1017ff229193fa867e1f73758df24e440ebfad1710e1af49e296a5fe4f00783c

同一行也通过 /log/checkpoint.vkey 提供。两者必须逐字节完全一致。 如果不一致,请勿信任其中任何一个,并提交 issue。41dfe27a 是 c2sp.org/signed-note 中的四字节密钥 ID,用于选择要尝试的密钥,并非安全边界。

diff <(curl -s https://dancenitra.github.io/inspeximus-log/log/checkpoint.vkey)      <(curl -s https://raw.githubusercontent.com/DanceNitra/inspeximus/main/README.md |
       sed -n '/checkpoint-vkey:begin/,/checkpoint-vkey:end/p' | sed -n '3p')

tools/check_published_key.py 会执行此比较,CI 也会每天运行它,因此密钥轮换不会悄悄造成两份副本分叉。两份副本将悄悄替换密钥的成本从一个系统上的一次写入,提高到了两个系统上的两次写入。但这并不能让我们值得信任,因为两份副本都由我们掌控。独立性来自见证者,它会记住我们无法触及的一个头部。


接下来的五分钟

上面的演示在 revert() 处结束。接下来说明如何使用它。

将它接入真正的 Agent。 无需额外接线:在输入时调用 remember,在输出时调用 recall。关键在于密钥,因为它能让之后的更正落在同一条事实记录上,而不是变成第二条记录。

from inspeximus import Inspeximus

m = Inspeximus("memory.json")
user_id, choice, user_question = "u-1", "dark mode", "what does this user prefer"

m.remember(f"user prefers {choice}", key=f"pref::{user_id}")      # correcting later needs the key

context = [hit["text"] for hit in m.recall(user_question, k=5)]
print(context[0])
# user prefers dark mode

如果你使用框架,我们为 LangChain、LangGraph、LlamaIndex、CrewAI、AutoGen、Haystack、Google ADK、OpenAI Agents 和 Pydantic-AI 提供适配器,并附有一份台账,记录哪些已通过实时安装验证,哪些已记录为无法运行,而不是只摆一墙 Logo: docs/INTEGRATIONS.md。

按顺序完成这些示例。 它们无需密钥即可离线运行,每个示例都会打印它执行的操作:

01_basics.py记忆、回忆、更正,以及读取某个密钥的历史记录
02_correction_and_erasure.py将更正和擦除作为独立通道处理,它们本来就是独立的
03_semantic_recall.py使用你自己的嵌入器
06_gdpr_erasure_receipt.py向不信任你的人证明删除确实发生过

熟悉代码结构。 docs/CORE_MAP.md 列出了每个公共方法及其起始行号,内容由 AST 生成,并在 CI 中重新检查。

然后再决定是否相信其中任何内容,请使用 不必信任我们,也能核验我们下的两个命令。


每个 Agent 都能使用同一份记忆

pip install inspeximus
inspeximus install --all

install --all(3.14.0)会查找你已安装的每个 Agent:Claude Code(包括 Claude Desktop 的 Code 选项卡运行的副本,3.14.4)、Codex CLI、Gemini CLI、Antigravity、Cursor、Windsurf(Devin Desktop)、Devin CLI、Cline 和 Hermes Agent。它会在每个 Agent 中注册 MCP 服务,并将它们指向同一个用户级存储,这样,一个 Agent 记录的决策就会保存在其他所有 Agent 都能读取的存储中。

  • 每个 Agent 如何回忆。 Claude Code 和 Hermes Agent 通过各自的钩子和记忆提供程序来回忆。Gemini CLI 和 Codex 会读取服务的指令,在每项任务开始时进行回忆。对于 Cursor、Windsurf、Devin、Cline 和 Antigravity,--all 会在 Agent 的规则文件中提供一行配置(--rules yes 或 --rules no)。
  • 保留现有配置。 它会合并现有条目,并在更改任何文件前先复制该文件。如果你的 Agent 已指向两个不同的存储,它会停止并询问你。
  • 明确告知是否成功。 安装结束时会显示一个五行信息块:版本和 ARMED 或 NOT ARMED、存储及其记录数量、已接入的 Agent、需要重启的应用,以及校验封印。inspeximus install --check 会再次打印该信息块,根据存储重新计算校验封印,并在校验不匹配时以非零状态码退出。

Claude Desktop 在 macOS 上的路径遵循 Windows 布局,尚未在 Mac 上测量。各 Agent 的安装步骤:docs/install/index.md。

在 Claude Code 中使用(单行命令)

在 Claude Code 中,无需 pip,也无需配置文件:

/plugin marketplace add DanceNitra/inspeximus
/plugin install inspeximus@inspeximus

或者在 Shell 中先运行 pip install inspeximus:

inspeximus install --ide claude     # also: cursor, windsurf, codex, cline

这两种方式都会接入一个包含 135 个工具和相同钩子的 MCP 服务。从下一个会话开始,你的 Agent 就会知道上一个 Agent 做过什么决定——无需编辑 CLAUDE.md,也无需重新解释:

  • SessionStart 会注入仍然有效的决策
  • PostToolUse 会按文件记录实际发生的情况
  • PreToolUse 会在操作运行之前展示与该操作相关的决策

已在干净配置下,通过 Claude Code CLI 验证这两种接入方式,测试跨越两个会话。在 Windows 上 Claude 桌面应用的 Code 选项卡中,3.16.2 版本的实时会话会将钩子捕获的内容写入存储、在每条提示词中显示回忆区块,并提供 MCP 工具。Code 选项卡尚未在 macOS 上测量。

钩子耗时根据我们自己的项目存储副本测量,并记录在 CHANGELOG 中:在包含 67,165 条记录的存储中,读取耗时从 4.96 秒降至 0.41 秒(3.15.1);在包含 71,772 条记录的存储中,运行 --archive 后,提示词钩子的耗时中位数从 6.39 秒降至 1.82 秒(3.16.1)。

项目存储不断增长时

钩子会记录捕获的每条命令,因此项目存储每周会增长数千行,而每个提示词都会读取所有内容。--archive 会将旧的命令捕获记录从存储中移出,按月存入旁边的单个文件。不会删除任何内容。

python -P -m inspeximus.claude_code --archive --older-than 7         # what would move; writes nothing
python -P -m inspeximus.claude_code --archive --older-than 7 --apply # move it
  • 默认情况下,Recall 只读取存储。recall(..., include_archive=True) 也会搜索归档文件,MCP recall 工具接受 include_archive。
  • 擦除操作会覆盖每个月份。forget、forget_subject、forget_pii 和 --scrub-secrets 也会擦除归档文件中的内容;如果无法检查某些文件,则会拒绝操作并列出这些文件。擦除证书会列出每个文件,以及是否已确认其中不存在被擦除的记录。
  • 这些文件足够小,可以存放在 git 仓库中,但擦除操作无法覆盖 git 历史。除非传入 --allow-git-tracked,否则会拒绝使用位于 git 工作树内的存储。将归档文件提交到任何位置之前,请先运行 --scrub-secrets。
  • 此版本的一项限制:加密存储和固定为 JSON 格式的存储会被拒绝,因为归档文件是纯行存储。加密存储会保持完整。要归档固定为 JSON 格式的存储,请取消设置 INSPEXIMUS_STORE_FORMAT 并打开一次,这会将其转换为行存储。
  • 存储会记录归档日志包含的条目数以及最后一条记录的哈希,因此,如果日志被截断或单独替换,就会无法通过验证,并阻止擦除,直到日志恢复为止。这可以捕捉意外情况或单个被编辑的文件。编辑存储和日志的人可以让两者重新匹配。第二份头部副本位于存储目录之外;自 2.38.0 起,收据链的头部一直保存在那里(在配置中设置 guards.heads: false 可同时关闭两者)。除非同一个人也能写入该位置,否则这份副本可以捕捉这种编辑;对于这种情况,写入收据(签名日志)是检查手段。

你将获得

将更正作为一等操作。 remember(key=...) 会让该键的先前值失效。revert(key) 会将其恢复。history(key) 会显示链条。所有操作都是确定性的,且都可审计。

可验证的擦除。 forget_subject() 会硬删除可归因于某个主体的每条记忆——包括沿谱系继承了该主体信息的摘要——并留下经过签名、不含内容的墓碑记录,因此之后的审计可以区分主动擦除和篡改。

适用于任何存储、会读取字节内容的删除检查。 delete() 返回成功,只能说明某一行已从索引中移除。它并不能说明该值已从磁盘上消失;而对于擦除义务来说,真正重要的正是这一点。scan_residue(root, values) 会在目录中搜索应该已被清除的值,并区分通常会被混为一谈的三种结果:LIVE(某个表仍在一行中保存该值)、UNRECLAIMED(字节仍然存在,但不在任何活动行中,因为存储引擎尚未重新使用该页;这是引擎特性,不是供应商缺陷)以及 PLAIN(日志、跟踪记录或备份文件中仍包含该值)。这并非 inspeximus 专有功能:将其指向向量数据库、SQLite 历史记录、JSONL 跟踪文件或其他库的数据目录,它都能针对相应部署给出结果。

residue_certificate() 会将此类扫描结果转换成其他人可以检查的文档。它会记录所读取每个文件的 SHA-256,因此第三方可以使用 verify_residue_certificate() 重新遍历同一目录,确认搜索覆盖了其声称检查的字节,并确认这些字节此后未发生变化。签名可识别扫描器,但不能证明发现的内容属实;真正使其成为证据的,是任何人都可以重新运行扫描。从 shell 运行:inspeximus residue --root DIR --value SECRET --cert-out cert.json,然后运行 inspeximus residue-verify cert.json --root DIR。 在将干净结果视为一切正常之前,请先了解其范围。匹配是字面且区分大小写的,因此,将值改为小写或重新调整空格后得到的副本会按设计被漏掉;扫描无法读取的文件会被报告,并使判定保持为否定,因为“干净”绝不能意味着“我们没检查那里”。这两项限制都会写入签名证书。

可核查的来源,而不只是存储来源。 check_sources() 会重新读取每条记录的来源,并返回 FRESH / DRIFTED / ORPHANED / UNCHECKABLE,以及四个刻意分开统计的覆盖率数字——因为 source 字段的填充率达到 98.3%,但可重新获取率只有 0.01%,这只是一个 schema,而非保证。(这两个数字是我们在自有生产存储上测得的。)

对当前状态的适用性。 evaluate_applicability() 回答的是一个不同于“这条记忆是否属实”的问题:它现在能否在此处驱动操作? 历史证据可能完全有效,却不再获得授权——分支已变更、策略已更改、租户不同、有效期已过。该功能实现了与供应商无关的 CML 契约;两个独立实现对其冻结测试样例的结果一致。

多租户隔离。 for_tenant("acme") 会为一个共享存储提供限定范围的视图,并将租户绑定到签名消息中,因此记录无法在租户之间转移后仍通过验证。

审计人员熟悉的格式中的审计轨迹。 哈希链可以证明记录未被修改,但无法告诉第三方是谁写入了记录、记录内容是什么,或写入时间——而检查你系统的人实际会问的正是这三件事。四项 IETF 标准为此提供了解答,inspeximus 无需依赖项即可生成全部四种文件:

你想证明的内容文件标准
这条记录在日志中包含性收据RFC 9942(COSE Receipts)
这是我说的,且内容与此有关签名声明RFC 9943(SCITT)
遵循这些已发布的规则注册策略,作为日志本身的第 0 条记录RFC 9943 s5.1.1
第三方证明的此时间点RFC 3161 时间戳RFC 3161
pip install "inspeximus[crypto]"
from inspeximus import Inspeximus, new_receipt_keypair, verify_transparent_statement

secret, public = new_receipt_keypair()
m = Inspeximus("memory.json", receipts=True, receipt_key=secret)
m.remember("The staging database is db-7.internal", key="staging-db")

doc = m.transparent_statement(0, issuer="did:web:your-company.example")
# -> a COSE_Sign1 carrying your claim AND its inclusion proof, checkable by anyone

inspeximus.transparency.TransparencyService 会在其自身日志中发布的策略下注册其他方的声明,而 python -m inspeximus.scrapi 会通过 SCITT 客户端使用的 HTTP 接口提供该服务(draft-ietf-scitt-scrapi-11),因此这里没人编写的工具也能使用它。

签名并不能带来什么,我们会提前说明。 收据能证明某条记录包含在某个日志中,却无法证明你向他人展示的只有这一个日志;这需要独立见证者,因此 witnessed_head() 会收集 k-of-n 份联署签名,并将拒绝视为警报,而非错误。时间戳表示第三方在某个时间看到了某个摘要;令牌的完整验证交由 openssl ts -verify 处理,而不是手写实现,因为只回答“有效”的简易 CMS 解析器会放过真实验证器会拒绝的令牌。而且这些都不代表合规:没有任何法规要求使用签名账本。这是用于证明履行义务的证据质量,全文均以此方式表述。

零依赖项。 核心仅需一个文件:将 inspeximus/core.py 复制到任意位置,即可在未安装任何软件的情况下导入并运行。语义召回是可选的(embed=your_model);词法回退不需要任何依赖项。MCP 服务、加密功能和框架适配器是独立模块,均可按需启用。签名(Ed25519)需要 pip install "inspeximus[crypto]";基础包始终保持零依赖项。


适配

langchain · langgraph-store · llamaindex · haystack · autogen · pydantic-ai · google-adk · memoryagentbench · hermes-agent

对于 Hermes Agent,请将 inspeximus 安装到 Hermes 运行所用的 venv 中,而不是安装到 shell 的 Python 中(方法)。请使用 Hermes 自带的安装程序安装 Hermes:PyPI 软件包 hermes-agent 的版本是 0.19.0,此版本永远不会加载该提供程序。

14 个中有 14 个已通过针对当前上游版本的验证,记录为故障的有 0 个。 一天前,其中 3 个还无法正常工作, 列表也如实记录了这一点——正因如此,你才可以相信这里的说法:openai-agents 缺少 SDK 会进行类型检查的一个 属性;langgraph-checkpointer 下,存储的单写入者保护机制错误地拦截了此进程自己的线程;而 CrewAI 完全替换了 其存储协议,因此需要新增一个类,而非修复原有类。声明审核会从 docs/integration_conformance.json 读取这些计数,因此这里的说法不会与运行器 最近一次测量结果不符。

只列出成功项的“适配”列表,不过是展示商标墙。这里会告诉你哪个适配器会出问题,让你在基于它构建之前就心中有数。


测试方式

2,600+ 项测试,以及一道让这些测试值得信赖的变异测试门槛:植入 175 个缺陷,全部 175 个均被发现,无一漏过。 仅仅通过测试套件并不能证明什么;能够捕获每一个故意引入的问题,才有说服力。

本页面上的每个数字都已登记在 docs/CLAIMS.md 中,并附有重新计算该数字的准确命令。如果某个数字 与你运行得到的结果不一致,请向我们报告,这是我们希望收到的错误报告。

针对 agmi 一致性测试套件的五种静态数据攻击(篡改、截断、删除中间条目、 重排、伪造),按照攻击者的方式对存储背后的 SQLite 文件进行测试:开启凭据并提供密钥时,5 种攻击全部被检测到, 且每种情况都有明确指出原因的说明。即使攻击者还持有凭据旁路文件(对存储目录有写入权限便可获得),并删除了其所 删除的每条记录对应的凭据,所有攻击仍会被检测到:存储每写入一条凭据,都会将链的头部写入用户的配置主目录,该目录 位于存储目录之外;verify_writes() 会报告链比该头部更短。若攻击者也持有配置主目录并删除了头部,则5 种攻击中有 4 种仍会被检测到:删除中间条目仍会破坏签名链,截断末尾则不会;这种情况下需要一个保存在机器之外的 anchor() 以及 verify_consistency()。检测通过 verify_writes() 这一审计调用完成;无论记录是否被篡改,recall() 都会返回 该记录。默认情况下,凭据处于关闭状态,验证器会拒绝为存储作出任何担保,无论存储是否被篡改;这种情况计为“无法验证”, 而非检测到攻击。探测脚本: probes/five_at_rest_attacks_on_the_store_with_receipts_off_and_on.py。

不必信任我们,也能检查我们

只需运行两条命令。两条都不需要 API 密钥、服务或我们的任何数据。

python claims_audit.py

四十秒。它会读取我们在 README、文档和网站中发布的每个数字,并报告每个数字是否已登记、其固定版本是否仍可解析,以及是否有已提交的命令能够重新计算该数字。最后,它会输出问题列表,或者只输出一行:

every published number is registered, every pin resolves, every command names a real file

这里故意不引用统计数字。在审计会读取的文件中引用审计自身的总数,会导致文档每次变更时总数也随之变化;本节的第一个草稿就这么做了,并发布了过时的数据。运行它,查看当前数字。

运行结果会显示:有几行标记为 WITHDRAWN。这些是我们发布过、后来却无法复现的数字;我们将它们连同反驳它们的探针一起留在登记册中,而不是删掉。基准测试表是对竞争者的声明;登记册是对我们自己的声明,而我们更希望你先检查后者。

python probes/integrity_bench_revert.py --systems inspeximus --judge local --n 5

免费、离线、确定性,而且会自行说明:本地评估器无法与上表中由 OpenAI 评判的数据相提并论。诚实的测量工具和能让结果显得更好看的工具,不应是同一个工具。


文档

项目网站 →导览:基准测试、MCP 接口、治理说明
与 mem0 和 Graphiti 的测量对比完整的恢复表,包含对照组和真实适用范围
Claude Code 设置一行 MCP 安装命令,以及三个钩子的作用
长篇详解每种机制、每项测量,以及失败的项目
完整 API每个方法,以及它旨在防止的故障
擦除与 GDPR派生摘要中的删除权及相关凭证;擦除页面展示了完整的真实运行过程
从 mem0 迁移inspeximus import-mem0 export.json:每条记忆对应一条记录,以用户为主体,以 mem0 的时间戳为事件时间,可安全重复运行;包含 API 映射,以及导入无法恢复的内容
审计追踪页面Agent 采取行动时掌握的信息:签名账本条目、转录匹配,以及 IETF 草案导出,以真实运行示例展示
欧盟 AI 法案证据页面第 12 条日志记录和第 17 条擦除要求,以及它们与存储中现有内容的对应关系;对应说明见 docs/AI_ACT.md
MCP 工具全部 134 个工具及其用途
声明账本每个已发布的数字,以及重新计算该数字的命令
core.py 映射每个公共方法及其所在位置,由 AST 生成并在 CI 中检查
可运行示例可运行的脚本,而非代码片段
框架适配器哪些已通过实时安装验证,哪些被记录为已损坏
变更日志更改内容及原因,包括我们出错之处

适用对象

你正在构建一个持续运行数周、而非数分钟的 Agent。它会学到一些东西,而后那些东西会发生变化——配置值、策略、某个人的偏好,或一条事实。让你付出代价的故障,不是 Agent 忘记了,而是它信心满满地记住了旧答案。

这正是这个库所要解决的问题,也是我们唯一用来进行自我基准测试的问题。这个领域的大多数演示展示的是写入,而这个演示展示的是撤回,因为 Agent 将因这项操作而受到评判。


名称

这个名称源自中世纪的特许状。国王、主教、修道院院长或市议会会以 inspeximus 开篇, 意为“我们已查验”,并全文复述一份较早的文书,以记录他们已审阅该文书,通常还会予以确认, 再为结果加盖印章,以便后来的读者核查。这证明副本忠实地对应原件,而非证明原件属实。这里 提供的也是同样的保证,provenance() 会在 limits 字段中说明这一点,而不会让你自行发现。

引用

已存档于 Zenodo,并提供与版本无关的 DOI — 10.5281/zenodo.21708778。 机器可读的元数据位于 CITATION.cff,因此 GitHub 的“引用此仓库”按钮 可直接为你提供 BibTeX 和 APA 格式。


采用 MIT 许可。由 Agora 构建。Agora 是一个自主研究 组织,会将失败的复现与成功的复现一同发布。

mcp-name: io.github.DanceNitra/inspeximus

评论

支持 Markdown

第一次接触 MCP?

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

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