> 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-tree.md).

# Memory Tree

<figure><img src="/files/d35b6fc623896ca971d0227edc0ce81c7ab824c8" alt=""><figcaption><p>记忆树。对你所有文档的高度压缩视图。</p></figcaption></figure>

记忆树是 OpenHuman 的知识库。它不是带有一个薄薄“记忆”包装层的向量数据库。它是一个确定性、分桶封存式流水线，会把你一天中杂乱的流——聊天、电子邮件、文档、集成同步结果——转换为结构化、可查询、由摘要支撑的 Markdown，并保存在你的机器上。

## 作用

你连接的每个来源都会进入同一条流水线：

```
来源适配器（聊天 / 电子邮件 / 文档）
        |
        v
规范化    标准化 Markdown + 溯源元数据
        |
        v
分块器         确定性 ID，<=3k 令牌的受限片段
        |
        v
content_store   磁盘上的原子 .md 文件（正文 + 标签）
        |
        v
store           持久化（分块、评分、摘要、任务）
        |
        v
score           信号 + 嵌入 + 实体提取
        |
        v
来源 / 主题 / 全局树   各作用域摘要树
        |
        v
检索           搜索 / 深入展开 / 主题 / 全局 / 获取
```

热路径（canonicalize → chunk → fast-score → persist → enqueue follow-up work）很快。重活——嵌入、实体提取、封存摘要桶、每日摘要——都在后台工作线程中运行，因此 UI 永远不会被阻塞。

嵌入和摘要树构建可以 **通过 Ollama 在本地设备上运行** 如果你开启 [本地 AI](/openhuman/zh/gong-neng/model-routing/local-ai.md)；否则它们会像任何其他模型调用一样通过 OpenHuman 后端。

## 三棵树，三个范围

* **来源树**，按来源的滚动缓冲区（L0），随着填满会封存成 L1 → L2 → …。每个 Gmail 标签一个、每个 Slack 频道一个、每份上传文档一个，等等。
* **主题树**，按实体的摘要由 *热度*懒加载生成。某个实体（人、项目、股票代码、代码仓库）出现得越多，它的主题树就会被越积极地构建和刷新。
* **全局树**，每天一份覆盖当天摄取内容的全局摘要。

检索可以针对任何范围：搜索单个来源、深入某个主题，或拉取全局摘要。

## 它在磁盘上的位置

在你的工作区内（默认 `~/.openhuman`，或 whatever `OPENHUMAN_WORKSPACE` 指向的地方）：

| 路径                      | 这里有什么                                                                      |
| ----------------------- | -------------------------------------------------------------------------- |
| `memory_tree/chunks.db` | 分块、评分、摘要、实体索引、任务、热度                                                        |
| `wiki/`                 | Markdown 保管库 - 见 [Obsidian Wiki](/openhuman/zh/gong-neng/obsidian-wiki.md) |

一切都是本地的。除非你明确发送一条包含原始数据的聊天消息，否则你的原始数据不会离开你的机器。

## 为什么是树，而不是向量库

向量库回答的是“什么和这个查询相似？”。记忆需要回答的不止这些：

* **今天发生了什么？** （全局摘要）
* **这个人最近怎么样？** （主题树，由热度驱动）
* **上周二下午 3 点 Stripe webhook 说了什么？** （来源树 + 溯源）

树给你带来压缩 *以及* 导航。嵌入仍然保留在内部，因此语义搜索依然可用，但上层结构才让记忆感觉像大脑，而不是一袋碎片。

## 流水线是如何工作的？

面向用户的说法很简单：连接一个来源，代理就会获得对它的持久记忆。实现这一说法的流水线涵盖一个由 HTTP 触发的摄取路径、一个持久化任务队列、一个后台工作线程池、三棵独立的摘要树，以及一个每天运行的 UTC 调度器

### 1. 摄取

一条新的聊天 / 电子邮件 / 文档到达。热路径会把它规范化为 Markdown，将其拆分为带有确定性 ID 的受限分块，运行一次廉价的快速评分，把所有内容在一次事务中持久化，将每个分块标记为 `pending_extraction`，并为工作线程排队后续工作。

这里有三个关键属性：

* **确定性。** 分块 ID 采用内容寻址，因此对相同输入重复执行摄取永远不会产生重复项。
* **快速。** 这条路径里没有 LLM 调用——只有廉价的启发式方法。
* **写入有边界。** 一切都发生在一个事务中，因此部分摄取不会留下悬空行。

### 2. 队列

后续工作进入一个持久化任务队列（与分块位于同一个磁盘存储中）。每个任务都带有一种类型、一个负载、一个去重键、重试记录，以及一个调度窗口。类型包括：

| 类型              | 作用                                     |
| --------------- | -------------------------------------- |
| `extract_chunk` | 深度评分 + 实体提取。决定 `admitted` 与 `dropped`. |
| `append_buffer` | 将一个通过的叶子添加到来源（或主题）树的 L0 缓冲区。可能触发封存。    |
| `seal`          | 将 L0 缓冲区压缩为 L1 摘要；如果父缓冲区现在已满，则继续向上级联。  |
| `topic_route`   | 将叶子路由到按实体划分的主题树中，并由热度检查进行门控。           |
| `digest_daily`  | 构建全局每日摘要节点。                            |
| `flush_stale`   | 强制封存停留过久的缓冲区。                          |

