> 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/agentmemory-backend.md).

# agentmemory 后端

OpenHuman 的默认 `记忆` trait 后端是 `sqlite`，即文档中说明的统一存储 [Memory Trees](/openhuman/zh/gong-neng/obsidian-wiki/memory-tree.md)。有些用户已经自托管 [agentmemory](https://github.com/rohitg00/agentmemory)，通常是因为他们希望在 Claude Code、Cursor、Codex、OpenCode 和 OpenHuman 之间共享一个持久化记忆。为此，OpenHuman 提供了一个可选启用的后端，通过 agentmemory 的 REST 接口代理每次 trait 调用。

选择 `backend = "agentmemory"` 会完全跳过 OpenHuman 的 SQLite + embedder 路径。存储、嵌入和检索层都由 agentmemory 负责。OpenHuman 变成一个轻量的 REST 客户端。

## 何时使用

如果满足以下情况，请使用 agentmemory 后端：

* 你已经在运行 `npx -y @agentmemory/agentmemory` ，并且希望 OpenHuman 共享同一个持久化存储。
* 你希望使用混合 BM25 + 向量 + 图检索，而无需在 OpenHuman 侧单独部署 embedder。
* 你更偏好 agentmemory 的生命周期机制（合并、保留评分、自动遗忘、图提取）而不是 OpenHuman 的统一存储。

保持默认 `sqlite` 后端，如果：

* 你想要自包含、单进程运行，并且不依赖外部守护进程。
* 你依赖 OpenHuman 特有的 Memory Tree 功能（分块、封存、摘要树），这些功能运行在 SQLite 存储之上。Memory Tree 管道不受 trait 后端影响，因为它会独立作用于宿主的文档存储。即便如此，当你已经在其他代理中统一使用 agentmemory 时，agentmemory 后端最有价值。

## 快速开始

1. **安装并启动 agentmemory** （一个终端）：

   ```bash
   npx -y @agentmemory/agentmemory
   ```

   默认为 `http://localhost:3111` （REST）+ `ws://localhost:49134` （引擎）。首次启动会在以下位置生成一个 HMAC 密钥： `~/.agentmemory/.hmac` 并只打印一次。
2. **将 OpenHuman 指向它** 你的 `config.toml`:

   ```toml
   [memory]
   backend = "agentmemory"
   # 以下为默认值——仅在覆盖时设置。
   # agentmemory_url        = "http://localhost:3111"
   # agentmemory_secret     = ""           # 可选的 HMAC 持有者令牌
   # agentmemory_timeout_ms = 5000
   ```
3. **重启 OpenHuman**。工厂函数会直接跳过 SQLite 路径并记录 `[memory::factory] 使用 agentmemory 后端于 <url>`.

就是这样。现有 OpenHuman 调用点（`存储`, `回忆`, `获取`, `列表`, `忘记`, `namespace_summaries`, `计数`, `health_check`）无需改动即可正常工作。

## 配置键

| 字段                       | 默认                      | 目的                                                  |
| ------------------------ | ----------------------- | --------------------------------------------------- |
| `agentmemory_url`        | `http://localhost:3111` | agentmemory REST 服务器的基础 URL                         |
| `agentmemory_secret`     | *无*                     | 可选的 HMAC 持有者令牌。发送为 `Authorization: Bearer <secret>` |
| `agentmemory_timeout_ms` | `5000`                  | 每次请求的 reqwest 超时                                    |

当 `backend == "agentmemory"`时，以下现有的 `MemoryConfig` 字段将被 **忽略**，因为 agentmemory 通过以下方式拥有自己的嵌入栈： `~/.agentmemory/.env`:

* `embedding_provider`
* `embedding_model`
* `embedding_dimensions`
* `sqlite_open_timeout_secs`

在这条路径上设置它们不会产生任何效果。本地 AI Ollama 健康检查门也不会在这条路径上运行，因为 agentmemory 的守护进程会自行管理 embedder 生命周期。

## 字段映射

OpenHuman 的 `MemoryEntry` ↔ agentmemory 传输行：

| OpenHuman 字段 | agentmemory 字段         | 备注                                     |
| ------------ | ---------------------- | -------------------------------------- |
| `namespace`  | `project`              | 默认为 `"default"` 当为空时                   |
| `key`        | `标题`                   |                                        |
| `内容`         | `内容`                   |                                        |
| `id`         | `id`                   | agentmemory 生成（`mem_<rand>`)           |
| `类别：核心`      | `类型："fact"`            |                                        |
| `类别：日常`      | `类型："conversation"`    |                                        |
| `类别：对话`      | `类型："conversation"`    |                                        |
| `类别：自定义`     | `类型："fact"` + `概念：[s]` | 自定义标签并入 concepts 数组中，以便仍可查询            |
| `session_id` | `sessionIds: [...]`    | OpenHuman 只暴露单个 id；agentmemory 持久化一个数组 |
| `时间戳`        | `更新时间` (RFC3339)       | 回退到 `创建时间` 如果 `更新时间` 不存在               |
| `得分` （仅回忆命中） | smart-search `得分`      | 填充于 `回忆` 响应， `None` 于 `获取` / `列表`      |

