🌟 LangChain 30 天保姆级教程 · Day 18|RAG 终极整合!用 RetrievalQA 构建企业级问答系统,支持引用溯源!

4 阅读4分钟

系列目标:30 天从 LangChain 入门到企业级部署
今日任务:理解 RAG 工作流 → 掌握 RetrievalQA 链 → 实现“检索 + 生成 + 引用标注”三位一体问答系统!


🔗 一、RAG 是什么?为什么重要?

RAG = Retrieval-Augmented Generation(检索增强生成)

传统 LLM 的问题:

  • ❌ 知识截止(如 Qwen 训练数据止于 2024)
  • ❌ 幻觉(编造公司政策)
  • ❌ 无法访问私有数据

RAG 的解决方案

  1. 检索:从你的知识库(PDF/数据库等)找出相关片段
  2. 增强:将片段作为上下文注入 Prompt
  3. 生成:LLM 基于真实资料回答,减少幻觉

✅ 今天,我们就用 LangChain 的 RetrievalQA Chain,5 行代码构建 RAG 系统!


🧱 二、RAG 核心组件回顾

表格

组件来源
文档加载Day 16(PDF/Word/网页)
向量存储Day 17(Chroma + nomic-embed-text)
LLMOllama + Qwen(本地运行)
检索链今日主角:RetrievalQA

💡 所有组件均已就绪,只需“拼装”!


🛠️ 三、动手实践:构建端到端 RAG 问答系统

步骤 1:加载已有的 Chroma 向量库

# day18_rag_qa.py
from langchain_chroma import Chroma
from langchain_ollama import OllamaEmbeddings, ChatOllama

# 加载 Embedding 模型
embeddings = OllamaEmbeddings(model="nomic-embed-text")

# 加载持久化的向量库(来自 Day 17)
vectorstore = Chroma(
    persist_directory="./chroma_db",
    embedding_function=embeddings
)

步骤 2:创建检索器(Retriever)

# 创建检索器,返回最相关的 3 个片段
retriever = vectorstore.as_retriever(
    search_type="similarity",
    search_kwargs={"k": 3}
)

🔍 可选 search_type="mmr"(最大边际相关性),提升多样性。


步骤 3:初始化 LLM

# 使用 Qwen 7B 生成答案
llm = ChatOllama(
    model="qwen:7b",
    temperature=0,
    streaming=True  # 支持流式输出(Day 15)
)

步骤 4:构建 RetrievalQA Chain

from langchain.chains import RetrievalQA

# 创建 RAG 链
qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",        # 将所有检索结果塞入 prompt
    retriever=retriever,
    return_source_documents=True  # 关键!返回引用来源
)

📌 chain_type 选项:

  • "stuff":适合短文档(默认)
  • "map_reduce" / "refine":适合长文档(Day 22 讲)

步骤 5:提问并查看带引用的回答

query = "员工年假最多可以休多少天?"

result = qa_chain.invoke({"query": query})

print("🤖 AI 回答:")
print(result["result"])

print("\n📚 引用来源:")
for i, doc in enumerate(result["source_documents"], 1):
    print(f"{i}. {doc.metadata.get('source')} (页码: {doc.metadata.get('page')})")
    print(f"   内容预览: {doc.page_content[:100]}...\n")

▶️ 输出示例:

🤖 AI 回答:
根据公司政策,员工每年最多可休15天带薪年假,未使用部分不可跨年累计。

📚 引用来源:
1. ./docs/company_policy.pdf (页码: 12)
   内容预览: 第五章 年假管理 第三条:正式员工每年享有15天带薪年假...

2. ./docs/company_policy.pdf (页码: 13)
   内容预览: 年假不可跨年度累计,未休年假将按日薪200%折算补偿...

✅ 完美实现

  • 基于真实文档回答
  • 自动标注引用来源
  • 避免幻觉

🎨 四、优化 Prompt:让回答更专业

默认 Prompt 可能不够精准,可自定义:

from langchain_core.prompts import PromptTemplate

prompt_template = """
你是一个公司HR助手,请基于以下上下文回答问题。
如果不知道答案,请说“根据现有资料无法回答”,不要编造。

上下文:
{context}

问题:{question}

回答:
"""

PROMPT = PromptTemplate(
    template=prompt_template,
    input_variables=["context", "question"]
)

qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",
    retriever=retriever,
    return_source_documents=True,
    chain_type_kwargs={"prompt": PROMPT}
)

💡 自定义 Prompt 可控制语气、格式、安全边界!


⚠️ 五、注意事项 & 最佳实践

表格

问题建议
检索结果不相关调整 k 值;优化分块策略(Day 16)
LLM 忽略上下文在 Prompt 中强调“必须基于上下文回答”
引用太多干扰阅读前端只展示“来源文件名”,点击展开详情
敏感信息泄露在文档加载阶段脱敏(Day 16 + Day 14 Callback)
响应慢缓存高频问题;限制 k 值(通常 3~5 足够)

💡 生产建议

  • 所有回答附带 source_documents,支持审计
  • 对“无法回答”的问题记录日志,持续补充知识库

📦 六、配套代码结构

langchain-30-days/
└── day18/
    ├── rag_qa_system.py          # RAG 问答主程序
    └── chroma_db/                # 向量库(来自 Day 17)

📝 七、今日小结

  • ✅ 理解了 RAG 的核心价值:用私有知识增强 LLM
  • ✅ 学会了用 RetrievalQA 快速构建问答系统
  • ✅ 实现了带引用溯源的专业回答
  • ✅ 掌握了自定义 Prompt 优化回答质量
  • ✅ 知道了 RAG 系统的常见陷阱与对策

🎯 明日预告:Day 19 —— RAG 进阶:多路召回、重排序(Rerank)、HyDE 查询扩展!