### 3. 工作线程

一小组后台工作线程（默认 3 个）从队列中取出任务并执行。摄取路径会立即唤醒该线程池，同时还有一个短轮询回退，以防漏唤醒导致工作滞留。一个共享信号量限制并发的 LLM 绑定调用，因此一波新来源不会意外扩散成几十个并发嵌入。

启动时，任何工作线程租约已过期的任务（因为崩溃或被终止）都会回到队列中。崩溃不会丢失已通过但尚未封存的工作。

### 4. 树状态

同一条叶子流会构建出三棵彼此独立的树。

* **来源树** - 每个来源一棵。新叶子进入 L0 缓冲区；当缓冲区填满（或触发陈旧刷新）时， `seal` 会写入一个 L1 摘要，然后继续向上级联。
* **主题树** - 每个高热度实体一棵。路由器会检查某个实体是否足够“热”，以值得拥有自己的树；如果是，就把它追加到其缓冲区。
* **全局树** - 一棵树，每个 UTC 日增长一个节点，并随着天数累积沿层级向上推进。

### 5. 调度器

一个调度器循环独立于摄取路径运行。每天 00:00 UTC，它会为昨天排入一个全局每日摘要任务，并为今天排入一次陈旧刷新。调度器 **不会** 本身不运行摘要器——一切都通过队列进行，因此重试、去重和陈旧锁恢复都保持集中处理。

### 6. 叶子生命周期

每个分块都会经过一个小型状态机：

```
pending_extraction --> admitted --> buffered --> sealed
        \
         --> dropped
```

* 抽取决定 `admitted` 与 `dropped` 基于深度评分。
* 通过的叶子会进入一个缓冲区（`buffered`).
* 当缓冲区封存时，其中的每个叶子都会被标记为 `sealed`.
* `dropped` 叶子会停在这里。它们的 chunk 行会保留用于溯源，但不会再被任何缓冲区或摘要引用。

这就是为什么检索可以在不重新运行流水线的情况下展示溯源：分块行加上它的最终生命周期状态就足够了。

## 触发摄取

* **自动** - 每个活跃集成都每二十分钟自动抓取一次；参见 [自动获取](/openhuman/zh/gong-neng/obsidian-wiki/auto-fetch.md).
* **手动** - 桌面应用中的 Memory 标签页为每个来源提供一个“运行摄取”触发器。
* **RPC** - `openhuman.memory_tree_ingest` 用于高级工作流。

## 在桌面应用中 - 智能标签页

从底部导航栏打开它。

**系统状态。** 页面顶部显示当前状态（空闲、摄取中、汇总中）以及一个 **运行摄取** 按钮，用于手动触发任意已连接来源的同步。

**记忆指标：**

| 指标            | 显示内容                                                     |
| ------------- | -------------------------------------------------------- |
| **存储**        | 总大小 `<workspace>/memory_tree/chunks.db` 以及 Obsidian 保管库。 |
| **来源**        | 已摄取了多少个不同来源（每个 Gmail 标签、Slack 频道、文档等算一个）。                |
| **分块**        | 存储中的 ≤3k 令牌分块总数。                                         |
| **主题**        | 截至目前已实体化的主题树数量（基于“热”实体构建的每实体摘要）。                         |
| **最早 / 最新记忆** | 最旧和最新分块的时间戳。                                             |

**记忆图谱。** 一种力导向的实体及其关系可视化图，基于实体索引绘制。随着自动抓取拉入更多数据，图会不断增长——一开始很稀疏，几天之内就会变得更密集。

**Obsidian 保管库。** 一个 **在 Obsidian 中查看 vault** 按钮会打开 `<workspace>/wiki/` 可通过一个 `obsidian://open?path=...` 深度链接直接打开。你也可以在任何文件浏览器中打开该文件夹。

**摄取活动。** 一个按时间显示摄取事件的热力图，类似 GitHub 贡献图。适合发现自动抓取空闲的时期（例如连接中断并停止同步）。

**搜索与检索。** 围绕 Memory Tree 的搜索栏。支持来源范围、主题范围或全局查询，任何结果都会链接回 Obsidian 保管库中的底层分块文件，以提供完整溯源。

**路由。** 智能标签页还会显示代理在每个任务中使用的是哪个模型 - 见 [自动模型路由](/openhuman/zh/gong-neng/model-routing.md).

## 切换后端

Memory Tree 流水线（chunker → score → seal → summarise）是默认方案。自行托管 [agentmemory](https://github.com/rohitg00/agentmemory) 且希望 OpenHuman 在多个代理之间共享同一个持久化存储的运维人员，可以通过以下方式启用外部后端： `MemoryConfig.backend = "agentmemory"`。参见 [agentmemory 后端](/openhuman/zh/gong-neng/obsidian-wiki/agentmemory-backend.md) 配置键、字段映射、端点表、安全性和故障模式。
