【LangGraph】langgraph.prebuilt.InjectedStore 类:在工具函数中注入 LangGraph 的存储对象(Store)
·
详细介绍 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
class InjectedStore(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})
# 定义工具
@tool
def store_tool(x: int, my_store: Annotated[Any, InjectedStore()]) -> str:
"""处理存储的工具。"""
stored_value = my_store.get(("values",), "foo").value["bar"]
return str(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
# 定义状态
class State(TypedDict):
messages: List[BaseMessage]
# 定义 Agent 节点
def agent(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 无缝集成,适用于聊天机器人、自动化工作流等场景。通过自动注入机制,它简化了存储管理,提升了开发效率。
更多推荐
所有评论(0)