使用Langchain与Gemini Pro实现文档问答系统时遇消息类型错误求助
解决Gemini Pro与Langchain RetrievalQA的system消息不兼容问题
你遇到的错误核心原因是Gemini Pro不支持system类型的对话消息,而Langchain默认的map_reduce链会向LLM发送带system角色的指令,这与Gemini仅接受Human/AI(user/assistant)消息的要求冲突。以下是两种可行的解决方法:
方案1:更换链类型(简单直接)
将chain_type改为stuff或refine,这两种链默认不会生成system消息,完美适配Gemini的格式要求。
修正后的完整代码
from langchain_google_genai import ChatGoogleGenerativeAI from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_google_genai.embeddings import GoogleGenerativeAIEmbeddings from PyPDF2 import PdfReader import google.generativeai as genai genai.configure(api_key='api_key') # 读取PDF文档,过滤空文本 reader = PdfReader('Document Path') file_data = [] for page in reader.pages: text = page.extract_text() if text: file_data.append(text) file_data = " ".join(file_data) # 文本分割 text_splitter = RecursiveCharacterTextSplitter(separators=["\n\n","\n","\t"],chunk_size=8000,chunk_overlap=500) docs = text_splitter.create_documents([file_data]) # 初始化嵌入模型与向量库 embeddings = GoogleGenerativeAIEmbeddings(google_api_key='api_key',model='models/embedding-001') vectorstore = Chroma.from_documents(docs, embeddings) # 初始化Gemini LLM llm = ChatGoogleGenerativeAI(google_api_key='api_key',model='gemini-pro',temperature=0) # 关键改动:更换chain_type为'stuff'(或'refine') qa = RetrievalQA.from_chain_type(llm=llm, chain_type="stuff", retriever=vectorstore.as_retriever()) # 执行查询(直接传字符串格式的问题即可) question = "What is the main argument of this document?" response = qa({'query': question}) print(response)
关键改动说明
- 移除了未使用的
load_summarize_chain导入 - 增加空文本过滤,避免无效内容干扰
- 将
chain_type从map_reduce改为stuff(该链会把检索到的所有文档内容一次性传入LLM,适合文档总长度不超过模型上下文窗口的场景) - 查询时直接传字符串问题,无需额外指定
role参数(RetrievalQA内部会自动处理消息格式)
方案2:自定义map_reduce的Prompt(保留map_reduce链)
如果必须使用map_reduce链,可通过自定义prompt模板,强制所有消息使用Human角色,避开system角色限制。
示例代码
from langchain_google_genai import ChatGoogleGenerativeAI from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_google_genai.embeddings import GoogleGenerativeAIEmbeddings from PyPDF2 import PdfReader from langchain.prompts import PromptTemplate from langchain.chains import MapReduceDocumentsChain, ReduceDocumentsChain from langchain.chains.llm import LLMChain from langchain.chains.combine_documents.stuff import StuffDocumentsChain from langchain.chains import RetrievalQA import google.generativeai as genai genai.configure(api_key='api_key') # 读取PDF、文本分割、向量库初始化步骤同方案1 # (此处省略重复代码,直接从初始化LLM开始) llm = ChatGoogleGenerativeAI(google_api_key='api_key',model='gemini-pro',temperature=0) # 自定义Map阶段Prompt(仅用Human角色) map_template = """以下是一段文档内容: {docs} 请总结这段文档的核心内容。""" map_prompt = PromptTemplate.from_template(map_template) map_chain = LLMChain(llm=llm, prompt=map_prompt) # 自定义Reduce阶段Prompt(仅用Human角色) reduce_template = """以下是多个文档片段的总结: {docs} 请将这些总结合并,给出整个文档的核心论点。""" reduce_prompt = PromptTemplate.from_template(reduce_template) reduce_chain = LLMChain(llm=llm, prompt=reduce_prompt) # 构建Reduce链 combine_documents_chain = StuffDocumentsChain( llm_chain=reduce_chain, document_variable_name="docs" ) reduce_documents_chain = ReduceDocumentsChain( combine_documents_chain=combine_documents_chain, collapse_documents_chain=combine_documents_chain, token_max=8000, ) # 构建自定义MapReduce链 map_reduce_chain = MapReduceDocumentsChain( llm_chain=map_chain, reduce_documents_chain=reduce_documents_chain, document_variable_name="docs", return_intermediate_steps=False, ) # 包装为RetrievalQA qa = RetrievalQA( retriever=vectorstore.as_retriever(), combine_documents_chain=map_reduce_chain ) # 执行查询 question = "What is the main argument of this document?" response = qa({'query': question}) print(response)
关键改动说明
通过自定义map和reduce阶段的prompt模板,确保所有指令都以Human消息的形式发送给Gemini,完全避开了system角色的限制,同时保留了map_reduce链的分块处理能力。
内容的提问来源于stack exchange,提问作者Ronak Nandanwar
相关产品推荐
相关产品推荐

