ConversationalRetrievalChain替换Map_Reduce链及响应截断问题求解
电商聊天机器人ConversationalRetrievalChain问题解决方案
1. Stuff链Token超限问题(替换链类型的坑与解决)
问题根源
Stuff链会把所有检索到的文档一次性塞进prompt,当文档量大时必然触发token上限。替换为MapReduce链时,因为该链分为**Map(单文档生成中间结果)和Reduce(合并中间结果)**两个阶段,默认使用两个独立prompt,自定义单个QA prompt会引发参数冲突;且MapReduce链不支持流式输出(多prompt与流输出逻辑不兼容),所以会出现ValueError: Cannot stream results with multiple prompts。
可行解决方案
方案A:优化Stuff链(最简单,适合新手)
不需要更换链类型,通过减少检索文档数量、精简文档内容降低输入token:
- 调整Redis检索器的
search_kwargs参数,减少返回的文档数量(比如设为k=3,只取最相关的3条):
# 初始化Redis检索器时添加搜索参数 retriever = your_redis_vector_store.as_retriever(search_kwargs={"k": 3}) # 构建ConversationalRetrievalChain时使用自定义prompt chat_chain = ConversationalRetrievalChain.from_llm( llm=your_llm_model, retriever=retriever, combine_docs_chain_kwargs={ "prompt": your_custom_qa_prompt # 保留自定义prompt }, streaming=True # 支持流式输出 )
- 如果文档本身冗余,可以在存入Redis前做预处理:提取关键信息(比如商品核心参数、售后规则摘要),缩短单文档长度。
方案B:替换为Refine链(兼容自定义prompt,支持复杂文档)
Refine链会先基于第一个文档生成初始回答,再依次用后续文档优化回答,支持自定义两个阶段的prompt,且部分场景下可支持流式输出(取决于LLM支持):
from langchain.chains import RefineDocumentsChain, LLMChain from langchain.prompts import PromptTemplate # 自定义初始回答prompt(处理第一个文档) initial_prompt = PromptTemplate( input_variables=["question", "context"], template="""你是电商客服机器人,根据以下上下文回答用户问题: 上下文:{context} 问题:{question} 请给出准确详细的回答。""" ) # 自定义优化prompt(用后续文档优化已有回答) refine_prompt = PromptTemplate( input_variables=["question", "existing_answer", "context"], template="""现有回答:{existing_answer} 新增上下文:{context} 问题:{question} 请结合新增上下文优化回答,若新增信息无价值则直接返回原回答。""" ) # 构建两个阶段的LLM链 initial_llm_chain = LLMChain(llm=your_llm_model, prompt=initial_prompt) refine_llm_chain = LLMChain(llm=your_llm_model, prompt=refine_prompt) # 组装RefineDocumentsChain refine_qa_chain = RefineDocumentsChain( initial_llm_chain=initial_llm_chain, refine_llm_chain=refine_llm_chain, document_variable_name="context", return_intermediate_steps=False ) # 传入ConversationalRetrievalChain chat_chain = ConversationalRetrievalChain.from_llm( llm=your_llm_model, retriever=your_redis_retriever, combine_docs_chain=refine_qa_chain, return_source_documents=True )
注意:如果需要流式输出,需确认所用LLM支持流式,且部分版本的Refine链可能不兼容流式,此时优先选方案A。
2. Max_tokens=150导致响应截断问题
问题根源
max_tokens是限制LLM输出的token数量,设为150时,超过长度的内容会被强制截断。
解决方案
- 直接调整max_tokens值:根据所用LLM的上下文窗口设置合理值,比如GPT-3.5-Turbo(4k窗口)可设为5001000,GPT-4(8k/32k窗口)可设为10002000。调整方式:
# 初始化LLM时设置max_tokens from langchain.chat_models import ChatOpenAI llm = ChatOpenAI( model_name="gpt-3.5-turbo", max_tokens=800, # 调整为合适值 temperature=0.3 )
- 用prompt引导精简/分点回答:如果担心输出过长,可在自定义prompt中明确要求分点、简洁回答,避免冗余:
custom_qa_prompt = PromptTemplate( input_variables=["question", "context", "chat_history"], template="""聊天历史:{chat_history} 上下文:{context} 问题:{question} 请分点给出简洁准确的回答,不要冗余内容。""" )
内容的提问来源于stack exchange,提问作者AqashaT
相关产品推荐
相关产品推荐

