langchain中的上下文压缩方案

news/2025/10/30 10:26:03/文章来源:https://www.cnblogs.com/huangdh/p/19176094
chain_extract.pycontextual_compression.py在 LangChain 中,多轮对话的上下文压缩主要用于解决长对话场景下的 Token 超限问题,通过对历史对话内容进行总结、提取关键信息或截断,在保留核心上下文的同时减少 Token 消耗。以下从核心方案、具体实现代码及逻辑展开分析:

一、核心方案:对话历史总结(Summarization Middleware)

针对多轮对话的上下文压缩,LangChain 中最直接的实现是 SummarizationMiddleware(对话总结中间件)。该方案通过监控对话历史的 Token 数量,当接近预设阈值时,自动总结较早的对话内容,保留最近的消息,并确保 AI 与工具调用的消息对不被拆分,维持上下文连贯性。

具体代码位置

文件路径:langchain/libs/langchain_v1/langchain/agents/middleware/summarization.py

核心逻辑解析

SummarizationMiddleware 实现了 AgentMiddleware 接口,在 Agent 调用模型前(before_model 方法)处理对话消息,核心步骤如下:
 
  1. Token 监控与触发条件
     
    计算当前对话历史的总 Token 数,若超过 max_tokens_before_summary 阈值,则触发压缩逻辑。
     
     
    def before_model(self, state: AgentState, runtime: Runtime) -> dict[str, Any] | None:messages = state["messages"]self._ensure_message_ids(messages)  # 确保消息有唯一ID,用于后续替换total_tokens = self.token_counter(messages)if self.max_tokens_before_summary is not None and total_tokens < self.max_tokens_before_summary:return None  # 未达阈值,不压缩# 触发压缩...
     
     
  2. 安全截断点选择
     
    为避免拆分 AI 消息与对应的工具调用消息(如 AIMessage 和 ToolMessage 成对出现),通过 _find_safe_cutoff 找到合适的截断索引,确保保留的消息中不包含拆分的消息对。
     
     
    def _find_safe_cutoff(self, messages: list[AnyMessage]) -> int:if len(messages) <= self.messages_to_keep:return 0  # 消息数量不足,无需截断target_cutoff = len(messages) - self.messages_to_keep  # 目标截断点(保留最近N条)# 从目标截断点向前搜索安全位置,避免拆分AI-工具消息对for i in range(target_cutoff, -1, -1):if self._is_safe_cutoff_point(messages, i):return ireturn 0
     
     
  3. 对话总结生成
     
    将截断点之前的消息(待总结部分)传入 LLM 生成总结,并替换原历史消息,保留截断点之后的最近消息。
     
     
    def _create_summary(self, messages_to_summarize: list[AnyMessage]) -> str:if not messages_to_summarize:return "No previous conversation history."trimmed_messages = self._trim_messages_for_summary(messages_to_summarize)  # 确保总结输入不超限response = self.model.invoke(self.summary_prompt.format(messages=trimmed_messages))  # 生成总结return cast("str", response.content).strip()
     
     
  4. 替换历史消息
     
    用总结结果替换旧消息,并保留最近的消息,通过 RemoveMessage 指令清除原历史,再插入新的总结和保留消息。
     
     
    return {"messages": [RemoveMessage(id=REMOVE_ALL_MESSAGES),  # 清除原历史*self._build_new_messages(summary),  # 插入总结*preserved_messages,  # 插入保留的最近消息]
    }
     
     

二、辅助方案:文档压缩(间接支持对话上下文)

在多轮对话中,若涉及外部文档检索(如 RAG 场景),对话上下文可能包含检索到的长文档,此时会用到文档压缩方案,间接减少上下文 Token 消耗。

1. 上下文压缩检索器(ContextualCompressionRetriever)

  • 功能:对检索到的文档先压缩再返回,减少传入对话的文档长度。
  • 代码位置langchain/libs/langchain/langchain_classic/retrievers/contextual_compression.py
  • 核心逻辑
     
    包装基础检索器(base_retriever)和文档压缩器(base_compressor),检索后自动调用压缩器处理文档。
     
    class ContextualCompressionRetriever(BaseRetriever):base_compressor: BaseDocumentCompressor  # 文档压缩器base_retriever: RetrieverLike  # 基础检索器def _get_relevant_documents(self, query: str, **kwargs) -> list[Document]:docs = self.base_retriever.invoke(query,** kwargs)  # 检索文档if docs:compressed_docs = self.base_compressor.compress_documents(docs, query)  # 压缩文档return list(compressed_docs)return []
     
     

2. LLM 链提取器(LLMChainExtractor)

  • 功能:通过 LLM 提取文档中与当前查询相关的内容,剔除无关信息。
  • 代码位置langchain/libs/langchain/langchain_classic/retrievers/document_compressors/chain_extract.py
  • 核心逻辑
     
    使用 LLM 链(llm_chain)根据查询从文档中提取相关片段,仅保留有用内容。
     
    class LLMChainExtractor(BaseDocumentCompressor):llm_chain: Runnable  # 用于提取的LLM链def compress_documents(self, documents: Sequence[Document], query: str, **kwargs) -> Sequence[Document]:compressed_docs = []for doc in documents:input_ = self.get_input(query, doc)  # 构造查询+文档输入output = self.llm_chain.invoke(input_,** kwargs)  # 提取相关内容if output:  # 仅保留非空结果compressed_docs.append(Document(page_content=output, metadata=doc.metadata))return compressed_docs
     
     

三、总结

  1. 多轮对话历史压缩:核心依赖 SummarizationMiddlewaresummarization.py),通过总结旧对话、保留新消息实现上下文压缩,适配长对话场景。
  2. 文档相关上下文压缩:通过 ContextualCompressionRetrievercontextual_compression.py)和 LLMChainExtractorchain_extract.py)处理检索文档,间接减少对话上下文长度。
 
