作者:彬彬侠
详细介绍 langgraph.prebuilt.InjectedStore 类
langgraph.prebuilt.InjectedStore 是 LangGraph 库中 langgraph.prebuilt 模块的一个类型注解类,继承自 InjectedToolArg,用于在工具函数中注入 LangGraph 的存储对象(Store)。LangGraph 是 LangChain 生态的扩展,专注于构建复杂、有状态、多步骤的交互式应用,通过状态图管理节点和边,支持动态路由、循环和状态管理。InjectedStore 允许工具访问持久化存储(如对话历史、用户数据),而不暴露给语言模型(LLM),确保安全性和开发效率。以下是对其详细、条理清晰的介绍,基于提供的参考信息和 LangGraph 文档。
1. 定义与功能
1.1 类定义
- from langgraph.prebuilt import InjectedStore
- classInjectedStore(InjectedToolArg):"""
- 用于工具参数的注解,表示该参数将注入 LangGraph 的存储对象。
- 参数:
- field: 可选,指定存储中要注入的特定键。如果为 None,则注入整个存储对象。
- 示例:
- @tool
- def store_tool(x: int, my_store: Annotated[Any, InjectedStore()]) -> str:
- '''处理存储的工具。'''
- stored_value = my_store.get(("values",), "foo").value["bar"]
- return stored_value + x
- """
复制代码继承:继承自 InjectedToolArg,表明它是工具参数注入机制的一部分。作用:标记工具函数中的参数,指示 LangGraph 在运行时注入存储对象。
- 关键特性:
隐藏参数:使用 InjectedStore 注解的参数不出现在工具的模式(schema)中,LLM 无法生成该参数的值。自动注入:当工具通过 ToolNode 执行时,LangGraph 自动将存储对象(或指定字段)注入到参数中。存储支持:需要图编译时提供存储对象(如 InMemoryStore),自动传播到工具。
1.2 核心功能
存储注入:将 LangGraph 的存储对象(或其特定字段)传递给工具,供工具访问和操作持久化数据。模式隔离:隐藏存储参数,防止 LLM 生成或修改存储对象,确保安全和正确性。与 ToolNode 集成:与 ToolNode 配合,自动处理工具调用和存储注入。
1.3 使用场景
持久化数据访问:工具需要从存储中获取对话历史、用户信息或中间结果。多轮对话:聊天机器人中,工具需要引用存储中的上下文或历史消息。复杂工作流:工具需要访问共享存储以协调多步骤任务。安全敏感场景:存储包含敏感数据(如用户 ID、会话令牌),不应暴露给 LLM。
2. 用法
InjectedStore 与 typing_extensions.Annotated 结合使用,注解工具函数的参数。基本步骤如下:
定义存储:创建存储对象(如 InMemoryStore)并存储数据。定义工具:使用 @tool 装饰器,添加 InjectedStore 注解。集成状态图:使用 ToolNode 处理工具调用,LangGraph 自动注入存储。运行工作流:通过状态图的 invoke 或 stream 方法执行,传入存储对象。
3. 实现原理
3.1 存储注入机制
注解识别:LangGraph 的运行时(通过 ToolNode)识别工具函数中带有 InjectedStore 注解的参数。参数注入:在工具调用时,运行时将存储注入到工具的参数中,绕过 LLM 的生成过程。模式隐藏:InjectedStore 参数从工具的模式中移除,LLM 只看到其他暴露的参数(如 x: int)。
3.2 与 ToolNode 的协作
ToolNode 负责解析 AIMessage 中的工具调用(tool_calls)。当工具包含 InjectedStore 参数,ToolNode 在调用工具前自动注入存储对象。图编译时必须提供存储对象(如 store=InMemoryStore()),以便传播到工具。
3.3 存储格式
存储类型:通常是 BaseStore 的子类,如 InMemoryStore(内存存储)或 PostgresStore(数据库存储)。数据结构:支持层次化命名空间(如 ("values", "foo")),键值对存储数据(如 {"bar": 2})。操作接口:通过 get、put 等方法访问和修改存储。
4. 使用示例
4.1 基本示例
以下是一个独立工具节点的示例,展示 InjectedStore 的使用。- from typing import Any
- from typing_extensions import Annotated
- from langchain_core.messages import AIMessage
- from langchain_core.tools import tool
- from langgraph.store.memory import InMemoryStore
- from langgraph.prebuilt import InjectedStore, ToolNode
- # 创建存储并添加数据
- store = InMemoryStore()
- store.put(("values",),"foo",{"bar":2})# 定义工具@tooldefstore_tool(x:int, my_store: Annotated[Any, InjectedStore()])->str:"""处理存储的工具。"""
- stored_value = my_store.get(("values",),"foo").value["bar"]returnstr(stored_value + x)# 创建 ToolNode
- node = ToolNode([store_tool])# 定义工具调用和状态
- tool_call ={"name":"store_tool","args":{"x":1},"id":"1","type":"tool_call"}
- state ={"messages":[AIMessage("", tool_calls=[tool_call])],}# 执行工具节点,传入存储
- result = node.invoke(state, store=store)print(result["messages"][0].content)# 输出: 3
复制代码 解析
存储:InMemoryStore 存储键值对 ("values", "foo") = {"bar": 2}。工具:store_tool 使用 InjectedStore 注入存储,访问 bar 值并加 x。ToolNode:处理工具调用,注入存储,生成 ToolMessage(内容为 3)。
4.2 集成到状态图
以下是将工具集成到完整状态图的示例。- from langgraph.graph import StateGraph, END
- from langchain_openai import ChatOpenAI
- from langchain_core.prompts import ChatPromptTemplate
- from langchain_core.messages import HumanMessage
- # 定义状态classState(TypedDict):
- messages: List[BaseMessage]# 定义 Agent 节点defagent(state: State)-> State:
- prompt = ChatPromptTemplate.from_template("根据输入调用工具:{input}")
- llm = ChatOpenAI(model="gpt-3.5-turbo").bind_tools([store_tool])
- message = llm.invoke(state["messages"][-1].content)
- state["messages"].append(message)return state
- # 构建状态图
- workflow = StateGraph(State)
- workflow.add_node("agent", agent)
- workflow.add_node("tools", node)
- workflow.add_edge("tools","agent")
- workflow.add_conditional_edges("agent",lambda state:"tools"if state["messages"][-1].tool_calls else END)
- workflow.set_entry_point("agent")# 编译并运行
- graph = workflow.compile()
- initial_state ={"messages":[HumanMessage(content="处理数字 1")]}
- result = graph.invoke(initial_state, store=store)print(result["messages"][-1].content)# 输出: 3
复制代码 解析
状态图:包含 agent(LLM)和 tools(ToolNode)节点。流程:用户输入触发 LLM 生成工具调用,ToolNode 执行并注入存储。结果:工具从存储中获取值,计算并返回结果。
5. 使用场景
持久化数据访问:工具需要从存储中获取长期数据,如用户偏好或历史记录。多轮对话:聊天机器人中,工具访问存储中的对话上下文,提供个性化回答。复杂工作流:工具使用存储协调多步骤任务,如共享中间结果。安全敏感场景:存储包含敏感信息(如 API 密钥),不应暴露给 LLM。
示例场景:
聊天机器人:工具从存储中获取用户历史问题,生成上下文相关回答。自动化工作流:工具根据存储中的数据更新任务状态。
6. 注意事项
存储配置:
图编译时必须提供存储对象(如 store=InMemoryStore())。确保存储包含工具期望的键,否则可能引发错误。
工具模式:
InjectedStore 参数不出现在工具模式中,LLM 只生成其他参数。确保非注入参数有清晰的类型注解。
性能:
注入整个存储可能增加开销,优先使用 field 指定字段。使用异步工具调用优化性能。
调试:
启用 debug=True 查看存储注入日志。使用 graph.get_graph().to_dot() 可视化状态图。
版本兼容性:
要求 langchain-core >= 0.3.8,请确认版本支持。检查 LangGraph 文档 获取最新信息。
7. 与其他注解的对比
| 注解 | 用途 | 是否暴露给 LLM | 示例场景 | | InjectedStore | 注入 LangGraph 存储对象 | 否 | 工具访问持久化数据 | | InjectedState | 注入状态图状态 | 否 | 工具访问对话历史或用户上下文 | | InjectedToolArg | 注入运行时参数(如特定值) | 否 | 注入动态用户 ID 或会话令牌 | | RunnableConfig | 注入运行时配置(如执行设置) | 否 | 传递执行超时或元数据 | InjectedStore 专注于持久化存储,适合需要长期记忆的工具,而 InjectedState 更适合当前状态。
8. 总结
langgraph.prebuilt.InjectedStore 是一个高效的类型注解,用于在 LangGraph 工具中注入存储对象。它通过隐藏存储参数,防止 LLM 生成敏感数据,同时允许工具访问持久化数据,实现安全、上下文相关的操作。支持注入整个存储或特定字段,与 ToolNode 无缝集成,适用于聊天机器人、自动化工作流等场景。通过自动注入机制,它简化了存储管理,提升了开发效率。
原文地址:https://blog.csdn.net/u013172930/article/details/148013385 |