news 2026/9/13 22:24:27

使用 Hindsight 为 LangGraph 智能体构建持久化记忆:工具、节点与记忆注入完整实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
使用 Hindsight 为 LangGraph 智能体构建持久化记忆:工具、节点与记忆注入完整实战指南

使用 Hindsight 为 LangGraph 智能体构建持久化记忆:工具、节点与记忆注入完整实战指南

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

本文以hindsight-langgraph集成包为主线,讲解如何为 LangGraph(以及普通 LangChain)应用接入 Hindsight 的长期记忆能力,让智能体在多次运行之间记住用户的偏好与项目事实。读完本文,你将掌握三种接线方式(工具、记忆节点、记忆指令注入)的完整写法,理解 bank 的作用域策略与动态解析机制,并学会如何验证记忆真正跨会话生效。

快速结论

  1. 安装hindsight-langgraph集成包;
  2. 指向 Hindsight Cloud 或本地 Hindsight API;
  3. 用一个稳定的 bank ID 把记忆接入 LangGraph 运行时;
  4. 先存储一条偏好或项目事实,再开启一次全新运行;
  5. 确认 recall 能自动带回之前的上下文。

为什么这种接线方式有效

LangGraph 本身就有清晰的执行图(StateGraph+ 边),记忆的放置位置因此非常明确:recall 节点运行在 LLM 节点之前,负责把相关记忆注入上下文;retain 节点运行在 LLM 节点之后,负责把本轮对话沉淀为记忆。同时,LangGraph 的RunnableConfig天然支持运行时配置传递,这让“每次运行动态解析 bank ID”成为可能——无需在图中硬编码任何用户标识符,就能实现按用户隔离的持久记忆。

从源码看,create_recall_nodecreate_retain_node返回的都是兼容StateGraph的异步节点函数(见 hindsight-integrations/langgraph/hindsight_langgraph/nodes.py 与 create_retain_node 定义),可以直接通过builder.add_node(...)注册进图。

前置条件

  • 一个可运行的 LangGraph 或 LangChain 应用;
  • Python 3.10+,并已安装hindsight-langgraph
  • 一个稳定的用户或线程标识符,用于映射到 Hindsight bank;
  • 一个可用的 Hindsight 后端:Hindsight Cloud 账户,或自托管的 Hindsight 实例(本地 API 默认端口8888)。

关于依赖版本,pyproject.toml 明确了langchain-core>=0.3.0hindsight-client>=0.4.0;节点模式额外要求langgraph>=0.3.0(需通过pip install hindsight-langgraph[langgraph]安装)。

第一步:安装集成包

pip install hindsight-langgraph

如果使用节点模式(需要在StateGraph中插入 recall/retain 节点),请一并安装 langgraph 依赖:

pip install hindsight-langgraph[langgraph]

从源码结构看,hindsight_langgraph包对 langgraph 采用惰性导入create_recall_node/create_retain_node只在真正被访问时才导入,若此时未安装 langgraph 会抛出明确的提示错误(见 hindsight-integrations/langgraph/hindsight_langgraph/init.py)。因此纯 LangChain 场景可以只装基础包,无需引入 langgraph。

第二步:连接 LangGraph 与 Hindsight

连接的核心是一个Hindsight客户端实例:

