Hindsight Paperclip 集成指南:为 Paperclip Agent 注入跨会话长期记忆的插件架构与演进全解析
2026/9/15 1:19:37 网站建设 项目流程

Hindsight Paperclip 集成指南:为 Paperclip Agent 注入跨会话长期记忆的插件架构与演进全解析

【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight

本文围绕 Hindsight 官方 Paperclip 集成@vectorize-io/hindsight-paperclip的变更历史(integrations/paperclip 变更日志)展开,结合仓库中的插件源码与测试用例,系统讲解其从嵌入式库重写为正式 Paperclip 插件(v0.2.0)后的架构设计、事件驱动记忆流程、Bank 粒度隔离机制、配置项含义以及后续各版本的能力演进。读完本文,你将掌握如何安装、配置并深度理解这套"运行前自动回忆、运行中实时读写、评论后自动沉淀"的长期记忆插件,并能在源码层面定位其关键实现。

为什么需要一条"Paperclip 专属"的集成

Paperclip 是运行在 Issue/评论工作流中的多 Agent 平台,每个 Agent 默认是无状态的——每一次agent.run都从空白上下文开始,既不记得上一次运行的用户偏好,也不记得自己此前的决策。Hindsight 提供的正是 Agent 长期记忆(retain 写入 / recall 召回),而@vectorize-io/hindsight-paperclip就是两者之间的桥梁:

  • 一次安装,Paperclip 实例中的所有 Agent 都能获得跨运行、跨公司、跨重启的持久记忆;
  • 无需为每个 Agent 手写记忆代码,记忆的召回与沉淀由事件钩子自动完成。

仓库中的集成源码位于 hindsight-integrations/paperclip,当前package.json版本为 0.3.0,以 npm 包形式发布,包体仅包含dist构建产物与README.md(见 package.json)。

安装与前置条件

pnpm paperclipai plugin install @vectorize-io/hindsight-paperclip

安装完成后在Settings → Plugins → Hindsight Memory中完成配置。前置条件是有一个可用的 Hindsight 服务:推荐直接注册 Hindsight Cloud 获取 API Key;自托管方式则在本机运行:

pip install hindsight-all export HINDSIGHT_API_LLM_API_KEY=your-openai-key hindsight-api

v0.2.0:从嵌入式库到正式插件的架构重构

变更日志中最关键的一个节点是v0.2.0,它标记了一次破坏性重构(Breaking Changes),彻底改变了集成的形态:

  • 重写为正式的 Paperclip 插件,通过pnpm paperclipai plugin install安装,记忆钩子经由事件系统自动运行,无需任何代码改动
  • 旧版本要求手动调用recall()/retain(),且只支持 HTTP 适配器 Agent;新版本兼容所有适配器类型(Claude、Codex、Cursor、HTTP、Process)。

从源码结构可以印证这一点:插件由两个构建入口组成(package.json):

  • ./dist/manifest.js—— 插件清单(manifest.ts),声明插件 ID、能力(capabilities)、实例配置 schema 与两个 Agent 工具;
  • ./dist/worker.js—— 插件工作线程(worker.ts),实现全部事件订阅、工具注册与配置校验。

清单声明的capabilities包括events.subscribeagent.tools.registerplugin.state.read/writehttp.outboundsecrets.read-refagents.readissues.readissue.comments.read(manifest.ts),其中issues.readissue.comments.read是 v0.2.0 新增 SDK 调用所需的权限——首次安装或升级时 Paperclip 可能会向用户请求授权。

事件驱动的记忆生命周期:三个钩子一条链路

插件核心是一个生命周期编排,全部实现在 worker.ts 的setup(ctx)中:

agent.run.started └─ 通过 ctx.issues.get 获取 run 对应的 issue └─ recall(issue.title + issue.description) → 结果缓存进 run 级插件状态 agent 运行中… ├─ hindsight_recall(query) → 优先返回缓存记忆,否则实时 recall └─ hindsight_retain(content) → 立即写入 Hindsight issue.comment.created └─ 通过 ctx.issues.listComments 获取完整评论正文 └─ retain(full body),document_id = commentId └─ Bank 归属:评论作者 Agent,缺省时回退到 issue 受理人 agent.run.finished └─ no-op(订阅保留,等待未来载荷携带输出)

钩子一:agent.run.started—— 运行前自动召回

Paperclip 的生命周期载荷只携带runId/agentId/issueId等字段,不包含标题与描述,因此插件先调用ctx.issues.get(issueId, companyId)取回 issue,再用title + description拼成召回查询(worker.ts)。召回结果通过ctx.state.set缓存到run作用域的recalled-memories键中,供本次运行内的工具调用直接复用,避免重复 API 请求。

