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)
核心思路总结
- 拆分Token占用:分别计算系统提示词、对话历史、检索文档的Token数,预留足够空间给前两者
- 精准裁剪:用
TokenTextSplitter和get_num_tokens工具实现内容的Token级裁剪 - 组合使用:同时对文档和对话历史进行Token限制,确保总Token数不超过模型上限(如8192)
内容的提问来源于stack exchange,提问作者WQYeo
相关产品推荐
相关产品推荐

