发布时间:2026-03-02 21:29:53编辑:123阅读(20)
LangChain 1.0基于中间件的消息压缩
修剪是最轻量、最直接的压缩方式。它的思想是:只保留最近N条消息或M个token以内的上下文,其余的自动裁剪掉。这种方法通常配合@before_model钩子使用,在每次模型调用前计算历史消息数量或token长度;当接近模型的最大上下文限制(如4k、16k、128k)时,就删除较早的对话,只保留关键的系统提示和最新几轮对话。它的优点是实现简单、执行快速、成本可控,非常适合聊天型Agent或RAG问答系统;缺点是容易丢失远期上下文记忆。
代码如下:
from langchain.agents import create_agent, AgentState
from langchain.agents.middleware import before_model
from langchain.messages import RemoveMessage
from langgraph.graph.message import REMOVE_ALL_MESSAGES
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.runtime import Runtime
from typing import Any
from langchain_ollama import ChatOllama
import requests
import time
from lxml import etree
from langchain.tools import tool
# 初始化模型
model = ChatOllama(
model="qwen3:8b",
temperature=0.2,
top_p=0.95,
)
@tool
def get_weather(city):
"""
查询即时天气函数
:param city: 必要参数,字符串类型。用于表示查询天气的具体城市名称
:return: 返回即时天气的结果,dict类型
"""
today_time = time.strftime("%Y-%m-%d",time.localtime())
url = f'https://www.ks121.com/history/?location={city}&startdate={today_time}&enddate={today_time}'
headers = {
"sec-ch-ua": '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"',
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/144.0.0.0 Safari/537.36"
}
response = requests.get(url=url, headers=headers, timeout=10)
html = etree.HTML(response.text)
res = html.xpath("//div[@class='box']/div[2]/div[1]/div/table/tbody/tr")
ret = {}
for i in res:
one = i.xpath("./td[1]/p[2]/text()")[0]
two = i.xpath("./td[2]/p[2]/span/text()")[0]
three = i.xpath("./td[3]/p/text()")[0]
four = i.xpath("./td[4]/p/text()")[0]
ret.setdefault('日期', one)
ret.setdefault('气象', two)
ret.setdefault('温度', three)
ret.setdefault('风级', four)
print(f"工具调用:{today_time}:{city}天气信息:{ret}")
return ret
@before_model
def trim_message(state: AgentState, runtime:Runtime) -> dict[str, Any] | None:
"""在模型调用前修剪消息历史,只保留前1+后3条。"""
messages = state["messages"]
# 只有超过4条消息才裁剪
if len(messages) <= 4:
return None
# 保留首条System提示 + 最近3条
first_msg = messages[0]
new_messages = [first_msg] + messages[-3:]
print(f"修剪消息:从{len(messages)}条 -> {len(new_messages)}条")
return {
"messages": [RemoveMessage(id=REMOVE_ALL_MESSAGES),*new_messages]
}
agent = create_agent(
model=model,
tools=[get_weather],
middleware=[trim_message],
checkpointer=InMemorySaver(),
)
config = {
"configurable":{
"thread_id":"2"
}
}
resp1 = agent.invoke(
{"messages":"今天上海的天气? 你好,我叫张三。"},
config=config,
)
print(resp1["messages"][-1].content)
resp2 = agent.invoke(
{"messages":"你还记得我叫什么吗?"},
config=config,
)
print(resp2["messages"][-1].content)
resp3 = agent.invoke(
{"messages":"一天喝多少水比较健康?"},
config=config,
)
print(resp3["messages"][-1].content)
resp4 = agent.invoke(
{"messages":"介绍下你自己"},
config=config,
)
print(resp4["messages"][-1].content)
resp5 = agent.invoke(
{"messages":"帮我写一句每日格言"},
config=config,
)
print(resp5["messages"][-1].content)
# 查看保留的历史消息
for i in agent.get_state(config).values["messages"]:
print(i.content)运行结果:
工具调用:2026-03-02:上海天气信息:{'日期': '2026-03-02', '气象': '阴', '温度': '6℃\n~ 10℃', '风级': '南风转西北风<3级转3-4
级'}
张三你好!今天是2026年3月2日,上海天气阴,气温在6℃到10℃之间,风向由南风转西北风,风级从<3级转为3-4级。建议
根据温度变化适时增减衣物哦!
修剪消息:从5条 -> 4条
记得啊,你叫张三!是不是有什么需要我帮忙的吗? 😊
修剪消息:从6条 -> 4条
一般建议成年人每天饮用约2-3升水(约8-12杯),但具体需求因体重、活动量、气候和健康状况而异。例如:
- 每公斤体重约需30-35ml水
- 运动后或干燥环境中需增加摄入
- 摄入含电解质的饮料也可补充水分
不过每个人的情况不同,如有特殊健康需求,建议咨询专业医生获取个性化建议。
修剪消息:从6条 -> 4条
你好!我是一个大型语言模型,可以回答各种问题、提供建议,并帮助你获取信息。我的知识库涵盖了广泛的主题,包括科学
、文化、技术等。如果遇到复杂问题,我可以通过调用工具获取最新数据。不过我无法处理需要实时操作的任务(如网页点击)
,但会尽力用文字描述解决方案。需要什么帮助吗?
修剪消息:从6条 -> 4条
“种下习惯,收获命运;点亮微光,终成星河。”
今天上海的天气? 你好,我叫张三。
介绍下你自己
你好!我是一个大型语言模型,可以回答各种问题、提供建议,并帮助你获取信息。我的知识库涵盖了广泛的主题,包括科学
、文化、技术等。如果遇到复杂问题,我可以通过调用工具获取最新数据。不过我无法处理需要实时操作的任务(如网页点击)
,但会尽力用文字描述解决方案。需要什么帮助吗?
帮我写一句每日格言
“种下习惯,收获命运;点亮微光,终成星河。”
52180
52078
42258
39120
33619
30581
29255
24241
24130
22499
17°
24°
20°
108°
280°
329°
332°
307°
353°
318°