药品 RAG 项目今日重点问题总结(Markdown 版)

适用场景:LangChain 新版 + Chroma 向量库 + 通义千问 ChatTongyi,聚焦今日核心报错及解决方案,适配项目实际代码。

一、核心报错:400 InvalidParameter(input.texts should be array)

1. 报错原因

通义千问(ChatTongyi)新版 API 强制要求输入为 消息数组格式(如 \[\{\&\#34;role\&\#34;: \&\#34;system\&\#34;, \&\#34;content\&\#34;: \&\#34;\.\.\.\&\#34;\}, \{\&\#34;role\&\#34;: \&\#34;user\&\#34;, \&\#34;content\&\#34;: \&\#34;\.\.\.\&\#34;\}\]),不接受纯字符串输入。

2. 关联错误及解决方案

错误1:提示词模板格式错误(用 from_template 生成纯字符串)

错误写法

prompt = ChatPromptTemplate.from_template("""
你是专业的药品AI助手,请只根据资料回答,不能编造。没有答案就说无法回答。
资料:{context}
问题:{question}
""")

正确写法(用 from_messages 生成数组):

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是专业的药品AI助手,请只根据资料回答,不能编造。没有答案就说无法回答。"),
    ("user", "资料:{context}\n问题:{question}")
])
错误2:format_docs 函数无 return 或变量覆盖

错误写法1(无 return)

def format_docs(docs:list):
    doc=''
    for doc in docs:
        doc +=doc.page_content + '\n'
# 无 return,默认返回 None,传给模型报错

错误写法2(变量覆盖)

def format_docs(docs:list):
    doc=''
    for doc in docs:  # 变量 doc 被 Document 对象覆盖
        doc +=doc.page_content + '\n'
    return doc  # 最终返回 Document 对象,非字符串

正确写法

def format_docs(docs: list):
    doc_string = ""  # 独立变量,避免覆盖
    for d in docs:
        doc_string += d.page_content + "\n"
    return doc_string  # 必须返回字符串
错误3:LCEL 链 invoke 调用格式错误

错误写法(多一层字典包装):

answer = self.rag_chain.invoke({"question": question})

正确写法(直接传入问题字符串):

answer = self.rag_chain.invoke(question)

原因:链结构中已用 RunnablePassthrough\(\) 自动接收问题字符串,无需额外包装。

二、ChatTongyi 模型参数问题

1. 报错/警告原因

新版 ChatTongyi 不再支持直接传入 temperature 参数,需将生成参数放入 model\_kwargs 字典。

2. 正确写法

self.llm = ChatTongyi(
    model_name=self.llm_model,
    dashscope_api_key=self.api_key,
    model_kwargs={'temperature': self.temperature}  # 生成参数放此处
)

3. temperature 参数作用(重点)

  • 取值范围:0~1

  • 温度越低(0.1~0.2):回答越严谨、固定,不编造信息,适配医药 RAG 场景

  • 温度越高(趋近1):回答越灵活、随机,易编造信息,不适合医药场景

三、LangChain 新版废弃方法/包路径

1. 旧版 chains 废弃(RetrievalQA)

旧版错误写法

from langchain.chains import RetrievalQA  # 已废弃,黑盒式,不支持自定义

新版正确写法(LCEL 链式写法)

self.rag_chain = (
    {
        "context": self.retriever | format_docs,  # 检索器+文档格式化
        "question": RunnablePassthrough()          # 接收用户问题
    }
    | prompt  # 提示词模板
    | self.llm  # 大模型
    | StrOutputParser()  # 输出解析为字符串
)

2. Chroma 向量库旧方法废弃(persist())

旧版错误写法

vector_store.add_documents(documents)
vector_store.persist()  # 手动持久化,新版已废弃

新版正确写法

vector_store.add_documents(documents)  # 自动持久化,无需手动调用 persist()

3. 文本分割器包路径变更

旧版错误写法

from langchain.text_splitter import RecursiveCharacterTextSplitter  # 找不到模块

新版正确写法

from langchain_text_splitters import RecursiveCharacterTextSplitter

需安装依赖:pip install langchain\-text\-splitters

四、Retriever 检索器核心理解(易混淆点)

1. 代码及关键结论

self.retriever = self.vector_store.vector_store.as_retriever(
    search_kwargs={'k': self.k}
)
  • 核心结论as\_retriever\(\) 返回的是 BaseRetriever 子类实例(检索工具),不是直接返回文档列表。

  • 作用:预绑定向量库、搜索参数(k值),LCEL 链会自动将用户问题传入检索器,无需手动传参。

  • 正确使用:需搭配 format\_docs 函数,将检索到的 Document 列表转为字符串(如 self\.retriever \| format\_docs)。

五、文档切割策略(多格式混合场景)

你的切割逻辑完全合理,必须保留:

  • 结构化文档(药品 JSON,含 通用名称:品牌名称:)→ 不切割(避免破坏药品信息完整性)

  • 非结构化文档(PDF/TXT/DOCX)→ 用 RecursiveCharacterTextSplitter 切割(解决长文本检索精度问题)

六、今日核心总结

  1. 400 报错是今日核心,本质是「通义 API 输入格式要求数组」,需解决提示词模板、format_docs、invoke 调用3个问题。

  2. 新版 LangChain 核心是 LCEL 链式写法,替代旧版 RetrievalQA,更透明、可自定义。

  3. 医药 RAG 关键:temperature 设 0.1~0.2、不编造信息、结构化药品不切割。

  4. 所有废弃方法/参数,均需按新版规范调整(如 model_kwargs、from_messages、自动持久化)。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