内存 - LangChain 框架 --知识铺
内存¶
LangGraph支持两种对于构建对话代理至关重要的内存类型:
本指南演示了如何在LangGraph中将这两种内存类型与代理结合使用。要更深入地了解内存概念,请参阅LangGraph内存文档。
短期内存和长期内存都需要持久存储,以在LLM交互中保持连续性。在生产环境中,这些数据通常存储在数据库中。
术语
在LangGraph中
- _短期内存_也称为线程级内存。
- _长期内存_也称为跨线程内存。
线程表示由相同thread_id分组的一系列相关运行。
短期内存¶
短期内存使代理能够跟踪多轮对话。要使用它,您必须:
- 在创建代理时提供
checkpointer。checkpointer可以实现代理状态的持久性。 - 在运行代理时在配置中提供
thread_id。thread_id是对话会话的唯一标识符。
API参考:create_react_agent | InMemorySaver
<span id="__span-0-1">from langgraph.prebuilt import create_react_agent
<span id="__span-0-2">from langgraph.checkpoint.memory import InMemorySaver
<span id="__span-0-3">
<span id="__span-0-4">checkpointer = InMemorySaver()
<span id="__span-0-5">
<span id="__span-0-6">
<span id="__span-0-7">def get_weather(city: str) -> str:
<span id="__span-0-8"> """Get weather for a given city."""
<span id="__span-0-9"> return f"It's always sunny in {city}!"
<span id="__span-0-10">
<span id="__span-0-11">
<span id="__span-0-12">agent = create_react_agent(
<span id="__span-0-13"> model="anthropic:claude-3-7-sonnet-latest",
<span id="__span-0-14"> tools=[get_weather],
<span id="__span-0-15"> checkpointer=checkpointer
<span id="__span-0-16">)
<span id="__span-0-17">
<span id="__span-0-18"># Run the agent
<span id="__span-0-19">config = {
<span id="__span-0-20"> "configurable": {
<span id="__span-0-21"> "thread_id": "1"
<span id="__span-0-22"> }
<span id="__span-0-23">}
<span id="__span-0-24">
<span id="__span-0-25">sf_response = agent.invoke(
<span id="__span-0-26"> {"messages": [{"role": "user", "content": "what is the weather in sf"}]},
<span id="__span-0-27"> config
<span id="__span-0-28">)
<span id="__span-0-29">
<span id="__span-0-30"># Continue the conversation using the same thread_id
<span id="__span-0-31">ny_response = agent.invoke(
<span id="__span-0-32"> {"messages": [{"role": "user", "content": "what about new york?"}]},
<span id="__span-0-33"> config
<span id="__span-0-34">)
当代理第二次使用相同的thread_id被调用时,第一次对话的原始消息历史会自动包含在内,从而允许代理推断用户是在特别询问纽约的天气。
LangGraph平台提供生产就绪的检查点
如果您使用LangGraph平台,在部署期间,您的检查点将自动配置为使用生产就绪的数据库。
管理消息历史¶
长对话可能超出LLM的上下文窗口。常见的解决方案是:
这使得代理能够跟踪对话而不会超出LLM的上下文窗口。
要管理消息历史,请指定pre_model_hook——一个始终在调用语言模型之前运行的函数(节点)。
总结消息历史¶
长对话可能超出LLM的上下文窗口。一个常见的解决方案是维护对话的运行摘要。这使得代理能够跟踪对话而不会超出LLM的上下文窗口。
要总结消息历史,您可以将[pre_model_hook](https://langgraph.com.cn/reference/agents.1.html#langgraph.prebuilt.chat_agent_executor.create_react_agent “ create_react_agent")与预构建的SummarizationNode一起使用。
API参考:ChatAnthropic | count_tokens_approximately | create_react_agent | AgentState | InMemorySaver
<span id="__span-1-1">from langchain_anthropic import ChatAnthropic
<span id="__span-1-2">from langmem.short_term import SummarizationNode
<span id="__span-1-3">from langchain_core.messages.utils import count_tokens_approximately
<span id="__span-1-4">from langgraph.prebuilt import create_react_agent
<span id="__span-1-5">from langgraph.prebuilt.chat_agent_executor import AgentState
<span id="__span-1-6">from langgraph.checkpoint.memory import InMemorySaver
<span id="__span-1-7">from typing import Any
<span id="__span-1-8">
<span id="__span-1-9">model = ChatAnthropic(model="claude-3-7-sonnet-latest")
<span id="__span-1-10">
<span id="__span-1-11">summarization_node = SummarizationNode(
<span id="__span-1-12"> token_counter=count_tokens_approximately,
<span id="__span-1-13"> model=model,
<span id="__span-1-14"> max_tokens=384,
<span id="__span-1-15"> max_summary_tokens=128,
<span id="__span-1-16"> output_messages_key="llm_input_messages",
<span id="__span-1-17">)
<span id="__span-1-18">
<span id="__span-1-19">class State(AgentState):
<span id="__span-1-20"> # NOTE: we're adding this key to keep track of previous summary information
<span id="__span-1-21"> # to make sure we're not summarizing on every LLM call
<span id="__span-1-22"> context: dict[str, Any]
<span id="__span-1-23">
<span id="__span-1-24">
<span id="__span-1-25">checkpointer = InMemorySaver()
<span id="__span-1-26">
<span id="__span-1-27">agent = create_react_agent(
<span id="__span-1-28"> model=model,
<span id="__span-1-29"> tools=tools,
<span id="__span-1-30"> pre_model_hook=summarization_node,
<span id="__span-1-31"> state_schema=State,
<span id="__span-1-32"> checkpointer=checkpointer,
<span id="__span-1-33">)
裁剪消息历史¶
要裁剪消息历史,您可以将[pre_model_hook](https://langgraph.com.cn/reference/agents.1.html#langgraph.prebuilt.chat_agent_executor.create_react_agent “ create_react_agent")与trim_messages函数一起使用。
API参考:trim_messages | count_tokens_approximately | create_react_agent
<span id="__span-2-1">from langchain_core.messages.utils import (
<span id="__span-2-2"> trim_messages,
<span id="__span-2-3"> count_tokens_approximately
<span id="__span-2-4">)
<span id="__span-2-5">from langgraph.prebuilt import create_react_agent
<span id="__span-2-6">
<span id="__span-2-7"># This function will be called every time before the node that calls LLM
<span id="__span-2-8">def pre_model_hook(state):
<span id="__span-2-9"> trimmed_messages = trim_messages(
<span id="__span-2-10"> state["messages"],
<span id="__span-2-11"> strategy="last",
<span id="__span-2-12"> token_counter=count_tokens_approximately,
<span id="__span-2-13"> max_tokens=384,
<span id="__span-2-14"> start_on="human",
<span id="__span-2-15"> end_on=("human", "tool"),
<span id="__span-2-16"> )
<span id="__span-2-17"> return {"llm_input_messages": trimmed_messages}
<span id="__span-2-18">
<span id="__span-2-19">checkpointer = InMemorySaver()
<span id="__span-2-20">agent = create_react_agent(
<span id="__span-2-21"> model,
<span id="__span-2-22"> tools,
<span id="__span-2-23"> pre_model_hook=pre_model_hook,
<span id="__span-2-24"> checkpointer=checkpointer,
<span id="__span-2-25">)
要了解更多关于使用pre_model_hook管理消息历史的信息,请参阅此操作指南
从工具读取¶
LangGraph允许代理在其工具内部访问其短期内存(状态)。
API参考:InjectedState | create_react_agent
<span id="__span-3-1">from typing import Annotated
<span id="__span-3-2">from langgraph.prebuilt import InjectedState, create_react_agent
<span id="__span-3-3">
<span id="__span-3-4">class CustomState(AgentState):
<span id="__span-3-5"> user_id: str
<span id="__span-3-6">
<span id="__span-3-7">def get_user_info(
<span id="__span-3-8"> state: Annotated[CustomState, InjectedState]
<span id="__span-3-9">) -> str:
<span id="__span-3-10"> """Look up user info."""
<span id="__span-3-11"> user_id = state["user_id"]
<span id="__span-3-12"> return "User is John Smith" if user_id == "user_123" else "Unknown user"
<span id="__span-3-13">
<span id="__span-3-14">agent = create_react_agent(
<span id="__span-3-15"> model="anthropic:claude-3-7-sonnet-latest",
<span id="__span-3-16"> tools=[get_user_info],
<span id="__span-3-17"> state_schema=CustomState,
<span id="__span-3-18">)
<span id="__span-3-19">
<span id="__span-3-20">agent.invoke({
<span id="__span-3-21"> "messages": "look up user information",
<span id="__span-3-22"> "user_id": "user_123"
<span id="__span-3-23">})
有关更多信息,请参阅上下文指南。
从工具写入¶
要在执行期间修改代理的短期内存(状态),您可以直接从工具返回状态更新。这对于持久化中间结果或使信息可供后续工具或提示访问非常有用。
API参考:InjectedToolCallId | RunnableConfig | ToolMessage | InjectedState | create_react_agent | AgentState | Command
<span id="__span-4-1">from typing import Annotated
<span id="__span-4-2">from langchain_core.tools import InjectedToolCallId
<span id="__span-4-3">from langchain_core.runnables import RunnableConfig
<span id="__span-4-4">from langchain_core.messages import ToolMessage
<span id="__span-4-5">from langgraph.prebuilt import InjectedState, create_react_agent
<span id="__span-4-6">from langgraph.prebuilt.chat_agent_executor import AgentState
<span id="__span-4-7">from langgraph.types import Command
<span id="__span-4-8">
<span id="__span-4-9">class CustomState(AgentState):
<span id="__span-4-10"> user_name: str
<span id="__span-4-11">
<span id="__span-4-12">def update_user_info(
<span id="__span-4-13"> tool_call_id: Annotated[str, InjectedToolCallId],
<span id="__span-4-14"> config: RunnableConfig
<span id="__span-4-15">) -> Command:
<span id="__span-4-16"> """Look up and update user info."""
<span id="__span-4-17"> user_id = config["configurable"].get("user_id")
<span id="__span-4-18"> name = "John Smith" if user_id == "user_123" else "Unknown user"
<span id="__span-4-19"> return Command(update={
<span id="__span-4-20"> "user_name": name,
<span id="__span-4-21"> # update the message history
<span id="__span-4-22"> "messages": [
<span id="__span-4-23"> ToolMessage(
<span id="__span-4-24"> "Successfully looked up user information",
<span id="__span-4-25"> tool_call_id=tool_call_id
<span id="__span-4-26"> )
<span id="__span-4-27"> ]
<span id="__span-4-28"> })
<span id="__span-4-29">
<span id="__span-4-30">def greet(
<span id="__span-4-31"> state: Annotated[CustomState, InjectedState]
<span id="__span-4-32">) -> str:
<span id="__span-4-33"> """Use this to greet the user once you found their info."""
<span id="__span-4-34"> user_name = state["user_name"]
<span id="__span-4-35"> return f"Hello {user_name}!"
<span id="__span-4-36">
<span id="__span-4-37">agent = create_react_agent(
<span id="__span-4-38"> model="anthropic:claude-3-7-sonnet-latest",
<span id="__span-4-39"> tools=[update_user_info, greet],
<span id="__span-4-40"> state_schema=CustomState
<span id="__span-4-41">)
<span id="__span-4-42">
<span id="__span-4-43">agent.invoke(
<span id="__span-4-44"> {"messages": [{"role": "user", "content": "greet the user"}]},
<span id="__span-4-45"> config={"configurable": {"user_id": "user_123"}}
<span id="__span-4-46">)
有关更多详细信息,请参阅如何从工具更新状态。
长期内存¶
使用长期内存来跨对话存储用户特定或应用程序特定的数据。这对于聊天机器人等应用程序非常有用,您可能希望记住用户偏好或其他信息。
要使用长期内存,您需要:
- 配置一个存储以在调用之间持久化数据。
- 使用[
get_store](https://langgraph.com.cn/reference/config/index.html#langgraph.config.get_store “ get_store")函数从工具或提示中访问存储。
读取¶
代理可以用来查找用户信息的一个工具
<span id="__span-5-1">from langchain_core.runnables import RunnableConfig
<span id="__span-5-2">from langgraph.config import get_store
<span id="__span-5-3">from langgraph.prebuilt import create_react_agent
<span id="__span-5-4">from langgraph.store.memory import InMemoryStore
<span id="__span-5-5">
<span id="__span-5-6">store = InMemoryStore()
<span id="__span-5-7">
<span id="__span-5-8">store.put(
<span id="__span-5-9"> ("users",),
<span id="__span-5-10"> "user_123",
<span id="__span-5-11"> {
<span id="__span-5-12"> "name": "John Smith",
<span id="__span-5-13"> "language": "English",
<span id="__span-5-14"> }
<span id="__span-5-15">)
<span id="__span-5-16">
<span id="__span-5-17">def get_user_info(config: RunnableConfig) -> str:
<span id="__span-5-18"> """Look up user info."""
<span id="__span-5-19"> # Same as that provided to `create_react_agent`
<span id="__span-5-20"> store = get_store()
<span id="__span-5-21"> user_id = config["configurable"].get("user_id")
<span id="__span-5-22"> user_info = store.get(("users",), user_id)
<span id="__span-5-23"> return str(user_info.value) if user_info else "Unknown user"
<span id="__span-5-24">
<span id="__span-5-25">agent = create_react_agent(
<span id="__span-5-26"> model="anthropic:claude-3-7-sonnet-latest",
<span id="__span-5-27"> tools=[get_user_info],
<span id="__span-5-28"> store=store
<span id="__span-5-29">)
<span id="__span-5-30">
<span id="__span-5-31"># Run the agent
<span id="__span-5-32">agent.invoke(
<span id="__span-5-33"> {"messages": [{"role": "user", "content": "look up user information"}]},
<span id="__span-5-34"> config={"configurable": {"user_id": "user_123"}}
<span id="__span-5-35">)
写入¶
一个更新用户信息的工具示例
<span id="__span-6-1">from typing_extensions import TypedDict
<span id="__span-6-2">
<span id="__span-6-3">from langgraph.config import get_store
<span id="__span-6-4">from langgraph.prebuilt import create_react_agent
<span id="__span-6-5">from langgraph.store.memory import InMemoryStore
<span id="__span-6-6">
<span id="__span-6-7">store = InMemoryStore()
<span id="__span-6-8">
<span id="__span-6-9">class UserInfo(TypedDict):
<span id="__span-6-10"> name: str
<span id="__span-6-11">
<span id="__span-6-12">def save_user_info(user_info: UserInfo, config: RunnableConfig) -> str:
<span id="__span-6-13"> """Save user info."""
<span id="__span-6-14"> # Same as that provided to `create_react_agent`
<span id="__span-6-15"> store = get_store()
<span id="__span-6-16"> user_id = config["configurable"].get("user_id")
<span id="__span-6-17"> store.put(("users",), user_id, user_info)
<span id="__span-6-18"> return "Successfully saved user info."
<span id="__span-6-19">
<span id="__span-6-20">agent = create_react_agent(
<span id="__span-6-21"> model="anthropic:claude-3-7-sonnet-latest",
<span id="__span-6-22"> tools=[save_user_info],
<span id="__span-6-23"> store=store
<span id="__span-6-24">)
<span id="__span-6-25">
<span id="__span-6-26"># Run the agent
<span id="__span-6-27">agent.invoke(
<span id="__span-6-28"> {"messages": [{"role": "user", "content": "My name is John Smith"}]},
<span id="__span-6-29"> config={"configurable": {"user_id": "user_123"}}
<span id="__span-6-30">)
<span id="__span-6-31">
<span id="__span-6-32"># You can access the store directly to get the value
<span id="__span-6-33">store.get(("users",), "user_123").value
语义搜索¶
LangGraph还允许您通过语义相似性在长期内存中搜索项目。
预构建内存工具¶
LangMem是一个LangChain维护的库,提供用于管理代理中长期内存的工具。请参阅LangMem文档以获取使用示例。
附加资源¶
- 原文作者:知识铺
- 原文链接:https://index.zshipu.com/ai002/post/20251125/%E5%86%85%E5%AD%98-LangChain-%E6%A1%86%E6%9E%B6/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。
- 免责声明:本页面内容均来源于站内编辑发布,部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性,如涉及版权等问题,请立即联系客服进行更改或删除,保证您的合法权益。转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。也可以邮件至 sblig@126.com