LangChain核心组件之Short-term memory

概述

记忆是一种用于记录先前交互信息的系统。对于 AI Agent(智能体)而言,记忆至关重要——它使智能体能够记住过往对话、从用户反馈中学习,并适应用户的偏好。随着智能体处理的任务越来越复杂、交互轮次越来越多,这种能力对提升效率和用户体验变得不可或缺。

短期记忆允许你的应用在单个线程(thread)或一次会话(conversation)中记住之前的交互内容。

注:
一个 线程(thread) 用于组织一次会话中的多次交互,类似于电子邮件中将多条消息归为同一对话的方式。

最常见的短期记忆形式就是对话历史。然而,长对话对当前的大语言模型(LLM)构成了挑战:完整的对话历史可能超出 LLM 的上下文窗口(context window),导致上下文丢失或出错。

即使你的模型支持超长上下文,大多数 LLM 在处理过长上下文时表现依然不佳——它们容易被陈旧或无关的内容“干扰”,同时还会带来响应变慢和成本上升的问题。

聊天模型通过 消息(messages) 接收上下文,这些消息包括指令(system message)和用户输入(human message)。在聊天应用中,消息通常在用户输入与模型回复之间交替出现,随着时间推移形成一个不断增长的消息列表。由于上下文窗口有限,许多应用都需要采用一些策略来移除或“遗忘”过时的信息。

使用方法

要为智能体添加短期记忆(即线程级别的持久化能力),你需要在创建智能体时指定一个 checkpointer。

说明:
LangChain 的智能体将短期记忆作为其状态(state)的一部分进行管理。
通过将这些状态存储在图(graph)中,智能体可以在保持不同线程隔离的同时,访问特定会话的完整上下文。
状态通过 checkpointer 持久化到数据库(或内存)中,使得线程可以在任意时刻恢复。
每次调用智能体或完成一个步骤(如工具调用)后,短期记忆会被更新;而在每个步骤开始时,状态会被读取。

from langchain.agents import create_agent
from langgraph.checkpoint.memory import InMemorySaver  

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

agent.invoke(
    {"messages": [{"role": "user", "content": "Hi! My name is Bob."}]},
    {"configurable": {"thread_id": "1"}},  
)
在生产环境中

在生产环境中,应使用基于数据库的 checkpointer:

pip install langgraph-checkpoint-postgres
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()  # 自动在 PostgreSQL 中创建所需表
    agent = create_agent(
        "gpt-5",
        tools=[get_user_info],
        checkpointer=checkpointer,  
    )

自定义智能体记忆

默认情况下,智能体使用 AgentState 来管理短期记忆,特别是通过 messages 键保存对话历史。

你可以通过继承 AgentState 来添加自定义字段。自定义的状态结构(state schema)可通过 create_agent 的 state_schema 参数传入。

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",
    tools=[get_user_info],
    state_schema=CustomAgentState,   
    checkpointer=InMemorySaver(),
)

# 调用时可传入自定义状态
result = agent.invoke(
    {
        "messages": [{"role": "user", "content": "Hello"}],
        "user_id": "user_123",       
        "preferences": {"theme": "dark"}  
    },
    {"configurable": {"thread_id": "1"}}
)

常见模式

启用 短期记忆 后,长对话仍可能超出 LLM 的上下文窗口。常见解决方案包括:

移除最前或最后 N 条消息(在调用 LLM 前) 从 LangGraph 状态中永久删除消息 将早期消息摘要后替换原消息 自定义策略(如消息过滤等)
这些方法可帮助智能体在不超出上下文限制的前提下,持续跟踪对话上下文。

裁剪消息(Trim messages)

大多数 LLM 都有最大上下文长度限制(以 token 计)。

一种判断何时裁剪消息的方法是:统计消息历史中的 token 数量,当接近上限时进行截断。如果你使用 LangChain,可以借助内置的 trim messages 工具,指定保留多少 token,并选择裁剪策略(例如保留最近的 max_tokens)。

