mcpField
I
IHMT Memory

IHMT Memory

本地服务
github.com/gonzaroman记忆与知识372 周前更新

关于 IHMT Memory

IHMT Memory 是面向 AI 编码 Agent 的本地长期记忆 MCP 服务,将记忆保存为可读文本文件树,供不同会话和 Agent 共用。它支持按时间标记过时信息,并通过树状检索避免读取全部内容。

主要功能

  1. 01跨会话保存决策与偏好
  2. 02多个 Agent 共用一份记忆
  3. 03树状文件结构与检索
  4. 04标记过时信息并保留历史
  5. 05本地纯文本存储,无云端依赖

适用场景

  1. 01避免在新会话重复解释项目背景
  2. 02让不同编码 Agent 共享个人设置
  3. 03查找某项决策及其变化历史

MCP 相关

通过标准 stdio MCP 服务向客户端提供长期记忆、项目索引和会话暂存记忆工具。README 提到提供九个工具,分为三类。

配置

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

mcp.json · 通用配置
{
"mcpServers": {
"gonzaroman-ihmt-memory": {
"command": "uvx",
"args": [
"ihmt-memory"
],
"env": {
"IHMT_HOME": "<IHMT_HOME>"
}
}
}
}
启动命令uvx ihmt-memory
需要配置的环境变量
IHMT_HOMEFolder that holds the memory (created on first use). Defaults to ~/.ihmt.

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

安装包
pypiihmt-memory1.2.1

工具

9

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

参数类型必填说明
clueany否
querystring是
detailstring否

详细介绍

IHMT — 无限层级记忆树

Listed on mcpservers.org ihmt-memory MCP server – quality and maintenance score on Glama

为 AI 编码 Agent 提供长期记忆。 告诉 Agent 一次某件事——一个决定、你的环境如何运行、一个更正——它就会在之后的每次会话、每个项目中,为你的所有 Agent 记住它。

IHMT 的功能

  • 跨会话记忆。 记录决定及其原因、你的环境、偏好、相关人员和项目,以及更正。Agent 会在回答前搜索记忆,并保存值得长期保留的信息,让你不必反复说明。
  • 所有 Agent 和模型共享同一份记忆。 Claude Code、Codex 和 opencode 可以共享同一份记忆:一个保存的内容,其他 Agent 也能找到。已使用 Anthropic、OpenAI、Google 和 Meta 的模型进行测试。
  • 节省 token。 Agent 无需每次都粘贴笔记或重新解释上下文,而只会检索问题所需的信息——通常为 200–900 个 token,无论记忆中有 50 条还是 50,000 条,因为搜索会遍历树,而非读取所有内容。 真实数据,包括它无法节省 token 的情况。
  • 理解时间变化。 当某些信息发生变化(“我搬到了 Valencia”“staging 现在使用 PostgreSQL 17”)时,旧记忆会作为历史记录保留,并标记为 OUTDATED,搜索会优先返回当前信息。你的居住地、工作地点和技术栈会自动跟踪;其他更正则会在 Agent 保存时通过 replaces 关联起来。当问题有歧义时(“Luis”——是哪一位?),它会先询问,而不是猜测。
  • 可移植。 你的记忆就是一个包含纯文本文件的文件夹。你可以将它复制到另一台电脑、备份,或纳入版本控制——无论放在哪里都能使用。
  • 本地、私密且易读。 无云服务、无数据库、无账号:IHMT 会将所有内容保存在你的磁盘上,不会将任何内容发送到其他地方。(Agent 检索到的记忆会像其他上下文一样传给其模型。)每条记忆都是可打开的文本文件,每位安装 IHMT 的用户都有自己的空白记忆。

兼容性。 官方支持:Claude Code。也已测试:Codex(CLI 和 ChatGPT 桌面应用——设置方法)以及 opencode (设置方法)。IHMT 是标准的 stdio MCP 服务,因此任何支持本地 MCP 服务的 Agent 都应该能使用——GitHub Copilot、Antigravity、Cursor、Windsurf、Gemini CLI、Claude Desktop……——而 INSTALL.md 也提供了配置方法,但我们尚未测试这些工具。它们都可以共享同一份记忆。

