详细介绍 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 结合使用,注解工具函数的参数。基本步骤如下:

  1. 定义存储:创建存储对象(如 InMemoryStore)并存储数据。
  2. 定义工具:使用 @tool 装饰器,添加 InjectedStore 注解。
  3. 集成状态图:使用 ToolNode 处理工具调用,LangGraph 自动注入存储。
  4. 运行工作流:通过状态图的 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. 注意事项

  1. 存储配置:

    • 图编译时必须提供存储对象(如 store=InMemoryStore())。
    • 确保存储包含工具期望的键,否则可能引发错误。
  2. 工具模式:

    • InjectedStore 参数不出现在工具模式中,LLM 只生成其他参数。
    • 确保非注入参数有清晰的类型注解。
  3. 性能:

    • 注入整个存储可能增加开销,优先使用 field 指定字段。
    • 使用异步工具调用优化性能。
  4. 调试:

    • 启用 debug=True 查看存储注入日志。
    • 使用 graph.get_graph().to_dot() 可视化状态图。
  5. 版本兼容性:

    • 要求 langchain-core >= 0.3.8,请确认版本支持。
    • 检查 LangGraph 文档 获取最新信息。

7. 与其他注解的对比

注解用途是否暴露给 LLM示例场景
InjectedStore注入 LangGraph 存储对象否工具访问持久化数据
InjectedState注入状态图状态否工具访问对话历史或用户上下文
InjectedToolArg注入运行时参数(如特定值)否注入动态用户 ID 或会话令牌
RunnableConfig注入运行时配置(如执行设置)否传递执行超时或元数据

InjectedStore 专注于持久化存储,适合需要长期记忆的工具,而 InjectedState 更适合当前状态。


8. 总结

langgraph.prebuilt.InjectedStore 是一个高效的类型注解,用于在 LangGraph 工具中注入存储对象。它通过隐藏存储参数,防止 LLM 生成敏感数据,同时允许工具访问持久化数据,实现安全、上下文相关的操作。支持注入整个存储或特定字段,与 ToolNode 无缝集成,适用于聊天机器人、自动化工作流等场景。通过自动注入机制,它简化了存储管理,提升了开发效率。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