Hindsight 集成 elizaOS:为 Agent 构建持久化长期记忆的插件实践指南
【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight
导读
本文围绕 Hindsight 仓库中 elizaOS 官方集成包(@vectorize-io/hindsight-eliza,v0.1.0)展开,介绍如何通过"召回 Provider + 留存 Evaluator"双组件为 elizaOS Agent 接入基于 Hindsight 的长期记忆,使 Agent 能够在每轮对话前自动召回相关记忆、在每轮对话后自动沉淀新记忆。读完本文,你将掌握该插件的安装方式、全部可配置参数、bank 隔离机制,以及其 fail-safe(故障不阻塞对话)设计背后的源码原理。
一、集成背景:为什么 elizaOS 需要 Hindsight 长期记忆
elizaOS(@elizaos/core,要求^1.7.2作为 peer dependency)本身自带对话级记忆能力,但当对话跨越会话、长时间中断后,Agent 往往会遗忘用户偏好、历史约定等关键信息。Hindsight 提供的是以"memory bank"(记忆库)为核心的长期记忆服务:消息通过retain写入、按相关性通过recall读回。
@vectorize-io/hindsight-eliza正是连接两者的桥梁。根据 eliza 集成包变更日志,v0.1.0 的核心功能即为:
Features:Added a Hindsight long-term memory integration for elizaOS, enabling eliza to store and retrieve persistent memories via Hindsight.
该功能由 hindsight-integrations/eliza 目录实现,包描述为 "Hindsight long-term memory for elizaOS agents - recall and retain via a plugin provider and evaluator"。
二、插件整体架构:Provider + Evaluator 双组件模型
在 elizaOS 的插件体系里,Plugin可以同时挂载providers和evaluators。@vectorize-io/hindsight-eliza在两者各注册一个组件,见 plugin.ts:
export function createHindsightPlugin(options: HindsightPluginOptions): Plugin { const { client, bank, recall = {}, retain = {} } = options; const providers = recall.enabled === false ? [] : [createHindsightProvider(client, bank, recall)]; const evaluators = retain.enabled === false ? [] : [createHindsightEvaluator(client, bank, retain)]; return { name: "@vectorize-io/hindsight-eliza", description: "Hindsight long-term memory: recall relevant memories and retain conversations.", providers, evaluators, }; }两个组件的职责分工:
| 组件 | 名称 | 时机 | 职责 |
|---|---|---|---|
| Provider(召回) | HINDSIGHT_MEMORY | 每次模型调用前 | 用当前消息文本查询 Hindsight,把相关记忆注入 prompt |
| Evaluator(留存) | HINDSIGHT_RETAIN | 每轮对话后 | 把对话消息写入 Hindsight 长期记忆 |
两者默认全部开启,可通过recall.enabled/retain.enabled分别关闭。plugin.test.ts中的测试(plugin.test.ts)覆盖了默认注册、全禁用、仅禁用召回、仅禁用留存四种组合,验证了组件装配逻辑。
三、快速上手:安装与最小配置
3.1 安装
需要同时安装集成包与官方 Hindsight 客户端(用于创建 client 实例):
npm install @vectorize-io/hindsight-eliza @vectorize-io/hindsight-client环境要求:@elizaos/core^1.7.2(peer dependency,开发依赖锁定1.7.2)、Node.js>=22(见 package.json)。
3.2 在角色(character)中启用插件
import { createHindsightPlugin } from "@vectorize-io/hindsight-eliza"; import { Hindsight } from "@vectorize-io/hindsight-client"; const hindsightPlugin = createHindsightPlugin({ client: new Hindsight({ apiKey: process.env.HINDSIGHT_API_KEY }), recall: { budget: "high", includeEntities: true }, retain: { tags: ["source:eliza"] }, }); export const character = { name: "Ada", plugins: [hindsightPlugin], };上述配置实现的效果:
- 每轮对话前,Agent 的 prompt 中会自动出现一个"# Relevant long-term memories"小节(可通过
recall.heading自定义),以 Markdown 列表形式列出召回的相关记忆; - 每轮对话后,用户消息会被自动写入 Hindsight,并打上
source:eliza标签。
3.3 记忆隔离:bank 机制
默认情况下,记忆按用户隔离——每个消息以其entityId作为 memory bank 标识,用户之间互不串记忆。也可以传入固定字符串或按消息动态求值的函数:
// 固定 bank:所有消息写入同一个库 createHindsightPlugin({ client, bank: "team-bank" }); // 按消息动态解析:例如按房间隔离 createHindsightPlugin({ client, bank: (message) => `room:${message.roomId}`, });bank 解析逻辑实现在 options.ts:优先使用函数返回值;其次使用非空字符串;都未提供时回退到message.entityId。测试defaults the bank to the message entityId but honours an override(plugin.test.ts)验证了固定 bank 覆盖默认行为的路径。
四、配置参数全表
插件选项定义在 options.ts,完整参数如下:
| Option | 类型 | 说明 | 默认值 |
|---|---|---|---|
client | HindsightClient | Hindsight 客户端实例 | 必填 |
bank | string \| (message) => string | 固定 bank 或按消息解析 bank | message.entityId |
recall.enabled | boolean | 是否启用召回 Provider | true |
recall.budget | "low" \| "mid" \| "high" | 处理预算,权衡延迟与深度 | "mid" |
recall.types | FactType[] | 限定召回的事实类型 | 全部 |
recall.maxTokens | number | 召回结果的 token 上限 | API 默认 |
recall.includeEntities | boolean | 是否包含实体观测 | false |
recall.heading | string | 注入 prompt 的记忆小节标题 | # Relevant long-term memories |
retain.enabled | boolean | 是否启用留存 Evaluator | true |
retain.async | boolean | 异步 fire-and-forget,不增加回合延迟 | true |
retain.tags | string[] | 每条留存记忆附加的标签 | — |
retain.metadata | Record<string, string> | 每条留存记忆附加的元数据 | — |
retain.includeAgentMessages | boolean | 是否同时留存 Agent 的回复 | false |
其中FactType与Budget定义在 client.ts:
export type Budget = "low" | "mid" | "high"; export type FactType = "world" | "experience" | "observation";即 Hindsight 记忆按事实类型分为三类:world(世界知识)、experience(经历)、observation(观测)。召回时可通过recall.types精确筛选,例如只想检索实体观测时传入["observation"]。
五、召回侧原理:HINDSIGHT_MEMORY Provider 深度解析
召回 Provider 的实现位于 provider.ts,核心流程:
- 空消息短路:若消息文本为空(trim 后为空字符串),直接返回空文本,不发起网络调用——测试
returns empty text for an empty message without calling recall对此有明确断言; - 发起召回:调用
client.recall(bankId, query, { types, maxTokens, budget, includeEntities }),query 为当前消息全文; - 格式化注入:将召回结果渲染为
# Relevant long-term memories标题下的 Markdown 列表(- 记忆文本),通过formatMemories实现(provider.ts),空结果时返回空字符串不注入; - 结果透出:返回结构同时携带
values.hindsightMemoryCount(召回条数)与data.hindsight(完整响应,含 trace 追踪信息),便于上层观测与调试。
fail-safe 设计:记忆服务故障永不阻塞对话
这是该插件最关键的设计原则之一。Provider 的get方法被try/catch包裹:任何recall异常都会被吞掉,返回空记忆文本,并将错误信息放入data.hindsightError。测试never throws when recall fails(plugin.test.ts)验证了这一点——Hindsight 服务宕机时,Agent 依然能正常回复,只是少了记忆增强。
六、留存侧原理:HINDSIGHT_RETAIN Evaluator 深度解析
留存 Evaluator 的实现位于 evaluator.ts,几个关键行为:
- validate 门槛:仅当消息包含非空文本时才执行留存(
validate返回布尔值); - 按身份过滤:通过
message.entityId === runtime.agentId判断消息是否来自 Agent 自身。默认情况下只留存用户消息,Agent 自己的回复会被跳过(skips the agent's own message by default测试);设置retain.includeAgentMessages: true后,触发消息与responses数组中的全部 Agent 回复都会被逐一留存; - 异步留存:默认
retain.async: true,以 fire-and-forget 方式调用client.retain,Evaluator 立即返回,不增加对话回合延迟;同时.catch(() => undefined)确保留存失败也不会让整个 turn 抛错(测试does not reject the turn when retain fails (async mode)验证)。若设retain.async: false,则会等待留存完成后再返回,适合需要确认写入成功的场景。
留存请求会携带tags与metadata,用于记忆的后续检索、过滤与溯源。
七、进阶用法:按需组装 Provider 与 Evaluator
如果你不想使用打包好的createHindsightPlugin,可以分别调用createHindsightProvider和createHindsightEvaluator自行组装(index.ts 中导出全部公共 API):
import { createHindsightProvider, createHindsightEvaluator, } from "@vectorize-io/hindsight-eliza"; // 只做召回:每轮把记忆注入 prompt const provider = createHindsightProvider(client, "my-bank", { budget: "high", includeEntities: true, }); // 只做留存:每轮把消息写入 Hindsight const evaluator = createHindsightEvaluator(client, "my-bank", { async: true, tags: ["source:eliza"], });这种模式适用于你已经有了自定义插件容器、或者需要在多个角色间共享同一套记忆读写逻辑的场景。此外,resolveBank函数也被公开导出,便于在外部复用同一套 bank 解析规则。
八、客户端接口约定:结构子集而非硬依赖
一个值得注意的架构细节:插件并未对@vectorize-io/hindsight-client建立硬依赖,而是在 client.ts 中定义了结构化的最小接口HindsightClient,只要求实现两个方法:
retain(bankId, content, options?):写入记忆,返回{ success, bank_id, items_count, async };recall(bankId, query, options?):召回记忆,返回{ results, trace?, entities?, chunks? }。
这意味着任何实现了这两个方法签名的对象都可以作为client传入(测试中使用的mockClient即是一个典型示例),既保持了类型安全,又避免了不必要的依赖耦合。RecallResult中还包含id、type、entities、context、occurred_start/end、mentioned_at、document_id、metadata、chunk_id等字段,上层可据此做更精细的展示与过滤。
九、本地开发与验证
该集成包自带完整的 Vitest 测试套件,覆盖 Provider 召回、Evaluator 留存、bank 解析、选项透传、异常兜底等全部关键路径(tests 目录):
cd hindsight-integrations/eliza npm install npm test # vitest run npm run build # tsup 打包到 dist/常用脚本定义在 package.json:build(tsup)、test(vitest run)、dev(tsc --watch)、prepublishOnly(发布前自动 clean + build)。
十、变更日志与版本现状
截至本文,该集成包的变更日志(hindsight-docs/src/pages/changelog/integrations/eliza.md)仅包含v0.1.0一个版本条目,其核心内容即本文主题——为 elizaOS 提供基于 Hindsight 的长期记忆读写能力。后续版本的功能演进均可通过该 changelog 页面持续跟踪;包本身的完整使用说明以 hindsight-integrations/eliza/README.md 为准,源码与测试则分别位于 src 与 tests 目录。
小结
@vectorize-io/hindsight-eliza用约两百行源码,在 elizaOS 的 Provider/Evaluator 扩展点上完成了"召回 + 留存"的长期记忆闭环,并通过 bank 机制、异步留存、异常吞没三层设计保证了记忆能力对 Agent 主流程的绝对无侵入。对于希望让 Agent 具备跨会话持久记忆能力的开发者而言,这是一个开箱即用、行为可预期、源码可审计的参考实现。
【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考