agentmemory 还携带一些附加字段，而此后端将它们保持为默认值： `concepts` （自动提取）， `文件` （路径标签）， `强度` （保留评分）， `版本`，以及 `取代` （生命周期链）。它们属于 agentmemory 生命周期层内部，不需要通过 OpenHuman 的 trait 往返。

## Trait 方法 → 端点

| `记忆` 方法               | agentmemory REST                                     | 备注                                                      |
| --------------------- | ---------------------------------------------------- | ------------------------------------------------------- |
| `存储`                  | `POST /agentmemory/remember`                         | `{project, title, content, type, concepts, sessionIds}` |
| `回忆`                  | `POST /agentmemory/smart-search`                     | 混合 BM25 + 向量 + 图                                        |
| `获取`                  | `POST /agentmemory/smart-search`                     | + 客户端精确标题过滤                                             |
| `列表`                  | `GET /agentmemory/memories?latest=true&project=<ns>` |                                                         |
| `忘记`                  | `get(ns, key)` → `POST /agentmemory/forget`          | 两步：先解析 id，再遗忘                                           |
| `namespace_summaries` | `GET /agentmemory/projects`                          | 返回 `[{name, count, lastUpdated}]`                       |
| `计数`                  | `GET /agentmemory/health`                            | 读取 `memories` 字段                                        |
| `health_check`        | `GET /agentmemory/livez`                             |                                                         |

`RecallOpts.category`, `RecallOpts.session_id`，以及 `RecallOpts.min_score` 会作为 **客户端过滤器** 应用于 smart-search 响应。agentmemory 的 REST 接口目前并未将它们暴露为服务器端过滤器。对于非常大的回忆窗口（limit > 100），建议直接发出更精确的查询字符串，以减少服务器端工作，而不是依赖客户端后置过滤。

## 安全性

当 `agentmemory_secret` 若已设置，客户端将遵守 agentmemory v0.9.12 的明文 bearer 保护约定：

