Langchain_v1.0|核心模块-core_component_05_short_term_memory

Langchain_v1.0|核心模块-core_component_05_short_term_memory

  • [@短期记忆 Short Term Memory](#@短期记忆 Short Term Memory)

    • [@Overview 概述](#@Overview 概述)

    • [@Usage 使用](#@Usage 使用)

    • [@In production 生产环境](#@In production 生产环境)

    • [@Customizing agent memory 自定义代理内存](#@Customizing agent memory 自定义代理内存)

    • [@Common patterns 常见模式](#@Common patterns 常见模式)

      • [@Trim messages 修剪消息](#@Trim messages 修剪消息)
      • [@delete message 删除消息](#@delete message 删除消息)
      • [@Summarize messages 总结消息](#@Summarize messages 总结消息)
    • [@Access memory 访问内存](#@Access memory 访问内存)

      • @Tool

        • [@Read short-term memory in a tool 从工具中读取短期记忆](#@Read short-term memory in a tool 从工具中读取短期记忆)
        • [@Write short-term memory from tools 从工具中写入短期记忆](#@Write short-term memory from tools 从工具中写入短期记忆)
    • @Prompt

    • [@Before model](#@Before model)

    • [@After model 在模型之后](#@After model 在模型之后)

短期记忆 Short Term Memory

Overview 概述

记忆是一个能够记住先前交互信息的系统。对于 AI 代理来说,记忆至关重要,因为它能让它们记住先前的交互,从反馈中学习,并适应用户偏好。随着代理处理更复杂的任务和更多的用户交互,这种能力对于效率和用户满意度都变得不可或缺。

短期记忆能让你的应用程序记住单个线程对话中的先前交互

线程将多个交互组织在一个会话中,类似于电子邮件将多条消息组织在单个对话中的方式。

对话历史是最常见的短期记忆形式

长对话对当今的 LLMs 构成挑战;完整的历史可能无法适应 LLM 的上下文窗口,导致上下文丢失或错误

即使您的模型支持完整上下文长度,大多数 LLMs 在长上下文中表现仍然不佳。它们会被过时或离题的内容"分心",同时还会遭受响应时间变慢成本增加的问题。

聊天模型通过消息接受上下文,这些消息包括指令(系统消息)输入(人类消息)。在聊天应用中,消息在人类输入和模型响应之间交替,导致消息列表随着时间的推移而增长。由于上下文窗口有限,许多应用可以从使用删除或"遗忘"过时信息的技巧中受益。

Usage 使用

为给代理添加短期记忆(线程级持久化),在创建代理时需要指定一个 checkpointer

LangChain 的代理将短期记忆作为代理状态的一部分进行管理。

通过将这些信息存储在图的状态中,代理可以在不同线程之间保持分离的同时,访问给定对话的完整上下文。

状态通过检查点器持久化到数据库(或内存)中,以便线程可以随时恢复。

短期记忆在代理被调用或一个步骤(如工具调用)完成更新,并在每个步骤开始时读取状态。

python 复制代码
from langchain.agents import create_agent

from langchain_01.models.scii_deepseekv3 import model 

from langgraph.checkpoint.memory import InMemorySaver

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

agent.invoke(
    {"messages": [{"role": "user", "content": "Hi! My name is Bob."}]},
    {"configurable": {"thread_id": "1"}},  
)
复制代码
https://api.siliconflow.cn/v1





{'messages': [HumanMessage(content='Hi! My name is Bob.', additional_kwargs={}, response_metadata={}, id='e49aeb8e-5443-4500-95da-3d46e7fa8757'),
  AIMessage(content='Hi Bob! Nice to meet you! How can I help you today?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 15, 'total_tokens': 30, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_provider': 'openai', 'model_name': 'Qwen/Qwen3-Coder-30B-A3B-Instruct', 'system_fingerprint': '', 'id': '019bdbc4e0da873dbe8a4b4cba9b4ab7', 'finish_reason': 'stop', 'logprobs': None}, id='lc_run--019bdbc4-e05f-7b63-bdfd-be76ab82fb1b-0', tool_calls=[], invalid_tool_calls=[], usage_metadata={'input_tokens': 15, 'output_tokens': 15, 'total_tokens': 30, 'input_token_details': {}, 'output_token_details': {}})]}

In production 生产环境

在·生产环境中,使用一个由数据库支持的检查点:

pip install langgraph-checkpoint-sqlite

pip install langgraph-checkpoint-postgres

python 复制代码
from langchain.agents import create_agent
from langgraph.checkpoint.sqlite import SqliteSaver
# 初始化数据库连接 sqlite3
import sqlite3
conn = sqlite3.connect("checkpoints.sqlite", check_same_thread=False)
checkpointer = SqliteSaver(conn)

agent = create_agent(
    model,
    tools=[],
    checkpointer=checkpointer,
)

agent.invoke(
    {"messages": [{"role": "user", "content": "Hi! My name is Bob."}]},
    config={"thread_id": "2"},
)

agent.invoke(
    {"messages": [{"role": "user", "content": "What is my name?"}]},
    config={"thread_id": "2"},
)
复制代码
{'messages': [HumanMessage(content='Hi! My name is Bob.', additional_kwargs={}, response_metadata={}, id='2ea89215-5e1c-405d-886b-486a296dc13a'),
  AIMessage(content='Hi Bob! Nice to meet you! How can I help you today?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 15, 'total_tokens': 30, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_provider': 'openai', 'model_name': 'Qwen/Qwen3-Coder-30B-A3B-Instruct', 'system_fingerprint': '', 'id': '019bdbcf3470a27c3971a847aff18c38', 'finish_reason': 'stop', 'logprobs': None}, id='lc_run--019bdbcf-340a-71d1-ab7c-ed6230dc6493-0', tool_calls=[], invalid_tool_calls=[], usage_metadata={'input_tokens': 15, 'output_tokens': 15, 'total_tokens': 30, 'input_token_details': {}, 'output_token_details': {}}),
  HumanMessage(content='What is my name?', additional_kwargs={}, response_metadata={}, id='147cd35c-6a57-4e31-9664-86ecc4e1824d'),
  AIMessage(content='Your name is Bob, as you introduced yourself earlier. It was nice meeting you, Bob! Is there something I can help you with today?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 29, 'prompt_tokens': 45, 'total_tokens': 74, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_provider': 'openai', 'model_name': 'Qwen/Qwen3-Coder-30B-A3B-Instruct', 'system_fingerprint': '', 'id': '019bdbcf377abf5c587490e9346a74b7', 'finish_reason': 'stop', 'logprobs': None}, id='lc_run--019bdbcf-37c8-7ee0-8bb0-7ea713f0a45c-0', tool_calls=[], invalid_tool_calls=[], usage_metadata={'input_tokens': 45, 'output_tokens': 29, 'total_tokens': 74, 'input_token_details': {}, 'output_token_details': {}})]}

Customizing agent memory 自定义代理内存

默认情况下,代理使用 AgentState 来管理短期记忆,具体通过 messages 键来管理对话历史

你可以扩展 AgentState 来添加额外的字段。自定义状态模式通过 state_schema 参数传递给 create_agent

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

# 1. 定义自定义状态模式
# 额外字段
class CustomState(AgentState):
    user_id: str
    preference: dict

# 2. 创建代理 state_schema 开启自定义状态模式 
agent = create_agent(
    model,
    tools=[],
    state_schema=CustomState,
    checkpointer=InMemorySaver(),
    system_prompt="你是一个智能助手,能够根据用户的偏好提供服务。",
)

# 3. 调用代理 传入自定义状态字段
# messages 对话
agent.invoke(
    {"messages": [{"role": "user", "content": "你好"}],
     "user_id": "123",
      "preference": {"language": "中文"}},config={"configurable":{"thread_id":"1"}}
)

# {'messages': [HumanMessage(content='你好', additional_kwargs={}, response_metadata={}, id='b85484fb-1c60-45a4-a72c-e5f83ab23413'),
#  AIMessage(content='你好!很高兴见到你!有什么我可以帮助你的吗?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 12, 'prompt_tokens': 26, 'total_tokens': 38, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_provider': 'openai', 'model_name': 'Qwen/Qwen3-Coder-30B-A3B-Instruct', 'system_fingerprint': '', 'id': '019bdbd62f2ef1ef676d64d71b0b5880', 'finish_reason': 'stop', 'logprobs': None}, id='lc_run--019bdbd6-2eec-7bf1-90db-732da288d675-0', tool_calls=[], invalid_tool_calls=[], usage_metadata={'input_tokens': 26, 'output_tokens': 12, 'total_tokens': 38, 'input_token_details': {}, 'output_token_details': {}})],
# 'user_id': '123',
# 'preference': {'language': '中文'}}
复制代码
{'messages': [HumanMessage(content='你好', additional_kwargs={}, response_metadata={}, id='b85484fb-1c60-45a4-a72c-e5f83ab23413'),
  AIMessage(content='你好!很高兴见到你!有什么我可以帮助你的吗?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 12, 'prompt_tokens': 26, 'total_tokens': 38, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_provider': 'openai', 'model_name': 'Qwen/Qwen3-Coder-30B-A3B-Instruct', 'system_fingerprint': '', 'id': '019bdbd62f2ef1ef676d64d71b0b5880', 'finish_reason': 'stop', 'logprobs': None}, id='lc_run--019bdbd6-2eec-7bf1-90db-732da288d675-0', tool_calls=[], invalid_tool_calls=[], usage_metadata={'input_tokens': 26, 'output_tokens': 12, 'total_tokens': 38, 'input_token_details': {}, 'output_token_details': {}})],
 'user_id': '123',
 'preference': {'language': '中文'}}

Common patterns 常见模式

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

  1. Trim messages 修剪消息: 移除调用大模型之前头N条或尾N条消息
  2. Delete Message 删除消息: 永久删除langgraph State中的消息
  3. Summarize messages 总结消息:总结历史记录中的早期消息,并用摘要替换它们。
  4. Custom strategies 自定义策略: 自定义策略(例如,消息过滤等)

这允许代理在不超出 LLM 的上下文窗口的情况下跟踪对话。

Trim messages 修剪消息

大多数 LLMs 都有一个最大支持上下文窗口(以 token 为单位)。

决定何时截断消息的一种方法是·通过计算消息历史中的 token 数量,并在接近该限制时进行截断

如果你使用 LangChain,可以使用 trim messages 工具,并指定要保留的 token 数量,以及使用 strategy (例如,保留最后一个 max_tokens )来处理边界。

要在代理中裁剪消息历史,请使用 @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_agent, before_model
from langgraph.runtime import Runtime
from langchain_core.runnables import RunnableConfig
from typing import TypedDict,Any

# 定义修剪消息的中间件
@before_model
def trim_messages(state:AgentState,runtime:Runtime) -> dict[str,Any]|None:
    """保留最后一部分消息适应模型的上下文窗口"""
    # 获取所有历史记录
    messages = state["messages"]
    if len(messages) <= 3:
        return None # 消息不足,不进行修剪
    # 保留第一条和最后3条消息
    first_message = messages[0]
    recent_message = messages[-3:] if len(messages) %2 == 0 else messages[-4:]
    new_message = [first_message] + recent_message

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

agent = create_agent(
    model ,
    tools = [],
    checkpointer = InMemorySaver(),
    middleware = [trim_messages],
    system_prompt = "你是一个有帮助的助手,保持回答简洁准确。"
)

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

agent.invoke({"messages": [{"role": "user", "content": "你好,我是张三"}]},config = config)
agent.invoke({"messages": [{"role": "user", "content": "写一首李白短诗"}]},config = config)
agent.invoke({"messages": [{"role": "user", "content": "解释机器学习?"}]},config = config)
final_response = agent.invoke({"messages": [{"role": "user", "content": "我是谁?"}]},config = config)

final_response["messages"][-1].pretty_print()
复制代码
==================================[1m Ai Message [0m==================================

根据之前的对话,你是张三。

不过从更深层的角度来说,"你是谁"这个问题涉及哲学层面的思考。从存在主义的角度,你是一个独特的个体,有着自己的思想、经历和身份认同。

如果你愿意分享更多关于自己的信息,我很乐意进一步了解你。

delete message 删除消息

当您想删除特定消息或清空整个消息历史时,这很有用。

要从图状态中删除消息,您可以使用 RemoveMessage

为了让 RemoveMessage 正常工作,你需要使用一个与 add_messages reducer 配合的状态键。

默认的 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 复制代码
from langgraph.graph.message import REMOVE_ALL_MESSAGES
def delete_all_messages(state):
    return {"messages": [RemoveMessage(id=REMOVE_ALL_MESSAGES)]}  
python 复制代码
from langgraph.checkpoint.memory import InMemorySaver
from langchain.agents.middleware import after_model
from langchain.agents import create_agent,AgentState
from langchain_core.runnables import RunnableConfig
from langchain.messages import RemoveMessage
from langgraph.runtime import Runtime
from langgraph.graph.message import REMOVE_ALL_MESSAGES
from typing import Any

@after_model
def delete_messages(state:AgentState,runtime:Runtime) -> dict[str,Any] | None : 
    """移除最前2条消息"""
    messages = state["messages"]
    if len(messages) >= 3:
        return {"messages": [RemoveMessage(id=m.id) for m in messages[:2]]}
    return None

agent = create_agent(
    model,
    tools=[],
    system_prompt="You are a helpful assistant. Be concise and accurate.",
    middleware=[delete_messages],
    checkpointer=InMemorySaver()
)

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

for event in agent.stream( {"messages": [{"role": "user", "content": "你好,我是刘德华"}]},
config,
stream_mode="values"
):
    print([(message.type,message.content) for message in event["messages"]])


for event in agent.stream(
        {"messages":[{"role":"user","content":"我的名字叫什么?"}]},
    config,
    stream_mode="values"
):
    print([(message.type,message.content)  for message in event["messages"]])
复制代码
[('human', '你好,我是刘德华')]
[('human', '你好,我是刘德华'), ('ai', '你好,刘德华!不过我需要澄清一下,我是通义千问,是阿里巴巴集团开发的AI助手。我并不是真正的刘德华。如果你有任何问题或需要帮助,我会尽力为你提供支持。有什么我可以帮你的吗?')]
[('human', '你好,我是刘德华'), ('ai', '你好,刘德华!不过我需要澄清一下,我是通义千问,是阿里巴巴集团开发的AI助手。我并不是真正的刘德华。如果你有任何问题或需要帮助,我会尽力为你提供支持。有什么我可以帮你的吗?'), ('human', '我的名字叫什么?')]
[('human', '你好,我是刘德华'), ('ai', '你好,刘德华!不过我需要澄清一下,我是通义千问,是阿里巴巴集团开发的AI助手。我并不是真正的刘德华。如果你有任何问题或需要帮助,我会尽力为你提供支持。有什么我可以帮你的吗?'), ('human', '我的名字叫什么?'), ('ai', '根据我们之前的对话,你的名字叫刘德华。不过我需要提醒你,我是通义千问,一个AI助手,并不是真正的刘德华。如果你有任何问题或需要帮助,我会很乐意为你提供支持。')]
[('human', '我的名字叫什么?'), ('ai', '根据我们之前的对话,你的名字叫刘德华。不过我需要提醒你,我是通义千问,一个AI助手,并不是真正的刘德华。如果你有任何问题或需要帮助,我会很乐意为你提供支持。')]

Summarize messages 总结消息

如上所示,修剪或删除消息的问题在于,你可能会因为筛选消息队列而丢失信息。由于这个原因,一些应用程序受益于使用聊天模型来总结消息历史记录的更复杂的方法。

要总结代理中的消息历史,使用内置的 SummarizationMiddleware :

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

from langgraph.checkpoint.memory import InMemorySaver


memory = InMemorySaver()

agent = create_agent(
    model , 
    tools = [],
    middleware=[SummarizationMiddleware(
        model=model,
        # 触发摘要的条件:当消息队列中的令牌数超过 1000 时触发摘要。
        # trigger:一个或多个触发摘要的阈值。可提供单个 [ContextSize][langchain.agents.middleware.summarization.ContextSize] 元组,
        # 或一个元组列表;在后一种情况下,只要满足任意一个阈值,就会执行摘要。
        # 当上下文达到 3000 个 token 时触发摘要
        #("tokens", 3000)
        # 当达到模型最大输入 token 数的 80% 或消息数量达到 100 条时触发摘要(以先达到者为准)
        #[("fraction", 0.8), ("messages", 100)]
        trigger=("tokens", 1000),
        # keep:在摘要之后应用上下文保留策略。请提供一个 [ContextSize][langchain.agents.middleware.summarization.ContextSize] 元组,以指定要保留多少历史记录。默认保留最近的 20 条消息。不支持像 trigger 那样的多个值!
        # 保留最近的 20 条消息
        keep=("messages", 20)
    )],
    checkpointer = memory ,
    system_prompt="你是一个助手,你需要根据用户的问题来回答用户的问题。"
)

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()
复制代码
==================================[1m Ai Message [0m==================================

Your name is Bob! You told me that earlier when we started talking. It's nice to meet you, Bob!

Access memory 访问内存

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

  • Tool

Tool

Read short-term memory in a tool 从工具中读取短期记忆

使用 runtime 参数(类型为 ToolRuntime )在一个工具中访问短期记忆(状态)。

runtime 参数在工具签名中被隐藏(因此模型看不到它),但工具可以通过它访问状态。

Write short-term memory from tools 从工具中写入短期记忆

要在执行过程中修改代理的短期记忆(状态),你可以直接从工具中返回状态更新。

这对于持久化中间结果或使信息可供后续工具或提示使用很有用。

python 复制代码
# read short-term memory from tools 从工具中读取短期记忆
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:
    """查找用户信息"""
    user_id = runtime.state["user_id"]
    return f"用户ID: {user_id}"

agent = create_agent(
    model=model,
    tools=[get_user_info],
    state_schema=CustomState,
    system_prompt="You are a helpful assistant. Be concise and accurate."
)

result = agent.invoke(
    {"messages": [{"role": "user", "content": "查找用户信息"}],"user_id":"12345"}
)

print(result["messages"][-1].content)
复制代码
已找到用户信息:

- **用户ID**: 12345

如果您需要更多详细信息,请告诉我!
python 复制代码
# Write short-term memory from tools 从工具中写入短期记忆

from langchain.agents import create_agent,AgentState
from langchain.tools import tool,ToolRuntime
from langchain.messages import ToolMessage
from pydantic import BaseModel 
from langgraph.types import Command

class CustomContext(BaseModel):
    user_id : str 

class CustomState(AgentState):
    user_name: str 

@tool 
def update_user_info(runtime:ToolRuntime[CustomContext,CustomState],user_name:str) -> str:
    """ 查询和更新用户信息 """
    user_id = runtime.context.user_id
    user_name = "张三" if user_id == "1" else "未知用户"
    return Command (update={
        "user_name":user_name,
        "messages":[
            ToolMessage(
                tool_call_id=runtime.tool_call_id,
                content=f"Successfully looked up user information"
            )
        ]
    })

@tool
def greet_user(runtime:ToolRuntime[CustomContext,CustomState]) -> str:
    """ 打招呼和用户 """
    user_name  = runtime.state.get("user_name",None)
    if user_name is None:
        return Command(update={
            "messages":[
                ToolMessage(
                    tool_call_id=runtime.tool_call_id,
                    content="请使用`update_user_info`工具查询和更新用户姓名"
                )
            ]
        })

    return f"Hello {user_name}"

agent = create_agent(
    model,
    tools=[update_user_info,greet_user],
    system_prompt="You are a helpful assistant. Be concise and accurate.",
    state_schema=CustomState,
    context_schema=CustomContext,
    
)

agent.invoke({"messages": [{"role": "user", "content": "打招呼给用户"}]},context=CustomContext(user_id="2"))
复制代码
{'messages': [HumanMessage(content='打招呼给用户', additional_kwargs={}, response_metadata={}, id='f84eb892-77f4-463c-9fca-915c91b9331e'),
  AIMessage(content='', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 12, 'prompt_tokens': 301, 'total_tokens': 313, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': None}, 'model_provider': 'openai', 'model_name': 'Qwen/Qwen3-Coder-30B-A3B-Instruct', 'system_fingerprint': '', 'id': '019bdc26567117a3d895712b72e982bd', 'finish_reason': 'tool_calls', 'logprobs': None}, id='lc_run--019bdc26-56b0-71e3-a651-d102fe72ba33-0', tool_calls=[{'name': 'greet_user', 'args': {}, 'id': '019bdc2658bc03e9ff9895b92965a85f', 'type': 'tool_call'}], invalid_tool_calls=[], usage_metadata={'input_tokens': 301, 'output_tokens': 12, 'total_tokens': 313, 'input_token_details': {}, 'output_token_details': {'reasoning': 0}}),
  ToolMessage(content='请使用`update_user_info`工具查询和更新用户姓名', name='greet_user', id='2b05ee9a-3f9e-4c28-b61f-5958dfe23cf1', tool_call_id='019bdc2658bc03e9ff9895b92965a85f'),
  AIMessage(content='', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 24, 'prompt_tokens': 341, 'total_tokens': 365, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': None}, 'model_provider': 'openai', 'model_name': 'Qwen/Qwen3-Coder-30B-A3B-Instruct', 'system_fingerprint': '', 'id': '019bdc265944ec65c14879d149b7a528', 'finish_reason': 'tool_calls', 'logprobs': None}, id='lc_run--019bdc26-5a80-7541-9718-2b566037910b-0', tool_calls=[{'name': 'update_user_info', 'args': {'user_name': '张三'}, 'id': '019bdc265cf7a9b1f66f146a898d3ebe', 'type': 'tool_call'}], invalid_tool_calls=[], usage_metadata={'input_tokens': 341, 'output_tokens': 24, 'total_tokens': 365, 'input_token_details': {}, 'output_token_details': {'reasoning': 0}}),
  ToolMessage(content='Successfully looked up user information', name='update_user_info', id='391c9d4a-0bfe-4456-8720-f7a1504b817a', tool_call_id='019bdc265cf7a9b1f66f146a898d3ebe'),
  AIMessage(content='我已经成功查询了用户信息。请问您需要更新用户姓名吗?如果需要,请提供新的姓名。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 385, 'total_tokens': 407, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': None}, 'model_provider': 'openai', 'model_name': 'Qwen/Qwen3-Coder-30B-A3B-Instruct', 'system_fingerprint': '', 'id': '019bdc265d99b670858dcce0910d9a5f', 'finish_reason': 'stop', 'logprobs': None}, id='lc_run--019bdc26-5ebe-7272-a34a-3fcf9f8931c0-0', tool_calls=[], invalid_tool_calls=[], usage_metadata={'input_tokens': 385, 'output_tokens': 22, 'total_tokens': 407, 'input_token_details': {}, 'output_token_details': {'reasoning': 0}})],
 'user_name': '未知用户'}

Prompt

在中间件中访问短期记忆(状态),以根据对话历史或自定义状态字段创建动态提示。

python 复制代码
from langchain.agents import create_agent
from langchain.agents.middleware import dynamic_prompt , ModelRequest 
from typing import TypedDict
from langchain.tools import tool 
# 定义自定义额外上下文
class CustomContext(TypedDict):
    user_name : str

# 定义获取天气的工具
@tool
def get_weather(city: str) -> str:
    """获取城市的天气"""
    return f"城市{city}的天气是晴朗的"

# 定义动态系统提示
@dynamic_prompt
def dynamic_system_prompt(request:ModelRequest) -> str:
    user_name = request.runtime.context["user_name"]
    return f"You  是一个助手, 可以帮助你获取城市的天气。 Address the user as {user_name}"

agent = create_agent(
    model=model,
    tools=[get_weather],
    middleware=[dynamic_system_prompt],
    context_schema=CustomContext
)

result =agent.invoke({"messages":[{"role":"user","content":"加利福尼亚的天气如何"}]}
,    context=CustomContext({"user_name":"里斯本"})
)
for msg in result["messages"]:
    msg.pretty_print()
复制代码
================================[1m Human Message [0m=================================

加利福尼亚的天气如何
==================================[1m Ai Message [0m==================================
Tool Calls:
  get_weather (019bdc349d11a181d97388ffb13c9e49)
 Call ID: 019bdc349d11a181d97388ffb13c9e49
  Args:
    city: 加利福尼亚
=================================[1m Tool Message [0m=================================
Name: get_weather

城市加利福尼亚的天气是晴朗的
==================================[1m Ai Message [0m==================================

里斯本,加利福尼亚的天气目前是晴朗的。

Before model

在 @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 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(
    model,
    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.
"""
复制代码
==================================[1m Ai Message [0m==================================

Your name is Bob! I remember you telling me that earlier in our conversation. It's nice to meet you, Bob!





"\n================================== Ai Message ==================================\n\nYour name is Bob. You told me that earlier.\nIf you'd like me to call you a nickname or use a different name, just say the word.\n"

After model 在模型之后

@after_model 中间件中访问短期记忆(状态),以在模型调用后处理消息。

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):
        print("包含敏感词:", last_message.content)
        # 移除包含敏感词的消息
        print("移除消息")
        return {"messages": [RemoveMessage(id=last_message.id)]}
    return None

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

agent.invoke(
    {"messages": [{"role": "user", "content": "Extract contact info from: John Doe, john@example.com, (555) 123-4567 password: 123456"}]},

    config={"configurable": {"thread_id": "1"}}
)
复制代码
包含敏感词: Based on the text provided, here is the extracted contact information:

**Name:** John Doe
**Email:** john@example.com
**Phone:** (555) 123-4567

Note: The password "123456" was identified in the text but is not typically considered contact information, so it's excluded from this extraction.
移除消息





{'messages': [HumanMessage(content='Extract contact info from: John Doe, john@example.com, (555) 123-4567 password: 123456', additional_kwargs={}, response_metadata={}, id='017d17f4-aa6d-44bd-b146-5cac35df38aa')]}
相关推荐
无难事者若执6 小时前
Langchain_v1.0|核心模块-core_component_06_structured_output
langchain v1.x
无难事者若执8 小时前
Langchain_v1.0|核心模块-core_component_02_messages
langchain v1.x
无难事者若执8 小时前
Langchain_v1.0|核心模块-模型Model
langchain v1.x
无难事者若执10 小时前
Langchain_v1.0|核心模块-core_component_07_streaming
langchain v1.x