# 记忆树

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

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

## 它的作用

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

```
源适配器（聊天 / 电子邮件 / 文档）
        |
        v
标准化    规范化 Markdown + 来源元数据
        |
        v
分块器         确定性 ID，<=3k token 的受限片段
        |
        v
内容存储   磁盘上的原子 .md 文件（正文 + 标签）
        |
        v
存储           持久化（块、分数、摘要、任务）
        |
        v
评分           信号 + 向量嵌入 + 实体抽取
        |
        v
来源 / 主题 / 全局树   按作用域的摘要树
        |
        v
检索       搜索 / 深入查看 / 主题 / 全局 / 获取
```

热路径（标准化 → 分块 → 快速评分 → 持久化 → 入队后续工作）很快。重型工作——向量嵌入、实体抽取、封存摘要桶、每日摘要——在后台工作进程中运行，因此 UI 不会阻塞。

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

## 三棵树，三个作用域

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

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

## 它在磁盘上的位置

在你的工作区内（默认 `~/.openhuman`，或由 `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. 调度器

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

### 6. 叶子生命周期

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

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

* 抽取决定 `admitted` 与 `dropped` 基于深度评分。
* 被接纳的叶子会进入缓冲区（`buffered`).
* 当缓冲区封存时，里面的每个叶子都会被标记为 `sealed`.
* `dropped` 被丢弃的叶子到此为止。它们的块行会保留用于来源证明，但没有任何缓冲区或摘要引用它们。

这就是为什么检索可以显示来源证明而无需重新运行流水线：块行加上其终态生命周期状态就足够了。

## 触发摄取

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

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

从底部导航栏打开它。

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

**记忆指标：**

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

**记忆图。** 由实体索引绘制的实体及其关系的力导向可视化。随着自动抓取获取更多数据，图会不断增长——起初稀疏，几天内变得更稠密。

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

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

**搜索与检索。** 覆盖记忆树的搜索栏。支持来源作用域、主题作用域或全局查询，任何结果都会链接回你 Obsidian 保险库中的底层块文件，以提供完整来源证明。

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

## 切换后端

记忆树流水线（分块器 → 评分 → 封存 → 摘要）是默认配置。自行托管 [agentmemory](https://github.com/rohitg00/agentmemory) 并希望 OpenHuman 在多个代理之间共享同一个持久化存储的运维人员，可以通过 `MemoryConfig.backend = "agentmemory"` 选择外部后端——参见 [agentmemory 后端](/openhuman/zh/gong-neng/obsidian-wiki/agentmemory-backend.md) 了解配置键、字段映射、端点表、安全性和故障模式。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://tinyhumans.gitbook.io/openhuman/zh/gong-neng/obsidian-wiki/memory-tree.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
