当前位置: 首页 > news >正文

智能体上下文压缩-裁剪和摘要

如何在不牺牲Agent智能度的前提下,把送进 LLM 的 token 控制在上下文窗口以内,让智能体既“记性好”又“胃口小”。

1 为什么要压缩上下文

大型语言模型(LLM)的上下文窗口是有限的。无论是多轮聊天机器人,还是频繁调用工具的智能体(agent),消息数量都会迅速膨胀。如果把全部历史原样送给 LLM,最终会:

  • 触发截断:模型只能看到后面的内容,前文丢失;
  • 成本翻倍:Token 越多,调用费用越高;
  • 性能下降:上下文过长会显著拉低推理速度和准确度。

因此必须在 送给 LLM 之前 对历史做瘦身。

2 上下文压缩核心机制

LangGraph 把 Agent等同于 节点 + 有向图 + 状态对象

  1. 节点(Node):纯函数,接受 state,返回增量。

  2. 边(Edge):决定节点执行顺序;可 条件跳转

  3. 状态(State dataclass):可自由加字段,例如 messages+summary

有了自定义 State,我们就能把“压缩逻辑”作为普通节点插入到任意位置。

任何在 调用 LLM 的节点 之前运行的步骤,都可以写成一个 hook。可以定义一个 pre_model_hook 函数接收当前 graph state(其中 state["messages"] 是完整历史)并返回一个 增量更新 dict。在这个位置实现了上下文压缩。

3 上下文压缩两大常用策略

在这里插入图片描述

📊 常见的上下文压缩策略包括:裁剪:按先后顺序删除历史中的前 N 条或后 N 条消息。摘要:将较早的消息总结成一段摘要并替换原始内容。

策略原理适合场景代价/风险
裁剪 (trim)直接丢弃最早或最新的 N 条消息;常用 trim_messages + count_tokens_approximately 快速估算 token对话可被上下文无关处理,且用户不关心早期细节
如 FAQ Bot、检索问答
可能误删关键信息;需要设定 start_onend_on 规则避免截断半句话
摘要 (summary)使用另一轮 LLM 把旧消息压缩成几百 token 的“摘要块”需要把历史语义长期保留的复杂交互
如 任务型助手、长对话陪聊
摘要本身会随时间漂移——信息逐步丢失或被误改,需要定期重新压缩或保留关键信息字段

📊 裁剪和摘要的对比表格,若上下文的“长尾”对后续推理影响不大,优先选择裁剪,简单、快、便宜;否则上摘要。

含义典型用途
llm_input_messages仅改变传给 LLM 的消息,不动原始历史保真调试
messages覆盖图状态里的历史,本质上“删旧写新”节省内存或持久化存储

📊 保留原始历史:若想在图状态中保持完整历史,只将裁剪/摘要后的消息作为 LLM 输入,可把更新结果放入llm_input_messages 键。覆盖原始历史:若希望直接替换图状态中的历史,将更新结果放入 messages 键。

4 裁剪策略的示例代码

from langchain_core.messages.utils import trim_messages
from langgraph.prebuilt import create_react_agent
def pre_model_hook(state):trimmed = trim_messages(state["messages"],strategy="last",          # 从历史末尾开始数,保留最近消息token_counter=count_tokens_approximately,max_tokens=384,           # 目标总 token 上限start_on="human",         # 确保从人类消息开头开始数end_on=("human", "tool"), # 或者数到工具调用/人类消息就停)return {"llm_input_messages": trimmed}checkpointer = InMemorySaver()
graph = create_react_agent(model,tools,pre_model_hook=pre_model_hook,checkpointer=checkpointer,
)

📊 strategy=last保留最近消息,如果系统 prompt本身占用大量 token,可改用first或自定义过滤规则,先丢系统 prompt 再丢中间对话。count_tokens是近似计数,速度快,在高并发 Agent 场景尤为重要。

5 摘要策略的示例代码

from langmem.short_term import SummarizationNode
summarization_node = SummarizationNode(token_counter=count_tokens_approximately,model=summarization_model, # 可以用更便宜的模型max_tokens=384,max_summary_tokens=128, # 每次新增的摘要 token 上限output_messages_key="llm_input_messages",
)
class State(AgentState):# 新增此键用于保存先前的摘要信息,以避免每次 LLM 调用都重新摘要context: dict[str, Any]checkpointer = InMemorySaver()
graph = create_react_agent(model,tools,pre_model_hook=summarization_node,state_schema=State,checkpointer=checkpointer,
)

📊 摘要策略可利用 langmem 库的 SummarizationNode。当对话达到 max_tokens 时,它会自动对较早的消息生成摘要。当历史 + 新请求 > 384 token,就把“过界”的部分喂给 summarization_model ⇒ 产出摘要块 ⇒ 用摘要块 + 最新消息继续。在多轮对话后,你将看到早期消息被替换为“对话至今的摘要”,有效压缩上下文而不丢失关键信息。

6 总结

核心目标

在不牺牲 Agent 智能度的前提下,把送进 LLM 的 token 控制在上下文窗口以内。

技术抓手

  • 节点之前运行pre_model_hook
  • 裁剪使用trim_messages
  • 摘要使用SummarizationNode

两种写入键位

  • llm_input_messages只影响输入,保留完整历史;
  • messages覆盖历史,节省存储。

策略选择

  • 对信息保真要求低 ⇒ 裁剪;
  • 需要长时语境,且能接受摘要带来的信息损耗 ⇒ 摘要;

nput_messages` ⇒ 只影响输入,保留完整历史;

  • messages覆盖历史,节省存储。

策略选择

  • 对信息保真要求低 ⇒ 裁剪;
  • 需要长时语境,且能接受摘要带来的信息损耗 ⇒ 摘要;
http://www.dtcms.com/a/288479.html

相关文章:

  • Compose笔记(三十六)--SearchBar
  • 人脸识别独立部署解决方案:一劳永逸的本地化对接方案
  • python的多线程无法并行只能并发,why?
  • 80、【OS】【Nuttx】【启动】caller-saved 和 callee-saved 示例:栈空间对齐
  • kubeadm方式部署Kubernetes v1.22.2集群
  • 零基础学习性能测试第二章-linux服务器监控:磁盘监控
  • 如何设计一个高效的网页爬虫?
  • 7月19日 暴雨蓝色预警:全国多地迎强降雨,需防范次生灾害
  • Linux练习二
  • 信息系统风险的安全技术防范思路
  • 零基础学习性能测试第二章-linux服务器监控:CPU监控
  • [每日随题10] DP - 重链剖分 - 状压DP
  • stm32继电器使用方法
  • Java并发7--FutrureTask 及CompletetableFuture
  • 高速SAR架构ADC选型设计
  • 为什么选择PGCE中级认证?
  • startnet.cmd命令里面的factory -minint
  • 零基础学习性能测试第二章-监控体系
  • 多线程 示例
  • QML 动画效果详解
  • Public Key Retrieval is not allowed
  • CS231n-2017 Lecture3线性分类器、最优化笔记
  • 测试计划(抽奖系统)
  • DC-DC降压转换5.5V/3A高效率低静态同步降压转换具有自适应关断功能
  • CCF编程能力等级认证GESP—C++7级—20250628
  • Navicat 查看单张表建表ddl
  • Python观察者模式详解:从理论到实战
  • 142. 环形链表 II
  • Spring IOC容器在Web环境中是如何启动的(源码级剖析)?
  • MCP 协议详细分析 二 Sampling