You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LangChain文档检索链上下文Token超限问题及适配方案咨询

适配LangChain 0.1.9版本的上下文Token限制方案

针对你使用langchain===0.1.9、openai===1.5.0、langchain-community===0.0.24版本遇到的Token超限问题,以下是几个适配当前版本的可行方案:

方案1:自定义文档Token裁剪器

绕过废弃的ReduceDocumentsChain,直接基于LangChain的Token工具实现文档内容裁剪,确保检索结果的Token数在可用范围内。

from langchain.text_splitter import TokenTextSplitter
from langchain_core.documents import Document
from langchain_openai import ChatOpenAI

def trim_docs_by_token_limit(
    documents: list[Document],
    max_total_tokens: int = 8192,
    reserved_tokens: int = 2000  # 预留系统提示词+对话历史的Token数
) -> list[Document]:
    # 计算文档可占用的最大Token数
    available_tokens = max_total_tokens - reserved_tokens
    # 初始化适配目标模型的Token分割器
    token_splitter = TokenTextSplitter(
        model_name="gpt-3.5-turbo",
        chunk_size=available_tokens,
        chunk_overlap=0
    )
    
    # 合并所有文档内容并裁剪
    combined_content = "\n\n".join([doc.page_content for doc in documents])
    trimmed_chunks = token_splitter.split_text(combined_content)
    
    # 转换回Document对象返回
    return [Document(page_content=chunk) for chunk in trimmed_chunks]

# 使用示例
# 1. 先执行检索
retrieved_docs = retriever.invoke(user_query)
# 2. 裁剪文档
trimmed_docs = trim_docs_by_token_limit(retrieved_docs)
# 3. 将裁剪后的文档传入对话链

方案2:对话历史Token裁剪

对话历史也是Token占用的大户,通过裁剪历史消息控制总Token数:

from langchain_core.messages import BaseMessage
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-3.5-turbo")

def trim_history_by_token(history: list[BaseMessage], max_history_tokens: int) -> list[BaseMessage]:
    trimmed_history = []
    total_tokens = 0
    # 从最新的消息往前累加,直到达到Token上限
    for msg in reversed(history):
        msg_token_count = llm.get_num_tokens_from_messages([msg])
        if total_tokens + msg_token_count > max_history_tokens:
            break
        trimmed_history.insert(0, msg)
        total_tokens += msg_token_count
    return trimmed_history

# 使用示例
max_history_tokens = 2000
trimmed_history = trim_history_by_token(conversation_history, max_history_tokens)

方案3:结合上下文压缩检索器

利用ContextualCompressionRetriever自定义压缩逻辑,同时控制Token占用:

from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import BaseDocumentCompressor
from langchain_core.documents import Document
from langchain_openai import ChatOpenAI

class TokenControlledCompressor(BaseDocumentCompressor):
    def __init__(self, llm: ChatOpenAI, max_doc_tokens: int):
        self.llm = llm
        self.max_doc_tokens = max_doc_tokens
    
    def compress_documents(self, documents: list[Document], query: str) -> list[Document]:
        combined_content = "\n\n".join([doc.page_content for doc in documents])
        total_tokens = self.llm.get_num_tokens(combined_content)
        
        if total_tokens <= self.max_doc_tokens:
            return documents
        
        # 超过上限时,用Token分割器裁剪内容
        splitter = TokenTextSplitter(
            model_name="gpt-3.5-turbo",
            chunk_size=self.max_doc_tokens,
            chunk_overlap=0
        )
        trimmed_chunks = splitter.split_text(combined_content)
        return [Document(page_content=trimmed_chunks[0])]

# 初始化压缩检索器
llm = ChatOpenAI(model="gpt-3.5-turbo")
compressor = TokenControlledCompressor(llm=llm, max_doc_tokens=6000)
compression_retriever = ContextualCompressionRetriever(
    base_compressor=compressor,
    base_retriever=your_base_retriever
)

# 检索时自动压缩文档
compressed_docs = compression_retriever.invoke(user_query)

核心思路总结

  1. 拆分Token占用:分别计算系统提示词、对话历史、检索文档的Token数,预留足够空间给前两者
  2. 精准裁剪:用TokenTextSplitter和get_num_tokens工具实现内容的Token级裁剪
  3. 组合使用:同时对文档和对话历史进行Token限制,确保总Token数不超过模型上限(如8192)

内容的提问来源于stack exchange,提问作者WQYeo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 22:22:38