* **回环主机** (`localhost`, `127.0.0.1`, `::1`）上的 `http://` 是允许的。这是本地开发路径。
* **`https://`** 到任何主机均允许。
* **对非回环主机使用明文 HTTP** 会在构造时向 stderr 发出一次警告。该 bearer 会在网络上传输时被观察到。
* **`AGENTMEMORY_REQUIRE_HTTPS=1`** （进程环境变量，ASCII 大小写不敏感匹配 `1` 或 `true`）会将警告升级为客户端构造时的硬拒绝。后端会启动失败，而不是泄露一次 bearer。

生产部署应设置 `AGENTMEMORY_REQUIRE_HTTPS=1` ，这样 TLS 终止器配置错误时会显式失败，而不是静默泄露。

明文 bearer 保护与 agentmemory 中的集成插件保护机制一致， [PR #315](https://github.com/rohitg00/agentmemory/pull/315) 因此，曾在 Hermes / OpenClaw / pi 上见过该警告的运维人员，会在 OpenHuman 上认出同样的信息。

## 失败模式

| 失败情形                                               | 后端行为                                                                                     |
| -------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| 启动时守护进程不可达                                         | `from_config` 成功（URL 解析通过），但 `health_check()` 首次调用时返回 false。Trait 方法会向上传递 `reqwest` 传输错误 |
| 网络超时                                               | `anyhow::Error` ，符合 trait 约定；并呈现给调用方                                                     |
| 4xx / 5xx 响应                                       | `anyhow::Error` 带状态码 + 响应体片段                                                             |
| 在非回环明文连接上使用 bearer（无环境变量）                          | 一次性 stderr 警告，请求继续                                                                       |
| 在非回环明文连接上使用 bearer + `AGENTMEMORY_REQUIRE_HTTPS=1` | 构造时硬拒绝                                                                                   |
| 为空 `agentmemory_url`                               | 构造时硬拒绝，并提示将其留空以使用默认值                                                                     |
| 无效的 URL 语法                                         | 构造时硬拒绝，并返回解析器错误                                                                          |

**不会自动回退到 SQLite。** 如果守护进程在启动时宕机，后端会明确抛出传输错误。运维人员可切回 `backend = "sqlite"` 在 `config.toml` 以恢复。理由：静默回退到 SQLite 会掩盖守护进程配置错误，而“私有、简单、可预测”胜过“神奇地容错”。

## 性能说明

该后端是一个轻量 REST 代理：每次 trait 调用会额外增加一次 HTTP 往返。实际影响如下：

* `存储` 以及 `忘记` 是单次 RTT。
* `回忆`, `获取`, `列表` 是单次 RTT。
* `忘记` 对未知 key 的操作是双 RTT（隐式的 `获取` 查找
  * 以及一个空操作确认）。 `列表`.
* 调用方可以通过检查先前 `127.0.0.1` 默认情况下是本地的，因此同主机延迟低于 1 毫秒。在带 HTTPS 终止的托管部署中，每次 RTT 预计约 10 到 30 毫秒。
* 默认每次请求超时为 5 秒。若 `agentmemory_timeout_ms` 如果你在 iii 引擎冷启动时看到间歇性超时；agentmemory 在长时间空闲后的首次请求延迟，取决于持久化状态，可能会延长到 3 到 5 秒。

## 迁移：从 SQLite 到 agentmemory

目前没有就地迁移。推荐路径：

1. 通过 OpenHuman 现有的导出 RPC（或直接 SQL）从 SQLite 存储导出你现有的记忆。
2. 遍历导出的数据，并将每一行 POST 到 `/agentmemory/remember` 使用相同的 `project` + `标题` + `内容`。agentmemory 会分配新的 id；OpenHuman 侧会在首次 `列表`.
3. 设置 `backend = "agentmemory"` 并重启。

专门的批量导入路径已作为后续事项提交。

## 实现参考

树内文件：

* [`store/agentmemory/mod.rs`](https://github.com/tinyhumansai/openhuman/tree/main/src/openhuman/memory/store/agentmemory/mod.rs)：模块接口
* [`store/agentmemory/backend.rs`](https://github.com/tinyhumansai/openhuman/tree/main/src/openhuman/memory/store/agentmemory/backend.rs): `impl Memory for AgentMemoryBackend`
* [`store/agentmemory/client.rs`](https://github.com/tinyhumansai/openhuman/tree/main/src/openhuman/memory/store/agentmemory/client.rs)：reqwest 封装 + 明文 bearer 保护
* [`store/agentmemory/mapping.rs`](https://github.com/tinyhumansai/openhuman/tree/main/src/openhuman/memory/store/agentmemory/mapping.rs): `MemoryEntry` ↔ agentmemory JSON
* [`tests/agentmemory_backend.rs`](https://github.com/tinyhumansai/openhuman/tree/main/tests/agentmemory_backend.rs)：12 个 axum-mock 集成测试

相关上游：

* agentmemory 仓库： <https://github.com/rohitg00/agentmemory>
* agentmemory REST 协议： `~/.agentmemory/.env` agentmemory README 中的键 + 端点列表
* v0.9.12 明文 bearer 保护：agentmemory PR #315
