--- description: >- OpenHuman 的本地优先存储库。从工具中摄入数据,规范化为 Markdown, 分块,评分,并折叠为层级化的摘要树。 icon: tree --- # 记忆树

记忆树。所有文档的高度压缩视图。

记忆树是 OpenHuman 的存储库。它不是一个披着"记忆"外衣的向量数据库,而是一个确定性的、bucket-sealed(桶密封)处理流水线,将你一天中杂乱的数据流——聊天、邮件、文档、集成同步结果——转化为你机器上结构化的、可查询的、带摘要支撑的 Markdown。 ## 它做什么 每个连接的源都走同样的流水线: ```text 源适配器(聊天 / 邮件 / 文档) | v 规范化 规范化的 Markdown + 来源元数据 | v 分块器 确定性的 ID,≤3k token 的有界片段 | v 内容存储 原子 .md 文件(正文 + 标签) | v 存储 持久化(块、评分、摘要、任务、热度) | v 评分 信号 + 向量 + 实体提取 | v 源 / 主题 / 全局树 按作用域的摘要树 | v 检索 搜索 / 深入 / 主题 / 全局 / 获取 ``` 热路径(规范化 → 分块 → 快速评分 → 持久化 → 入队后续工作)很快。重型工作——向量生成、实体提取、密封摘要 bucket、每日摘要——在后台 workers 中运行,UI 永远不会阻塞。 如果你开启了[本地 AI](../model-routing/local-ai.md),嵌入向量和摘要树的构建可以在**设备上通过 Ollama** 运行;否则它们像其他模型调用一样通过 OpenHuman 后端处理。 ## 三棵树,三个作用域 * **源树**,每个源一个滚动缓冲区(L0),填满后密封为 L1 → L2 → …。每个 Gmail 标签、每个 Slack 频道、每个上传的文档各一棵。 * **主题树**,按实体懒加载的摘要,由**热度**驱动。某个实体(人、项目、股票代码、仓库)出现得越频繁,其主题树就越积极地被构建和刷新。 * **全局树**,一个跨当天摄入的所有内容的每日全局摘要。 检索可以针对任何作用域:搜索单个源,深入某个主题,或拉取全局摘要。 ## 它在磁盘上的位置 位于你的工作区内(默认 `~/.openhuman`,或 `OPENHUMAN_WORKSPACE` 指向的路径): | 路径 | 内容 | | ------------------------- | ---------------------------------------------- | | `memory_tree/chunks.db` | 块、评分、摘要、实体索引、任务、热度 | | `wiki/` | Markdown 存储库 —— 见 [Obsidian Wiki](./README.zh-CN.md) | 一切都是本地的。除非你明确发送包含原始数据的聊天消息,否则你的原始数据不会离开你的机器。 ## 为什么是树,而不是向量存储 向量存储回答"与这个查询相似的是什么?"记忆需要回答更多: * **今天发生了什么?**(全局摘要) * **这个人的最新情况是什么?**(主题树,热度驱动) * **上周二下午 3 点 Stripe webhook 说了什么?**(源树 + 来源追溯) 树给你压缩**和**导航。嵌入向量仍然存在于内部,所以语义搜索继续工作,但上面的结构才是让记忆感觉像大脑而不是一堆碎片的原因。 ## 流水线如何工作? 用户看到的功能很简单:连接一个源,智能体就获得了对其的持久记忆。实现这一功能的流水线横跨一条 HTTP 触发的摄入路径、一个持久化的任务队列、一组后台 workers、三个独立的摘要树,以及一个每日 UTC 调度器。 ### 1. 摄入 新的聊天 / 邮件 / 文档到达。热路径将其规范化为 Markdown,用确定性 ID 分块,运行廉价的快速评分,在单个事务中持久化所有内容,将每个块标记为 `pending_extraction`,并为 workers 入队后续工作。 这里有三个重要属性: * **确定性的。** 块 ID 是内容寻址的,所以对相同输入重新运行摄入永远不会产生重复。 * **快速的。** 这条路径中没有 LLM 调用——只有廉价的启发式方法。 * **写入有界。** 所有操作在一个事务中完成,所以部分摄入不会留下悬空的行。 ### 2. 队列 后续工作进入持久化的任务队列(与块在同一个磁盘存储中)。每个任务携带一种类型、一个 payload、一个去重 key、重试记录和一个调度窗口。类型如下: | 类型 | 功能 | | --------------- | -------------------------------------------------------------------------------------- | | `extract_chunk` | 深度评分 + 实体提取。决定 `admitted` 还是 `dropped`。 | | `append_buffer` | 将一个 admitted 的叶子添加到源的(或主题的)树的 L0 缓冲区。可能触发密封。 | | `seal` | 将 L0 缓冲区压缩为 L1 摘要;如果父缓冲区已满,则向上级联。 | | `topic_route` | 将叶子路由到每个实体的主题树,由热度检查控制。 | | `digest_daily` | 构建全局每日摘要节点。 | | `flush_stale` | 强制密封停留太久的缓冲区。 | ### 3. Workers 一个小型的后台 workers 池(默认 3 个)从队列中取出任务并运行。池被摄入路径立即唤醒,有一个短轮询后备方案,所以错过的唤醒不会搁置工作。共享信号量限制并发 LLM 调用,这样新源的突发不会意外地扇出到数十个并发嵌入向量。 启动时,任何 worker 租约已过期的任务(因为崩溃或 kill)会被返还到队列。崩溃不会丢失已 admitted 但尚未密封的工作。 ### 4. 树状态 三棵独立的树从同一个叶子流构建。 * **源树** —— 每个源一个。新叶子进入 L0 缓冲区;当缓冲区填满(或 stale-flush 触发),一个 `seal` 写入 L1 摘要,级联继续向上。 * **主题树** —— 每个高热度实体一个。路由器检查实体是否足够热以值得拥有自己的树,如果是,则追加到其缓冲区。 * **全局树** —— 一棵树,每天增长一个节点,随着天数累积向上行走。 ### 5. 调度器 调度器循环独立于摄入路径运行。每天 00:00 UTC 它为昨天入队一个全局每日摘要,并为今天入队一个 stale-flush。调度器**不自己运行**摘要器——一切通过队列,所以重试、去重和 stale-lock 恢复保持集中。 ### 6. 叶子生命周期 每个块经历一个小型状态机: ```text pending_extraction --> admitted --> buffered --> sealed \ --> dropped ``` * 提取根据深度评分决定 `admitted` 还是 `dropped`。 * Admitted 的叶子移入缓冲区(`buffered`)。 * 当缓冲区密封时,里面的每个叶子被标记为 `sealed`。 * `dropped` 的叶子停在这里。它们的块行保留用于来源追溯,但没有缓冲区或摘要引用它们。 这就是为什么检索可以显示来源追溯而无需重新运行流水线:块行及其终端生命周期状态就够了。 ## 触发摄入 * **自动的** —— 每个活跃的集成每 20 分钟自动拉取一次;见 [自动拉取](auto-fetch.zh-CN.md)。 * **手动的** —— 桌面 app 的"记忆"标签页暴露了每个源的"运行摄入"触发器。 * **RPC** —— `openhuman.memory_tree_ingest`,用于高级工作流。 ## 在桌面 app 中 —— 智能标签页 从底部导航栏打开。 **系统状态。** 页面顶部显示当前状态(空闲、摄入中、摘要中)和一个**运行摄入**按钮,用于手动触发对任何连接源的同步。 **记忆指标:** | 指标 | 显示内容 | | ---------------------- | ------------------------------------------------------------------------------------------ | | **存储** | `/memory_tree/chunks.db` 和 Obsidian 存储库总大小。 | | **源** | 已摄入的不同源数量(每个 Gmail 标签、Slack 频道、文档等各算一个)。 | | **块** | 存储中 ≤3k token 的块总数。 | | **主题** | 目前已实例化的主题树数量(从"热"实体构建的每个实体摘要)。 | | **最早 / 最新记忆** | 最旧和最新块的时间戳。 | **记忆图谱。** 一个实体及其关系的力导向可视化,从实体索引绘制。图谱随着自动拉取获取更多数据而增长——早期稀疏,几天内变得密集。 **Obsidian 存储库。** 一个**"在 Obsidian 中查看存储库"**按钮通过 `obsidian://open?path=...` 深度链接直接打开 `/wiki/`。你也可以在任何文件浏览器中打开该文件夹。 **摄入活动。** 一个显示摄入事件随时间分布的热力图,类似于 GitHub 的贡献图。可用于发现自动拉取空闲的时期(例如连接中断导致同步停止)。 **搜索与检索。** 记忆树上的搜索栏。支持源作用域、主题作用域或全局查询,任何结果都可以链接回底层块文件(在你的 Obsidian 存储库中)以获取完整来源追溯。 **路由。** 智能标签页还显示智能体每个任务使用的模型——见[自动模型路由](../model-routing/README.zh-CN.md)。 ## 交换后端 记忆树流水线(分块 → 评分 → 密封 → 摘要)是默认的。在多个智能体间自托管 [agentmemory](https://github.com/rohitg00/agentmemory) 且希望 OpenHuman 共享相同持久化存储的操作员可以通过 `MemoryConfig.backend = "agentmemory"` 选择外部后端——参见 [agentmemory 后端](agentmemory-backend.zh-CN.md) 了解配置 keys、字段映射、端点表、安全措施和故障模式。