Hindsight 智能体记忆:Retain 与 Recall 如何消除重复与返工
【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight
当你尝试理解“智能体记忆如何减少重复与返工”时,应从工作流而不是名词入手。Hindsight 给出的商业理由很简单:人会厌烦重复——没有人希望每次会话都重新陈述偏好、重新交代项目背景、重复纠正同样的错误。本文围绕指南文档 How Agent Memory Reduces Repetition and Rework 展开,结合 Hindsight 仓库中 retain/recall 的 API 文档与引擎源码,讲清楚一条可落地的记忆设计:持久化正确细节,并在下一个任务开始前把它们找回来。
为什么智能体总是要求你“再说一遍”
很多团队在拥有词汇之前就注意到这个问题:智能体在一次会话中显得很强,到下一次会话却意外地脆弱。这通常意味着系统在依赖 prompt 状态,而不是持久记忆。因此,当你把智能体从 demo 推向生产工作流时,临时上下文(temporary context)与持久记忆(persistent memory)的区分就变得极其重要。
指南文档归纳了最常见的三类失败模式:
- 用户不断重申“我希望工作以某种方式完成”;
- 曾经成功的修复被遗忘,之后又被迫重新发现;
- 工具切换重置了上下文,造成重复劳动。
这些失败单独看都不大,但会不断叠加:一点遗忘变成反复 onboarding,反复 onboarding 变成返工,返工最终侵蚀信任——用户不再相信智能体能把关键上下文带到下一步。
指南给出的“快速答案”可以压缩为三条:
- 记忆通过保留可复用的上下文来减少重复;
- 记忆通过携带先前的决定与纠正来减少返工;
- 结果是更少的 setup、更少的 prompting、更顺的后续执行。
要做到这一点,核心机制就是 Hindsight 的两个原语:retain(存入)与recall(取回)。
Retain:把原始内容提炼成可查询的记忆
在 retain API 文档 中,Hindsight 明确了一个关键设计决策:当你 retain 一段内容时,系统不会原样存储原始文本——它会智能地分析内容,提取有意义的事实、识别实体,并构建相互连接的知识图谱。这个流程把非结构化信息转化为结构化、可查询的记忆。
retain 调用接受一个或多个 item,每个 item 是一段原始内容(对话、文档、笔记),Hindsight 会把它拆解为一条或多条记忆。几个关键参数的语义值得逐个理解:
content:唯一必填字段
原始文本存入后会被分块(chunking),每个块送 LLM 做事实抽取,最终存储的是结构化事实而不是原文。一段content可以产生多条记忆,取决于其中包含多少信息。从源码结构看,入口在 memory_engine.py 的retain_async:它把单条内容包装成RetainContentDict后交给retain_batch_async,document_id与event_date等字段在这里被装入 content dict 参与后续处理。
context:最高杠杆的质量参数
一个描述来源或场景的简短标签,例如"team meeting"、"slack"、"support ticket"。它会被直接注入 LLM 事实抽取 prompt,因此主动影响事实如何被提取:同一句“项目被终止”在"performance review"与"product roadmap"两种上下文下会产生不同的记忆。文档特别强调:持续提供 context 是提升记忆质量最有杠杆率的手段之一。
timestamp:支持时间性召回
三种取值形态:
| 取值 | 行为 |
|---|---|
省略 /null | 默认使用摄入时刻的当前时间。 |
ISO 8601 字符串(如"2024-01-15T10:30:00Z") | 使用提供的时间。 |
"unset" | 完全不带时间戳存储,适用于参考文档、书籍等“无事件时间”的材料。 |
timestamp 被注入事实抽取 prompt,让模型能用它作为锚点解析内容里的相对时间表达(例如“上周一”)。提供真实时间戳也让“去年春天发生了什么”这类时间性召回查询可以正确工作。
document_id:让 retain 幂等
document_id是调用方提供的字符串,把若干 item 归组到一个逻辑文档下。提供它之后,Hindsight 对文档做upsert:如果同 ID 文档已存在,该文档及其所有关联记忆会在新内容处理前被删除。这意味着你可以安全地对更新后的内容重新 retain——比如一条又变长的聊天线程——而不会累积重复记忆。这正是“把先前工作带向前、而不是每会话重来一遍”在 API 层的直接支撑。
metadata:随记忆往返的结构化上下文
任意字符串键值对,例如{"source": "slack", "channel": "engineering", "thread_id": "T123"}。它既参与事实抽取 prompt,也会挂在每条记忆单元上、随每次 recall 返回,让你可以做客户端过滤或静态富化(比如把记忆回链到来源 URL 或线程 ID),无需额外查询。
完整的多语言示例(Python / Node.js / CLI / Go)在 retain API 文档 中,事实抽取、实体消解与图构建的架构细节见 Retain 架构指南。
Recall:在新任务开始前找回来
指南强调,好的系统必须“retain 得好、retrieve 得好、还能把结果干净地放回当前上下文”。取回侧的实现见 recall API 文档:当你 recall 时,Hindsight并行执行四种检索策略——语义相似度、关键词(BM25)、图遍历、时间——然后融合、重排成单一排序列表。响应返回的是结构化事实,而不是原始文档。
从源码看,recall_async 的 docstring 完整描述了这条 N×4 并行管线(N 种事实类型 × 4 种检索方法):
- Retrieval:每种事实类型分别跑四路并行检索(语义向量、BM25 关键词、图激活、时间图);
- Merge:用 Reciprocal Rank Fusion(RRF)合并;
- Rerank:用选定的重排器(启发式或 cross-encoder)打分;
- Diversify:应用 MMR 做多样性控制;
- Token Filter:按
max_tokens预算返回结果。
RRF 的选择有明确理由:各策略产生的分数不在同一尺度上(余弦相似度、BM25 tf-idf、图激活分),原始分数无法直接比较,RRF 只用排名位置,对任意打分体系都稳健。Retrieval 架构文档 还说明了 RRF 之后的 cross-encoder 重排:重排前候选先被裁剪到 RRF 前 300 名(可用HINDSIGHT_API_RERANKER_MAX_CANDIDATES配置),cross-encoder 再把查询与每条候选作为一对联合评估——这能抓住“关键词命中常见词、排名靠前,但实际与查询意图无关”的候选。
对“减少返工”场景最相关的几个 recall 参数:
types:world / experience / observation
world:客观事实;experience:事件与对话;observation:从多条记忆中整合出的、去重且有证据支撑的信念(偏好、重复模式、持久教训)。
每种类型独立跑完整四路检索管线,因此收窄types会同时减小结果集和查询成本。observation 值得单独强调:它们是后台自动在 retain 操作之后创建和维护的(后台整合流程见 Observations 文档),每条 observation 引用其支撑记忆(含精确引文),新证据到达时是被精化而非覆盖——这正是“把纠正带向前、影响未来行为”在数据层的体现。
prefer_observations:让整合结果取代原始事实
同时召回observation与world/experience时,同一条信息可能以原始事实和 observation 两种形式各出现一次。开启prefer_observations(默认关闭,设为true显式开启)后,每当某条 observation 由某条原始事实构建而来,该原始事实会被丢弃、由 observation 取代,腾出的名额用次优结果回填,不损失覆盖度。这让你能“全都要”而不用在“只有原始事实”(无整合)和“只有 observation”(可能落后于最近 retain 的整合进度)之间二选一。
budget 与 max_tokens:控制召回的深度与体量
budget取low/mid(默认)/high:low用于快速简单查找,high用于需要间接连接或穷尽覆盖的场景。源码 docstring 注明 budget 控制图遍历规模(low=100、mid=300、high=600 units);max_tokens默认4096,只统计每条事实的text字段。重排后按相关性顺序装入事实直到预算耗尽——一条超出剩余预算的长事实会被跳过而不是终止选择,所以排在后面的短事实仍能返回。文档特别指出 Hindsight 是“为以 token 而非结果数思考的 agent 设计的”:把max_tokens设为你愿意分配给记忆的上下文窗口份额即可。一个查询只要有匹配,就不会返回空列表:如果连 top fact 都装不进预算,它会整体返回(超预算)而不是截断到半句——因为空列表会被误读为“库里没有这条记忆”,而截断的事实是记忆从未做出的陈述。
参数与多语言示例的完整清单见 recall API 文档。
更好的记忆层是“选择性”的
指南对“更好的记忆层”给出的定义很克制:它不试图永久保存每一个 token,而是聚焦能改善未来工作的信号,并在这些信号重要时让它们可恢复。一个好的系统通常包含:
- 保留那些应影响未来行为的纠正;
- 在新工作开始前召回先前的决定;
- 在参与同一任务的多个工具间共享记忆;
- 把“prompt 消耗减少”作为一个可度量的产出。
这也是为什么架构比标签更重要:一个产品可以宣称有 memory,但行为上仍像一个“加了搜索的长 prompt”。Hindsight 的对照是清晰的——retain 侧做事实抽取与图构建,而不是原文堆栈;recall 侧做四路并行检索 + RRF + cross-encoder 重排 + token 预算裁剪,返回的是可直接嵌入上下文的紧凑事实。两端都不把“整个过去”拖进每个 prompt。
三类最能体现价值的典型工作流
指南点名的三类场景与仓库中的对应集成可以对照来看:
- 工程智能体反复处理同一仓库的任务:对应 Claude Code 集成、Codex 集成、OpenClaw 集成 等,记忆让“上次修过的坑”不再每次重踩;
- 助手回访固定的每周工作流:偏好与流程性决定经 observation 整合后被持久携带,新会话开始时通过 recall 一次性恢复;
- 客服智能体处理重复出现的客户问题:
document_id幂等 upsert 意味着同一工单线不断变长时,记忆始终反映最新状态而非层层累积重复。
若需要跨工具共享记忆、以及代码级的持久记忆示例,指南文档指向的 Claude Code 与 Codex 记忆文章在仓库文档站中均有对应集成目录可查(如 hindsight-integrations)。
在自己的技术栈里评估记忆收益:五步框架
指南给出的评估框架可以直接落地,每一步都能映射到 Hindsight 的具体 API 行为:
- 找出智能体“今天学到、明天应该记住”的一件事——确定信号形态(偏好、纠正、项目规则);
- 判断它属于个人、项目还是共享记忆——在 Hindsight 中这对应选择哪个 memory bank 存放;
- 验证系统能有意识地保留它——用 retain 存入,配合
context标签(如"support ticket")与document_id保证幂等重放; - 测试它能否在正确的后续工作流中被取回——用 recall 验证:先用
types收窄到目标事实类型,必要时用时间窗口与 tags 过滤,确认目标记忆进入 top 结果; - 检查召回的上下文是否足够简洁、有帮助而不分心——用
max_tokens限制召回体量,用prefer_observations让整合后的信念取代原始事实,必要时开 trace 查看各检索策略的贡献。
这也是文档站与 quickstart 的价值所在:当存储与召回模型清晰到可以被检查时,好的记忆系统才更容易被信任。入门路径可从 Quick Start 开始,客户端 SDK 见 hindsight-clients/python 等目录。
常见问题
最常见被重复的是什么?偏好与项目规则通常最先被反复陈述——它们恰是 observation 整合最擅长沉淀的信号。
记忆能减少人工 review 吗?可以,前提条件是智能体不再犯同样的、可避免的错误;这正是“携带先前纠正”这一条设计的直接收益。
如何快速看到收益?观察前几次会话中重复 setup 是否减少。如果第二次会话开始时 recall 就能带回第一次会话确立的偏好与决定,而无需你重新输入,收益就在发生。
【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考