安装

开始之前
你需要原因
Python 3.10 或更高版本IHMT 使用 Python 编写
git用于下载 IHMT 并保持更新
能够运行命令的 AI Agent(Claude Code、Codex、opencode、Agent 模式下的 Copilot……)它会安装 IHMT,然后使用其中的记忆
安装期间需要互联网连接用于下载代码和 MCP 软件包;安装完成后不再需要

缺少 Python 或 git?你的 AI Agent 会为你安装(它会先征求你的同意)。 Python 会安装在你的用户文件夹中,无需管理员密码,因此不会对系统进行任何更改。在全新 Mac 上,git 可能需要你点击一次: Apple 会显示一个窗口,提示安装其命令行工具。

请注意,在 Mac 上,macOS 自带的 python3 是 3.9 版本,版本太旧——因此即使 python3 已存在,你的 Agent 仍可能提示缺少 Python。

你不需要管理员权限、数据库、账号,也不需要支付 Agent 之外的任何服务费用。已在 macOS 和 Linux(Ubuntu)上测试;Windows 说明已包含,但尚未测试。详情:GUIDE.md §3。

让你的 AI Agent 安装

将以下内容粘贴到你想赋予记忆能力的 AI Agent 中——已测试 Claude Code、Codex 和 opencode;GitHub Copilot、Antigravity、Cursor、Windsurf、Gemini CLI、 Claude Desktop 和其他 MCP 客户端也应该可以使用:

Install the IHMT memory MCP server for me from https://github.com/gonzaroman/IHMT-MEMORY — follow the instructions in its INSTALL.md.

Agent 会按照 INSTALL.md 操作:将 IHMT 下载到 ~/IHMT-MEMORY,将你的 记忆保存在 ~/.ihmt,只为它自己注册服务,添加使用说明,并告诉你它做了什么。然后启动新会话,以加载记忆工具。

使用多个 Agent? 想用的时候,可以在每个 Agent 中粘贴相同的提示词。如果已经安装了 IHMT——比如你用 Claude 已经几个月,现在想在 Codex 中使用——Agent 会找到该安装,在安全的情况下更新它,并连接到同一份记忆,因此从第一天起,它就能知道你告诉过其他 Agent 的内容。

Agent 必须能够运行终端命令或编辑文件;只能聊天的浏览器助手无法安装任何内容。

手动安装

要求:Python 3.10+、git,以及你的 Agent 的 CLI。

git clone https://github.com/gonzaroman/IHMT-MEMORY.git ~/IHMT-MEMORY
cd ~/IHMT-MEMORY
python3 -m venv .venv
.venv/bin/pip install -r requirements-mcp.txt
mkdir -p ~/.ihmt

Claude Code

claude mcp add ihmt-memory -s user -e IHMT_HOME="$HOME/.ihmt" -- "$PWD/.venv/bin/python" "$PWD/mcp_server.py"
claude mcp list                     # ihmt-memory … ✔ Connected

服务名称必须放在 -e 之前。然后将 templates/memory-instructions.md 追加到 ~/.claude/CLAUDE.md。

Codex — codex mcp add ihmt-memory --env IHMT_HOME="$HOME/.ihmt" -- "$PWD/.venv/bin/python" "$PWD/mcp_server.py", 然后在 ~/.codex/config.toml 的 [mcp_servers.ihmt-memory] 表中添加 default_tools_approval_mode = "approve"(放在其 env 表之前),并将模板追加到 ~/.codex/AGENTS.md。 详情。

opencode — 在 ~/.config/opencode/opencode.json 的 "mcp" 对象中添加一个 "ihmt-memory" 条目("type": "local"、"command": [<python>, <mcp_server.py>]、 "environment": {"IHMT_HOME": <memory folder>}),并将模板追加到 ~/.config/opencode/AGENTS.md。 详情。

