最小可运行的 RAG示例
上面代码是一个可用的 LangChain + 阿里云通义千问 RAG 最小示例。其逻辑非常清晰,就是:加载 → 切分 → 向量化 → 检索 → QA。
https://item.jd.com/15261772.html
# -*- coding: utf-8 -*-
"""
Created on Thu Jul 24 21:03:45 2025
@author: liguo
"""
from langchain_community.document_loaders import TextLoader
from langchain_community.indexes import VectorstoreIndexCreator
from langchain_text_splitters import CharacterTextSplitter
from langchain_community.embeddings import DashScopeEmbeddings # 👈 替换 QwenEmbeddings
from langchain_community.vectorstores import Chroma
from langchain.chains import RetrievalQA
from langchain_community.llms import Tongyi # Qwen
import os
# 设置阿里云 DashScope API Key(必须)
api_key=os.getenv("DASHSCOPE_API_KEY") # 👈 替换为你自己的 API Key
def basic_rag_flow():
# 1. 加载文档 —— 修复编码问题
loader = TextLoader("example.txt", encoding='utf-8')
documents = loader.load()
# 2. 分割文档
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_documents(documents)
# 3. 创建嵌入和向量存储(使用通义千问的 Embedding 模型)
embeddings = DashScopeEmbeddings(
model="text-embedding-v1", # 阿里云提供的嵌入模型
dashscope_api_key=os.environ["DASHSCOPE_API_KEY"]
)
vectorstore = Chroma.from_documents(texts, embeddings)
# 4. 构建检索器
retriever = vectorstore.as_retriever()
# 5. 创建RAG链(使用通义千问大模型)
llm = Tongyi(
model_name="qwen-max", # 也可以用 "qwen-plus", "qwen-turbo" 等
api_key=api_key,
temperature=0.1
)
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=retriever,
return_source_documents=True # 可选:返回参考文档
)
# 6. 执行查询并输出结果
query = "请总结文档的主要内容"
result = qa_chain.invoke({"query": query}) # 👈 注意:新版推荐用 invoke
print("问题:", query)
print("回答:", result["result"])
# 可选:打印参考文档
# for doc in result["source_documents"]:
# print("参考文档片段:", doc.page_content[:200], "...")
return qa_chain
# 调用函数以执行流程
if __name__ == "__main__":
basic_rag_flow()
下面我按模块 + 按流程对你给出的代码做一次完整解析,并明确说明:
👉 这个示例到底在演示什么?
👉 每一步解决了什么问题?
一、这个示例整体在演示什么?
✅ 这是一个“最小可运行的 RAG(检索增强生成)示例”
它演示了如何用 LangChain + 阿里云通义千问(Qwen) 完成:
“基于本地文档内容回答问题”
也就是:
📄 本地文本文件
⬇
🔍 向量检索
⬇
🤖 大模型生成答案
这正是 RAG 的核心流程。
二、RAG 的核心思想(先看这个)
RAG = Retrieval-Augmented Generation
用户问题
↓
从文档中检索相关内容
↓
把相关内容交给大模型
↓
生成基于事实的回答
✅ 目的:
-
减少大模型幻觉
-
利用私有数据
-
不依赖模型训练
三、代码结构总览
basic_rag_flow()
├─ 1. 加载文档
├─ 2. 切分文档
├─ 3. 向量化 + 存入向量库
├─ 4. 构建检索器
├─ 5. 构建 RAG 问答链
└─ 6. 执行查询
四、逐段代码解析
✅ 1️⃣ 导入依赖(基础设施)
from langchain_community.document_loaders import TextLoader
from langchain_community.indexes import VectorstoreIndexCreator
from langchain_text_splitters import CharacterTextSplitter
from langchain_community.embeddings import DashScopeEmbeddings
from langchain_community.vectorstores import Chroma
from langchain.chains import RetrievalQA
from langchain_community.llms import Tongyi
📌 这些模块分别对应:
|
模块 |
作用 |
|---|---|
|
TextLoader |
读取本地文本 |
|
CharacterTextSplitter |
文本切分成块 |
|
DashScopeEmbeddings |
阿里云向量模型 |
|
Chroma |
向量数据库 |
|
RetrievalQA |
RAG 问答链 |
|
Tongyi |
通义千问 LLM |
✅ 2️⃣ 加载文档(数据来源)
loader = TextLoader("example.txt", encoding='utf-8')
documents = loader.load()
📌 这一步在做什么?
-
从本地加载
example.txt -
返回一个
Document对象列表 -
每个 Document 包含:
page_content = 文本内容 metadata = {"source": "example.txt"}
✅ 这是 RAG 的数据入口
✅ 3️⃣ 文本切分(非常关键)
text_splitter = CharacterTextSplitter(
chunk_size=1000,
chunk_overlap=0
)
texts = text_splitter.split_documents(documents)
📌 为什么一定要切分?
-
Embedding 模型有长度限制
-
向量检索更适合“小块语义”
-
LLM 上下文有限
📌 切分后变成:
texts = [
Document(...),
Document(...),
Document(...)
]
每一段都是一个 可独立检索的语义单元
✅ 4️⃣ 向量化 & 向量库(检索基础)
embeddings = DashScopeEmbeddings(
model="text-embedding-v1",
dashscope_api_key=os.environ["DASHSCOPE_API_KEY"]
)
📌 这一步在做什么?
-
把 文本 → 向量(数字)
-
使用的是阿里云的
text-embedding-v1
vectorstore = Chroma.from_documents(texts, embeddings)
📌 Chroma 做了什么?
-
把所有文本块存成向量
-
建立索引
-
支持 相似度搜索
✅ 到这里,你已经拥有了一个 “可检索的知识库”
✅ 5️⃣ 构建检索器(Retriever)
retriever = vectorstore.as_retriever()
📌 Retriever 的作用:
给定一个问题 → 返回最相关的文档片段
等价于:
问题 → 向量化 → 相似度匹配 → Top-K 文档
✅ 6️⃣ 构建 RAG 问答链(核心)
llm = Tongyi(
model_name="qwen-max",
api_key=api_key,
temperature=0.1
)
📌 LLM 负责:
-
理解问题
-
阅读检索到的文档
-
生成最终答案
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=retriever,
return_source_documents=True
)
📌 RetrievalQA做了什么?
自动完成这个流程:
用户输入问题
↓
Retriever 找相关文档
↓
把问题和文档拼在一起
↓
LLM 生成答案
📌 chain_type="stuff"的含义:
-
把所有检索到的文档 直接塞进 prompt
-
简单、直观
-
适合文档不太长的场景
✅ 7️⃣ 执行查询
query = "请总结文档的主要内容"
result = qa_chain.invoke({"query": query})
📌 实际发生了什么?
-
问题 → embedding
-
去 Chroma 里找相关内容
-
拼接成类似这样的 prompt:
根据以下内容回答问题:
[文档片段1]
[文档片段2]
问题:请总结文档的主要内容
-
Qwen 生成答案
五、这个示例“演示了什么能力”?
✅ 它不是一个玩具,而是一个 标准 RAG 模板,展示了:
|
能力 |
是否演示 |
|---|---|
|
私有数据接入 |
✅ |
|
文本向量化 |
✅ |
|
向量检索 |
✅ |
|
大模型增强生成 |
✅ |
|
LangChain 标准用法 |
✅ |
|
阿里云通义千问集成 |
✅ |
六、一句话总结
这个示例演示了:如何使用 LangChain + 阿里云 DashScope,构建一个基于本地文档的检索增强生成(RAG)问答系统。
