Day21:(实战篇)从零搭建 RAG 系统(附通义千问 _ Deepseek _ 本地大模型完整代码)
Day21:(实战篇)从零搭建 RAG 系统(附通义千问 / Deepseek / 本地大模型完整代码)
前言:
上一篇我们讲透了 RAG 的核心原理,很多朋友在评论区催更代码。这篇直接上硬菜!全程保姆级,逐行注释,用 Python + LangChain + Chroma 搭建一个能精准回答 “2026 年 LPR 利率” 的 RAG 系统,通义千问、Deepseek、本地模型三种方案任选,新手复制粘贴就能跑!
开篇:别光看了,跑通代码才是自己的
上一篇发布后,有个朋友私信我说:“原理我都懂了,但一写代码就懵,能不能给个‘开箱即用’的?”
安排!这篇博客没有废话,全是干货。你只需要准备:
-
一台能上网的电脑(Windows/Mac/Linux 都行)
-
一个 Python 环境(3.8-3.11 版本最佳)
-
5 分钟申请的 API Key(不想用 API 也没关系,有纯本地方案)
跟着我走,30 分钟内,你就能看到自己的 RAG 系统精准输出答案,那种成就感,绝对比看 10 篇原理文都爽!
前情提要:
为了让我们能看出效果,我们先用千问、deepseek、本地qwen-7B模型,对于他们没有学习到的问题进行回答的结果:在不联网的情况下,在线的相关模型在2024年就截止更新数据了
qwen:qwen-plus模型
截至**2024年6月**,**2026年3月的1年期LPR利率尚未公布,也无法提前确定**。
原因如下:
✅ LPR(贷款市场报价利率)是由全国银行间同业拆借中心(NIFC)在**每月20日(遇节假日顺延)上午9:15**公布的**当月有效利率**,反映的是**当前市场资金供需和政策导向**,仅对未来一个月内新发放的贷款具有参考意义。
❌ LPR **不是长期固定利率**,也不会提前数年公布。因此,**2026年3月的LPR目前(2024年中)完全未知**,其具体数值将取决于届时的宏观经济形势、通胀水平、货币政策(如MLF操作利率调整)、银行资金成本及信贷需求等多重因素。
📌 当前最新数据(截至2024年6月20日公布):
- **1年期LPR为:3.45%**(自2023年8月起连续10个月维持不变)
- 5年期LPR为:3.95%
🔍 提示:若需预测2026年LPR趋势,可关注:
- 中国人民银行后续MLF利率调整;
- 国家统计局发布的CPI、PPI、GDP等宏观数据;
- 央行季度《货币政策执行报告》中的前瞻性指引;
- 市场对降准/降息的预期(如通过国债收益率、利率互换IRS定价推断)。
如您有特定用途(如贷款预算、财务建模),可基于当前利率+合理假设(如每年下调10–20BP)做情景分析,但需注明“假设性预测,非官方承诺”。
需要我帮您制作一个LPR敏感性分析表或未来两年的基准利率情景预测模板吗?
deepseek:deepseek-chat模型
截至2026年3月,中国最新的1年期贷款市场报价利率(LPR)尚未公布,因为当前时间仍为2024年。LPR由中国人民银行授权全国银行间同业拆借中心每月20日(遇节假日顺延)公布,具体数据需以官方发布为准。
如果您需要查询历史或未来的LPR数据,建议关注中国人民银行或全国银行间同业拆借中心的官方公告。对于当前(2024年)的LPR信息,我可以为您提供最新数据。
本地ollama:qwen:7b模型
提问:2026 年 3 月最新的 1 年期 LPR 利率是多少?
本地模型 (qwen:7b) 思考中...
💬 回答:对不起,但是作为一个AI,我无法提供实时的金融资讯,包括LPR利率的变化。建议您查询权威金融机构或使用相关的财经信息APP获取最准确的数据。
⏱️ 耗时:21.15 秒
环境准备:先把 “武器库” 配齐
在开始写代码前,我们需要先安装必要的 Python 库。打开你的终端(PyCharm 的 Terminal 或者 CMD 都行),复制粘贴以下命令:
# 一键安装所有依赖库(推荐用国内镜像源,速度飞快)
pip install langchain langchain-community chromadb dashscope openai sentence-transformers -i https://pypi.tuna.tsinghua.edu.cn/simple
第一步:准备 “弹药”—— 文档加载与预处理
我们先造一个简单的测试场景:假设我们有一份 “2026 年 3 月 LPR 利率公告”,我们要让 RAG 系统基于这份公告回答问题。
准备测试文档
在你的代码同级目录下,新建一个文本文件,命名为 lpr_2026.txt,内容如下:
中国人民银行授权全国银行间同业拆借中心公布,2026年3月20日贷款市场报价利率(LPR)为:1年期LPR为3.00%,5年期以上LPR为3.50%。以上LPR在下一次发布LPR之前有效。
该利率已连续10个月维持不变(自2025年6月以来未调整)。
写代码拆分文档
大模型没法直接啃下整份文档,我们要把它拆成 “小饼干”—— 文本块(Chunk)。新建一个 Python 文件 rag_demo.py,开始写代码:
from langchain.text_splitter import RecursiveCharacterTextSplitter
# ==========================================
# 第一步:文档加载与预处理
# ==========================================
print("📄 正在加载并拆分文档...")
# 1. 读取我们准备好的LPR公告
with open("lpr_2026.txt", "r", encoding="utf-8") as f:
raw_text = f.read()
# 2. 初始化文本拆分器(中文场景专属配置)
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=300, # 每个文本块最多300个字符(大概一段话)
chunk_overlap=50, # 块与块之间重叠50个字符,防止语义断裂
separators=["\n\n", "\n", "。", "!", "?", " ", ""] # 中文优先按标点符号拆分
)
# 3. 开始拆分!
chunks = text_splitter.split_text(raw_text)
# 打印看看效果
print(f"✅ 文档拆分完成!共拆成 {len(chunks)} 个文本块:")
for i, chunk in enumerate(chunks):
print(f"\n--- 第 {i+1} 块 ---\n{chunk}")
运行一下,你会看到文档被干净利落地拆成了小文本块,这一步就搞定了!
第二步:建立 “情报库”—— 向量化与存储
这是 RAG 最核心的一步:把文字变成计算机能懂的数字(向量),并存进向量数据库。
我给大家准备了两种方案,新手推荐用方案 A(省事),想完全离线的用方案 B(极客)。
方案 A:通义千问 Embedding(推荐新手首选)
首先你需要去阿里云申请一个通义千问的 API Key(百度 “通义千问 API Key 申请”,5 分钟搞定,新用户
有免费额度)。
在刚才的代码后面继续加:
import os
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import DashScopeEmbeddings
# ==========================================
# 第二步:向量化与存储(通义千问版)
# ==========================================
print("\n🔢 正在向量化并存入数据库...")
# 【重要】这里替换成你自己的通义千问API Key
os.environ["DASHSCOPE_API_KEY"] = "sk-你的API Key在这里"
# 1. 初始化通义千问Embedding模型
embedding_model = DashScopeEmbeddings(
model="text-embedding-v3" # 这是通义千问最新的Embedding模型,中文效果贼好
)
# 2. 初始化Chroma向量数据库
# 这会在当前目录下创建一个 chroma_db 文件夹,数据就存在里面
vector_db = Chroma.from_texts(
texts=chunks,
embedding=embedding_model,
persist_directory="./chroma_db"
)
# 3. 持久化保存(存到硬盘,下次不用重新向量化)
vector_db.persist()
print("✅ 向量化完成!数据已存入 chroma_db 文件夹")
方案 B:本地 Embedding 模型(bge-small-zh,完全免费)
如果你不想用 API,或者想在没网的环境下跑,就用这个方案。bge-small-zh 是中文场景最轻量最好用的 Embedding 模型,普通电脑就能跑。
把上面方案 A 的代码替换成:
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import HuggingFaceEmbeddings
# ==========================================
# 第二步:向量化与存储(本地模型版)
# ==========================================
print("\n🔢 正在加载本地Embedding模型并向量化...")
# 1. 初始化本地Embedding模型
# 第一次运行会自动下载模型(约100MB),之后就可以离线用了
embedding_model = HuggingFaceEmbeddings(
model_name="BAAI/bge-small-zh-v1.5",
model_kwargs={'device': 'cpu'} # 有N卡的同学可以把 'cpu' 改成 'cuda',速度更快
)
# 2. 初始化Chroma向量数据库
vector_db = Chroma.from_texts(
texts=chunks,
embedding=embedding_model,
persist_directory="./chroma_db_local" # 换个路径,和在线版区分开
)
vector_db.persist()
print("✅ 本地向量化完成!数据已存入 chroma_db_local 文件夹")
如果无法下载,可以使用ModelScope进行下载:
首先导入:pip install modelscope
然后代码改成这样:
# 1. 使用 ModelScope 下载模型(自动下载到本地缓存,下次直接用)
# 这是 bge-small-zh-v1.5 在 ModelScope 上的模型ID
model_dir = snapshot_download('AI-ModelScope/bge-small-zh-v1.5', cache_dir='./')
# 2. 初始化 Embedding 模型,指向刚才下载的本地路径
embedding_model = HuggingFaceEmbeddings(
model_name=model_dir, # 这里填本地路径,不再去 Hugging Face 下载
model_kwargs={'device': 'cpu'}
)
第三步:“检索员” 上线 —— 相似度检索
现在我们的 “情报库” 建好了,用户提问时,我们先让 “检索员” 去把最相关的资料找出来。
继续在代码后面加:
# ==========================================
# 第三步:相似度检索
# ==========================================
print("\n🔍 正在检索相关资料...")
# 用户的问题
user_question = "2026年3月最新的1年期LPR利率是多少?"
# 把向量数据库变成一个“检索器”,找最相关的3个文本块
retriever = vector_db.as_retriever(search_kwargs={"k": 3})
relevant_docs = retriever.get_relevant_documents(user_question)
# 打印检索结果
print(f"✅ 找到 {len(relevant_docs)} 条相关资料:")
for i, doc in enumerate(relevant_docs):
print(f"\n--- 资料 {i+1} ---\n{doc.page_content}")
运行到这里,你会看到系统精准地找到了我们存进去的 LPR 公告内容,是不是很神奇?
第四步:“智囊团” 作答 —— 增强生成(三种大模型任选)
最后一步,也是最激动人心的一步:把检索到的资料喂给大模型,让它基于资料回答。
这里我准备了通义千问、Deepseek、本地 Ollama三种方案,你想用哪个用哪个!
方案 A:通义千问(稳定靠谱,新手首选)
继续加代码:
from langchain_community.llms import Tongyi
from langchain.prompts import PromptTemplate
from langchain.chains import RetrievalQA
# ==========================================
# 第四步:增强生成(通义千问版)
# ==========================================
print("\n🤖 正在调用大模型生成答案...")
# 1. 初始化通义千问大模型
llm = Tongyi(
model="qwen-max", # 预算有限用 qwen-plus,追求效果用 qwen-max
temperature=0.1, # 温度设低一点,让大模型更严谨,少瞎编
dashscope_api_key="sk-你的API Key在这里" # 还是刚才那个API Key
)
# 2. 构建“防瞎编”Prompt模板(核心!)
prompt_template = """
你是一个专业、严谨的金融答疑助手。请严格遵守以下规则:
1. 只能使用下面【参考资料】里的内容回答问题,绝对不允许编造。
2. 如果参考资料里没有答案,直接说“抱歉,参考资料中没有相关内容”。
3. 回答要简洁明了,直接给答案,不要说废话。
【参考资料】
{context}
【用户问题】
{question}
"""
# 3. 初始化Prompt
PROMPT = PromptTemplate(
template=prompt_template,
input_variables=["context", "question"]
)
# 4. 构建RAG链(把检索和生成串起来)
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff", # 新手就用"stuff",简单直接
retriever=retriever,
return_source_documents=True, # 返回检索到的资料,方便我们验证
chain_type_kwargs={"prompt": PROMPT}
)
# 5. 运行!得到最终答案
result = qa_chain.invoke({"query": user_question})
# 6. 打印最终结果
print("\n" + "="*50)
print("🎯 【RAG系统最终回答】")
print(result["result"])
print("="*50)
回答结果:
💾 正在从硬盘加载向量库...
✅ 向量库加载成功!
🤖 正在查询: 2026年3月的1年期LPR是多少?
==================================================
🎯 【最终回答】
3.00%
==================================================
可以看出来,没有任何废话,直接给出答案
**换一种问法:**线上的API严格遵守了RAG的约束,我的资料中有5年以上是3.50%,理论上10年以上也是3.50%,但是线上的模型回答没有
💾 正在从硬盘加载向量库...
✅ 向量库加载成功!
🤖 正在查询: 2026年3月的10年期LPR是多少?
==================================================
🎯 【最终回答】
抱歉,参考资料中没有相关内容。
==================================================
方案B:Deepseek
# rag_query_deepseek_final.py (最终可运行版)
import os
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import DashScopeEmbeddings
# 改用 langchain_community 里的 ChatOpenAI(兼容性更好)
from langchain_community.chat_models import ChatOpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import RetrievalQA
# ==========================================
# 【必填配置】替换成你自己的 API Key
# ==========================================
# DeepSeek 的 API Key
DEEPSEEK_API_KEY = "你的API_KEY"
# ==========================================
# 1. 加载已有的向量库(通义千问 Embedding)
# ==========================================
print("💾 正在从硬盘加载向量库...")
# 初始化通义千问 Embedding(版本兼容)
embedding_model = DashScopeEmbeddings(
model="text-embedding-v3",
dashscope_api_key="你的API_KEY"
)
# 加载 Chroma 向量库
vector_db = Chroma(
persist_directory="./chroma_db", # 确保这个文件夹已存在(建库脚本生成的)
embedding_function=embedding_model
)
print("✅ 向量库加载成功!")
# ==========================================
# 2. 初始化 DeepSeek 大模型(核心适配)
# ==========================================
user_question = "2026年3月的1年期LPR是多少?"
# 构建检索器(取最相关的3条)
retriever = vector_db.as_retriever(search_kwargs={"k": 3})
# 初始化 DeepSeek 聊天模型(兼容 langchain 0.1.16)
llm = ChatOpenAI(
model="deepseek-chat",
temperature=0.1,
api_key=DEEPSEEK_API_KEY,
base_url="https://api.deepseek.com/v1" # 必须带 /v1
)
# ==========================================
# 3. 构建 Prompt 模板 + RAG 链
# ==========================================
# 防幻觉 Prompt 模板
prompt_template = """
你是一个专业、严谨的金融答疑助手。请严格遵守以下规则:
1. 只能使用下面【参考资料】里的内容回答问题,绝对不允许编造。
2. 如果参考资料里没有答案,直接说“抱歉,参考资料中没有相关内容”。
3. 回答要简洁明了,直接给答案。
【参考资料】
{context}
【用户问题】
{question}
"""
PROMPT = PromptTemplate(
template=prompt_template,
input_variables=["context", "question"]
)
# 构建 RAG 问答链
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=retriever,
return_source_documents=True,
chain_type_kwargs={"prompt": PROMPT}
)
# ==========================================
# 4. 执行查询并输出结果
# ==========================================
print(f"\n🤖 正在查询: {user_question}")
result = qa_chain.invoke({"query": user_question})
# 打印最终结果
print("\n" + "="*50)
print("🎯 【最终回答】")
print(result["result"])
print("="*50)
# 可选:打印检索到的参考资料(方便验证)
print("\n📚 检索到的参考资料:")
for i, doc in enumerate(result["source_documents"]):
print(f"\n--- 参考资料 {i+1} ---\n{doc.page_content}")
回答结果:
🤖 正在查询: 2026年3月的1年期LPR是多少?
==================================================
🎯 【最终回答】
3.00%。
==================================================
📚 检索到的参考资料:
--- 参考资料 1 ---
中国人民银行授权全国银行间同业拆借中心公布,2026年3月20日贷款市场报价利率(LPR)为:1年期LPR为3.00%,5年期以上LPR为3.50%。以上LPR在下一次发布LPR之前有效。
该利率已连续10个月维持不变(自2025年6月以来未调整)。
方案C:本地ollama+qwen:4b
# rag_query_qwen.py (通义千问查询版)
import os
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import DashScopeEmbeddings
# 导入 Ollama 来调用本地 qwen:7b
from langchain_community.llms import Ollama
from langchain.prompts import PromptTemplate
from langchain.chains import RetrievalQA
# ==========================================
# 【重要配置】填入你的通义千问 API Key
# ==========================================
os.environ["DASHSCOPE_API_KEY"] = "你的API_KEY"
# ==========================================
# 1. 加载已有的向量库
# ==========================================
print("💾 正在从硬盘加载向量库...")
# 【关键】必须使用和建库时完全一样的 Embedding 模型
embedding_model = DashScopeEmbeddings(
model="text-embedding-v3"
)
# 直接加载 Chroma 数据库
vector_db = Chroma(
persist_directory="./chroma_db", # 指向刚才建库的文件夹
embedding_function=embedding_model
)
print("✅ 向量库加载成功!")
# ==========================================
# 2. 初始化通义千问大模型并进行问答
# ==========================================
user_question = "2026年3月的10年期LPR是多少?"
# 把数据库变成检索器
retriever = vector_db.as_retriever(search_kwargs={"k": 3})
# 初始化通义千问大模型
llm = Ollama(
model="qwen:7b", # 对应 Ollama 拉取的 qwen:7b 模型名
temperature=0.1, # 低温度保证回答严谨
num_ctx=2048 # 上下文窗口大小,按需调整
)
# Prompt 模板
prompt_template = """
你是一个专业、严谨的金融答疑助手。请严格遵守以下规则:
1. 只能使用下面【参考资料】里的内容回答问题,绝对不允许编造。
2. 如果参考资料里没有答案,直接说“抱歉,参考资料中没有相关内容”。
3. 回答要简洁明了,直接给答案。
【参考资料】
{context}
【用户问题】
{question}
"""
PROMPT = PromptTemplate(template=prompt_template, input_variables=["context", "question"])
# 构建 RAG 链
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=retriever,
return_source_documents=True,
chain_type_kwargs={"prompt": PROMPT}
)
# 运行查询
print(f"\n🤖 正在查询: {user_question}")
result = qa_chain.invoke({"query": user_question})
print("\n" + "="*50)
print("🎯 【最终回答】")
print(result["result"])
print("="*50)
回答结果:
💾 正在从硬盘加载向量库...
✅ 向量库加载成功!
🤖 正在查询: 2026年3月的1年期LPR是多少?
==================================================
🎯 【最终回答】
2026年3月20日的1年期LPR为3.00%。
==================================================
换一种问法:
💾 正在从硬盘加载向量库...
✅ 向量库加载成功!
🤖 正在查询: 2026年3月的10年期LPR是多少?
==================================================
🎯 【最终回答】
2026年3月20日的贷款市场报价利率(LPR)中,10年期以上的LPR为3.50%。但需要注意的是,这个利率是到下一次发布LPR之前的有效信息。
==================================================
可以看出本地还能举一反三,实际上是调用了自身通用知识库
为什么?
| 维度 | 线上 qwen-plus | 本地 qwen:7b |
|---|---|---|
| 规则执行力度 | 严格遵守 “仅用参考资料”,拒绝越界 | 宽松遵守,优先调用自身知识补全 |
| 通用知识调用权限 | 被限制(RAG 模式下禁用) | 无限制(可自由调用训练数据中的知识) |
| 检索结果的权重 | 检索结果 = 全部依据,无结果则返回无内容 | 检索结果 = 参考,无结果也会补全自身知识 |
| 平台合规约束 | 强约束(避免编造) | 无约束(本地部署无合规限制) |
如何让线上 qwen-plus 也能正确回答?
-
优化检索(让 “10 年期” 能匹配到 “5 年期以上” 的内容)
修改检索器的配置,增加 “同义词 / 扩展匹配”,比如:
# 给检索器增加“模糊匹配”或“扩展关键词” retriever = vector_db.as_retriever( search_kwargs={ "k": 3, "score_threshold": 0.1 # 降低匹配阈值,让相似文本也能被检索到 } ) -
优化 Prompt(允许模型 “合理推导”)
把 Prompt 中过于严格的规则,调整为 “允许基于参考资料推导”:
prompt_template = """
你是专业金融答疑助手,遵守以下规则:
1. 优先使用【参考资料】的内容回答问题;
2. 如果参考资料中有相关逻辑(如“5年期以上”包含更长年限),可以基于此推导回答;
3. 完全无相关内容时,才说“抱歉,参考资料中没有相关内容”。
【参考资料】
{context}
【用户问题】
{question}
"""
总结与预告
这篇博客我们从零开始,用不到 100 行代码,跑通了 RAG 的全流程:
-
文档拆分:把大文档拆成小文本块
-
向量化存储:用通义千问或本地模型把文字变成向量,存进 Chroma
-
相似度检索:用户提问时,先找最相关的资料
-
增强生成:把资料喂给大模型,得到精准靠谱的答案
下一篇预告:
很多朋友说:“我只有 PDF 文件,怎么办?”“我有 100 个文档,能一起检索吗?”
下一篇我们就讲:如何用 RAG 处理 PDF、Word 等多格式文件,以及如何构建多文档知识库。
关注我,带你三个月从 AI Agent 入门到精通!如果这篇博客对你有帮助,别忘了点赞、收藏、评论三连哦!有问题评论区见~
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)