用 Hindsight 为 SmolAgents 赋予跨运行持久记忆:retain / recall / reflect 实战指南
【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight
导读:SmolAgents 的每一次
agent.run(...)都是独立生命周期,推理、执行、返回之后,运行内学到的一切随之蒸发。本文基于 Hindsight 仓库中的 SmolAgents 集成,讲解如何用稳定的 bank ID + 原生 Tool 子类 + 系统提示词预注入,构建一个跨运行累积事实、记住有效方案、规避已知失败路径的代码执行 Agent。读完你将掌握hindsight_retain/hindsight_recall/hindsight_reflect三个记忆工具的完整用法、memory_instructions()的热启动注入模式,以及一套可复现的跨运行记忆验证方法。
快速答案:五步打通跨运行记忆
pip install hindsight-smolagents,并连接 Hindsight(Cloud 或本地自托管服务)。- 为同一个 Agent / 用户 / 项目,在每一次运行中都使用同一个稳定的 bank ID。
- 用
create_hindsight_tools(bank_id=...)给 Agent 挂上 retain / recall 工具,让它在运行中可以存储与检索记忆。 - 每次新运行开始时,用
memory_instructions()把历史运行发现的记忆预注入到系统提示词中。 - 验证:让后一次运行能回答出前一次运行存储的事实。
这套方案对应的集成包位于仓库的 hindsight-integrations/smolagents,核心实现集中在 hindsight_smolagents/tools.py。
为什么"每次运行都从零开始"很昂贵
SmolAgents 的 Agent在单次运行内部是有记忆的——推理步骤、工具观察结果、中间代码状态都存在于 agent loop 之中。但这些状态的作用域仅限于这一次运行,下一次agent.run(...)启动时,一切归零。
对代码执行型 Agent 来说,这种冷启动代价尤为明显:
- 第一次运行可能发现某个库需要特定版本 pin;
- 可能发现某个 API 返回分页结果;
- 可能试出某个方案会抛异常、换一个方案才能跑通。
到第二次运行时,这些知识全部不存在。Agent 重新探索、重新踩坑、重新推导同一批事实——把 token 和墙钟时间烧在它早已掌握的知识上。
跨运行记忆打破了这个循环:运行边界不再抹除 Agent 学到的东西,而由一个持久化存储把"有用的残余"(事实、可行方案、值得避开的死胡同)带到下一次运行。从实现层面看,HindsightRetainTool在forward()中调用 Hindsight 客户端的retain(),HindsightRecallTool调用recall(),二者通过同一个bank_id落盘到同一个记忆库(见 tools.py 中的三个 Tool 子类)。
一次运行中,什么才值得 retain
并非运行中的一切内容都值得保留。完整 transcript 噪声太大,价值在于可长期复用的教训。适合交给hindsight_retain的候选:
- 任务相关事实:Agent 需要自行发现的 schema 形态、必需的版本 pin、接口的怪癖、凭据存放位置(永远不要存密钥本身)。
- 验证可行的方案:例如"用
pandas.read_csv(..., sep=';')解析这个 CSV 成功了,而默认分隔符失败了"。 - 验证失败的方案:例如"不传分页参数调用该端点,结果会被截断为 100 行"——这样下次运行就不会重蹈覆辙。
- 运行期间达成的决策与约定:Agent 或用户拍板定下的规范。
最佳做法是让 Agent 在抵达这些时刻时主动调用hindsight_retain,或者在运行结束时由你自己 retain 一段浓缩总结。要点是存储"教训"本身,而不是逐步骤的原始 trace。Hindsight 在写入时会做事实抽取与合并(ingest 阶段自动 consolidation),因此短小、具体、陈述明确的句子检索效果最好——这也正是 HindsightRetainTool 的输入设计(单个content字符串参数)所鼓励的用法。
新运行开始时的记忆注入:两条互补路径
一次新运行应当"开局即已知"历史运行学到的东西。有两种方式把上下文带进来,二者互为补充:
路径一:用memory_instructions()前置加载
在运行开始前,预先召回最相关的记忆,注入到 system prompt。Agent 从第一步起就把历史教训放在上下文中,据此规划行动:
from hindsight_smolagents import create_hindsight_tools, memory_instructions from smolagents import CodeAgent, HfApiModel BANK = "code-agent-project-x" memories = memory_instructions( bank_id=BANK, query="prior approaches, failures, and task facts for this project", ) agent = CodeAgent( tools=create_hindsight_tools(bank_id=BANK), model=HfApiModel(), system_prompt=f"You are a coding agent.\n\n{memories}", )从源码看,memory_instructions()是一个构造期同步召回函数:它调用resolved_client.recall(...),把返回结果格式化为编号列表字符串(前缀默认为"Relevant memories:\n"),再交给你拼进system_prompt。注意两个细节(见 tools.py 的 memory_instructions 实现):
- 默认
budget="low"、max_results=5,保证注入内容量小且受控; - 若召回失败或没有结果,函数静默返回空字符串,不会因为记忆层故障阻塞 Agent 启动。
路径二:用hindsight_recall按需检索
因为召回本身也是一个工具,Agent 可以在运行中途遇到前置上下文没覆盖的问题时,随时搜索完整记忆库。这让开局的上下文保持精简,同时仍给 Agent 访问全部存储的通道。
在每一次运行中使用同一个bank_id是这一切成立的前提——bank 就是串联各次运行的"线"。memory_instructions与工具必须指向同一个 bank,否则注入与检索会各说各话(这也是原文档与集成 README 反复强调的要点)。
连接 SmolAgents 与 Hindsight:一次配置,处处复用
安装
pip install hindsight-smolagents集成包要求 Python >= 3.10,依赖smolagents与hindsight-client>=0.4.0(见 pyproject.toml)。
连接(Cloud 或自托管)
指向 Hindsight Cloud 或本地服务器均可。推荐的全局配置方式:
from hindsight_smolagents import configure configure( hindsight_api_url="https://api.hindsight.vectorize.io", # 默认即 Cloud api_key="hsk_...", # 或设置 HINDSIGHT_API_KEY 环境变量 budget="mid", # 召回预算:low / mid / high max_tokens=4096, # 召回结果的最大 token 数 )自托管时把hindsight_api_url换成你的本地 API 地址(如http://localhost:8888)并省略api_key即可。也可以跳过全局配置,直接在create_hindsight_tools()里传hindsight_api_url与api_key。
从 config.py 的实现可以看到,configure()把连接信息与默认参数写入全局HindsightSmolAgentsConfig,此后创建工具时无需重复传参;api_key会优先取显式参数,其次回退到HINDSIGHT_API_KEY环境变量(test_config.py中通过patch.dict(os.environ, ...)验证了这一回退逻辑)。_resolve_client()则按"显式 client > 显式 url/key > 全局配置"的优先级解析客户端,并在没有任何 URL 可解析时抛出HindsightError(见 tools.py 的 _resolve_client)。
即插即用的记忆工具:三个原生 Tool 子类
集成包提供三个继承 SmolAgentsTool基类的原生工具子类,Agent 使用记忆的方式与使用其他任何工具完全一致。用工厂函数一键创建:
from hindsight_smolagents import create_hindsight_tools tools = create_hindsight_tools(bank_id="code-agent-project-x")这样 Agent 将获得:
| 工具 | 作用 | 输入 |
|---|---|---|
hindsight_retain | 把事实、教训或决策写入长期记忆 | content(要存储的信息) |
hindsight_recall | 在长期记忆中搜索相关历史事实 | query(检索查询) |
hindsight_reflect | 基于存储的记忆综合出有推理的回答 | query(要反思的问题) |
三个工具的name、description、inputs均在类属性中声明(见 tools.py 中三个 Tool 类的定义),因此 SmolAgents 能自动把它们暴露给模型。test_tools.py中的TestToolConstruction与TestCreateHindsightTools用例覆盖了工具属性、开关组合、客户端共享等行为。
你可以只保留需要的工具。对跨运行累积循环而言,retain 与 recall 是必需品;当你想要"综合后的答案"而非原始事实列表时,才需要 reflect:
tools = create_hindsight_tools( bank_id="code-agent-project-x", enable_retain=True, enable_recall=True, enable_reflect=False, )如果倾向于单独实例化,HindsightRetainTool与HindsightRecallTool接受同样的bank_id参数(也可传入hindsight_api_url/api_key/client)。工厂函数与独立类支持的完整参数如下(与 集成 README 的配置参考一致):
create_hindsight_tools()参数
| 参数 | 默认值 | 说明 |
|---|---|---|
bank_id | 必填 | Hindsight 记忆库 ID |
client | None | 预配置的 Hindsight 客户端(优先) |
hindsight_api_url | None | API 地址(未提供 client 时使用) |
api_key | None | API 密钥 |
budget | "mid" | 召回/反思预算等级(low/mid/high) |
max_tokens | 4096 | 召回结果最大 token 数 |
tags | None | retain 写入时附加的标签 |
recall_tags | None | 检索时用于过滤的标签 |
recall_tags_match | "any" | 标签匹配模式(any/all/any_strict/all_strict) |
enable_retain | True | 是否包含 retain 工具 |
enable_recall | True | 是否包含 recall 工具 |
enable_reflect | True | 是否包含 reflect 工具 |
memory_instructions()参数
| 参数 | 默认值 | 说明 |
|---|---|---|
bank_id | 必填 | 召回的 Hindsight 记忆库 ID |
query | "relevant context about the user" | 注入用召回查询 |
budget | "low" | 召回预算等级 |
max_results | 5 | 最多注入的记忆条数 |
max_tokens | 4096 | 召回结果最大 token 数 |
prefix | "Relevant memories:\n" | 记忆列表前的引导文本 |
tags/tags_match | None/"any" | 召回结果过滤标签及匹配模式 |
三个工具的低层行为细节
- retain 会自动建库:
HindsightRetainTool首次写入前会调用client.create_bank(bank_id=..., name=bank_id),且同一会话内只建一次(_created_banks集合去重);即使 bank 已存在也不报错(见 tools.py#L84-L92)。 - recall 返回编号列表:无结果时返回
"No relevant memories found.";有结果时按"1. {text}\n2. {text}..."格式返回(见 tools.py#L157-L179)。 - 错误统一包装:底层网络等异常会被包装为
HindsightError并记录日志,HindsightError本身则原样透传,便于上层捕获处理(test_tools.py的失败路径用例覆盖了这两类行为)。
验证记忆确实跨运行持久化
验证方法很简单:证明第二次运行知道只有第一次运行才可能学到的东西。
- 在第一次运行中,让 Agent 解决一个任务并调用
hindsight_retain存储一条具体教训——例如"导出端点按 100 行分页,所以必须传page参数"。 - 让这次运行完整结束,retain 的数据已落盘到该 bank。
- 用同一个
bank_id启动第二次运行,要么用memory_instructions()前置注入,要么问一个应当触发hindsight_recall的问题。 - 询问 Agent 关于分页行为的问题,或观察它是否直接围绕该行为规划、而无需重新探索。
如果第二次运行使用了第一次运行存储的事实,跨运行记忆即已生效。如果它依然冷启动,请检查两点:两次运行是否用了同一个 bank ID、第一次运行的 retain 调用是否真的完成。
常见错误
每次运行用不同的 bank ID
bank 是把各次运行串起来的纽带。如果每次运行都生成一个新的 bank ID,什么都不会持久化。为 Agent、用户或项目固定一个稳定的 ID——这是本方案最重要的一个约定。
retain 原始 transcript
把完整的逐步 trace 存进去,会让教训淹没在噪声里。只保留短小、具体的事实与决策,这样的内容在后续 recall 时才能被精准浮现。
只挂工具、从不注入上下文
给 Agent 挂上hindsight_recall只代表它"可以"按需检索,但它不会自动在每次运行开始时带上历史上下文——除非你同时用memory_instructions()注入。两者配合使用才能获得可靠的热启动。
retain 未完成就测试 recall
如果在第一次运行的 retain 落盘之前就检查第二次运行,记忆可能还没存进去。先让第一次运行完整结束,再断言第二次运行记得住。
常见问题
必须使用 Hindsight Cloud 吗?
不是。自托管的 Hindsight 服务器同样可用——把工具的hindsight_api_url指向本地 API 地址即可。全局configure()或逐工具传参都支持自托管场景。
Agent 如何决定何时 retain?
hindsight_retain与普通工具无异:你可以通过提示词让 Agent 在自然时机存储教训,也可以在运行结束时自己 retain 一段浓缩总结。核心原则始终是——存教训,不存原始 trace。
这会拖慢每一次运行吗?
memory_instructions()前置注入只在运行前增加一次召回,且注入内容受max_results与max_tokens约束(默认最多 5 条、4096 token)。按需的hindsight_recall只在 Agent 选择调用时才执行。测试test_tools.py::TestMemoryInstructions也验证了max_results对注入条数的截断行为。
只能用于 CodeAgent 吗?
不是。工具遵循 SmolAgents 的 Tool 模型,任何接受工具的 Agent 都能套用同一套跨运行记忆模式(集成 README 与__init__.py的导出 API 均未绑定 CodeAgent)。
下一步
- 完整安装与连接步骤可参考同仓库的姊妹篇 Guide: Add SmolAgents Persistent Memory with Hindsight,涵盖
configure()与自托管细节; - 阅读集成包完整说明与参数表:hindsight-integrations/smolagents/README.md;
- 深入阅读工具与配置源码:hindsight_smolagents/tools.py、hindsight_smolagents/config.py;
- 参考单元测试了解各工具行为的边界条件:tests/test_tools.py、tests/test_config.py;
- 了解 Hindsight 记忆库、召回与 retain 的低层 API,可进一步阅读 hindsight-api 下对应模块的实现与测试。
要点回顾:跨运行记忆的全部奥秘浓缩为三句话——用
create_hindsight_tools(bank_id=...)给 Agent 原生记忆工具;用固定的bank_id串联所有运行;用memory_instructions()让每次新运行开局即携带历史教训。三者齐备,代码执行 Agent 便从"每次都重新踩坑"进化为"踩着前次的脚印稳步前进"。
【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考