> For the complete documentation index, see [llms.txt](https://tinyhumans.gitbook.io/openhuman/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://tinyhumans.gitbook.io/openhuman/zh/gong-neng/obsidian-wiki/memory-diff.md).

# 记忆差异（Git 支持）

这个 [记忆树](/openhuman/zh/gong-neng/obsidian-wiki/memory-tree.md) 告诉代理它知道些什么。 **记忆差异** 告诉它什么 *已更改*。它是一个派生账本，按时间记录每个记忆源的状态，因此任何代理（或你）都可以问：有什么新内容、什么被编辑了、什么消失了——自上次同步以来、自我上次读取以来，或自某个命名基线以来。

分块存储（`mem_tree_chunks`）始终是权威来源。差异账本是一个只读视图，构建于 *来自* 已摄取的数据之上——因此快照不消耗任何 API 调用。来源： `src/openhuman/memory/diff/`.

***

## 这是一个 git 仓库

整个系统实际上是一个真正的 [libgit2](https://libgit2.org/) 仓库，位于 `<workspace>/memory_diff/repo` (`git_store.rs`）。OpenHuman 没有发明快照格式，而是将记忆变更跟踪直接映射到 git 的原生基元上：

| 记忆差异概念 | git 基元                                        |
| ------ | --------------------------------------------- |
| 快照     | 提交（快照 ID **是** 即提交 SHA）                       |
| 项目     | 一个扁平 blob，以（编码后的）项目 ID 命名                     |
| 来源     | 位于以下路径下的子树： `<source_id>/` 在根树中               |
| 检查点    | 带注释的标签 `ckpt_<uuid>` 在 HEAD 处                 |
| 读取标记   | 引用 `refs/openhuman/read/<source_id>` → 提交 SHA |
| diff   | 仅限定于某一来源路径的 git 树对树差异                         |

没有自然 git 归宿的快照元数据——来源类型、标签、触发方式（`自动` / `手动`）、项目数量、毫秒时间戳——会附带在 **提交信息的尾注中** (`Source-Id:`, `Trigger:`, `Item-Count:`, `Taken-At-Ms:`，…）并在读取时解析出来。

***

## 快照模型

每次成功同步后， `auto_snapshot_after_sync()` 从中读取该来源的当前分块 `mem_tree_chunks`，将它们按每个项目分组为一个 blob，并提交到 `<source_id>/`。关键是， **其他所有来源都会沿用** 来自父提交——因此每个提交的树都反映整个世界，尽管实际上只有一个来源发生了变化。

```
mem_tree_chunks（权威来源）
        |
        |  来源 A 的同步完成
        v
  take_snapshot(A)         项目分组，每个项目一个 blob
        |
        v
┌──────────────────────────────────────────────┐
│  commit_snapshot                              │
│                                               │
│   根树 = 父树                                 │
│      ├── src_A/   ← 由新项目重建              │
│      ├── src_B/   ← 原样沿用未变              │
│      └── src_C/   ← 原样沿用未变              │
│                                               │
│   消息尾注：Source-Id、Trigger、…             │
└───────────────────────┬───────────────────────┘
                        v
        HEAD ─► 提交（= 快照 ID / SHA）
```

来源 A 的差异就是 `git diff <from-tree>..<to-tree>` 且路径规格限定为 `src_A/`。新增/移除/修改直接由 git 的 delta 状态得出； **未变化** 计算公式为 `to_item_count - added - modified`。项目标识就是 blob 名称，因此编辑项目内容会保留名称（→ `已修改`），而更改其 ID 则是 `已移除` + `已新增`.

所有写入都通过进程级全局锁串行化，因为 git 的 HEAD/父提交簿记是读-改-写式的，并发提交否则可能会分叉历史。

***

## 代理用它来做什么

主要用例是 **“自我上次查看以来有什么变化？”** 在对话过程中，代理会调用 `memory_diff` 工具（`tools.rs`）。它的参数：

| 参数                  | 效果                                                          |
| ------------------- | ----------------------------------------------------------- |
| *（无）*               | 列出已启用来源及其快照数量。                                              |
| `source_id`         | 比较一个来源的差异。                                                  |
| `checkpoint_id`     | 跨源差异：自该命名检查点以来发生的所有变化。                                      |
| `自上次读取`             | 在比较某个来源时，显示自 **读取标记** 以来的变化，而不是自上次同步以来。默认 `true`.           |
| `提交`                | 使用 `自上次读取`时，在读取后将读取标记推进到 head。默认 `true`；将 `false` 设为预览而不确认。 |
| `include_text_diff` | 为已修改项目包含行级统一 diff（截断至约 2000 字符）。默认 `false`.                 |

读取标记机制是轮次之间的基本原语（`自读取以来的差异` 在 `ops.rs`）：第一次调用返回完整增量并将 `refs/openhuman/read/<source_id>` 移动到当前 head；下一次调用返回 *接入* 此后到达的内容。因此，反复轮询某个来源的代理不会把同一条消息读两遍。该工具对你的数据而言是 `只读` 的——它执行的唯一写入只是推进那个内部标记，绝不会写入 `action_dir`.

输出是简洁的 markdown，例如：

```
## 记忆变更（收件箱）

**2 个新增，1 个修改，0 个移除**（47 个未变化）

### 新增
- 来自 Acme 的发票 #4021
- 回复：Q3 规划

### 已修改
- 站会笔记
```

***

## 检查点和跨源差异

一个 **检查点** 是跨……的命名基线 *全部* 已启用来源——HEAD 处的带注释 git 标签，记录每个来源最新的快照 ID（`create_checkpoint`）。它甚至会为任何尚无快照的来源创建一个新快照，因此基线是完整的。之后， `diff_since_checkpoint` 会将每个已记录快照追溯到其当前 head，并把各来源的变化聚合为一个 `CrossSourceDiff` - “自今晨基线以来，我整个记忆中发生的一切。”

检查点很容易清理： `清理` 会删除早于 N 天的标签，但 **快照提交永不删除** - git 历史 *是* 账本，而 git 的增量压缩会让它保持紧凑。

***

## 这对你为什么重要

因为这个账本是真实的 git 历史，Memory Diff 为代理的知识提供了 **审计轨迹**:

* **可追溯性。** 代理所知道内容的每一次变化，都会成为一个带时间戳、触发方式（`自动` 还是 `手动`）、以及项目数量的提交。
* **没有意外。** 代理基于 *增量*进行操作，而不是每轮都处理整个世界——因此一封新邮件就会被注意到，而无需重新读取整个收件箱。
* **可恢复的历史。** 快照会无限期保留；你随时都可以重建某个来源在过去任意时刻的样子。
* **低成本。** 它建立在 Memory Tree 已摄取的数据之上，因此跟踪变化不会额外消耗模型或 API 调用。

***

## 另请参阅

* [记忆树](/openhuman/zh/gong-neng/obsidian-wiki/memory-tree.md) - 快照所派生自的权威知识库。
* [自动从集成获取](/openhuman/zh/gong-neng/obsidian-wiki/auto-fetch.md) - 触发生成新快照的同步条件。
* [Obsidian Wiki](/openhuman/zh/gong-neng/obsidian-wiki.md) - 这些来源摄取到的 Markdown 仓库。
* [潜意识循环](broken://pages/8f1b13c03e1006c2498f2a57983552beefceb5ac) - 后台循环，用于审查新的记忆变化并找出可执行项。
