管理内存 - LangChain 框架 --知识铺
管理内存¶
许多 AI 应用程序需要内存才能在多次交互中共享上下文。LangGraph 支持构建对话代理至关重要的两种内存类型:
启用短期内存后,长对话可能会超出 LLM 的上下文窗口。常见的解决方案有:
- 修剪:删除前或后 N 条消息(在调用 LLM 之前)
- 摘要:总结历史中较早的消息并用摘要替换它们
- 从 LangGraph 状态永久删除消息
- 自定义策略(例如,消息过滤等)
这使得代理能够跟踪对话,而不会超出 LLM 的上下文窗口。
添加短期内存¶
短期内存使代理能够跟踪多轮对话。
API 参考:InMemorySaver | StateGraph
<span id="__span-0-1">from langgraph.checkpoint.memory import InMemorySaver
<span id="__span-0-2">from langgraph.graph import StateGraph
<span id="__span-0-3">
<span id="__span-0-4">checkpointer = InMemorySaver()
<span id="__span-0-5">
<span id="__span-0-6">builder = StateGraph(...)
<span id="__span-0-7">graph = builder.compile(checkpointer=checkpointer)
<span id="__span-0-8">
<span id="__span-0-9">graph.invoke(
<span id="__span-0-10"> {"messages": [{"role": "user", "content": "hi! i am Bob"}]},
<span id="__span-0-11"> {"configurable": {"thread_id": "1"}},
<span id="__span-0-12">)
请参阅持久化指南,了解有关使用短期内存的更多信息。
添加长期内存¶
使用长期内存可以在对话之间存储用户特定或应用程序特定的数据。这对于聊天机器人等应用程序非常有用,您可能希望记住用户偏好或其他信息。
API 参考:StateGraph
<span id="__span-1-1">from langgraph.store.memory import InMemoryStore
<span id="__span-1-2">from langgraph.graph import StateGraph
<span id="__span-1-3">
<span id="__span-1-4">store = InMemoryStore()
<span id="__span-1-5">
<span id="__span-1-6">builder = StateGraph(...)
<span id="__span-1-7">graph = builder.compile(store=store)
请参阅持久化指南,了解有关使用长期内存的更多信息。
修剪消息¶
要修剪消息历史,您可以使用 trim_messages 函数
API 参考:trim_messages | count_tokens_approximately
<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">
<span id="__span-2-6">def call_model(state: MessagesState):
<span id="__span-2-7"> messages = trim_messages(
<span id="__span-2-8"> state["messages"],
<span id="__span-2-9"> strategy="last",
<span id="__span-2-10"> token_counter=count_tokens_approximately,
<span id="__span-2-11"> max_tokens=128,
<span id="__span-2-12"> start_on="human",
<span id="__span-2-13"> end_on=("human", "tool"),
<span id="__span-2-14"> )
<span id="__span-2-15"> response = model.invoke(messages)
<span id="__span-2-16"> return {"messages": [response]}
<span id="__span-2-17">
<span id="__span-2-18">builder = StateGraph(MessagesState)
<span id="__span-2-19">builder.add_node(call_model)
<span id="__span-2-20">...
完整示例:修剪消息
<span id="__span-3-1">from langchain_core.messages.utils import (
<span id="__span-3-2"> trim_messages,
<span id="__span-3-3"> count_tokens_approximately
<span id="__span-3-4">)
<span id="__span-3-5">from langchain.chat_models import init_chat_model
<span id="__span-3-6">from langgraph.graph import StateGraph, START, MessagesState
<span id="__span-3-7">
<span id="__span-3-8">model = init_chat_model("anthropic:claude-3-7-sonnet-latest")
<span id="__span-3-9">summarization_model = model.bind(max_tokens=128)
<span id="__span-3-10">
<span id="__span-3-11">def call_model(state: MessagesState):
<span id="__span-3-12"> messages = trim_messages(
<span id="__span-3-13"> state["messages"],
<span id="__span-3-14"> strategy="last",
<span id="__span-3-15"> token_counter=count_tokens_approximately,
<span id="__span-3-16"> max_tokens=128,
<span id="__span-3-17"> start_on="human",
<span id="__span-3-18"> end_on=("human", "tool"),
<span id="__span-3-19"> )
<span id="__span-3-20"> response = model.invoke(messages)
<span id="__span-3-21"> return {"messages": [response]}
<span id="__span-3-22">
<span id="__span-3-23">checkpointer = InMemorySaver()
<span id="__span-3-24">builder = StateGraph(MessagesState)
<span id="__span-3-25">builder.add_node(call_model)
<span id="__span-3-26">builder.add_edge(START, "call_model")
<span id="__span-3-27">graph = builder.compile(checkpointer=checkpointer)
<span id="__span-3-28">
<span id="__span-3-29">config = {"configurable": {"thread_id": "1"}}
<span id="__span-3-30">graph.invoke({"messages": "hi, my name is bob"}, config)
<span id="__span-3-31">graph.invoke({"messages": "write a short poem about cats"}, config)
<span id="__span-3-32">graph.invoke({"messages": "now do the same but for dogs"}, config)
<span id="__span-3-33">final_response = graph.invoke({"messages": "what's my name?"}, config)
<span id="__span-3-34">
<span id="__span-3-35">final_response["messages"][-1].pretty_print()
<span id="__span-4-1">================================== Ai Message ==================================
<span id="__span-4-2">
<span id="__span-4-3">Your name is Bob, as you mentioned when you first introduced yourself.
总结消息¶
处理长对话历史的有效策略是,一旦达到某个阈值,就总结较早的消息
API 参考:AnyMessage | count_tokens_approximately | StateGraph | START
<span id="__span-5-1">from typing import Any, TypedDict
<span id="__span-5-2">
<span id="__span-5-3">from langchain_core.messages import AnyMessage
<span id="__span-5-4">from langchain_core.messages.utils import count_tokens_approximately
<span id="__span-5-5">from langmem.short_term import SummarizationNode
<span id="__span-5-6">from langgraph.graph import StateGraph, START, MessagesState
<span id="__span-5-7">
<span id="__span-5-8">class State(MessagesState):
<span id="__span-5-9"> context: dict[str, Any]
<span id="__span-5-10">
<span id="__span-5-11">class LLMInputState(TypedDict):
<span id="__span-5-12"> summarized_messages: list[AnyMessage]
<span id="__span-5-13"> context: dict[str, Any]
<span id="__span-5-14">
<span id="__span-5-15">summarization_node = SummarizationNode(
<span id="__span-5-16"> token_counter=count_tokens_approximately,
<span id="__span-5-17"> model=summarization_model,
<span id="__span-5-18"> max_tokens=512,
<span id="__span-5-19"> max_tokens_before_summary=256,
<span id="__span-5-20"> max_summary_tokens=256,
<span id="__span-5-21">)
<span id="__span-5-22">
<span id="__span-5-23">def call_model(state: LLMInputState):
<span id="__span-5-24"> response = model.invoke(state["summarized_messages"])
<span id="__span-5-25"> return {"messages": [response]}
<span id="__span-5-26">
<span id="__span-5-27">builder = StateGraph(State)
<span id="__span-5-28">builder.add_node(call_model)
<span id="__span-5-29">builder.add_node("summarize", summarization_node)
<span id="__span-5-30">builder.add_edge(START, "summarize")
<span id="__span-5-31">builder.add_edge("summarize", "call_model")
<span id="__span-5-32">...
完整示例:总结消息
<span id="__span-6-1">from typing import Any, TypedDict
<span id="__span-6-2">
<span id="__span-6-3">from langchain.chat_models import init_chat_model
<span id="__span-6-4">from langchain_core.messages import AnyMessage
<span id="__span-6-5">from langchain_core.messages.utils import count_tokens_approximately
<span id="__span-6-6">from langgraph.graph import StateGraph, START, MessagesState
<span id="__span-6-7">from langgraph.checkpoint.memory import InMemorySaver
<span id="__span-6-8">from langmem.short_term import SummarizationNode
<span id="__span-6-9">
<span id="__span-6-10">model = init_chat_model("anthropic:claude-3-7-sonnet-latest")
<span id="__span-6-11">summarization_model = model.bind(max_tokens=128)
<span id="__span-6-12">
<span id="__span-6-13">class State(MessagesState):
<span id="__span-6-14"> context: dict[str, Any]
<span id="__span-6-15">
<span id="__span-6-16">class LLMInputState(TypedDict):
<span id="__span-6-17"> summarized_messages: list[AnyMessage]
<span id="__span-6-18"> context: dict[str, Any]
<span id="__span-6-19">
<span id="__span-6-20">summarization_node = SummarizationNode(
<span id="__span-6-21"> token_counter=count_tokens_approximately,
<span id="__span-6-22"> model=summarization_model,
<span id="__span-6-23"> max_tokens=256,
<span id="__span-6-24"> max_tokens_before_summary=256,
<span id="__span-6-25"> max_summary_tokens=128,
<span id="__span-6-26">)
<span id="__span-6-27">
<span id="__span-6-28">def call_model(state: LLMInputState):
<span id="__span-6-29"> response = model.invoke(state["summarized_messages"])
<span id="__span-6-30"> return {"messages": [response]}
<span id="__span-6-31">
<span id="__span-6-32">checkpointer = InMemorySaver()
<span id="__span-6-33">builder = StateGraph(State)
<span id="__span-6-34">builder.add_node(call_model)
<span id="__span-6-35">builder.add_node("summarize", summarization_node)
<span id="__span-6-36">builder.add_edge(START, "summarize")
<span id="__span-6-37">builder.add_edge("summarize", "call_model")
<span id="__span-6-38">graph = builder.compile(checkpointer=checkpointer)
<span id="__span-6-39">
<span id="__span-6-40"># Invoke the graph
<span id="__span-6-41">config = {"configurable": {"thread_id": "1"}}
<span id="__span-6-42">graph.invoke({"messages": "hi, my name is bob"}, config)
<span id="__span-6-43">graph.invoke({"messages": "write a short poem about cats"}, config)
<span id="__span-6-44">graph.invoke({"messages": "now do the same but for dogs"}, config)
<span id="__span-6-45">final_response = graph.invoke({"messages": "what's my name?"}, config)
<span id="__span-6-46">
<span id="__span-6-47">final_response["messages"][-1].pretty_print()
<span id="__span-6-48">print("\nSummary:", final_response["context"]["running_summary"].summary)
<code tabindex="0"><span id="__span-7-1">================================== Ai Message ==================================
<span id="__span-7-2">
<span id="__span-7-3">From our conversation, I can see that you introduced yourself as Bob. That's the name you shared with me when we began talking.
<span id="__span-7-4">
<span id="__span-7-5">Summary: In this conversation, I was introduced to Bob, who then asked me to write a poem about cats. I composed a poem titled "The Mystery of Cats" that captured cats' graceful movements, independent nature, and their special relationship with humans. Bob then requested a similar poem about dogs, so I wrote "The Joy of Dogs," which highlighted dogs' loyalty, enthusiasm, and loving companionship. Both poems were written in a similar style but emphasized the distinct characteristics that make each pet special.
删除消息¶
要从图状态中删除消息,您可以使用 RemoveMessage。
-
删除特定消息
<span id="__span-8-1">from langchain_core.messages import RemoveMessage <span id="__span-8-2"> <span id="__span-8-3">def delete_messages(state): <span id="__span-8-4"> messages = state["messages"] <span id="__span-8-5"> if len(messages) > 2: <span id="__span-8-6"> # remove the earliest two messages <span id="__span-8-7"> return {"messages": [RemoveMessage(id=m.id) for m in messages[:2]]} -
删除所有消息
<span id="__span-9-1">from langgraph.graph.message import REMOVE_ALL_MESSAGES <span id="__span-9-2"> <span id="__span-9-3">def delete_messages(state): <span id="__span-9-4"> return {"messages": [RemoveMessage(id=REMOVE_ALL_MESSAGES)]}
有效的消息历史
删除消息时,请确保生成的消息历史有效。检查您正在使用的 LLM 提供商的限制。例如:
- 有些提供商期望消息历史以
user消息开头 - 大多数提供商要求带有工具调用的
assistant消息后跟相应的tool结果消息。
完整示例:删除消息
<span id="__span-10-1">from langchain_core.messages import RemoveMessage
<span id="__span-10-2">
<span id="__span-10-3">def delete_messages(state):
<span id="__span-10-4"> messages = state["messages"]
<span id="__span-10-5"> if len(messages) > 2:
<span id="__span-10-6"> # remove the earliest two messages
<span id="__span-10-7"> return {"messages": [RemoveMessage(id=m.id) for m in messages[:2]]}
<span id="__span-10-8">
<span id="__span-10-9">def call_model(state: MessagesState):
<span id="__span-10-10"> response = model.invoke(state["messages"])
<span id="__span-10-11"> return {"messages": response}
<span id="__span-10-12">
<span id="__span-10-13">builder = StateGraph(MessagesState)
<span id="__span-10-14">builder.add_sequence([call_model, delete_messages])
<span id="__span-10-15">builder.add_edge(START, "call_model")
<span id="__span-10-16">
<span id="__span-10-17">checkpointer = InMemorySaver()
<span id="__span-10-18">app = builder.compile(checkpointer=checkpointer)
<span id="__span-10-19">
<span id="__span-10-20">for event in app.stream(
<span id="__span-10-21"> {"messages": [{"role": "user", "content": "hi! I'm bob"}]},
<span id="__span-10-22"> config,
<span id="__span-10-23"> stream_mode="values"
<span id="__span-10-24">):
<span id="__span-10-25"> print([(message.type, message.content) for message in event["messages"]])
<span id="__span-10-26">
<span id="__span-10-27">for event in app.stream(
<span id="__span-10-28"> {"messages": [{"role": "user", "content": "what's my name?"}]},
<span id="__span-10-29"> config,
<span id="__span-10-30"> stream_mode="values"
<span id="__span-10-31">):
<span id="__span-10-32"> print([(message.type, message.content) for message in event["messages"]])
<code tabindex="0"><span id="__span-11-1">[('human', "hi! I'm bob")]
<span id="__span-11-2">[('human', "hi! I'm bob"), ('ai', 'Hi Bob! How are you doing today? Is there anything I can help you with?')]
<span id="__span-11-3">[('human', "hi! I'm bob"), ('ai', 'Hi Bob! How are you doing today? Is there anything I can help you with?'), ('human', "what's my name?")]
<span id="__span-11-4">[('human', "hi! I'm bob"), ('ai', 'Hi Bob! How are you doing today? Is there anything I can help you with?'), ('human', "what's my name?"), ('ai', 'Your name is Bob.')]
<span id="__span-11-5">[('human', "what's my name?"), ('ai', 'Your name is Bob.')]
- 原文作者:知识铺
- 原文链接:https://index.zshipu.com/ai002/post/20251125/%E7%AE%A1%E7%90%86%E5%86%85%E5%AD%98-LangChain-%E6%A1%86%E6%9E%B6/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。
- 免责声明:本页面内容均来源于站内编辑发布,部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性,如涉及版权等问题,请立即联系客服进行更改或删除,保证您的合法权益。转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。也可以邮件至 sblig@126.com