两个防御性设计值得注意:

  1. 非致命降级:issue 获取失败或 Hindsight 不可达时,只记录warn日志并返回,Agent 照常运行(只是没有记忆上下文)——测试用例 "does not throw when Hindsight is unreachable" 明确验证了这一点(plugin.spec.ts);
  2. 空查询短路:title 与 description 均为空时不发起 recall 调用。

钩子二:issue.comment.created—— 评论即记忆

这是记忆沉淀的主通道(worker.ts)。设计上有一个关键细节:Paperclip 的 comment-created 事件载荷只携带 120 字符的bodySnippet截断片段,因此插件调用ctx.issues.listComments取回完整评论正文;只有在该 SDK 调用不可用时才回退到截断片段。

评论同时覆盖用户与 Agent 两种产出,因此它比"运行结束再保留输出"更可靠。写入时:

  • document_id = commentId,保证幂等更新(同一评论重复事件不会产生重复文档);
  • 附带metadataagentIdcompanyIdissueIdcommentId,便于在 Hindsight 中追溯来源;
  • Bank 归属规则:评论作者是 Agent 时归入该 Agent 的 bank;用户/系统评论无作者时,回退到 issue 的assigneeAgentId;两者都取不到则跳过 retain(测试用例见 plugin.spec.ts)。

钩子三:agent.run.finished—— 预留的 no-op

变更日志与源码都注明该订阅目前是no-op:Paperclip 的 run 生命周期载荷只包含状态与计时字段,并不携带 Agent 输出,因此记忆沉淀实际由上面的评论钩子承担。订阅被保留,一是让插件在事件订阅列表中保持可见,二是为未来载荷新增输出引用时预留入口(worker.ts)。

Agent 工具:运行中主动读写记忆

插件向 Agent 暴露两个工具(清单声明见 manifest.ts,实现见 worker.ts):

工具参数行为
hindsight_recall(query)query: string(必填)先读取agent.run.started缓存的记忆;无缓存时实时调用 recall 接口;失败时返回错误文案而非抛异常
hindsight_retain(content)content: string(必填)立即将内容写入当前 bank 的 Hindsight 记忆,附带agentId/companyId/runId元数据

工具与生命周期钩子共享同一套 bank 推导逻辑(deriveBankId),并且当启用user粒度时,工具会读取agent.run.started阶段缓存的user-id,确保同一次运行内所有读写落在同一个user 级 bank(worker.ts)。

Bank 粒度:多租户记忆隔离的核心机制

"每个 Agent 有自己的记忆"由 Bank ID 推导规则保证。核心实现在 bank.ts,逻辑清晰:静态模式(dynamicBankId=false+ 配置了bankId)直接返回静态 ID,绕过所有推导;动态模式按bankGranularity逐段拼接:

paperclip::{companyId}::{agentId} ← 默认(company + agent) paperclip::{companyId} ← 公司粒度(跨 Agent 共享) paperclip::{agentId} ← Agent 粒度(跨公司共享) paperclip::{companyId}::{agentId}::user::{userId} ← 用户粒度(GDPR 友好) {bankId} ← 静态共享 bank

用户 ID 的提取(bank.ts)优先使用 issue 的creatorEmail;否则从originId(格式为channel-key::user-email,如slack::alice@acme.com)从后往前扫描带@的段。测试覆盖了多段originId(如zendesk::org-42::ticket-7::user@corp.io)与无用户可识别时回退到 company+agent 的行为(plugin.spec.ts)。

值得注意的是变更日志中v0.2.3 的"per-user memory isolation"正是这项能力的版本落点——通过可配置的 bank 粒度实现,满足 GDPR 等合规场景下"用户间记忆互不可见"的要求。

配置项详解

插件实例配置 schema 定义在 manifest.ts,完整字段如下(默认值以仓库 README 与源码为准):

字段默认值说明
hindsightApiUrlhttps://api.hindsight.vectorize.ioHindsight 服务地址;自托管用http://localhost:8888。必填
hindsightApiKeyRef存放 Hindsight API Key 的 Paperclip secret 名称;自托管可留空
dynamicBankIdtruetrue时按bankGranularity推导 bank ID;设false并提供bankId则所有 Agent 共享一个静态 bank
bankIddynamicBankId=false时使用的静态 bank ID
bankGranularity["company", "agent"]动态模式下的隔离粒度,可组合company/agent/user;加入"user"启用按用户隔离(GDPR 友好)
recallBudgetmidlow=最快,mid=均衡,high=最彻底
autoRetaintrue是否自动在评论事件后保留记忆
enabledAgentIds仅对这些 Agent ID 启用 recall/retain;留空则对所有 Agent 生效

