RAG知识库问答系统实战:从零搭建并用Deepseek驱动

发布时间:2026/9/8 10:40:27
RAG知识库问答系统实战:从零搭建并用Deepseek驱动 在业务中接入大模型时很多同学都会走到同一步希望大模型能回答自己企业内部文档里的问题。但直接提问会发现模型既不了解你的业务也容易一本正经地编造答案。要解决这个问题RAG 是目前最实用、成本最低的方案。本文将基于一套完整可运行的代码带你从零搭建一个RAG知识库问答系统并把 Deepseek 作为最终生成模型接入其中从原理到落地一次性讲透。先说一下本文适合谁对大模型感兴趣但还没系统接触过 RAG 的开发者、正在做企业知识库需求的后端工程师、想在自己电脑上跑通一套完整问答系统的学习者。读完本文你会理解 RAG 的完整处理链路掌握文档加载、文本切分、向量化、向量检索、Prompt 组装、大模型生成这几个关键环节并拿到一套可以扩展成真实项目的基础源码。1. RAG 到底是什么为什么大模型需要它1.1 从大模型的“知识缺陷”说起大模型虽然能写文章、写代码、做翻译但有一个天然缺陷它的知识来自训练数据存在明显的“知识截止时间”。如果你的问题涉及企业最新制度、某个产品的使用手册、某个系统的内部操作说明大模型很可能会回答一个看似合理、实则错误的内容这就是常说的“幻觉”问题。举个例子你问“公司请休假制度是什么”模型可能会编造一套看似标准的制度而它根本没有见过你公司的文档。此时你不可能为了这个问题重新训练一个大模型成本太高也不现实。RAG 的解决思路很直接与其让模型“背”下所有知识不如在它回答问题之前先帮它找到相关资料。这就好比考试时允许翻书模型不用死记硬背只需要根据“查到的那几页”来组织答案。1.2 RAG 的完整定义与核心流程RAG全称 Retrieval-Augmented Generation检索增强生成。它是一种将信息检索与文本生成相结合的架构先从外部知识库中检索出与用户问题相关的文档片段再将片段与问题一起交给大模型让模型基于这些片段生成回答。标准 RAG 的处理流程可以拆成八个环节文档加载读取内部文档支持 txt、PDF、Word、Markdown 等格式。文本切分长文档不能整体向量化需要按一定策略切分成 chunk文本块。向量化使用 embedding 模型将每个 chunk 转换为向量向量可以理解为一段文本的语义坐标。向量存储将向量和原文一起存入向量数据库例如 Chroma、FAISS、Milvus。问题向量化用户提问时将问题也转换为向量。相似度检索计算问题向量与知识库向量的相似度返回最相关的 Top K 个片段。Prompt 组装将系统提示词、检索到的片段、用户问题拼接成一个完整的 Prompt。生成回答将 Prompt 发送给大模型模型基于片段内容生成最终答案。1.3 RAG 与模型微调的区别很多初学者会把 RAG 和微调搞混。简单来说微调是修改模型的“记忆”RAG 是给模型“查资料”。两者各有适用场景对比维度RAG微调成本较低无需训练显卡较高需要训练资源和数据准备知识更新替换文档即可实时生效需要重新训练周期长可解释性回答可溯源到具体文档片段相对难以解释模型参考了什么幻觉控制通过限定参考片段效果明显降低有限模型仍可能生成非训练知识适用场景企业知识库、文档问答、实时信息改变模型语气风格、专业术语理解、特定格式输出真实项目中RAG 和微调也经常配合使用。如果模型本身对你所在行业的术语理解较弱可以先用部分数据微调模型再叠加 RAG 让模型获取最新知识。但对大多数知识库问答需求来说RAG 是首选中低成本方案。2. 系统方案设计与技术选型2.1 方案目标我们要搭建的这套系统需要满足以下需求支持把本地文档导入知识库。文档必须支持持续追加和更新不需要重训练模型。用户提问后系统能检索到相关文档片段并在回答中给出依据。最终生成模型使用 Deepseek API保证中文效果且调用简单。整个系统可以本地运行不依赖大型 GPU 环境。2.2 总体架构根据需求系统的整体架构可以这样设计用户提问Web界面 / 命令行 ↓ 中文问题向量化本地Embedding模型 ↓ Chroma向量库相似度检索 ↓ 返回 Top-K 相关文档片段 ↓ 组装 Prompt系统提示词 参考片段 用户问题 ↓ 调用 Deepseek Chat API ↓ 生成最终回答并返回给用户在这个架构中文档离线处理链路把原始知识库转换为向量索引在线问答链路负责检索与生成。两条链路合起来就是一套完整的 RAG 系统。2.3 技术栈说明本方案涉及的主要技术组件如下模块技术选型选择原因文档加载Python 内置文件读取轻量零依赖适合 txt 文档入门文本切分LangChain Text Splitters成熟的切分策略支持重叠窗口向量化模型sentence-transformers bge-small-zh-v1.5中文效果好本地运行免费向量数据库Chroma轻量级无需独立服务适合快速开发生成模型Deepseek Chat API中文能力强兼容 OpenAI 协议接入成本低Web 展示层Streamlit用 Python 快速搭建交互界面为什么使用 Deepseek 作为生成模型这是很多读者关心的问题。Deepseek 的 API 调用方式与 OpenAI 协议兼容只需要安装 openai SDK 并修改 base_url 和 api_key 就能完成接入非常省事。同时Deepseek 在中文理解与生成上的表现足够优秀适合中文知识库问答场景。相比本地部署一个十几B或几十B的大模型API 方式对电脑性能要求极低个人开发者和中小规模应用都能低成本使用。为什么 embedding 模型选用本地部署原因也很实际。如果每次写文档和提问都调用外部 embedding 接口会产生持续费用同时还会把文档内容送到第三方服务。使用本地 bge-small-zh-v1.5 模型只需要首次运行下载模型文件之后便可以在完全离线的状态下完成向量化成本低、隐私性也更好。3. 环境准备与项目结构3.1 安装 Python 与依赖本文示例以 Python 3.9 及以上版本为例。老规矩先创建一个独立的虚拟环境避免依赖污染系统环境python -m venv rag-demo-env source rag-demo-env/bin/activate # Windows 下为 rag-demo-env\Scripts\activate然后安装依赖包pip install openai sentence-transformers chromadb langchain-text-splitters streamlit python-dotenv如果你的环境安装速度较慢可以更换为国内 pip 镜像源pip install -i https://pypi.tuna.tsinghua.edu.cn/simple openai sentence-transformers chromadb langchain-text-splitters streamlit python-dotenv这里不锁定具体版本号因为这些库的迭代速度较快建议使用当前最新稳定版即可。如果后续遇到某个库升级导致接口变动可以回到对应官方文档确认最新用法。3.2 项目目录结构完整源码建议按照下面的目录结构保存rag-demo/ ├── .env # API Key 等敏感配置不提交到仓库 ├── requirements.txt # 依赖清单 ├── config.py # 全局配置 ├── ingest.py # 文档加载与向量库构建 ├── retriever.py # 检索模块 ├── rag.py # RAG 问答主流程 ├── app.py # Streamlit Web 界面 └── data/ # 存放私有文档 ├── 公司介绍.txt └── product_faq.txtrequirements.txt 文件内容如下openai1.0.0 sentence-transformers2.2.0 chromadb0.4.0 langchain-text-splitters0.0.1 streamlit1.30.0 python-dotenv1.0.04. 核心代码实现从文档到知识库4.1 全局配置 config.py代码的第一步是写一个配置模块把路径、模型名称、检索参数等集中管理起来。这样后续修改参数时不需要翻遍每个文件。# 文件路径rag-demo/config.py import os from dotenv import load_dotenv # 加载 .env 文件中的环境变量 load_dotenv() # 知识库文档目录 KNOWLEDGE_BASE_DIR data # Chroma 向量库持久化目录 CHROMA_DIR ./chroma_db # 向量库集合名称 COLLECTION_NAME rag_demo # 本地 Embedding 模型名称 EMBEDDING_MODEL_NAME BAAI/bge-small-zh-v1.5 # 检索返回的片段数量 TOP_K 3 # 文档切分参数 CHUNK_SIZE 500 CHUNK_OVERLAP 50 # Deepseek API 配置 DEEPSEEK_API_KEY os.getenv(DEEPSEEK_API_KEY, ) DEEPSEEK_BASE_URL os.getenv(DEEPSEEK_BASE_URL, https://api.deepseek.com) DEEPSEEK_MODEL os.getenv(DEEPSEEK_MODEL, deepseek-chat)有一处要重点说明DEEPSEEK_API_KEY 不建议硬编码在代码文件中应该写在项目根目录的 .env 文件里并确保 .env 被加入 .gitignore。这样可以避免 API Key 意外提交到公开仓库造成安全风险。.env 文件的格式如下DEEPSEEK_API_KEY你的Deepseek_API_Key关于 Deepseek API 的使用请前往 Deepseek 官方开放平台注册并创建 API Key。使用 API 会产生少量费用具体计费标准以官方页面为准建议先小额充值并查看接口文档中的价格说明。4.2 文档加载与向量化入库 ingest.pyingest.py 的作用是读取 data 目录下的文档进行切分、向量化然后写入向量数据库。这是整个 RAG 系统的离线构建阶段。# 文件路径rag-demo/ingest.py import os from typing import List from langchain_text_splitters import CharacterTextSplitter from sentence_transformers import SentenceTransformer import chromadb import config def load_documents(data_dir: str) - List[str]: 读取 data 目录下的所有 txt 文件返回文档内容列表。 docs [] for filename in os.listdir(data_dir): if filename.endswith(.txt): filepath os.path.join(data_dir, filename) with open(filepath, r, encodingutf-8) as f: content f.read() if content.strip(): docs.append(content) print(f已加载文档: {filename}) return docs def split_text(documents: List[str]) - List[str]: 将长文档切分成指定大小的文本块 chunk。 splitter CharacterTextSplitter( separator\n, chunk_sizeconfig.CHUNK_SIZE, chunk_overlapconfig.CHUNK_OVERLAP, length_functionlen, ) chunks [] for doc in documents: chunks.extend(splitter.split_text(doc)) return chunks def build_vector_store(chunks: List[str]): 将文本块向量化并写入 Chroma 向量库。 # 加载本地 embedding 模型首次运行会自动下载 print(正在加载 embedding 模型...) embedder SentenceTransformer(config.EMBEDDING_MODEL_NAME) # 生成向量 print(正在生成向量...) embeddings embedder.encode(chunks, show_progress_barTrue).tolist() # 创建 Chroma 客户端持久化到本地目录 client chromadb.PersistentClient(pathconfig.CHROMA_DIR) # 如果集合已存在先删除避免重复插入 existing_collections client.list_collections() for col in existing_collections: if col.name config.COLLECTION_NAME: client.delete_collection(config.COLLECTION_NAME) print(已删除旧的向量库集合) collection client.create_collection( nameconfig.COLLECTION_NAME, metadata{hnsw:space: cosine}, # 使用余弦相似度 ) # 写入向量库id 使用序号方便管理 ids [str(i) for i in range(len(chunks))] # 这里直接把原始文本和向量一起存入 collection.add( idsids, embeddingsembeddings, documentschunks, ) print(f向量库构建完成共写入 {len(chunks)} 个文本块) if __name__ __main__: all_docs load_documents(config.KNOWLEDGE_BASE_DIR) if not all_docs: raise ValueError(fdata 目录下没有找到可用文档请检查目录: {config.KNOWLEDGE_BASE_DIR}) all_chunks split_text(all_docs) print(f文档切分完成共得到 {len(all_chunks)} 个文本块) build_vector_store(all_chunks)这段代码的重点有几个。文本切分参数值得专门调试。CHUNK_SIZE 表示每个文本块的最大字符数CHUNK_OVERLAP 表示相邻块之间重叠的字符数。重叠的部分可以让切块边界处的语义不丢失尤其是当问题和答案分别跨越两个块边界时重叠能明显提升召回效果。实际项目中500 到 800 字是比较常见的块大小过小会导致检索上下文不足过大则会让单块包含太多无关信息降低检索精度。Chroma 的持久化方式在代码中使用了 PersistentClient向量库数据会保存到 ./chroma_db 目录。这样下次启动系统时不需要重新构建向量库直接读取即可。如果知识库文档发生了更新重新运行一次 ingest.py 即可不必重启任何服务。4.3 检索模块 retriever.pyretriever.py 负责接收用户问题将其向量化后在 Chroma 中检索最相关的 Top K 个片段。# 文件路径rag-demo/retriever.py import chromadb from sentence_transformers import SentenceTransformer import config def get_embedder(): 获取共享的 embedding 模型实例避免多次重复加载。 return SentenceTransformer(config.EMBEDDING_MODEL_NAME) def search(query: str, top_k: int None): 根据用户问题检索知识库返回相关片段列表。 if top_k is None: top_k config.TOP_K # 加载向量库 client chromadb.PersistentClient(pathconfig.CHROMA_DIR) collection client.get_collection(config.COLLECTION_NAME) # 对用户问题进行向量化 embedder get_embedder() query_embedding embedder.encode([query]).tolist() # 执行相似度检索 results collection.query( query_embeddingsquery_embedding, n_resultstop_k, ) documents results.get(documents, [[]])[0] distances results.get(distances, [[]])[0] return documents, distances这里需要留意一个问题每次调用 get_embedder 都会重新加载一次模型。在 Streamlit 这种 Web 服务中频繁加载模型会拖慢速度。实际开发时可以把 embedder 设计成全局单例或者放到内存缓存中。我在这里保留简单写法是为了让流程更清晰后面工程优化部分再讨论如何改进。Chroma 的 query 接口返回结果中documents 是对应的原始文本内容distances 是余弦距离。距离越小表示相似度越高后续可以把距离信息一并展示帮助用户判断答案的可信度。4.4 RAG 问答主流程 rag.pyrag.py 是系统的核心负责把检索结果和用户问题组装成 Prompt然后调用 Deepseek 生成回答。# 文件路径rag-demo/rag.py from openai import OpenAI import config from retriever import search # 初始化 Deepseek 客户端兼容 OpenAI SDK client OpenAI( api_keyconfig.DEEPSEEK_API_KEY, base_urlconfig.DEEPSEEK_BASE_URL, ) def build_prompt(query: str, context_docs: list) - str: 组装发送给大模型的 Prompt。 system_prompt ( 你是一个专业的知识库问答助手。 请根据提供的参考资料回答用户问题。 必须优先参考参考资料中的内容不要臆造答案。 如果参考资料无法回答该问题请直接说明知识库中暂未找到相关信息。 ) context \n\n.join(context_docs) user_prompt f请根据以下参考资料回答用户问题。 【参考资料】 {context} 【用户问题】 {query} 请用中文回答如果引用了参考资料可以说明信息来源于哪个部分。 return system_prompt, user_prompt def ask(query: str) - dict: Retrieve Generate 完整流程。 # 检索相关片段 docs, distances search(query) # 组装 Prompt system_prompt, user_prompt build_prompt(query, docs) # 调用 Deepseek 生成回答 response client.chat.completions.create( modelconfig.DEEPSEEK_MODEL, temperature0.3, messages[ {role: system, content: system_prompt}, {role: user, content: user_prompt}, ], ) answer response.choices[0].message.content return { answer: answer, source_documents: docs, distances: distances, } if __name__ __main__: question input(请输入你的问题) result ask(question) print(\n 回答 ) print(result[answer]) print(\n 引用片段 ) for i, doc in enumerate(result[source_documents]): print(f\n[{i 1}] {doc[:200]})Deepseek 的接入方式与 OpenAI 几乎一致核心代码只有这么几行。这里给出的 model 名称是 deepseek-chat对应 Deepseek 的对话模型。temperature 设置为 0.3会让回答更加稳定、更贴近参考资料内容。如果你想获得更有创造性的回答可以调高到 0.7 左右但在知识库问答场景下推荐保持低 temperature以减少胡说八道的概率。Prompt 的设计值得仔细思考。系统提示词明确要求“必须优先参考参考资料中的内容不要臆造答案”这一步是抑制幻觉的关键。如果直接把问题和检索片段丢给模型而不加任何约束模型仍然可能倾向使用自己的知识回答。所以在 RAG 系统中Prompt 不是随便拼一段文字而是需要反复打磨的工程质量项。4.5 Streamlit Web 界面 app.py最后写一个简单的 Web 界面让系统可以被同事或用户直接使用。# 文件路径rag-demo/app.py import streamlit as st import config from rag import ask st.set_page_config(page_titleRAG 知识库问答系统, page_icon, layoutwide) st.title( RAG 知识库问答系统) st.caption(基于 Deepseek Chroma 构建的私有知识库问答系统) query st.text_area(请输入你的问题, height100) if st.button(获取答案, typeprimary): if not query.strip(): st.warning(请输入问题内容) elif not config.DEEPSEEK_API_KEY: st.error(未检测到 DEEPSEEK_API_KEY请检查 .env 文件配置) else: with st.spinner(正在检索并生成回答...): result ask(query.strip()) st.subheader(回答) st.write(result[answer]) with st.expander(查看参考文档片段): for i, (doc, dist) in enumerate(zip(result[source_documents], result[distances])): st.markdown(f**片段 {i 1}**距离{dist:.4f}) st.text(doc[:500])这个界面就是典型的“输入框 按钮 结果展示”结构没有复杂的前端依赖。st.expander 折叠展示参考片段让用户既能看答案也能核对答案的出处符合 RAG 可溯源的优势。5. 运行系统与效果验证5.1 准备示例文档在 data 目录下创建两个测试文档这里以一个虚构的公司场景为例# 文件路径rag-demo/data/公司介绍.txt 某某科技有限公司成立于2018年总部位于上海主营业务是企业级人工智能解决方案定制服务。 公司核心技术团队来自国内一线互联网公司与高校实验室在自然语言处理、知识图谱、大模型应用方向有丰富经验。 公司的主要产品包括智能客服系统、知识库问答平台、数据中台建设服务。 截至2025年公司已服务超过200家中小企业客户覆盖零售、金融、教育等行业。# 文件路径rag-demo/data/product_faq.txt 问知识库问答平台支持哪些文档格式 答平台支持 txt、PDF、Word、Markdown 等常见格式推荐使用 Markdown 或 txt 以获得最佳解析效果。 问平台的数据是否安全 答平台支持私有化部署文档向量化和检索过程可以在企业内部网络独立完成只有最终生成回答时会调用大模型 API。 问知识库更新需要重新训练模型吗 答不需要。知识库问答系统采用 RAG 架构只需要更新向量库即可让模型基于最新文档回答问题。5.2 初始化知识库在项目根目录执行python ingest.py正常情况下会看到类似输出已加载文档: 公司介绍.txt 已加载文档: product_faq.txt 文档切分完成共得到 6 个文本块 正在加载 embedding 模型... 正在生成向量... 向量库构建完成共写入 6 个文本块首次运行会下载 bge-small-zh-v1.5 模型文件大小在 100MB 左右需要保持网络畅通。下载完成后模型会缓存在本地之后运行不会再重复下载。5.3 启动 Web 界面streamlit run app.py浏览器会自动打开 Streamlit 提供的本地地址默认是 http://localhost:8501。可以看到一个简洁的问答界面输入问题后点击“获取答案”。尝试提问“公司知识库平台支持哪些文档格式”预期回答会参考 product_faq.txt 中的内容并明确指出支持 txt、PDF、Word、Markdown 等格式。如果提问“公司成立于哪一年”系统应该从公司介绍文档中检索到对应信息并给出答案。在“查看参考文档片段”区域你会看到检索到的原始片段和对应的相似度距离这能帮助你判断系统是否真正用上了知识库内容。6. 常见问题与排查思路在实际运行中很多问题其实是共通的。下面把高频问题整理成表格再逐个展开。问题现象常见原因解决思路首次运行下载模型失败网络不稳定或 HuggingFace 地址无法访问使用镜像地址或手动下载模型到本地向量库查询报错 Collection not found未执行 ingest.py 或目录不一致执行 ingest.py 构建向量库检查 CHROMA_DIR检索结果与问题无关chunk 过大、top_k 过小、文档格式混乱调整 CHUNK_SIZE、增大 TOP_K清洗文档Deepseek API 返回 401 错误API Key 不正确或未加载成功检查 .env 文件确认 load_dotenv 生效回答没有引用知识库内容Prompt 约束不够或检索片段为空加强 system prompt检查检索结果Chroma old database version 报错向量库版本升级不兼容删除 chroma_db 目录后重新 ingest6.1 首次运行模型下载失败bge-small-zh-v1.5 模型默认从 HuggingFace 下载。如果你的网络环境无法稳定访问可以设置镜像环境变量export HF_ENDPOINThttps://hf-mirror.com然后在终端重新运行 ingest.py。设置镜像环境变量的目的是解决下载通道问题属于开发过程中的常规操作。模型下载完成后可以不再依赖外网。另一种方式是从其他方式下载模型文件后把模型目录放到本地然后在 config.py 中将 EMBEDDING_MODEL_NAME 改为模型所在的本地路径。例如EMBEDDING_MODEL_NAME ./models/bge-small-zh-v1.56.2 检索结果不理想检索结果差通常不是单一原因造成的需要按照顺序排查几个关键参数。先检查 TOP_K。如果设置为 1结果可能只覆盖一个片段信息量不足如果设置为 5又可能混入大量不相关内容。对于短文档3 是合理的起点。再检查 CHUNK_SIZE。如果文档本身是 FAQ 格式每条问答很短那么把 CHUNK_SIZE 设置成 500会把多个问答切进同一个块导致检索时指向内容不准确。对这种结构化文档建议将 chunk_size 调小比如 200 到 300并去掉过大的 overlap。最重要的还是文档清洗。如果原始文档包含大量页眉页脚、特殊符号、乱码向量化效果会明显变差。在真实项目中文档预处理往往占用整个 RAG 项目一半以上的工作量这是很正常的现象。6.3 Deepseek API 接入问题如果调用时报 401最直接的排查方式是打印 config.DEEPSEEK_API_KEY确认 .env 是否被正确加载。.env 文件必须和运行命令所在目录一致也就是项目根目录。如果报连接超时先确认网络环境能够访问 Deepseek API。同时可以在代码中打印 DEEPSEEK_BASE_URL确认没有因为之前的项目设置而覆盖成了其他地址。6.4 向量库版本兼容问题Chroma 版本迭代较快不同版本生成的数据库文件可能不兼容出现类似“old database version”的报错时最简单的处理是备份并删除 chroma_db 目录然后重新运行 ingest.py。这只是开发阶段的做法生产环境中应该提前规划向量库的升级策略例如使用独立的向量数据库服务。7. 最佳实践与工程化建议文章到这里整套代码已经能跑通了。但如果你想把这个 Demo 变成真正可用的系统还需要注意下面几个工程问题。7.1 把 Prompt 单独管理不要把 Prompt 字符串散落在业务代码里。随着项目迭代Prompt 的调整频率很高应该单独提取为一个配置文件或 Prompt 管理模块。某些团队还会为不同场景编写多套 Prompt比如“摘要模式”“对比模式”“严格引用模式”然后用模版变量动态切换。7.2 增加检索结果的引用溯源RAG 的核心优势之一就是可解释性。在 Web 界面和 API 返回中都应该保留 source_documents 字段最好把文档名、页码、片段位置一起返回。这样用户能够点击查看原文运营人员也能快速发现错误片段并及时修正知识库。7.3 完善文档更新机制目前 ingest.py 每次都会删除旧集合重新写入。当知识库规模变大后应该改成增量更新根据文档的 hash 值或更新时间只处理变更部分。向量库中也要增加元数据字段比如来源文件名、更新时间、部门标签方便按条件过滤。7.4 引入重排Rerank提升精度向量检索拿到的 Top K 片段里可能顺序并不完全符合语义相关度。更成熟的方案是在向量检索之后增加一个 rerank 模型对候选片段重新打分。比如本地部署 bge-reranker-base 模型先用向量召回 20 个候选再重排取前 3 个送给大模型。实践表明加一层 rerank 后回答准确率往往会有明显提升。7.5 从 RAG 走向 Agentic RAG目前实现的是标准 RAG每次提问只做一次检索。当问题复杂时例如“对比公司产品 A 和产品 B 的区别”或者“找出去年所有投诉工单中的高频问题”单次检索可能不够。Agentic RAG 的核心思想是让大模型具备“工具调用”能力它可以决定先搜索什么、搜索几次、是否改写问题、是否需要查看多个文档后再综合回答。这个方向可以作为下一步的进阶学习目标。本质上是把 RAG 的“搜索链路”从固定流程升级成由模型驱动的动态流程对 Prompt 设计和工具调用的工程质量要求更高。7.6 安全与合规注意事项涉及到 API 调用、内部文档时有几个安全底线需要坚持。第一API Key 绝不硬编码在源码中.env 文件必须加入 .gitignore第二生产环境建议通过独立的密钥管理服务接收 API Key由后端服务统一调用不要把密钥直接暴露给前端第三企业内部敏感文档如果涉及数据保密要求需要确认是否允许调用外部大模型 API。如果严格禁止外部传输则应该采用本地部署的模型替换 Deepseek API把整个链路都收敛在内网环境中完成。8. 从入门到落地下一步可以做什么至此你已经亲手搭完了一套完整的 RAG 知识库问答系统从文档加载、切分、向量化、检索到 Prompt 组装和 Deepseek 生成回答所有环节都是可运行、可扩展的。相比直接调用大模型接口“硬问”这套方案让模型真正学会利用你的私有资料来回答问题。如果你打算继续深入有两条推荐路线。一条是优化检索质量尝试引入 rerank、多路召回、元数据过滤让召回结果更精准另一条是走向 Agentic RAG让模型能自主规划检索步骤处理更复杂的多跳问答任务。两条路线都不需要重新训练模型完全符合 RAG 低成本的核心理念。构建知识库本身也是一门细活。文档清洗、文本切分、领域词表、Prompt 调优每一个环节都会影响最终回答质量。不要指望运行一遍代码就得到完美效果真正的项目落地就是在这些细节里不断打磨的过程。希望这份手把手教程能帮你迈出扎实的第一步也欢迎把你在搭建过程中遇到的问题留在评论区大家互相交流排错经验。