AI Agent 为何每次都要重学?从 Hindsight 看长期记忆怎么设计
很多 AI Agent 看起来像是「有记忆」,实际上只是把最近几轮对话塞回 prompt,或在外部文件库做一次向量搜寻。前者会随对话变长而增加上下文成本,后者能找到相似文件,却不一定知道使用者的偏好如何随时间改变、某个决定是谁提出的、旧资讯是否已被新证据修正。当代理每次开新工作阶段都得重新问一遍「你偏好哪种格式」,问题就不只是缺少更多文字,而是缺少一套可以累积、整理、检索并修正的状态。
我看 Hindsight 的角度,不是「再接一个向量资料库」,而是把代理记忆视为一个独立的资料与推理层。它把输入转为可检索的记忆单元,之后再用不同路径找回相关资讯,必要时进一步整理成较稳定的观察或心智模型。这个方向值得看,但也要记住:记忆系统不会自动让代理变得正确;它只是让「过去发生过什么」能以更有结构的方式参与下一次回答。
先分清楚:对话纪录、RAG 与代理记忆
对话纪录保存的是原始互动。它完整,却可能冗长、重复,也不会自动把「我不喜欢表格」整理成日后可直接使用的偏好。把整段历史反复塞进上下文,简单易做,却很难控制成本、更新与权限;只截取最近几轮,又容易漏掉较早但仍重要的资讯。
RAG 通常从文件集合中找出与查询相近的片段,再交给语言模型生成答案。它非常适合产品手册、政策文件、研究报告等相对稳定的知识来源。若有人问「公司差旅规则是什么」,找出最新政策原文比让模型凭印象作答可靠得多。可是个人偏好、跨多次工作形成的经验、事件时间顺序与关系推理,不一定能靠单次相似度搜寻完整处理。这不是 RAG 做错了,而是它原本解决的问题不同。
代理记忆关心的是另一件事:系统如何记下与某个使用者、代理或专案有关的事实与经验,如何在日后依查询找回,如何在新证据出现后调整旧有理解。理想情况下,RAG 负责「从可信文件找答案」,记忆层负责「累积这个代理与工作脉络的历史」。两者可以一起使用,不必把其中一方说成另一方的替代品。
Hindsight 的核心:retain、recall、reflect
官方文件用三个操作描述主要工作流程:retain、recall 与 reflect。我会把它们理解成「写入、找回、推论」,但三者不是单纯的资料库 CRUD 别名。
retain:把原始输入整理成可用记忆
呼叫 retain 时,应用程式把一段内容送入指定的 memory bank。官方文件指出,系统会透过语言模型撷取重要事实、时间资讯、实体及关系,再进行正规化,供后续搜寻使用。它区分世界事实与代理自身经验,也会把多次输入逐步整合成 observations。换句话说,送进去的内容不只是被原封不动地保存;系统会尝试从中形成更有用的索引与摘要。
这带来方便,也带来新的风险。抽取结果可能漏掉否定、误认时间、把不确定的说法写成事实,或因来源内容本身错误而留下错误记忆。若应用场景要求可稽核,不能只看「有写进去」;还要确认来源、时间、证据与修正流程是否留得住。Hindsight 文件提到 observations 会保留支持证据并在新证据到来时修订,但团队仍应以自己的资料和查询方式测试这种行为,而不是把产品说明当成正确性保证。
recall:同时用多种线索找回资讯
recall 是面向查询的检索操作。官方 retrieval 文件列出四种并行策略:语意搜寻、关键字搜寻、实体关系图与时间搜寻;结果再融合、重新排序,并依 token 预算裁切。这种设计的价值在于,使用者的问题可能靠不同线索回答:精确人名需要关键字,改写过的描述需要语意,相隔数个事件的关系需要实体连结,「去年春天」则需要时间范围。
我认为最实用的设计判断,是不要把「找到相似段落」误认为「已理解使用者」。如果产品需求只需从十份静态 FAQ 找出段落,传统检索可能更简单;若问题常跨越人、事件与时间,才有理由评估多路检索和持续整理是否真的改善答案。最后仍要记录每次回答用了哪些记忆、哪个 bank、哪个时间范围,才方便追查「为什么代理会这样回答」。
reflect:针对脉络做较深入的推理
reflect 不只是把搜寻结果原样交回。官方文件把它描述成一个 agentic loop:模型会在 bank 设定的任务与 disposition 条件下,逐步查找记忆、补足证据,再组成回应。这比较适合需要把多条线索整理成判断的问题,例如「这个专案最近有哪些风险」,而不是只问「使用者上次选了哪个版本」。
这里也要把「模型推论」和「记忆内容」分开验证。更长的推理流程代表可能增加延迟与模型成本,也可能因资料不完整而产生貌似连贯、实际上站不住脚的结论。产品团队应设定停止条件、来源引用与人工覆核门槛;对高风险回答,应回传支持该回答的记忆证据,而不是只给一段流畅文字。
记忆单元、observations 与 mental models
Hindsight 文件把记忆区分为 world facts、experiences、observations 与 mental models。可以把它们想成不同成熟度的资讯:世界事实描述外部状态,experiences 描述代理或使用者曾经做过什么,observations 是从多笔记忆整理出的证据型观察,而 mental model 则是针对一个长期问题维护的答案,例如「这个团队目前如何分工」。
这种分层的好处,是避免把所有内容都当成同等可信、同等新鲜的向量片段。官方 mental models 文件说明,团队可以先定义值得长期维护的问题,系统在记忆累积后更新答案,应用程式读取时不必每次都重新跑完整推理。这类摘要更接近「经过整理的工作状态」,但也因此要管理它的更新频率、适用范围与失效条件。若模型只在某些资料变更后更新,旧答案仍可能被误当成现况;因此我会把「最后更新时间」与来源一起呈现给下游应用。
Memory bank 则是隔离记忆的基本单位。官方文件将其描述为使用者、代理或专案各自的记忆储存空间。实务上,bank 的边界应由产品的租户与授权模型决定:不要把所有人的记忆都写进同一个 bank,再期待 prompt 替你隔离资料。正式上线前,应测试跨 bank 查询、删除、汇出与权限变更,并确认备份和日志也遵循相同的资料治理规则。
如何开始:先跑通本机,再接一笔记忆
最适合的第一步不是把整个客服或 coding agent 接上去,而是建立一个没有真实个资的测试 bank,验证「写入一件事、稍后用不同问法找回、查看结果是否符合预期」。官方 README 提供 Docker、Python、Node.js 与 Go 等入口;以下以 Docker 启动 API,再用 Python client 做最小验证。前置条件是可用的 Docker 环境,以及 Hindsight 支援的 LLM provider 设定。若使用外部模型,将必要凭证安全地注入环境,不要硬编码在程式码或 shell history。
# Configure the provider and key through environment variables or a secret manager first.
export HINDSIGHT_API_LLM_PROVIDER=openai
# Inject the real key securely. Do not put it in source control or shell history.
docker run -d --name hindsight \
-p 8888:8888 -p 9999:9999 \
-e HINDSIGHT_API_LLM_PROVIDER \
-e HINDSIGHT_API_LLM_API_KEY \
-v hindsight-data:/home/hindsight/.pg0 \
ghcr.io/vectorize-io/hindsight:latest
这个官方 quick start 使用本机容器与持久化 volume;API 预设在 http://localhost:8888,控制介面在 http://localhost:9999。请先确认容器已启动,并能开启控制介面。正式环境不要直接把示范设定当成部署设计:安装文件说明 embedded pg0 主要适合开发,production 应采用外部 PostgreSQL 与支援的向量扩充;同时还要评估备份、网路存取、工作伫列和模型供应商的资料处理条款。容器的 latest 标签也不适合重现性要求高的部署,正式环境应锁定经测试的版本或 digest。
接着建立 Python 专案并加入官方 client:
uv init hindsight-demo
cd hindsight-demo
uv add hindsight-client
建立 main.py,先写入一条不含真实个资的测试事实,再用不同措辞查询:
from hindsight_client import Hindsight
client = Hindsight(base_url="http://localhost:8888")
bank_id = "demo-project"
client.retain(
bank_id=bank_id,
content="The demo team prefers short weekly status reports.",
context="project preference",
)
matches = client.recall(
bank_id=bank_id,
query="How should the weekly update be written?",
)
print(matches)
reflection = client.reflect(
bank_id=bank_id,
query="What working preferences should the demo assistant keep in mind?",
)
print(reflection)
可用 uv run python main.py 执行。验证不应只看 HTTP 成功;要看 recall 是否能从改写后的问题找到刚写入的内容,并确认 reflect 回答没有把范例偏好扩大成不存在的规则。若连线失败,先检查容器状态、API 埠号与 provider 设定;若检索不到,确认 bank_id 一致、retain 已完成,并查看 server log 是否有抽取或模型呼叫错误。遇到模型认证问题时,到官方 installation 与 provider 文件核对环境变数名称,不要把金钥贴到 issue 或除错讯息。
之后再按需求增加正式整合:若想少改既有程式,可评估 LiteLLM wrapper;若必须控制何时写入、如何附上 metadata,则直接用 SDK 或 REST API。Coding agent 整合也可让每个 repo 建立自己的 bank,但应先限定会被保留的内容,避免把临时提示、测试资料或不可信网页当成长期事实。MCP endpoint 是另一个整合入口,并不等于自动完成授权设计;仍要由呼叫端管理谁能读取哪个 bank。
上线前先回答的四个问题
第一,什么内容值得记? 把使用者偏好、专案决策、敏感资料与一次性对话分开。预设不要把完整 prompt、原始文件或工具回传都写入长期记忆;先定义 allowlist、保存期限与删除流程。
第二,记忆错了怎么办? 设计检视、修正、撤回与重建路径,确认旧 observation 或 mental model 不会在来源变更后继续被引用。测试否定句、相似人名、时间修正与互相矛盾的资讯。
第三,谁可以看? 使用者隔离、租户隔离、bank 权限、备份和观测资料都要纳入威胁模型。文件提到的 Memory Defense 是每个 bank 可选择启用的敏感资料扫描,而且只影响启用后的新 retain;它是减少特定格式秘密进入记忆的保护层,不是完整 DLP,也不是「可以放心丢入任何资料」的理由。仍要先在应用程式入口做资料最小化和权限控制。
第四,成本值得吗? 衡量的不只是向量搜寻费用,还包括 retain 的抽取、背景整理、reflect 推论、资料库维运、备份与除错。建立一组代表性问题集,与「只用最近对话」、「一般 RAG」和人工维护摘要比较,观察答案可追溯性、错误率、延迟与总成本;用自己的任务测试,比引用单一厂商 benchmark 更能做采购决策。
我会怎么判断是否采用
Hindsight 适合需要跨工作阶段保留状态、使用者偏好或专案经验,且能接受加入记忆治理层的 Agent 团队。它也提供多种部署与 SDK 入口,让概念验证不必先重写整套应用。相反地,如果你的问答只需要搜寻一批固定文件、资料不应长期保存,或每次回答都必须严格限定在可引用的权威文本,那就先把 RAG 或一般资料库做好,通常更简单。
我最看重的不是「代理会记得更多」,而是能否说清楚它记住了什么、为何在此刻取回、来源是否还有效,以及如何让错误记忆退出系统。若这些问题尚未回答,长期记忆只是把旧错误保存得更久;若治理与评测先到位,retain、recall、reflect 才有机会把短暂互动转成可管理的工作脉络。
参考资料