要在智能体中裁剪消息历史,可使用 @before_model 中间件装饰器:

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:
    """仅保留最近几条消息,以适配上下文窗口。"""
    messages = state["messages"]
    if len(messages) <= 3:
        return None  # 无需修改

    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(
    your_model_here,
    tools=your_tools_here,
    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()
"""
================================== Ai Message ==================================

Your name is Bob. You told me that earlier.
If you'd like me to call you a nickname or use a different name, just say the word.
"""
删除消息(Delete messages)

你可以从图状态中删除消息,以管理消息历史。这在需要移除特定消息或清空整个历史时非常有用。

要删除消息,需使用 RemoveMessage。

注意:RemoveMessage 要求状态键使用 add_messages 这个 reducer(归约器)。

默认的 AgentState 已经提供了该功能。

  1. 删除特定消息:
from langchain.messages import RemoveMessage

def delete_messages(state):
    messages = state["messages"]
    if len(messages) > 2:
        # 删除最早的两条消息
        return {"messages": [RemoveMessage(id=m.id) for m in messages[:2]]}
  1. 删除全部消息:
from langgraph.graph.message import REMOVE_ALL_MESSAGES

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

警告:
删除消息时,请确保剩余的消息历史仍然有效。请参考你所用 LLM 提供商的限制,例如:
某些提供商要求消息历史必须以 user 消息开头;
大多数提供商要求带有工具调用的 assistant 消息后必须紧跟对应的 tool 结果消息。

示例:

# 使用 @after_model 中间件在模型调用后删除旧消息
@after_model
def delete_old_messages(state: AgentState, runtime: Runtime) -> dict | None:
    messages = state["messages"]
    if len(messages) > 2:
        return {"messages": [RemoveMessage(id=m.id) for m in messages[:2]]}
    return None

# ...(后续调用略)

输出示例显示:随着新消息加入,旧消息被逐步移除,但关键信息(如用户名)仍被保留。

摘要消息(Summarize messages)
上述裁剪或删除消息的方法可能导致重要信息丢失。因此,某些应用更适合采用更高级的策略:使用 LLM 对历史消息进行摘要。
在这里插入图片描述
LangChain 提供了内置的 SummarizationMiddleware 来实现这一功能:

from langchain.agents import create_agent
from langchain.agents.middleware import SummarizationMiddleware
from langgraph.checkpoint.memory import InMemorySaver

agent = create_agent(
    model="gpt-4o",
    tools=[],
    middleware=[
        SummarizationMiddleware(
            model="gpt-4o-mini",
            trigger=("tokens", 4000),  # 当 token 数超过 4000 时触发摘要
            keep=("messages", 20)      # 保留最近 20 条消息
        )
    ],
    checkpointer=InMemorySaver(),
)

config = {"configurable": {"thread_id": "1"}}
agent.invoke({"messages": "hi, my name is bob"}, config)
# ... 多轮交互后
final_response = agent.invoke({"messages": "what's my name?"}, config)
final_response["messages"][-1].pretty_print()
"""
================================== Ai Message ==================================

Your name is Bob!
"""

更多配置选项请参阅 SummarizationMiddleware 文档

访问记忆

你可以通过多种方式访问和修改智能体的短期记忆(即状态):

在工具(Tools)中
  1. 读取短期记忆

在工具函数中,可通过 runtime 参数(类型为 ToolRuntime)访问当前状态。

该参数对模型不可见(不会出现在工具签名中),但工具内部可读取状态。

from langchain.agents import create_agent, AgentState
from langchain.tools import tool, ToolRuntime


class CustomState(AgentState):
    user_id: str

@tool
def get_user_info(
    runtime: ToolRuntime
) -> str:
    """Look up user info."""
    user_id = runtime.state["user_id"]
    return "User is John Smith" if user_id == "user_123" else "Unknown user"

agent = create_agent(
    model="gpt-5-nano",
    tools=[get_user_info],
    state_schema=CustomState,
)

result = agent.invoke({
    "messages": "look up user information",
    "user_id": "user_123"
})
print(result["messages"][-1].content)
# > User is John Smith.
  1. 写入短期记忆

工具可通过返回 Command 对象直接更新智能体状态,适用于保存中间结果或供后续步骤使用。

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 | Command:
    """Use this to greet the user once you found their info."""
    user_name = runtime.state.get("user_name", None)
    if user_name is None:
       return Command(update={
            "messages": [
                ToolMessage(
                    "Please call the 'update_user_info' tool it will get and update the user's name.",
                    tool_call_id=runtime.tool_call_id
                )
            ]
        })
    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"),
)
在提示词(Prompt)中