Windows、项目级安装、图形化设置和故障排除均见指南。

从 PyPI 安装(uvx)

无需克隆,也无需创建 venv:uv 会下载并运行 ihmt-memory 包。记忆会保存到 ~/.ihmt;设置 IHMT_HOME 可使用其他文件夹(例如,已有的记忆文件夹)。

Claude Code

claude mcp add ihmt-memory -s user -- uvx ihmt-memory
claude mcp list                     # ihmt-memory … ✔ Connected
uvx ihmt-memory --instructions >> ~/.claude/CLAUDE.md

Codex — codex mcp add ihmt-memory -- uvx ihmt-memory,在 ~/.codex/config.toml 的 [mcp_servers.ihmt-memory] 表中添加 default_tools_approval_mode = "approve",并运行 uvx ihmt-memory --instructions >> ~/.codex/AGENTS.md。

opencode — 在 ~/.config/opencode/opencode.json 的 "mcp" 对象中添加一个 "ihmt-memory" 条目("type": "local"、"command": ["uvx", "ihmt-memory"]),并运行 uvx ihmt-memory --instructions >> ~/.config/opencode/AGENTS.md。

最后一步适用于任何安装方式,至关重要:这些说明能让 Agent 在回答前先搜索,并保存更正。也可以使用 pipx install ihmt-memory,将 uvx ihmt-memory 替换为 ihmt-memory。

刚来?请阅读 GUIDE.md——通过真实输出,一步步了解日常使用。README 的其余部分是技术参考。


工作原理

为大模型提供通用、与领域无关的长期记忆,以本地磁盘上的纯文件递归树形式存储。无需向量数据库、服务器,也无需第三方依赖——仅需 Python 3.10+ 和标准库。

IHMT 不会把所有内容嵌入一个扁平索引再进行扫描,而是将知识组织成一棵树:底部是原始文本叶节点,其上是递归 JSON 摘要,顶部则是单个 root.json 主干。查询会遍历这棵树——根节点 → 分支 → 分支 → 叶节点——因此,打开的文件数量随树的深度增长(≈ beam × log_B(n)),而不是随存储内容的多少增长。

扁平 RAGIHMT
检索成本扫描全部 n 个分块,或对其执行 ANN读取 beam × log_B(n) 个文件
结构无——只是一个向量集合清晰的层级结构,可供检查
分块固定字符窗口感知语法、场景和日期
过时事实静默提供标记为已取代、注明日期并加以标记
歧义返回看似合理的猜测向你询问线索
存储二进制索引可读取的 UTF-8 .txt 和 JSON

快速开始

python3 gui.py                       # graphical interface: set up, browse, inspect
python3 init_ihmt.py                 # or from the terminal: create ./ihmt_memory
python3 main.py demo                 # full walkthrough in ./demo_workspace
python3 -m unittest discover -v      # stdlib only; MCP tests skip without the SDK

然后用它处理你自己的材料:

python3 main.py ingest ~/notes ~/project/src/Main.java
python3 main.py consolidate --force
python3 main.py search "how did we handle stock reservations"
python3 main.py ask "Luis"                    # interactive clue loop
python3 main.py conflicts                     # what changed over time

作为库使用:

from ihmt import IHMT

memory = IHMT.initialize("./workspace")
memory.ingest_file("examples/InventoryService.java")
memory.ingest_file("examples/journal_personal.txt")
memory.flush()                                # close the tree up to the root

answer = memory.search("reserveStock soft hold")
print(answer.best.content)                    # the leaf
print(answer.best.path)                       # ['root', 'N1-software.java-…', 'L-software.java-…']
print(answer.node_reads)                      # how many branch files were opened

for notice in memory.notices():
    print(notice)   # "On 2024-03-11 you said user location = 'Madrid', but on 2026-02-03 you updated to 'Valencia'."

图形界面

python3 gui.py                       # opens a browser at 127.0.0.1
python3 gui.py --path ~/my-memory --port 8765 --no-browser