v0.3.0:按 Agent 开关与可观测性增强

最新版本(0.3.0)在配置与运维层面各增加一项能力:

  • enabledAgentIds白名单(新功能):支持按 Agent 粒度开启/关闭集成,用于分阶段试点上线(staged pilot rollouts)——先对少数 Agent 启用,验证效果后再全量放开。isAgentEnabled的判定逻辑与空数组/未配置均视为"全部允许"的行为都有对应测试(plugin.spec.ts);
  • 操作指标(改进):新增以 gauge 形式暴露异步操作队列深度与 consolidation 积压量的运维指标,便于监控记忆管道健康度。

配置保存即校验:onValidateConfig 与健康检查

v0.2.0 引入的onValidateConfig让运营人员在保存设置时就能获得实时连通性反馈(worker.ts):

  1. 检查hindsightApiUrl非空(缺失直接返回{ ok: false, errors: ["hindsightApiUrl is required"] });
  2. 通过 HTTP 调用/health探活,超时 5 秒(AbortSignal.timeout(5000),见 client.ts);
  3. 不可达时返回明确的错误信息,如Cannot reach Hindsight at {url}Connection failed: ...

插件的 HTTP 客户端(client.ts)非常精简:基于 Node 20+ 原生fetch,零外部依赖;每个请求带 15 秒AbortController超时;API Key 存在时附加Authorization: Bearer头。它与 Hindsight API 的交互路径为:

  • 召回:POST /v1/default/banks/{bankId}/memories/recall,请求体携带querybudgetmax_tokens: 1024
  • 写入:POST /v1/default/banks/{bankId}/memoriesitems: [{ content, context: "paperclip", document_id?, metadata? }],并启用async: true异步处理。

稳定性与安全演进:0.2.1 与 0.2.2

v0.2.1(Breaking Changes):将集成替换为新的 Paperclip 插件(对应 v0.2.0 的产物),改变了打包与使用方式——这与核心变更日志中 0.5.3 的 "Replace the embedded Paperclip library with the Paperclip plugin" 条目互相印证(见 主变更日志)。

v0.2.2(改进 + Bug 修复)

  • 更新 npm 与 pip 依赖以修复已知安全漏洞(安全基线维护);
  • 修复集成对Paperclip 真实事件载荷的处理——此前事件结构假设与实际载荷不一致,导致事实抽取不可靠。这一点在主变更日志 0.6.2 中有更完整的描述:"Aligned the Paperclip integration with Paperclip's actual event payload shape, restoring correct fact extraction from incoming events",对应的正是本插件当前"事件只带 snippet、需回查 listComments 获取全文"的实现由来。

v0.1.x 历史能力:v0.1.1 首次加入 TypeScript 集成;v0.1.2 为所有 HTTP 请求附加标识性的User-Agent头,便于服务端请求追踪与兼容性诊断。

本地开发与测试验证

仓库内集成的开发流程(package.json):

npm install npm run build # esbuild 打包 manifest + worker 到 dist/ npm test # vitest 运行 tests/ 下的全部用例

测试套件(plugin.spec.ts)使用@paperclipai/plugin-sdkcreateTestHarness模拟 Paperclip 宿主环境,通过全局fetchmock 拦截 Hindsight API 调用,覆盖了:bank ID 推导的 7 种组合、用户 ID 提取的 5 种场景、agent.run.started的召回与缓存、issue.comment.created的自动保留与归属回退、两个 Agent 工具、onValidateConfig三种结果以及enabledAgentIds的 6 个开关场景——是理解插件行为的权威参考。

本地安装到正在运行的 Paperclip 实例:

curl -X POST http://127.0.0.1:3100/api/plugins/install \ -H "Content-Type: application/json" \ -d '{"packageName":"/absolute/path/to/hindsight-integrations/paperclip","isLocalPath":true}'

小结

从 v0.1.1 的嵌入式 TypeScript 库,到 v0.2.0 的正式插件化重写(事件钩子 + Agent 工具 + 配置校验),再到 v0.2.2 的事件载荷对齐、v0.2.3 的用户粒度隔离与 v0.3.0 的按 Agent 试点开关与队列指标——这条变更史完整勾勒出@vectorize-io/hindsight-paperclip的成熟路径。其核心设计可总结为三点:用 issue 的标题与描述驱动运行前召回(而非依赖不存在的会话 ID)、用评论事件作为记忆沉淀的持久信号(覆盖用户与 Agent 双重产出)、用可组合的 bank 粒度实现从公司级共享到用户级隔离的灵活租户边界。理解这套事件驱动模型,即可在 Paperclip 平台上为任意适配器类型的 Agent 快速获得跨运行、可审计的长期记忆能力。

【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询