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

langchain中的上下文压缩方案

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.jsqmd.com/news/26312/

相关文章:

  • 2025 年楼盘住宅最新推荐榜,聚焦企业开发实力与宜居价值深度评测
  • 山海鲸可视化分组面板常见的问题解答
  • 2025年风速仪订制厂家权威推荐榜单:风向风速仪/手持式风速仪/负氧离子监测站源头厂家精选
  • 【学习笔记】带权并查集
  • 2025年钢带木箱生产商权威推荐榜单:物流运输包装木箱/可拆卸木箱/物流运输钢边箱源头厂家精选
  • 大促全链路隔离
  • Notepad++ 下载安装与配置全攻略(2025最新版)—— 高效编辑技巧全指南
  • 利用React Hooks简化状态管理
  • 2025年靠谱的304冲压式潜水搅拌机最新TOP厂家推荐
  • 我们如何解决求子集团个数
  • 从零开始制作 MyOS(四)
  • 2025年10月压力监测厂家对比榜:五强评测与选型参考
  • 2025年质量好的洗菜盆厨房水槽优质厂家推荐榜单
  • 基于VC++和ObjectARX开发的AutoCAD曲线交点打断功能实现代码
  • 12个单词
  • 不是,斜二倍增是啥啊
  • 2025年评价高的滚珠丝杆升降机用户好评厂家排行
  • 2025 年消防培训学校最新推荐榜,技术实力与市场口碑深度解析
  • 2025年知名的GXN-CMS型碳分子筛实力源头
  • 2025年10月中国离婚财产分割律师榜单:官方资质与用户口碑综合排名
  • 2025 年上海留学服务机构最新推荐榜,聚焦机构综合服务实力与留学申请口碑深度解析
  • 用Fiddler修改网页title的步骤
  • K3s x RustFS,边缘场景下的云原生存储解决之道
  • 2025年10月进度管理工具推荐:信创适配进度系统排名榜
  • 2025-10-29 ZR-J 模拟赛 赛后总结【ZR】
  • 2025年热门的上海行星式搅拌机设备行业内口碑厂家排行榜
  • 阿里云 OSS postObject V4 使用
  • 2025年10月武汉离婚律师推荐榜:五强对比评测与选择指南
  • 用筛选过滤器修改京东界面名字
  • 2025年靠谱的精冲工艺座椅齿板厂家最新TOP排行榜