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

LangChain中ChatOpenAI结合RetrievalQA多提问触发Token超限问题

问题

我正在用LangChain构建一个基于给定文档回答问题的简单应用,以下是可正常运行的概念验证代码:

from langchain_openai import ChatOpenAI
from langchain.vectorstores.chroma import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain.chains import RetrievalQA

embedding_client = OpenAIEmbeddings(openai_api_key)
embeddings = Chroma.from_texts([document_text], embedding_client)

llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0, max_tokens=4096)
retriever = RetrievalQA.from_chain_type(llm, retriever=embeddings.as_retriever())

answer = retriever({"query": question})

但循环提问时,第二次或第三次后会收到OpenAI的context_length_exceeded错误,哪怕每次循环都重新实例化对象、提问相同问题:

openai.BadRequestError: Error code: 400 - {'error': {'message': "This model's maximum context length is 16385 tokens. However, your messages resulted in 17725 tokens. Please reduce the length of the messages.", 'type': 'invalid_request_error', 'param': 'messages', 'code': 'context_length_exceeded'}

我怀疑ChatOpenAI底层调用复用了聊天历史或文档内容导致问题,调整token限制解决不了核心问题。本以为每次提问新建ChatOpenAI实例就能解决,希望有人解释原因,并提供无需复杂修改的解决方案(无需保留聊天历史)。

原因分析

核心问题并非ChatOpenAI实例复用聊天历史,而是RetrievalQA默认的stuff链类型逻辑:该类型会将检索到的所有文档内容直接拼接进prompt,若document_text本身token量接近gpt-3.5-turbo的16385上限,即使每次新建ChatOpenAI实例,单次请求中prompt(含文档内容+问题+模板固定内容)的总token量也会超过限制。

另外,若循环内未正确管理Chroma向量存储(比如重复添加相同文档),会导致检索返回重复内容,进一步叠加token数量,加速触发超限错误。

解决方案
  • 切换链类型:改用map_reduce或refine链类型,这类链会分批次处理文档内容,避免一次性将所有文档塞进prompt:

    # 循环内创建RetrievalQA时指定链类型
    retriever = RetrievalQA.from_chain_type(
        llm=llm,
        retriever=embeddings.as_retriever(),
        chain_type="map_reduce"  # 可选"refine"
    )
    
  • 限制检索文档数量:通过search_kwargs减少每次检索返回的文档数,降低prompt内容长度:

    # 只返回最相关的2条文档
    retrieval_retriever = embeddings.as_retriever(search_kwargs={"k": 2})
    retriever = RetrievalQA.from_chain_type(llm=llm, retriever=retrieval_retriever)
    
  • 自定义无历史prompt模板:明确使用仅包含当前问题和检索文档的模板,彻底杜绝历史内容残留:

    from langchain.prompts import PromptTemplate
    
    # 自定义prompt,仅保留必要内容
    prompt = PromptTemplate(
        template="基于以下文档回答问题:\n{context}\n\n问题:{question}\n回答:",
        input_variables=["context", "question"]
    )
    
    retriever = RetrievalQA.from_chain_type(
        llm=llm,
        retriever=embeddings.as_retriever(),
        chain_type_kwargs={"prompt": prompt}
    )
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 06:37:25