这些方案共同解决了多轮对话中的 Token 限制问题,平衡了上下文完整性与系统性能。在 LangChain 中,多轮对话的上下文压缩主要用于解决长对话场景下的 Token 超限问题,通过对历史对话内容进行总结、提取关键信息或截断,在保留核心上下文的同时减少 Token 消耗。以下从核心方案、具体实现代码及逻辑展开分析:

一、核心方案:对话历史总结(Summarization Middleware)

针对多轮对话的上下文压缩,LangChain 中最直接的实现是 SummarizationMiddleware(对话总结中间件)。该方案通过监控对话历史的 Token 数量,当接近预设阈值时,自动总结较早的对话内容,保留最近的消息,并确保 AI 与工具调用的消息对不被拆分,维持上下文连贯性。

具体代码位置

文件路径:langchain/libs/langchain_v1/langchain/agents/middleware/summarization.py

核心逻辑解析

SummarizationMiddleware 实现了 AgentMiddleware 接口,在 Agent 调用模型前(before_model 方法)处理对话消息,核心步骤如下:
 
  1. Token 监控与触发条件
     
    计算当前对话历史的总 Token 数,若超过 max_tokens_before_summary 阈值,则触发压缩逻辑。
     
    def before_model(self, state: AgentState, runtime: Runtime) -> dict[str, Any] | None:messages = state["messages"]self._ensure_message_ids(messages)  # 确保消息有唯一ID,用于后续替换total_tokens = self.token_counter(messages)if self.max_tokens_before_summary is not None and total_tokens < self.max_tokens_before_summary:return None  # 未达阈值,不压缩# 触发压缩...
     
     
  2. 安全截断点选择
     
    为避免拆分 AI 消息与对应的工具调用消息(如 AIMessage 和 ToolMessage 成对出现),通过 _find_safe_cutoff 找到合适的截断索引,确保保留的消息中不包含拆分的消息对。
     
     
    def _find_safe_cutoff(self, messages: list[AnyMessage]) -> int:if len(messages) <= self.messages_to_keep:return 0  # 消息数量不足,无需截断target_cutoff = len(messages) - self.messages_to_keep  # 目标截断点(保留最近N条)# 从目标截断点向前搜索安全位置,避免拆分AI-工具消息对for i in range(target_cutoff, -1, -1):if self._is_safe_cutoff_point(messages, i):return ireturn 0
     
     
  3. 对话总结生成
     
    将截断点之前的消息(待总结部分)传入 LLM 生成总结,并替换原历史消息,保留截断点之后的最近消息。
     
    def _create_summary(self, messages_to_summarize: list[AnyMessage]) -> str:if not messages_to_summarize:return "No previous conversation history."trimmed_messages = self._trim_messages_for_summary(messages_to_summarize)  # 确保总结输入不超限response = self.model.invoke(self.summary_prompt.format(messages=trimmed_messages))  # 生成总结return cast("str", response.content).strip()
     
     
  4. 替换历史消息
     
    用总结结果替换旧消息,并保留最近的消息,通过 RemoveMessage 指令清除原历史,再插入新的总结和保留消息。
     
    return {"messages": [RemoveMessage(id=REMOVE_ALL_MESSAGES),  # 清除原历史*self._build_new_messages(summary),  # 插入总结*preserved_messages,  # 插入保留的最近消息]
    }
     
     

二、辅助方案:文档压缩(间接支持对话上下文)

在多轮对话中,若涉及外部文档检索(如 RAG 场景),对话上下文可能包含检索到的长文档,此时会用到文档压缩方案,间接减少上下文 Token 消耗。

1. 上下文压缩检索器(ContextualCompressionRetriever)

  • 功能:对检索到的文档先压缩再返回,减少传入对话的文档长度。
  • 代码位置langchain/libs/langchain/langchain_classic/retrievers/contextual_compression.py
  • 核心逻辑
     
    包装基础检索器(base_retriever)和文档压缩器(base_compressor),检索后自动调用压缩器处理文档。
     
    class ContextualCompressionRetriever(BaseRetriever):base_compressor: BaseDocumentCompressor  # 文档压缩器base_retriever: RetrieverLike  # 基础检索器def _get_relevant_documents(self, query: str, **kwargs) -> list[Document]:docs = self.base_retriever.invoke(query,** kwargs)  # 检索文档if docs:compressed_docs = self.base_compressor.compress_documents(docs, query)  # 压缩文档return list(compressed_docs)return []
     
     

2. LLM 链提取器(LLMChainExtractor)

  • 功能:通过 LLM 提取文档中与当前查询相关的内容,剔除无关信息。
  • 代码位置langchain/libs/langchain/langchain_classic/retrievers/document_compressors/chain_extract.py
  • 核心逻辑
     
    使用 LLM 链(llm_chain)根据查询从文档中提取相关片段,仅保留有用内容。
     
     
    class LLMChainExtractor(BaseDocumentCompressor):llm_chain: Runnable  # 用于提取的LLM链def compress_documents(self, documents: Sequence[Document], query: str, **kwargs) -> Sequence[Document]:compressed_docs = []for doc in documents:input_ = self.get_input(query, doc)  # 构造查询+文档输入output = self.llm_chain.invoke(input_,** kwargs)  # 提取相关内容if output:  # 仅保留非空结果compressed_docs.append(Document(page_content=output, metadata=doc.metadata))return compressed_docs
     
     

三、总结

  1. 多轮对话历史压缩:核心依赖 SummarizationMiddlewaresummarization.py),通过总结旧对话、保留新消息实现上下文压缩,适配长对话场景。
  2. 文档相关上下文压缩:通过 ContextualCompressionRetrievercontextual_compression.py)和 LLMChainExtractorchain_extract.py)处理检索文档,间接减少对话上下文长度。
 