通过中间件动态生成系统提示词,可基于对话历史或自定义状态字段构建个性化 prompt。

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()
在模型调用前(@before_model)

可在模型调用前处理消息,例如裁剪、过滤或注入上下文。
在这里插入图片描述

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 langchain_core.runnables import RunnableConfig
from langgraph.runtime import Runtime
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(
    "gpt-5-nano",
    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()
"""
================================== Ai Message ==================================

Your name is Bob. You told me that earlier.
If you'd like me to call you a nickname or use a different name, just say the word.
"""
在模型调用后(@after_model)

可在模型生成回复后进行后处理,例如过滤敏感内容:
在这里插入图片描述

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(),
)
已经博主授权,源码转载自 https://pan.quark.cn/s/a4b39357ea24 常见问题解答 网页打开速度慢或者打不开网页? 受到多种因素的影响,对于非会员用户我们无法提供最优质的服务。 如果您希望得到最棒的体验,请至大会员页面("右上角菜单 → 大会员")根据说明操作。 请注意:受制于国际网络的诸多不确定性,我们无法对任何服务的可靠性做出任何保证。 如果出现了网络连接相关的问题,我们建议您先等待一段时间,之后再重试。 如果您在重试后发现问题仍然存在,请联系我们,并说明网络问题持续的时间。 图片下载后无法找到? 打开"右上角菜单 → 更多 → 修改下载路径",在弹出的对话框中可以看到当前图片的保存路径。 此外,由于网络因素,在保存图片之后,等待屏幕下方出现"已保存到..."后,才能在本地找到图片。 如何更改图片保存的目录? 请参见"右上角菜单 → 更多 → 修改下载路径"。 翻页不方便? 在点进某个图片后,通过在图片上向左或向右滑动,即可翻页查看下一个作品。 如何保存原图/导出动图? 长按图片/动图,在弹出的菜单中选择保存/导出即可。 输入账号密码后出现"进行人机身份验证"? 此为pixiv登陆时的验证码,请按照要求点击方框或图片。 在pxvr中注册pixiv账号后,收到验证邮件,无法访问邮件中的验证链接? 请复制邮件中的链接,打开pxvr中的"右上角菜单 → 输入地址"进行访问。 能否自动将页面内容翻译为汉语? 很抱歉,pxvr暂不提供语言翻译服务。 图片下载类型是否可以选择? 能否批量下载/批量管理下载? 已支持批量下载多图作品中的所有原图:找到一个多图作品,进入详情页面后,点击图片进入多图浏览模式,长按任意一张图片即可看到批量下载选项。 关于上述其他功能,我们...
考虑局部遮阴的光伏PSO-MPPT控制模型(Simulink仿真实现)内容概要:本文介绍了基于Simulink仿真实现的考虑局部遮阴的光伏PSO-MPPT控制模型,旨在通过粒子群优化(PSO)算法解决光伏发电系统在局部阴影条件下最大功率点跟踪(MPPT)的效率问题。文档不仅提供了该模型的技术实现方法,还列举了大量相关的MATLAB/Simulink仿真资源,涵盖电力系统、智能优化算法、机器学习、路径规划、信号处理等多个科研方向,适用于复现高水平期刊论文和开展创新性研究。文中强调科研需逻辑缜密、善于借力,并提倡结合实际仿真与理论分析以提升研究深度。 适合人群:具备一定电力电子、自动控制或新能源背景,熟悉MATLAB/Simulink环境,从事光伏系统优化、智能算法应用或相关领域研究的研发人员及硕博研究生。 使用场景及目标:①研究局部遮阴下光伏系统MPPT控制策略的性能提升;②利用PSO等智能优化算法解决非线性、多峰值优化问题;③复现SCI/EI级别论文中的MPPT控制模型;④开展光伏系统建模与仿真教学或项目开发。 阅读建议:建议读者结合文档提供的网盘资源,下载完整代码与模型文件,按照目录顺序逐步学习,重点理解PSO算法在MPPT中的应用机制,并通过修改参数、对比实验等方式深入掌握仿真细节,提升工程实践与科研创新能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SunnyRivers

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值