from hindsight_client import Hindsight client = Hindsight(base_url="http://localhost:8888")
  • 使用 Hindsight Cloud 时,将base_url设为https://api.hindsight.vectorize.io,并在客户端配置中传入你的 API token。
  • 使用自托管实例时,指向本地地址(如http://localhost:8888)。

客户端解析的底层逻辑

集成包内部通过resolve_client统一解析客户端(见 hindsight-integrations/langgraph/hindsight_langgraph/_client.py),优先级如下:

  1. 显式传入的client参数;
  2. hindsight_api_url/api_key参数;
  3. 之前调用过configure()时保存的全局配置;
  4. 默认 URLhttps://api.hindsight.vectorize.io+ 环境变量HINDSIGHT_API_KEY(见 config.py)。

也就是说,即使完全不调用configure(),只要设置了HINDSIGHT_API_KEY环境变量,create_hindsight_tools(bank_id="user-123")也能直接工作。API key 在构造阶段是可选的——缺失时只在真正发起调用时才报错。

全局配置 configure()

需要统一设置连接参数和默认行为时,可以调用configure()(见 hindsight-integrations/langgraph/hindsight_langgraph/config.py):

from hindsight_langgraph import configure configure( api_key="your-api-key", # 或设置 HINDSIGHT_API_KEY 环境变量 budget="mid", tags=["source:langgraph"], )

自托管实例的全局配置:

configure( hindsight_api_url="http://localhost:8888", )

也可以在任意工厂函数上直接传hindsight_api_url进行单点覆盖:

tools = create_hindsight_tools(bank_id="user-123", hindsight_api_url="http://localhost:8888")

所有工厂函数都接受clienthindsight_api_urlapi_key三个参数用于覆盖全局配置。核心参数含义如下:

参数说明默认值
hindsight_api_urlHindsight API 地址https://api.hindsight.vectorize.io
api_keyAPI key(或HINDSIGHT_API_KEY环境变量)None
budgetrecall 预算等级:low/mid/highmid
max_tokensrecall 结果的最大 token 数4096
tags应用于 retain 存储操作的标签None
recall_tags用于过滤 recall 结果的标签None
recall_tags_match标签匹配模式:any/all/any_strict/all_strictany

第三步:把记忆接入运行时(三种模式)

官方集成包提供了三种接线方式,本文档主推前两种,第三种适合纯 LangChain 链路(完整说明见 hindsight-integrations/langgraph/README.md):

  • 工具(Tools)——把 retain / recall / reflect 暴露为 LangChain@tool,由智能体自主决定何时读写记忆,同时兼容 LangChain 与 LangGraph
  • 记忆节点(Nodes)——在图中 LLM 节点前后自动插入 recall / retain 节点,无需智能体主动调用;
  • 记忆指令(Memory Instructions)——预取记忆并拼进系统提示词,适用于任何 LangChain 模型,无需构图。

模式一:工具调用(Tools)

create_hindsight_tools()会返回一组 LangChain 工具实例,可直接绑定到模型或挂进ToolNode(实现见 hindsight-integrations/langgraph/hindsight_langgraph/tools.py):

from hindsight_langgraph import create_hindsight_tools from langchain_openai import ChatOpenAI from langgraph.prebuilt import create_react_agent # 设置 HINDSIGHT_API_KEY 环境变量即可完成鉴权 tools = create_hindsight_tools(bank_id="user-123") agent = create_react_agent( ChatOpenAI(model="gpt-4o"), tools=tools, ) result = await agent.ainvoke( {"messages": [{"role": "user", "content": "Remember that I prefer dark mode"}]} )

默认返回三个工具:hindsight_retain(存储信息)、hindsight_recall(检索相关记忆,返回编号列表)、hindsight_reflect(基于记忆综合生成有推理的回答)。若需要裁剪,可分别用include_retain/include_recall/include_reflect开关控制;仓库中的单元测试验证了“默认三个工具”以及“只保留 retain 时仅返回一个工具”等行为(见 hindsight-integrations/langgraph/tests/test_tools.py)。

动态 bank ID 与工具:如果智能体只构建一次、却要服务多个用户,就省略静态bank_id,改为在每次请求时从config["configurable"]中解析:

tools = create_hindsight_tools(bank_id_from_config="user_id") agent = create_react_agent(ChatOpenAI(model="gpt-4o"), tools=tools) result = await agent.ainvoke( {"messages": [{"role": "user", "content": "Remember that I prefer dark mode"}]}, config={"configurable": {"user_id": "user-456"}}, )

传入bank_id="user-123"则会把所有工具调用固定到该 bank,且优先级高于bank_id_from_config

模式二:记忆节点(Nodes)

在图中 LLM 节点前后插入自动化的 recall 与 retain 节点:

from hindsight_client import Hindsight from hindsight_langgraph import create_recall_node, create_retain_node from langgraph.graph import StateGraph, MessagesState, START, END client = Hindsight(base_url="http://localhost:8888") recall = create_recall_node(client=client, bank_id_from_config="user_id") retain = create_retain_node(client=client, bank_id_from_config="user_id") builder = StateGraph(MessagesState) builder.add_node("recall", recall) builder.add_node("agent", agent_node) # 你的 LLM 节点 builder.add_node("retain", retain) builder.add_edge(START, "recall") builder.add_edge("recall", "agent") builder.add_edge("agent", "retain") builder.add_edge("retain", END) graph = builder.compile()

recall 节点的工作方式(见 nodes.py):从state["messages"]中取出最新一条HumanMessage作为查询,调用arecall,将命中的记忆格式化成一个SystemMessage(内容为Relevant memories about this user:开头的编号列表)追加回messagesmax_results控制注入条数上限,tags/tags_match/recall_types/recall_include_entities均可透传。相关行为在 test_nodes.py 中有完整覆盖。

retain 节点的工作方式(见 nodes.py):默认只取最新一条HumanMessage文本内容存入记忆(retain_human=True),可通过retain_ai=True同时存储 AI 回复。ToolMessage/FunctionMessage会被有意跳过,避免把工具调用协议噪音存进记忆;tagsmetadatadocument_id可附加到存储操作上。

关于消息顺序的注意点:默认把记忆SystemMessage追加进messages时,由于MessagesStateadd_messagesreducer 是追加语义,该消息会出现在已有消息之后而非最前。如果 LLM 提供商要求系统消息置顶,建议用output_key把记忆文本写入独立的 state 字段,再在 agent 节点手动拼进系统提示词:

from typing import Optional from langgraph.graph import MessagesState class AgentState(MessagesState): memory_context: Optional[str] = None recall = create_recall_node( client=client, bank_id="user-123", output_key="memory_context" ) # 在 agent 节点中读取 state["memory_context"],拼接到系统提示词头部

模式三:记忆指令(Memory Instructions)

不想构图时,可以用memory_instructions预取记忆并注入系统提示词,任何 LangChain 模型都适用(见 tools.py):

from hindsight_langgraph import memory_instructions from langchain_openai import ChatOpenAI get_instructions = memory_instructions( bank_id="user-123", base_instructions="You are a helpful assistant.", ) # 每次调用都会重新拉取记忆,保持最新 instructions = await get_instructions() response = await ChatOpenAI(model="gpt-4o").ainvoke([ {"role": "system", "content": instructions}, {"role": "user", "content": "What do you know about me?"}, ])

与 recall/retain 节点“失败即抛HindsightError”不同,memory_instructions面向提示词构建路径:当 Hindsight 调用失败(如网络异常)时,它会记录日志并原样返回base_instructions,让 LLM 调用继续执行,实现优雅降级。

关于 BaseStore 适配器

指南中还提到了HindsightStore适配器,用于需要 LangGraph 原生存储语义(BaseStore)的场景。需要说明的是:当前仓库的hindsight-langgraph包(hindsight-integrations/langgraph)中,源码结构确认提供的三种现成模式是工具、节点与记忆指令;如果你需要 BaseStore 原生模式,请以对应版本的包说明与集成文档为准。工具、节点、BaseStore 三者的选择原则是:要智能体自主控制记忆调用选工具,要自动注入与自动存储选节点,要 LangGraph 原生存储语义选 BaseStore

第四步:选择正确的 bank 策略

只要拥有稳定的用户或租户键,就应该RunnableConfig动态解析 bank ID,让记忆在多次图运行之间始终挂到正确的人身上:

# 动态解析:每次运行从 config 中读取 recall = create_recall_node(bank_id_from_config="user_id") retain = create_retain_node(bank_id_from_config="user_id") result = await graph.ainvoke( {"messages": [{"role": "user", "content": "hello"}]}, config={"configurable": {"user_id": "user-456"}}, )

解析逻辑位于 nodes.py(工具侧见 tools.py 的 _resolve_bank_id):静态bank_id优先;否则从config["configurable"][bank_id_from_config]读取;都拿不到时,recall/retain 节点会记录告警并跳过本次记忆操作,而工具会抛出HindsightError

作用域建议

  • 给团队内部单一助手使用时,共享 bank 可行;
  • 但绝大多数生产图应当按用户、租户或线程作用域隔离记忆——按用户隔离是最安全默认值,需要更强隔离时再叠加租户或线程上下文。

第五步:验证记忆是否真正生效

按以下步骤做一次端到端验证:

  1. 用测试用户运行一次图,存储一条偏好或项目事实;
  2. 相同的user_id(放在configurable中)再次调用图;
  3. 提出一个依赖之前事实的问题,确认 recall 能把上下文带回来;
  4. 换一个不同的user_id重复同样的测试,确认记忆按用户隔离

如果第二次运行能回答出第一次运行留下的细节,说明配置成功。如果不能,按顺序排查:打开调试日志、核对解析到的 bank ID、确认 retain 调用确实执行完毕(仓库中节点失败会抛HindsightError,错误信息包含Recall node failed/Retain node failed,见 test_nodes.py)。

仓库还提供了更高层的验证:test_graph_flow.pytest_e2e.py覆盖完整的图流程与端到端集成(见 hindsight-integrations/langgraph/tests),可作为你本地验证的参考模板。

常见错误

  • 在纯 LangChain 中绑定了工具,却忘记运行工具执行循环——工具模式在 LangChain 下同样可用,但工具调用需要你自己驱动;
  • 第二次运行使用了不同的运行时键——bank_id_from_config读取到的键不同,会静默创建一个全新 bank,导致记忆“丢失”;
  • 所有用户共用一个 bank——当应用真正需要按用户隔离记忆时,共享 bank 会造成串记忆。

FAQ

应该用工具、节点还是 BaseStore?

想由智能体自主控制记忆调用,用工具;想在图中自动 recall / retain,用节点;想要 LangGraph 原生存储模式,用BaseStore

纯 LangChain 也能用吗?

可以。工具模式在 LangChain 中同样可用,但你需要自己处理工具执行循环。

应该怎样划分 bank 作用域?

按用户隔离是最安全的默认值。当应用需要更强隔离时,再叠加租户或线程上下文。

下一步

  • 需要托管记忆后端,从 Hindsight Cloud 开始;
  • 阅读完整集成说明 hindsight-integrations/langgraph/README.md;
  • 查阅 Python 客户端与 recall / retain API 的实现细节 hindsight-clients/python/README.md 与 hindsight_client.py(recall见 L504、retain见 L346、reflect见 L590);
  • 参考测试用例 hindsight-integrations/langgraph/tests/test_nodes.py 与 hindsight-integrations/langgraph/tests/test_tools.py,加深对节点与工具行为边界的理解;
  • 若使用纯 LangChain 场景,优先尝试memory_instructions模式,它无需 langgraph 依赖即可完成记忆注入。

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

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 22:21:00

医疗数据分类分级:原理、技术与实践指南

1. 健康医疗数据分类分级概述医疗数据分类分级是数据治理的核心环节,其本质是根据数据的敏感程度、应用场景和潜在风险进行科学划分。以患者电子病历为例,基因检测数据与普通血常规数据的安全等级必然不同——前者可能涉及遗传隐私和家族健康风险&#x…

作者头像 李华
网站建设 2026/9/13 22:20:20

9款免费视频转思维导图工具实测与技巧

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 22:19:32

STM32CubeProgrammer:嵌入式AI部署的物理锚点与版本硬约束

1. 为什么STM32CubeProgrammer不是“可装可不装”的工具,而是嵌入式AI编程的物理锚点很多人在刚接触嵌入式AI开发时,会下意识把STM32CubeProgrammer当成一个“烧录器”——就像U盘插进去拷个文件那么简单。我带过三届校企联合实训班,每届都有…

作者头像 李华