LangChain 1.0智能体开发:记忆组件

阅读本文您将了解到:

  • 记忆系统的作用:记录过往的互动信息、推断对方的偏好,维持连贯的交互语境。
  • LangChain记忆组件:langchain.agents.AgentStatelanggraph.checkpoint.memory
  • LangChain记忆组件的使用方法:checkpointer设置。
  • 自定义智能体记忆:记忆自定义及state_schema设置。
  • 超长记忆的管理策略:修剪、清除、摘要、定制化。
  • 智能体记忆的访问途径:工具、中间件。

记忆是一种能记录以往交互信息的系统。对于人工智能智能体(AI agents)而言,记忆至关重要,因为它能让智能体记住之前的交互过程、从反馈中学习,并适应用户的偏好。当智能体需要处理更复杂的任务(这类任务往往涉及大量用户交互)时,这种记忆能力对于提升效率和满足用户需求两方面都不可或缺。 短期记忆能让你的应用程序记住单一线程或单次对话内的过往交互信息。对话历史是短期记忆最常见的形式。

超长对话对当前的大型语言模型(LLMs)构成挑战: 完整的对话历史可能无法装入大型语言模型的上下文窗口,进而导致上下文丢失或出错。 即便你的模型支持完整的上下文长度,大多数大型语言模型在处理长上下文时表现依然欠佳。它们会被过时 或偏离主题的内容 "分散注意力",同时还会面临响应速度变慢、成本升高的问题。

对话模型通过消息来接收上下文,这些消息包括指令(即系统消息)和输入(即人类消息)。在对话应用中,消息在人类输入与模型响应之间交替出现,形成一个随时间推移不断变长的消息列表。由于上下文窗口存在局限性,许多应用可借助相关技术移除或 "遗忘" 过时信息,从而从中获益。

本文结合以上问题对LangChain记忆组件进行深度解析。

Part1 基本用法

要为智能体添加短期记忆(即线程级持久性),需在创建智能体时设置一个检查点对象。

python 复制代码
from langchain.chat_models import init_chat_model
from langchain.agents import create_agent
from langchain.tools import tool
from langgraph.checkpoint.memory import InMemorySaver  
from config import api_key, api_base

def init_model():
    model = init_chat_model(
        api_key = api_key,
        base_url = api_base,
        model = "Qwen/Qwen3-8B",
        model_provider = "openai",
        temperature = 0.7,
    )
    return model

@tool
def get_user_info(name: str) -> str:
    """获取用户信息"""
    return f"用户 {name} 的信息是:姓名: {name}, 年龄: 28岁, 性别:男, 爱好:旅游、滑雪、喝茶。"

model=init_model()
agent = create_agent(
    model=model,
    tools=[get_user_info],
    checkpointer=InMemorySaver(),  # 设置内存记忆
)

config={"configurable": {"thread_id": "1"}}
# 第一轮对话
respones=agent.invoke({"messages": [{"role": "user", "content": "Hi! My name is Bob."}]}, config)
print(respones["messages"][-1].content)
# 第二轮对话
respones=agent.invoke({"messages": [{"role": "user", "content": "What's my name?"}]}, config)
print(respones["messages"][-1].content)
# 查看记忆
state=agent.get_state(config)
print(state.values)

在生产环境中,应使用由数据库提供支持的检查点对象。

shell 复制代码
pip install langgraph-checkpoint-postgres
python 复制代码
from langchain.agents import create_agent
from langgraph.checkpoint.postgres import PostgresSaver  


DB_URI = "postgresql://postgres:postgres@localhost:5442/postgres?sslmode=disable"
with PostgresSaver.from_conn_string(DB_URI) as checkpointer:
    checkpointer.setup() # auto create tables in PostgresSql
    agent = create_agent(
        "gpt-5",
        [get_user_info],
        checkpointer=checkpointer,  
    )

Part2 定制化智能体记忆

默认情况下,智能体使用AgentState管理短期记忆。AgentState是一个键为messages,值为历史对话消息列表的字典。开发者可以通过添加额外的字段来扩展AgentState。自定义状态模式通过state_schema参数传递给 create_agent接口。

python 复制代码
from langchain.agents import create_agent, AgentState
from langgraph.checkpoint.memory import InMemorySaver

class CustomAgentState(AgentState):  
    user_id: str
    preferences: dict

agent = create_agent(
    "gpt-5",
    [get_user_info],
    state_schema=CustomAgentState,  
    checkpointer=InMemorySaver(),
)

# Custom state can be passed in invoke
result = agent.invoke(
    {
        "messages": [{"role": "user", "content": "Hello"}],
        "user_id": "user_123",  
        "preferences": {"theme": "dark"}  
    },
    {"configurable": {"thread_id": "1"}})

Part3 超长记忆的管理策略

启用短期记忆后, 超长对话可能会超出大型语言模型(LLM)的上下文窗口。常见的解决方案如下:

  • 修剪消息
    (调用大型语言模型前)移除最先或最后 N 条消息
  • 删除消息
    从 LangGraph 状态中永久删除消息
  • 总结消息
    对历史记录中较早的消息进行总结,并用总结内容替代原消息
  • 自定义策略
    自定义策略(例如,消息过滤等)