这些方案共同解决了多轮对话中的 Token 限制问题,平衡了上下文完整性与系统性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/950553.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025 年楼盘住宅最新推荐榜,聚焦企业开发实力与宜居价值深度评测

引言 2025 年西安城北楼市迎来品质升级浪潮,低密小高层凭借宜居属性成为置业热点,但市场产品品质参差不齐。本次推荐榜依托房地产业协会《2025 年城市低密住宅测评标准》,结合第三方机构 30 项核心指标完成筛选,测…

2025年靠谱的控制台显示器支架最新TOP品牌厂家排行

2025年靠谱的控制台显示器支架最新TOP品牌厂家排行在数字化办公和工业控制领域,显示器支架已成为提升工作效率和人体工学舒适度的关键设备。随着2025年技术发展和市场需求变化,显示器支架行业涌现出一批技术领先、质…

山海鲸可视化分组面板常见的问题解答

在山海鲸可视化的场景搭建中,分组面板是整合组件、梳理逻辑的核心工具,却常因适配、缩放、布局等细节问题影响效率 —— 今天就来给大家拆解这些高频痛点,分享实用解决思路,让大家在使用分组面板时更加得心应手!!…

2025年风速仪订制厂家权威推荐榜单:风向风速仪/手持式风速仪/负氧离子监测站源头厂家精选

