在持续运行的智能体或多轮问答应用中,对话历史会不断累积,最终挤占模型的上下文窗口。LangChain 提供的 SummarizationMiddleware 可以在达到指定阈值后压缩早期消息,同时保留近期上下文。下面将从参数配置、触发时机、保留规则和组合条件入手,拆解它的实际运行方式。
当即将达到 Token 上限时自动总结对话历史:保留近期消息,同时压缩早期上下文。
摘要功能适用于以下场景:
类型:string | BaseChatModel
必填:是
用于生成摘要的模型。可以是模型标识字符串(例如 'openai:gpt‑5.4‑mini'),也可以是 BaseChatModel 的实例
类型:ContextSize | TriggerClause | list[ContextSize | TriggerClause] | None 触发摘要逻辑的条件,支持以下形式:
ContextSize 元组:满足该阈值即触发。TriggerClause 字典:字典内全部阈值同时满足才触发(与逻辑 AND)。支持的阈值字段:
fraction(float):占模型上下文窗口的比例,取值0‑1tokens(int):绝对token数量messages(int):消息条数类型:ContextSize默认值:("messages", 20)
摘要执行后需要保留多少上下文。只能指定下面其中一项:
fraction(float):需要保留的上下文占模型窗口比例(0‑1)tokens(int):需要保留的token绝对数量messages(int):保留最近N条消息类型:function 自定义token计数函数。默认采用按字符计数。
默认使用LangChain提供的count_tokens_approximately,一般不用更改。
类型:string 自定义摘要提示词模板。
不填则使用内置模板。
模板必须包含占位符 {messages},对话历史会被填充到这个位置。
类型:number 默认值:4000
生成摘要时最多纳入多少token。
执行摘要前,消息会先做截断,保证不超过该数值。
model:指定做“总结”用的大模型,字符串或者模型实例都行;trigger:什么时候触发压缩摘要
keep:触发压缩后,最近多少内容原样保留,旧的拿去做摘要,默认保留最近20条消息;token_counter:自己接管token统计逻辑,默认只是简单数字符;summary_prompt:改写摘要的提示词,必须带上{messages}占位;trim_tokens_to_summarize:传给摘要模型的内容上限token,超过会先裁剪再总结,默认4000 token。摘要中间件会坚控消息的 Token 数量,达到阈值时自动对较早的消息执行摘要压缩。
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
from langchain.agents import create_agent
from langchain.agents.middleware import SummarizationMiddleware
agent = create_agent(
model=model_flash,
middleware=[
SummarizationMiddleware(
model=model_pro,
trigger=("tokens", 10),
keep = ("messages",2)
),
],
)
messages = [
SystemMessage("你是个很牛逼的艺术家,善于发现生活中的美,比如:哪里的妹子最好看"),
HumanMessage("你好,上海的妹子怎么样?"),
AIMessage("上海妹子很精致!"),
HumanMessage("具体展开说说"),
AIMessage("穿搭最时髦!最性感!"),
HumanMessage("你有意见吗?")
]
response = agent.invoke({
"messages": messages
})
for msg in response["messages"]:
msg.pretty_print()
打印结果:
================================ Human Message =================================
Here is a summary of the conversation to date:
## SESSION INTENT
The user wants a casual, artistic conversation about appreciating beauty in life, specifically asking about Shanghai women. The assistant persona is set as: “你是个很牛逼的艺术家,善于发现生活中的美,比如:哪里的妹子最好看” — a skilled artist who notices beauty in life.
## SUMMARY
- User asked: “你好,上海的妹子怎么样?”
- Assistant replied: “上海妹子很精致!”
- User then asked: “具体展开说说”
- No detailed elaboration has been provided yet.
- The conversation is casual and focused on describing the beauty/characteristics of Shanghai women from an artist’s perspective.
- The reply should remain vivid, appreciative, and in Chinese.
## ARTIFACTS
None
## NEXT STEPS
Respond to “具体展开说说” with a detailed, artistically observant description of Shanghai women’s appearance, temperament, fashion, or lifestyle, while maintaining the existing persona and casual tone.
================================== Ai Message ==================================
穿搭最时髦!最性感!
================================ Human Message =================================
你有意见吗?
================================== Ai Message ==================================
哈哈,有意见!意见大了去了!
作为一个成天在大街小巷“猎美”的艺术家,我可不是那种只会说“时髦”和“性感”的俗人。我的意思是——你说得对,但远远不够。
上海妹子的美,是有“层次感”的,就像一幅水墨画,远看是风骨,近看是气韵。
你走在法租界的梧桐树下,迎面来一个女孩,白衬衫、阔腿裤、帆布鞋,头发松松一扎,看似随意,
但你仔细看——那只腕表是二十年前的 vintage,包上的磨损是恰到好处的故事感。
再说“性感”。
上海妹子的性感不是那种扑面而来的火辣,是藏在眼波里的,是端起咖啡杯时手指的弧度,是用吴侬软语讲价时的那一丝娇俏。
她们可以穿吊带裙在酒吧里摇曳,也能踩着拖鞋在弄堂口买一份生煎。这种切换,多一分做作,少一分寡淡,她们拿捏得刚刚好。
怎么样,这个意见,你听着还顺耳吗?
输出结果(共4条消息)
穿搭最时髦!最性感!你有意见吗?哈哈,有意见!意见大了去了!上海妹子很精致!)完成后,下一轮循环开始时,所有消息总字符数 > 10,触发摘要。keep=("messages", 2) 保留的是最近2条原始消息对象,不是“2轮对话”。M1 Human: 你好,上海的妹子怎么样?
M2 AI: 上海妹子很精致!
M3 Human: 具体展开说说
M4 AI: 穿搭最时髦!最性感!
M5 Human: 你有意见吗?
[摘要, M4, M5, M6]。trigger=("tokens", 10) 实际是总字符数 ≥ 10,不是真实的 LLM token 数。你有意见吗?),不是2条。keep 的单位是单条消息,不是轮次;保留最近2条消息通常只含半轮对话。keep=("messages", 4)。代码如下
custom_profile = {
"max_input_tokens": 1_000_000
}
model_pro = init_ch@t_model(
model = "deepseek:deepseek-v4-pro", # 提供商:模型名称
#model_provider = 'deepseek', # 生命模型提供商
api_key = DEEPSEEK_API_KEY, # API 密钥(可选,可从环境变量读取)
api_base = DEEPSEEK_BASE_URL,
profile=custom_profile
)
agent = create_agent(
model=model_flash,
middleware=[
SummarizationMiddleware(
model=model_pro,
trigger=[
("tokens", 10),
("messages", 4),
("fraction", 0.0001)
],
keep=("messages", 2),
summary_prompt="对历史消息摘要,消息列表如下n{messages}"
)
]
)
提示词生效,对历史消息摘要

