Hindsight × Google ADK:为 ADK Agent 接入持久化长期记忆的两种实战模式
【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight
Hindsight 为 Google ADK(Agent Development Kit)Agent 提供持久化的长期记忆能力,官方集成包hindsight-google-adk通过自动记忆(HindsightMemoryService,实现 ADK 的BaseMemoryService)与显式工具(create_hindsight_tools,返回hindsight_retain/hindsight_recall/hindsight_reflect三个FunctionTool)两种互补模式接入会话生命周期。本文基于仓库中 google-adk 集成文档 与 集成包源码,完整讲解安装、配置、Bank ID 推导、标签隔离与生产实践,并深入到源码与测试验证底层行为,读完即可在项目中落地可跨会话复用的 Agent 记忆。
集成原理:两种互补的接入模式
hindsight-google-adk(源码位于 hindsight-integrations/google-adk)是 Hindsight 与 Google ADK 之间的桥梁,其init.py 对外暴露了核心 API。两种模式解决的是不同层面的问题:
HindsightMemoryService:实现 ADK 的BaseMemoryService。将其传给Runner(memory_service=...)后,会话结束时由 Runner 自动触发记忆保留;Agent 调用search_memory时,从 Hindsight 返回匹配结果。适合"零侵入、全自动"的接入方式。create_hindsight_tools(...):返回一组 ADKFunctionTool(hindsight_retain、hindsight_recall、hindsight_reflect),由模型在单轮对话内自主决定何时调用。适合需要精细控制记忆写入/读取时机的场景。
两种模式可以同时使用:Runner(memory_service=...)负责会话结束时的自动 retain,tools=create_hindsight_tools(...)负责轮次中的 Agent 主动 recall,只要 Bank ID 对齐,两者共享同一个记忆库。
安装与环境要求
pip install hindsight-google-adk根据 pyproject.toml 声明,运行时要求如下:
| 要求 | 版本 |
|---|---|
| Python | >=3.10(支持 3.10 / 3.11 / 3.12) |
google-adk | >=2.0 |
hindsight-client | >=0.4.0 |
仓库内已提供 uv.lock 锁定依赖版本,开发组件的测试依赖(pytest、pytest-asyncio、ruff)定义在pyproject.toml的[dependency-groups]中。
模式一:自动记忆(BaseMemoryService)
将HindsightMemoryService注入 Runner,会话结束后记忆自动落库:
import asyncio from google.adk.agents import LlmAgent from google.adk.runners import Runner from google.adk.sessions import InMemorySessionService from hindsight_google_adk import HindsightMemoryService memory = HindsightMemoryService.from_url( hindsight_api_url="https://api.hindsight.vectorize.io", api_key="hsk_...", ) agent = LlmAgent(name="assistant", model="gemini-2.0-flash") runner = Runner( app_name="my-app", agent=agent, session_service=InMemorySessionService(), memory_service=memory, ) # ... 正常使用 runner.run_async(...),记忆完全自动源码层面的行为验证
从 memory.py 可以确认自动记忆的完整链路:
- 会话写入:
add_session_to_memory(session)将会话内所有事件的文本部分按"author: text"格式逐行拼接(_events_to_document,见 memory.py),并以session.id作为document_id调用aretain写入 Hindsight;会话为空或没有文本内容时直接跳过,不产生空文档。 - 事件级写入:
add_events_to_memory(...)支持增量保留单批事件,document_id形如{session_id}-{随机8位hex}(无 session_id 时前缀为events-),并自动附加session:{session_id}标签。 - 记忆条目写入:
add_memory(...)将 ADK 的MemoryEntry逐条转换为 Hindsight retain 调用,author与custom_metadata会并入 metadata。 - 查询映射:
search_memory(...)调用arecall,把返回结果映射为MemoryEntry(author="hindsight"、携带timestamp),再包装为 ADK 的SearchMemoryResponse返回。
关键的设计决策是容错:所有add_*与search_memory在 Hindsight 调用失败时只记录 ERROR 日志、绝不向 Runner 抛异常,保证记忆后端故障不影响 Agent 主流程(见 memory.py)。相关行为在 tests/test_memory.py(retain 失败仅记录日志)与 tests/test_memory.py(recall 失败返回空结果)中有测试覆盖。
Bank ID 推导:记忆如何按用户隔离
默认情况下,每一对(app_name, user_id)拥有独立的 Hindsight Bank:
"{app_name}::{user_id}"例如测试用例 test_bank_id_default_template 验证("apple", "alice")对应bank_id == "apple::alice"。该模板是HindsightAdkConfig.bank_id_template的默认值(见 config.py),并通过_bank_id()方法用str.format渲染(见 memory.py)。
可通过bank_id_template覆盖,实现不同的隔离粒度:
# 按用户隔离、跨应用共享 HindsightMemoryService.from_url( hindsight_api_url="https://api.hindsight.vectorize.io", api_key="hsk_...", bank_id_template="user::{user_id}", ) # 静态 Bank,全用户共享 HindsightMemoryService.from_url( hindsight_api_url="https://api.hindsight.vectorize.io", api_key="hsk_...", bank_id_template="my-shared-bank", )模板中必须含{app_name}或{user_id}占位符才能动态推导;静态字符串则让所有用户/应用落同一个 Bank。
模式二:显式工具(FunctionTool)
当希望模型在轮次内自主决定读写记忆时,使用工具工厂:
from google.adk.agents import LlmAgent from hindsight_google_adk import create_hindsight_tools tools = create_hindsight_tools( bank_id="user-123", hindsight_api_url="https://api.hindsight.vectorize.io", api_key="hsk_...", ) agent = LlmAgent( name="assistant", model="gemini-2.0-flash", tools=tools, )Agent 会获得三个工具(可用include_retain/include_recall/include_reflect开关裁剪,默认全部开启,见 tools.py):
hindsight_retain(content)— 将信息存入长期记忆(调用aretain),成功返回"Memory stored successfully.";hindsight_recall(query)— 搜索记忆并返回编号列表,例如"1. ...\n2. ...",无结果时返回友好提示"No relevant memories found.";hindsight_reflect(query)— 基于记忆综合生成连贯答案(调用areflect),返回response.text。
工具实现细节(tools.py)值得注意:
- 三个工具均为异步函数,通过
FunctionTool(...)包装后可直接传给LlmAgent(tools=[...]); hindsight_recall支持recall_types(事实类型过滤:world/experience/observation)与recall_include_entities(结果附带实体信息);hindsight_reflect额外支持reflect_context(补充上下文)、reflect_response_schema(JSON Schema 约束输出格式)、reflect_tags/reflect_tags_match(默认回退到recall_tags/recall_tags_match);- 与自动模式不同:显式工具在失败时会将底层异常包装为
HindsightError抛出(见 tools.py),让 Agent 感知失败并做出反应。测试见 tests/test_tools.py。
全局配置 configure():统一默认值
在应用启动时调用一次configure(...),后续所有HindsightMemoryService.from_url()/create_hindsight_tools()都会以全局配置作为回退默认值:
from hindsight_google_adk import configure configure( hindsight_api_url="https://api.hindsight.vectorize.io", api_key=None, # 未提供时回退到 HINDSIGHT_API_KEY 环境变量 budget="mid", max_tokens=4096, bank_id_template="{app_name}::{user_id}", )其实现位于 config.py:configure()会把参数解析为HindsightAdkConfig存入模块级全局变量,api_key为空时读取HINDSIGHT_API_KEY环境变量;HindsightMemoryService构造与create_hindsight_tools内部分别通过get_config()回退取值(见 memory.py 与 tools.py)。测试中还提供了reset_config()用于清理全局状态。
注意:
configure()返回HindsightAdkConfig且全局只保留一份,多次调用会覆盖。若同时显式传参(如from_url(url=..., api_key=...)),显式参数优先于全局配置。
配置参考(Configuration Reference)
完整参数语义如下(默认值与文档 google-adk.md 及 config.py 一致):
| 参数 | 默认值 | 说明 |
|---|---|---|
hindsight_api_url | https://api.hindsight.vectorize.io | Hindsight API 地址,默认指向 Cloud |
api_key | HINDSIGHT_API_KEY环境变量 | Hindsight Cloud 的 Bearer Token |
bank_id_template | "{app_name}::{user_id}" | 由 ADK 的app_name/user_id推导 Bank ID 的格式串 |
budget | "mid" | 召回预算等级:low/mid/high |
max_tokens | 4096 | 召回结果的最大 token 数 |
tags | None | 追加到每条 retain 文档的标签;app:<name>与user:<id>总是被自动加入 |
recall_tags | None | 追加到 recall 查询的标签;user:<id>总是被自动加入 |
recall_tags_match | "any" | 标签匹配模式:any/all/any_strict/all_strict |
mission | None | 若设置,首次使用时以该事实提取使命幂等创建 Bank |
context | "google-adk" | 附加到 retain 内容的来源标签(provenance) |
verbose | False | 是否启用详细日志(源码中新增参数) |
客户端解析与超时
HindsightMemoryService.from_url()与create_hindsight_tools()共用 resolve_client() 完成客户端解析:优先级为显式client=> 显式 URL/Key > 全局配置;未配置任何 URL 时抛出HindsightError。客户端还会附带hindsight-google-adk/{版本}的 User-Agent,并为不同操作预设了超时(retain 15s、recall 10s、reflect 30s、bank 15s、默认 30s,见 _client.py)。
生产实践
按环境给记忆打标签
HindsightMemoryService.from_url( hindsight_api_url="https://api.hindsight.vectorize.io", api_key="hsk_...", tags=["env:prod"], recall_tags=["env:prod"], )app:与user:标签总会叠加在自定义标签之上。回忆侧总是附加user:<id>,从而天然隔离不同用户——测试 test_user_tag_added_to_recall 验证了 recall 时user:alice与env:prod同时出现在标签中。
自托管 Hindsight(Self-hosted)
HindsightMemoryService.from_url( hindsight_api_url="http://localhost:8888", )未认证的本地服务无需api_key。
自动记忆 + 显式工具组合
runner = Runner( app_name="my-app", agent=agent, session_service=InMemorySessionService(), memory_service=HindsightMemoryService.from_url(...), # 会话结束自动 retain ) # 同时给 Agent 挂上 mid-turn 主动 recall 的工具 tools = create_hindsight_tools(bank_id="my-app::user-123", ...)自动 retain 与 Agent 驱动的 mid-turn recall 各司其职;只要bank_id_template推导出的 Bank 与工具传入的bank_id一致,二者共享同一记忆库。更多细节可参阅集成包自身的 README 与 变更记录。
总结
hindsight-google-adk为 Google ADK 开发者提供了"自动记忆"与"显式工具"两条互补路径:前者通过实现BaseMemoryService实现零侵入的会话级记忆持久化与查询,后者通过三个FunctionTool让模型在轮次内自主读写记忆。二者共享同一套以bank_id_template驱动的 Bank 隔离机制与app:/user:标签体系,既支持开箱即用的 Hindsight Cloud,也支持http://localhost:8888的自托管部署,且所有自动记忆操作对 Runner 完全容错。结合源码中的超时配置、标签匹配模式与mission幂等建库等细节,开发者可以按生产需求精细调整记忆的写入、隔离与检索行为。
【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考