在环境监测、气象观测和工业应用领域,精准的风速数据至关重要,而定制化风速仪正成为市场新需求。 根据QYResearch最新调研数据,全球风速仪表市场销售额预计在2031年将达到123.2亿元,年复合增长率为5.2%(2025-2031…

【学习笔记】带权并查集

简介 我们还可以在并查集的边上定义某种权值和这种权值在路径压缩时产生的运算,从而解决更多的问题。也称为「种类并查集」或「拓展域并查集」。 实现 为了维护并查集中的边权,需要将边权下放到子节点中存储。因此,…

2025年钢带木箱生产商权威推荐榜单:物流运输包装木箱/可拆卸木箱/物流运输钢边箱源头厂家精选

在工业包装领域,优质钢带木箱不仅能有效保护设备运输安全,还能显著降低物流成本。 工业包装领域对钢带木箱的需求正日益增长,这种采用镀锌钢带与胶合板结合的可拆卸包装结构,因其可重复使用、拆装便捷的特点,已成…

大促全链路隔离

目录背景和价值一、业务容器集群:核心与非核心“物理/逻辑隔离”1. 为什么需要隔离?2. 如何实现?二、数据库:按业务拆分+读写分离,避免“一库拖全链路”1. 为什么需要隔离?2. 如何实现?三、缓存(如 Redis):业…

Notepad++ 下载安装与配置全攻略(2025最新版)—— 高效编辑技巧全指南

Notepad++ 是一款轻量高效的开源文本编辑器,支持多语言语法高亮与插件扩展。本文提供 Notepad++ 下载安装详细步骤、安装包下载地址、防坑安装建议及主题配置技巧。适配 Win7、Win10、Win11 系统,让你从入门到高效使…

2025年性价比高的纳米大单槽厂家推荐及选购参考榜

2025年性价比高的纳米大单槽厂家推荐及选购参考榜 随着家居生活品质的不断提升,厨房装修成为现代家庭关注的重点之一。纳米大单槽因其耐用、易清洁、抗菌等特性,成为厨房水槽的热门选择。2025年,市场上涌现出众多纳…

利用React Hooks简化状态管理

React 是当前最流行的前端框架之一,它以其高效的虚拟DOM和组件化的思想受到了广大开发者的青睐。随着React 16.8版本的发布,Hooks API的引入更是给React开发带来了革命性的变化。本文将通过一个简单的计数器应用示例…

2025年靠谱的304冲压式潜水搅拌机最新TOP厂家推荐

2025年靠谱的304冲压式潜水搅拌机最新TOP厂家推荐随着环保要求的不断提高和水处理行业的快速发展,304不锈钢冲压式潜水搅拌机作为污水处理系统中的关键设备,其市场需求持续增长。这类设备主要用于市政污水处理、工业…

我们如何解决求子集团个数

题面 方法一 首先预处理每个子集是否成团,然后枚举子集即可 \(O(3^n+n2^n)\)。 方法二 考虑 meet in the middle,左侧处理处每个子集是否成团,右侧处理每个子集是否成团,然后枚举其子集成团数量,最后在枚举左侧合…

从零开始制作 MyOS(四)

从零开始制作 MyOS(四)—— 跳转到 C 语言编写的小型内核 目标 在引导加载器准备好后,用 C 语言编写一个小型内核并实现从引导加载器跳转到内核执行。 代码 引导程序文件 org 0x7C00 bits 16start:; 初始化段寄存器…

2025年10月压力监测厂家对比榜:五强评测与选型参考

进入2025年,水务、热力及工业管网对“压力监测”的实时性、耐久性与数据闭环能力提出更高要求。用户常见场景有三类:一是水务集团需要长寿命、毫秒级水锤捕捉终端,以降低爆管率;二是热力公司希望在高温高湿环境下获…

2025年质量好的洗菜盆厨房水槽优质厂家推荐榜单

2025年质量好的洗菜盆厨房水槽优质厂家推荐榜单 随着现代厨房设计的不断升级,洗菜盆和水槽作为厨房的核心功能部件,其质量、设计和功能性越来越受到消费者的重视。优质的洗菜盆不仅能提升厨房的使用体验,还能延长使…

基于VC++和ObjectARX开发的AutoCAD曲线交点打断功能实现代码

// CurveIntersectionBreaker.h #pragma once #include "dbents.h" #include "dbsymtb.h" #include "gecurv.h"class CCurveIntersectionBreaker { public:CCurveIntersectionBreaker()…

12个单词

client 客户端 process 进程 request 请求 headers 请求头/响应头 breakpoints 断点 response 响应 status 状态 code 代码 type 类型 size 大小

2025年评价高的滚珠丝杆升降机用户好评厂家排行

2025年评价高的滚珠丝杆升降机用户好评厂家排行 随着工业自动化需求的持续增长,滚珠丝杆升降机作为精密传动设备的核心部件,其性能、稳定性和售后服务成为用户选择的关键指标。2025年,通过对市场用户反馈、技术实力…

2025 年消防培训学校最新推荐榜,技术实力与市场口碑深度解析

本次消防培训学校推荐榜,由消防协会联合职业技能鉴定中心共同测评发布,测评周期覆盖 2024-2025 年度。测评体系包含 6 大核心维度:教学资质合规性(权重 25%)、师资团队专业度(权重 20%)、教学设施完备性(权重 …