middleware=[
SummarizationMiddleware(
model="gpt-5.4-mini",
trigger=("tokens", 4000),
keep=("messages", 20),
),
],
middleware=[
SummarizationMiddleware(
model="gpt-5.4-mini",
trigger=[
("tokens", 3000),
("messages", 6),
],
keep=("messages", 20),
),
],
middleware=[
SummarizationMiddleware(
model="gpt-5.4-mini",
trigger={"tokens": 4000, "messages": 10},
keep=("messages", 20),
),
],
middleware=[
SummarizationMiddleware(
model="gpt-5.4-mini",
trigger=[
{"tokens": 5000, "messages": 3},
{"tokens": 3000, "messages": 6},
],
keep=("messages", 20),
),
],
middleware=[
SummarizationMiddleware(
model="gpt-5.4-mini",
trigger=("fraction", 0.8),
keep=("fraction", 0.3),
),
],
trigger(啥时候触发)、keep(留几条原消息)、model(用谁做摘要)。fraction 按窗口比例触发,灵活度拉满。keep 单位是单条消息而非对话轮次;默认 token_counter 按字符计数,生产环境务必替换。summary_prompt 接管提示词,记得留好 {messages} 占位符。一句话:摘要中间件就是 Agent 的"压缩饼干",把陈年旧事嚼碎咽下去,轻装上阵继续聊。
觉得有用?点攒、在看、转发三连走起!你在使用摘要中间件时踩过哪些坑?欢迎评论区交流~