这些策略可以使智能体在不超出大型语言模型(LLM)上下文窗口的前提下,对对话进行跟踪记录。

3.1 修剪消息

大多数大模型都有一个支持的最大上下文窗口(以 token 为单位计量)。 判断何时截断消息的一种方法是统计消息历史中的 token 数量,每当数量接近该上限时就进行截断。使用LangChain框架,可以借助修剪消息中间件,指定要从消息列表中保留的 token 数量,同时设置用于处理边界问题的策略(例如,保留最后 max_tokens 个 token)。 若要在智能体中修剪消息历史,可使用@before_model中间件装饰器:

python 复制代码
from langchain.messages import RemoveMessage
from langgraph.graph.message import REMOVE_ALL_MESSAGES
from langgraph.checkpoint.memory import InMemorySaver
from langchain.agents import create_agent, AgentState
from langchain.agents.middleware import before_model
from langgraph.runtime import Runtime
from langchain_core.runnables import RunnableConfig
from typing import Any


@before_model
def trim_messages(state: AgentState, runtime: Runtime) -> dict[str, Any] | None:
    """Keep only the last few messages to fit context window."""
    messages = state["messages"]

    if len(messages) <= 3:
        return None  # No changes needed

    first_msg = messages[0]
    recent_messages = messages[-3:] if len(messages) % 2 == 0 else messages[-4:]
    new_messages = [first_msg] + recent_messages

    return {
        "messages": [
            RemoveMessage(id=REMOVE_ALL_MESSAGES),
            *new_messages
        ]
    }

agent = create_agent(
    model,
    tools=tools,
    middleware=[trim_messages],
    checkpointer=InMemorySaver(),
)

config: RunnableConfig = {"configurable": {"thread_id": "1"}}

agent.invoke({"messages": "hi, my name is bob"}, config)
agent.invoke({"messages": "write a short poem about cats"}, config)
agent.invoke({"messages": "now do the same but for dogs"}, config)
final_response = agent.invoke({"messages": "what's my name?"}, config)

final_response["messages"][-1].pretty_print()

3.2 删除消息

你可以从图状态中删除消息,以管理消息历史。 当你需要移除特定消息或清空全部消息历史时,此功能十分实用。 若要从图状态中删除消息,可使用 RemoveMessage(消息移除工具)。 默认的 AgentState(智能体状态)已提供该状态键。 移除特定消息的操作方法如下:

python 复制代码
from langchain.messages import RemoveMessage  

def delete_messages(state):
    messages = state["messages"]
    if len(messages) > 2:
        # remove the earliest two messages
        return {"messages": [RemoveMessage(id=m.id) for m in messages[:2]]}

移除所有消息:

python 复制代码
python
from langgraph.graph.message import REMOVE_ALL_MESSAGES

def delete_messages(state):
    return {"messages": [RemoveMessage(id=REMOVE_ALL_MESSAGES)]} 

3.3 消息摘要

如上所述,修剪或删除消息存在一个问题:消息队列的筛选操作可能会导致信息丢失。正因为如此,部分应用会采用一种更完善的方案 ------ 借助对话模型对消息历史进行总结,这种方式能为其带来实际益处。要在智能体中总结消息历史,可使用内置的总结中间件(SummarizationMiddleware)。

python 复制代码
from langchain.agents import create_agent
from langchain.agents.middleware import SummarizationMiddleware
from langgraph.checkpoint.memory import InMemorySaver
from langchain_core.runnables import RunnableConfig


checkpointer = InMemorySaver()

agent = create_agent(
    model="gpt-4o",
    tools=[],
    middleware=[
        SummarizationMiddleware(
            model="gpt-4o-mini",
            max_tokens_before_summary=4000,  # Trigger summarization at 4000 tokens
            messages_to_keep=20,  # Keep last 20 messages after summary
        )
    ],
    checkpointer=checkpointer,
)

config: RunnableConfig = {"configurable": {"thread_id": "1"}}
agent.invoke({"messages": "hi, my name is bob"}, config)
agent.invoke({"messages": "write a short poem about cats"}, config)
agent.invoke({"messages": "now do the same but for dogs"}, config)
final_response = agent.invoke({"messages": "what's my name?"}, config)

final_response["messages"][-1].pretty_print()

##3.4 自定义策略

Part4 访问智能体记忆

4.1 通过工具

4.1.1 在工具中读取短期记忆

借助ToolRuntime参数在工具中访问短期记忆(状态)。 tool_runtime参数不会显示在工具的签名中(因此模型无法看到它),但工具可以通过该参数访问状态。

4.1.2 从工具中写入短期记忆

若要在执行过程中修改智能体的短期记忆(即状态),可直接通过工具返回状态更新内容。 此功能对于持久化存储中间结果,或让后续工具、提示词能够获取相关信息而言十分实用。