仍然零依赖——服务使用标准库中的 http.server,只监听环回接口,而且每个 /api/* 调用都需要携带在其打开 URL 中的随机令牌。

包含四个界面:设置(通过系统对话框选择记忆文件夹、创建存储、选择按项目或全局注册,并在写入任何内容前预览准确的命令或 JSON)、探索(可折叠的树,可逐层查看已存储文本,并显示取代通知)、诊断(搜索并报告置信度、已打开文件数与总数,以及遍历路径)和时间线(查看当前值与历史值,以及检测到的矛盾)。界面支持双语(ES/EN),对记忆内容只读:绝不删除或编辑叶节点。


在 Claude Code 中使用(MCP)

mcp_server.py 将树结构作为九个工具暴露给 Claude Code,分为三个类别:长期记忆、项目索引和会话临时记忆。核心功能不依赖任何依赖项;SDK 是可选扩展:

python3 -m venv .venv
.venv/bin/pip install -r requirements-mcp.txt        # mcp[cli]>=2.0

对于单个项目,将 .mcp.json.example 复制到该项目的 .mcp.json,并填入绝对路径;Claude Code 会在你下次进入该项目的会话时询问是否批准(在此之前,claude mcp list 会将其显示为 Pending approval):

{
  "mcpServers": {
    "ihmt-memory": {
      "command": "/absolute/path/to/IHMT-MEMORY/.venv/bin/python",
      "args": ["/absolute/path/to/IHMT-MEMORY/mcp_server.py"],
      "env": { "IHMT_HOME": "/absolute/path/to/IHMT-MEMORY" }
    }
  }
}

或者通过一条命令完成:

claude mcp add ihmt-memory --scope user \
  -e IHMT_HOME=/absolute/path/to/IHMT-MEMORY \
  -- /absolute/path/to/IHMT-MEMORY/.venv/bin/python /absolute/path/to/IHMT-MEMORY/mcp_server.py

IHMT_HOME 用于指定存储位置($IHMT_HOME/ihmt_memory),首次使用时会创建该目录。将每个项目都指向同一个共享目录,即可使用跨项目共享记忆;也可以为每个项目指定各自的目录。

工具行为
search_memory(query, clue=None, detail="compact")遍历树结构。精简输出包含最佳匹配记忆及其日期和 OUTDATED 提示;其他匹配项各占一行。detail="full" 会添加 ID、树路径和摘录。查询结果有歧义时,会返回列出候选项的 AMBIGUOUS 区块,而不是猜测——请使用 clue 再次调用。查询没有匹配项时会说明这一点;如果最接近的条目与查询仅共享一个偶然出现的词,也会如此说明(NOT FOUND)。
save_memory(content, domain="general", content_type="auto", replaces="")对文本进行分类、拆分并存储,提取带日期的事实,同时保持树结构整合。会报告内容的归档方式;如果保存内容与先前记忆相矛盾,也会报告需要转达给用户的提示。使用 replaces(用几个词描述先前的记忆)时,此次保存会被记录为对该记忆的更正:旧记忆会被标记为 OUTDATED,搜索时会优先返回新记忆。
mark_outdated(old_id, new_id)当 save_memory 为 replaces 找到多个候选项并列出它们的 ID 时,将其中一条记忆标记为已由另一条记忆更正。
project_map(path, detail="files", subpath="")生成代码库的精简映射:列出文件及其 token 数;使用 detail="symbols" 时,还会列出每个方法及其行范围。根据同步清单生成,不打开叶节点文件。
find_code(query, path, scope="main", subpath="", clue=None, max_tokens=1500)仅返回回答查询的符号,格式为 file:first-last + 代码。scope 可设为 main(跳过测试)、test 或 all。
read_file(path, force=False)读取文件,并记住本会话中已提供的内容:重复读取时会返回 UNCHANGED 或仅返回统一差异。
note(text) / recall(query, clue=None)会话临时记忆:上下文压缩后仍会保留,会话结束时消失。
digest_output(text, label="output")将长日志精简为开头几行、错误、失败项、测试总数和末尾几行;完整文本仍可供回忆。
在会话内节省令牌

长期记忆可在会话之间节省令牌。项目工具则可在单个会话内节省令牌,避免反复读取相同文件。ProjectIndex(ihmt/project_index.py)会在 $IHMT_PROJECTS_DIR 下为每个项目维护独立存储(默认路径为 $IHMT_HOME/ihmt_projects):

  • 每个符号对应一个叶节点——使用 code_chunk_mode="symbol",因此查找结果是一个方法,而不是整个文件;
  • 每次调用都会同步校验和——先检查大小和修改时间,仅对发生变动的文件计算 SHA-256;有变更的文件会重新导入,已删除的文件会被移除,分支也会重建。代码绝不会过时;
  • 分支按路径排序——每个文件都会标记其在路径顺序中的排名,因此每个分支都涵盖相邻文件,其摘要也能为逐层查找提供有意义的信息;
  • 代码感知排序——导航器会根据目录中的 scope/path_prefix 进行筛选,优先选择查询中提到的文件;除非用户明确要求,否则会降低测试文件和导入行的排名。

在一个有 55 个文件的 Spring Boot 项目中进行测量(8 个典型问题):读取包含答案的文件需消耗 3,613 个令牌;find_code 对全部 8 个问题都能返回准确的方法,只需 1,071 个令牌。查看项目地图需消耗 660 个令牌,而读取整个项目需 13,157 个令牌。

这些节省是相对于会读取整个文件的 Agent 而言。在一项包含 22 个真实无头 Claude Code 会话的 A/B 测试中,Claude 更倾向于批量使用 grep/sed -n,从未主动调用项目工具;强制使用这些工具反而让会话成本增加了 42–71 %。由于 Claude Code 会按需加载 MCP 工具,保持服务启用每次对话约需 460 个令牌。IHMT 的主要价值在于跨会话记忆;项目工具可按需使用,不要在 CLAUDE.md 中强制要求使用。

该服务透明支持 MCP SDK 2.x(MCPServer)、1.x(FastMCP)以及独立的 fastmcp 包。

~/.claude/CLAUDE.md 中的使用说明(模板)会告诉 Claude Code 何时使用每种工具:回答任何依赖先前会话的信息前先进行搜索;保存持久事实时附上日期;遇到 AMBIGUOUS 时绝不猜测;始终转达 OUTDATED;绝不存储机密。


存储布局

所有内容都存放在一个可迁移的目录中:

ihmt_memory/
  root.json                 # the trunk: domains, topics, top branches, counters
  layer_0/<domain>/*.txt    # the leaves: raw UTF-8 text + a strict JSON header
  layers/1/*.json           # branches: summaries of leaves
  layers/2..N/*.json        # branches: summaries of summaries
  state/catalog.json        # index: id -> path, domain, parent, timestamp
  state/facts.json          # the fact timeline
  ihmt.config.json          # branch factor, token budgets, backend

root.json 位于 ihmt_memory/ 内部,因此存储是自包含的:复制整个目录,记忆也会随之迁移。

叶节点是一个普通文本文件,会描述自身,因此即使目录丢失,内容仍然有意义:

<<<IHMT-META
{
  "leaf_id": "L-software.java-0001-84130ee123",
  "timestamp": "2026-09-09T17:45:00Z",
  "data_type": "CODE",
  "domain": "software.java",
  "tags": ["method:reserveStock", "class:InventoryService", "lang:java", "type:code"],
  "parent_id": "N1-software.java-5571a7baac",
  "span": {"start_line": 43, "end_line": 68},
  "checksum": "sha256:…",
  "extra": {"context": "public final class InventoryService {"}
}
IHMT-META>>>
    public Optional<String> reserveStock(Sku sku, int quantity) {
        …

分支节点会嵌入每个子节点的标题、摘录和关键词。正是这些细节让逐层查找成本低廉:无需打开任何子节点,就能对分支进行排序。


五个组件

1. UniversalIngestor — 检测、拆分、丰富并存储

DomainDetector 根据文档扩展名以及英文和西班牙文中的词汇特征,将每份文档分类为类型(CODE、NARRATIVE、CLINICAL、PERSONAL、PROCESS、GENERIC)和领域(software.java、medicine.clinical、process.cooking、personal,……)。两者都可以通过 --domain / --type 覆盖。

类型决定使用的拆分器,而每个拆分器都遵循同一条原则:

逻辑块绝不会被切开。 如果单个逻辑块超过 max_tokens,则整体存储,并标记为 oversized。保证逻辑块完整比满足 token 预算更重要。

  • 代码(chunkers/code.py)——通过标准库 ast 处理 Python;通过 BraceScanner 处理 Java/JS/TS/C/C++/C#/Go/Rust/Kotlin/Swift/PHP。BraceScanner 是一种逐字符扫描器,会跟踪花括号深度,同时跳过注释、字符串字面量、字符字面量、模板字面量和预处理器行。导入语句会合并;每个类或函数都是一个逻辑块;超大的类会按成员拆分,而外围类的头部会放在叶节点的 extra.context 中,而不会拼接到文本里。将某个文件的所有叶节点拼接起来,可以逐字节还原原文件——测试中对此有断言。
  • 叙述文本——以段落为不可拆分单位,并将 ***、---、Chapter / Capítulo 视为硬边界。只有超过 max_tokens 的段落才会拆分,且只会在句子边界处拆分。
  • 时间序列(日志、聊天记录、临床记录)——一条带日期的记录不可拆分,日期变化是硬边界,因此一个叶节点绝不会混合两次就诊的内容。文本中找到的日期会成为叶节点的时间戳,这样,近期性加权表示的是某事曾经成立的时间,而非内容被摄取的时间。
  • 流程(食谱、规程、操作手册)——步骤和配料清单会与其标题保持在一起。

叶节点 ID 根据 (domain, source, position, content) 生成,因此,重新摄取未更改的文档会重写相同的叶节点,而不会产生重复项。

2. RecursiveSummarizer — 摘要事件

它会监视第 0 层。当某个领域中有 branch_factor 个叶节点没有父节点时,就会触发一次摘要事件:这些叶节点会被汇总为一个第 1 层节点,写入该节点,之后才为子节点设置 parent_id——这样,即使运行中断,再次运行时也会重新处理整组节点,而不会留下孤立节点。第 1 层到第 2 层及后续层也遵循同一规则,直到树收敛;随后会重写 root.json。

consolidate() 是幂等的。flush()(--force)也会提升未满组,使树完全闭合。所有仍未整合的内容都会由主干直接引用,因此存储中的任何内容都不会无法从根节点访问。

3. SemanticNavigator — 向下遍历与交互式线索循环

排序采用 Okapi BM25,根据每个候选项的标题、关键词、标签和摘要进行计算,并使用字段权重以及当前层级同级节点之间的文档频率——这正是向下遍历所需的区分能力,而且不会产生额外的 I/O 开销。遍历时,每层会保留 beam_width 条分支。

置信度融合了两个独立信号:

confidence = 0.6 × coverage + 0.4 × margin

覆盖度用于判断“这个叶节点是否真的包含所询问的内容?”;区分度用于判断“它能否与其他候选项区分开来?”。常见的名字会在前者上得分很高,在后者上得分接近零——这恰恰是系统不应猜测的时候:

$ python main.py ask "Luis"

"Luis" is ambiguous (3 memories match this query equally well, confidence 0.62).
It could belong to any of these branches:
  1. [personal] journal_personal.txt · 2024-07-22 — Vacaciones en Benidorm con Luis, mi primo…
  2. [personal] journal_personal.txt · 2026-08-30 — Fin de semana en la playa de El Saler con Luis…
  3. [personal] journal_personal.txt · 2024-11-30 — Cierre de trimestre… Luis Marín revisó el pull request…
Give me a clue to narrow it down (e.g. a place, a date, a project):
> vacaciones en Benidorm

query: "Luis + vacaciones en Benidorm" · confidence 0.74 · 5 node reads, 3 leaf reads, depth 2
  1. [personal] journal_personal.txt · 2024-07-22
     path  root → N2-personal-ea34db33ae → N1-personal-59bf8bc291 → L-personal-0002-a17b3c8f35

线索会触发一次联合交叉引用:同时匹配两组词项的候选项会得到加权提升(×1.6),只匹配其中一组的候选项会被降权(×0.7)。循环最多运行 max_clue_rounds 次;如果用户拒绝,则提前停止;绝不会悄无声息地把含糊的查询转成有把握的答案。

clue_provider 可以是任意可调用对象,因此,这个循环既适用于终端上的人工用户(input),也适用于让大模型提供后续问题的 Agent。

4. ConflictResolver — 时间新近度加权与时间线

事实的格式为 (subject, attribute, value, timestamp, source_leaf),通过程序调用 record_fact() 记录,或在摄取时由模式规则提取(vivo en X / I live in X、 mi stack es Y、trabajo en Z、Diagnóstico:、Tratamiento:、Medicación: 等;可通过 add_pattern 扩展)。

每个 (subject, attribute) 都会保留一条带日期的时间线。最新值为 ACTIVE;此前的每个值 都会变为 HISTORICAL,并带有 superseded_by 和 valid_from/valid_to 时间区间。不会 删除任何内容,因此以下两个问题都能得到回答:

memory.resolver.active_state()["user::location"].value      # 'Valencia'  (now)
memory.resolver.state_at("2024-12-31")["user::location"].value  # 'Madrid'  (back then)

在较晚日期重复记录同一个值,属于确认,而非矛盾。真正发生变化时,会显示透明的通知——“你在 2024-03-11 表示用户位置 = 'Madrid',但在 2026-02-03 更新为 'Valencia'。”——并为被取代的叶节点添加注释,因此检索过时内容时总会附带对应的更正(SearchResult.notices)。

叶节点本身仍保持 ACTIVE:它所述内容在其自身日期是真实的,这仍然是回答历史问题的正确答案。变化的是,它不再能被视为当前信息。

5. 摘要后端
class SummarizerBackend(Protocol):
    name: str
    def summarize(self, children, *, domain: str, layer: int) -> NodeSummary: ...
  • HeuristicSummarizer(默认)——使用标准库的抽取式摘要:基于 TF 词项排名(含 EN/ES 停用词),并选择有代表性的句子。离线且结果确定,因此测试套件可以断言树的结构。
  • AnthropicSummarizer(可选)——仅在选中该后端,且同时安装了 anthropic 包并设置了 ANTHROPIC_API_KEY 时使用。所有失败情况(缺少 SDK、缺少密钥、网络错误、回复无法解析)都会回退到启发式后端,因此不会因无法连接模型而丢失合并结果。
python3 init_ihmt.py --backend anthropic     # model set by summarizer_model in ihmt.config.json

其他任何模型或本地运行时,只需实现相同的协议,并将其作为 IHMT(..., backend=MyBackend()) 传入即可接入。


CLI 参考

命令用途
init [--branch-factor N] [--target-tokens N] [--force]创建存储
ingest <paths…|-> [--domain D] [--type T] [--tag X] [--no-consolidate]摄取文件、目录或标准输入
consolidate [--force]运行待处理的摘要事件
search <query> [--top-k N] [--full]遍历树
ask <query> [--clue TEXT] [--top-k N]使用线索循环进行搜索
tree [--depth N]显示层级大纲
stats、facts [--subject S]、conflicts [--subject S]检查信息
rebuild根据文件重建目录、时间线和主干
demo端到端演示

--path 用于选择存储目录,--json 用于输出机器可读内容;两者都可放在子命令之前或之后。

配置

ihmt_memory/ihmt.config.json:

键默认值含义
branch_factor8每个分支的子节点数;检索成本的对数底数
target_tokens / max_tokens2000 / 3000叶节点大小目标和超大阈值
beam_width3每层保留的分支数
confidence_threshold0.45低于此值时请求线索
ambiguity_margin0.18候选分数差低于此值时,视为并列
max_clue_rounds3线索循环迭代次数
summarizer_backend / summarizer_modelheuristic / claude-sonnet-5摘要
code_chunk_modepacksymbol 会为每个类成员存储一个叶节点(用于项目索引)

小型语料适合使用较小的分支因子——演示使用 branch_factor=4, target_tokens=400,这样即使只有少量文档,也能构建真正的多层树。

测试

python3 -m unittest discover -v          # from the project root

共 187 项测试,其中 25 项用于 MCP 服务,未安装 SDK 时会跳过。测试涵盖:Java 和 Python 的字节级精确重建与边界深度不变性、场景/日期/章节的原子性、超大区块处理、叶节点标头往返、目录恢复、摘要阈值、向上传播、幂等性、从根节点出发的完整可达性、下行成本边界、线索循环、时效性加权、历史记录保留、项目索引、MCP 工具、图形界面和 CLI。

设计说明与限制

  • 检索是下行遍历,而非扫描。 这正是设计要点,也意味着在主干处被剪枝的分支不会再被访问。只有当查询在主干处包含实际信号时,才会进行领域级剪枝;如果没有信号,所有领域都会保留在候选范围内,并在下一层应用束搜索。线索循环是在下行遍历范围过宽时的恢复机制。
  • 基于词法,而非语义。 匹配使用 BM25,对重音符号进行折叠并拆分 CamelCase 词元:适用于任何语言,无需模型,但无法匹配同义词。将嵌入式重排序器接入 BM25Ranker 是自然的升级方式;树结构无需更改。
  • 词元数量为估算值,约为每个词元 4 个字符。预算只需保持一致,无需精确。
  • 事实提取基于模式。 随附规则涵盖常见的英语/西班牙语措辞和临床标头;record_fact() 是可靠的处理方式,add_pattern() 可扩展规则。
  • 单写入者。 写入是原子的(tmp + os.replace),重建目录时会锁定文件,但存储假定同一时间只有一个写入者。
  • initialize(force=True) 只会丢弃派生状态——分支、目录、时间线——并分离保留下来的叶节点,以便下一次合并时重建层级结构。叶节点内容永远不会被删除。

目录结构

ihmt/
  api.py                    IHMT facade wiring everything together
  config.py                 IHMTConfig
  models.py                 MemoryLeaf, BranchNode, ChildRef, RootIndex, Fact, Contradiction
  storage.py                MemoryStore: atomic I/O, catalog, recovery
  textutils.py              tokenizing, keywords, entities, extractive summary, timestamps
  detectors.py              DomainDetector
  chunkers/                 base · code · narrative · temporal · process · generic
  summarizers.py            SummarizerBackend · Heuristic · Anthropic
  universal_ingestor.py     UniversalIngestor
  recursive_summarizer.py   RecursiveSummarizer
  semantic_navigator.py     SemanticNavigator, BM25Ranker, ClueRequest, scope/path filters
  project_index.py          ProjectIndex: per-project code cache with checksum sync
  conflict_resolver.py      ConflictResolver + timeline manager
ihmt_gui/                   local graphical interface (stdlib only)
mcp_server.py               MCP server: the nine tools
ihmt_launcher.py            the `ihmt-memory` command of the PyPI package (~/.ihmt by default)
pyproject.toml · server.json   PyPI package · MCP Registry entry
init_ihmt.py · main.py · gui.py · examples/ · tests/
GUIDE.md                    installation and usage guide
INSTALL.md                  installation instructions for AI agents
templates/                  memory-instructions.md: the usage rules agents append to CLAUDE.md / AGENTS.md

许可证

MIT © 2026 Gonzalo Román Márquez (gonzaroman)

评论

支持 Markdown

第一次接触 MCP?

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

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