python 复制代码
from langchain.tools import tool, ToolRuntime
from langchain_core.runnables import RunnableConfig
from langchain.messages import ToolMessage
from langchain.agents import create_agent, AgentState
from langgraph.types import Command
from pydantic import BaseModel


class CustomState(AgentState):  
    user_name: str

class CustomContext(BaseModel):
    user_id: str

@tool
def update_user_info(
    runtime: ToolRuntime[CustomContext, CustomState],
) -> Command:
    """Look up and update user info."""
    user_id = runtime.context.user_id  
    name = "John Smith" if user_id == "user_123" else "Unknown user"
    return Command(update={
        "user_name": name,
        # update the message history
        "messages": [
            ToolMessage(
                "Successfully looked up user information",
                tool_call_id=runtime.tool_call_id
            )
        ]
    })

@tool
def greet(
    runtime: ToolRuntime[CustomContext, CustomState]
) -> str:
    """Use this to greet the user once you found their info."""
    user_name = runtime.state["user_name"]
    return f"Hello {user_name}!"
agent = create_agent(
    model="gpt-5-nano",
    tools=[update_user_info, greet],
    state_schema=CustomState,
    context_schema=CustomContext,  
)

agent.invoke(
    {"messages": [{"role": "user", "content": "greet the user"}]},
    context=CustomContext(user_id="user_123"),
)

4.2 通过中间件

在中间件中访问短期记忆(即状态,state),以基于对话历史或自定义状态字段创建动态提示词。 在@before_model中间件中访问短期记忆(即状态,state),以便在调用模型前处理消息。 在@after_model中间件中访问短期记忆(即状态,state),以便在调用模型后处理消息。

python 复制代码
from langchain.agents import create_agent
from typing import TypedDict
from langchain.agents.middleware import dynamic_prompt, ModelRequest


class CustomContext(TypedDict):
    user_name: str


def get_weather(city: str) -> str:
    """Get the weather in a city."""
    return f"The weather in {city} is always sunny!"


@dynamic_prompt
def dynamic_system_prompt(request: ModelRequest) -> str:
    user_name = request.runtime.context["user_name"]
    system_prompt = f"You are a helpful assistant. Address the user as {user_name}."
    return system_prompt


agent = create_agent(
    model="gpt-5-nano",
    tools=[get_weather],
    middleware=[dynamic_system_prompt],
    context_schema=CustomContext,
)

result = agent.invoke(
    {"messages": [{"role": "user", "content": "What is the weather in SF?"}]},
    context=CustomContext(user_name="John Smith"),
)
for msg in result["messages"]:
    msg.pretty_print()
python 复制代码
from langchain.messages import RemoveMessage
from langgraph.checkpoint.memory import InMemorySaver
from langchain.agents import create_agent, AgentState
from langchain.agents.middleware import after_model
from langgraph.runtime import Runtime


@after_model
def validate_response(state: AgentState, runtime: Runtime) -> dict | None:
    """Remove messages containing sensitive words."""
    STOP_WORDS = ["password", "secret"]
    last_message = state["messages"][-1]
    if any(word in last_message.content for word in STOP_WORDS):
        return {"messages": [RemoveMessage(id=last_message.id)]}
    return None

agent = create_agent(
    model="gpt-5-nano",
    tools=[],
    middleware=[validate_response],
    checkpointer=InMemorySaver(),
)

Part5 总结

  • 记忆系统的作用:记录过往的互动信息、推断对方的偏好,维持连贯的交互语境。
  • LangChain记忆组件:langchain.agents.AgentStatelanggraph.checkpoint.memory
  • LangChain记忆组件的使用方法:checkpointer设置。
  • 自定义智能体记忆:记忆自定义及state_schema设置。
  • 超长记忆的管理策略:修剪、清除、摘要、定制化。
  • 智能体记忆的访问途径:工具、中间件。
相关推荐
Geoking.2 小时前
PyTorch 中 model.eval() 的使用与作用详解
人工智能·pytorch·python
nn在炼金2 小时前
图模式分析:PyTorch Compile组件解析
人工智能·pytorch·python
Danceful_YJ2 小时前
25.样式迁移
人工智能·python·深度学习
悟乙己2 小时前
使用 RAG、LangChain、FastAPI 和 Streamlit 构建 Text-to-SQL 聊天机器人
sql·langchain·fastapi
woshihonghonga2 小时前
Deepseek在它擅长的AI数据处理领域还有是有低级错误【k折交叉验证中每折样本数计算】
人工智能·python·深度学习·机器学习
乌恩大侠2 小时前
以 NVIDIA Sionna Research Kit 赋能 AI 原生 6G 科研
人工智能·usrp
三掌柜6663 小时前
借助 Kiro:实现《晚间手机免打扰》应用,破解深夜刷屏困境
人工智能·aws
飞雁科技3 小时前
CRM客户管理系统定制开发:如何精准满足企业需求并提升效率?
大数据·运维·人工智能·devops·驻场开发
飞雁科技3 小时前
上位机软件定制开发技巧:如何打造专属工业解决方案?
大数据·人工智能·软件开发·devops·驻场开发