读完你能得到:一个跑在本机、能读你自己 Markdown/txt 文档、用 DeepSeek 回答问题并给出引用来源的命令行问答程序。全套代码可直接复制运行,基于 2026 最新依赖实测。
「直接问大模型」最大的问题是它不知道你的私有资料——你公司的文档、你项目的 README、你整理的笔记。RAG(检索增强生成)就是解决这个的:先把你的文档切片、向量化存起来,提问时先检索最相关的几段,再把这几段喂给大模型作答。这篇带你从 0 跑通一个最小但完整的 RAG。
一、RAG 到底在干什么(一张图讲清)
你的文档 ──切分──> 文本块 ──嵌入模型──> 向量 ──存入──> 向量库 │ 提问 ──嵌入──> 问题向量 ──相似度检索──> Top-K 相关块 ──┘ │ [相关块 + 问题] ──> DeepSeek ──> 带引用的答案记住两条主线:入库(文档→块→向量→库)和问答(问题→检索→拼上下文→大模型)。
二、前置环境
| 项 | 要求 |
|---|---|
| Python | 3.10 – 3.12 |
| 操作系统 | Windows / macOS / Linux 均可 |
| DeepSeek API Key | 官方平台申请(新用户通常有免费额度) |
| 显卡 | 不强制;嵌入用本地 CPU 模型也能跑 |
本文嵌入用开源的BAAI/bge-small-zh中文向量模型(本地跑、免费),生成用 DeepSeek 官方 API。
三、最短可跑通路径
python-mvenv .venv .venv\Scripts\activate# macOS/Linux: source .venv/bin/activatepipinstalllangchain langchain-community langchain-openai sentence-transformers faiss-cpu装好后准备一个docs/目录,扔几个.md或.txt进去(就用你手头的笔记),然后跑后面的两个脚本。
四、分步详解 + 完整代码
4.1 第一步:把文档切分并建向量库(ingest.py)
importosfromlangchain_community.document_loadersimportDirectoryLoader,TextLoaderfromlangchain.text_splitterimportRecursiveCharacterTextSplitterfromlangchain_community.embeddingsimportHuggingFaceEmbeddingsfromlangchain_community.vectorstoresimportFAISS DOCS_DIR="docs"INDEX_DIR="faiss_index"defbuild_index():# 1) 读取 docs/ 下所有 txt 与 mdloader=DirectoryLoader(DOCS_DIR,glob="**/*.*",loader_cls=TextLoader,loader_kwargs={"encoding":"utf-8"},)docs=loader.load()print(f"loaded{len(docs)}documents")# 2) 切分:每块 500 字符,重叠 80,避免把一句话切断splitter=RecursiveCharacterTextSplitter(chunk_size=500,chunk_overlap=80,separators=["\n\n","\n","。","!","?"," ",""],)chunks=splitter.split_documents(docs)print(f"split into{len(chunks)}chunks")# 3) 中文向量模型(首次会自动下载,约百 MB)emb=HuggingFaceEmbeddings(model_name="BAAI/bge-small-zh-v1.5")# 4) 建 FAISS 向量库并落盘vs=FAISS.from_documents(chunks,emb)vs.save_local(INDEX_DIR)print(f"index saved to{INDEX_DIR}/")if__name__=="__main__":build_index()运行python ingest.py,看到index saved to faiss_index/即建库成功。
4.2 第二步:检索 + 调用 DeepSeek 作答(ask.py)
importosfromlangchain_community.embeddingsimportHuggingFaceEmbeddingsfromlangchain_community.vectorstoresimportFAISSfromlangchain_openaiimportChatOpenAI INDEX_DIR="faiss_index"defload_retriever(k=4):emb=HuggingFaceEmbeddings(model_name="BAAI/bge-small-zh-v1.5")vs=FAISS.load_local(INDEX_DIR,emb,allow_dangerous_deserialization=True,)returnvs.as_retriever(search_kwargs={"k":k})defmake_llm():# DeepSeek 兼容 OpenAI 协议:改 base_url + 模型名即可returnChatOpenAI(model="deepseek-chat",base_url="https://api.deepseek.com",api_key=os.environ["DEEPSEEK_API_KEY"],temperature=0.2,)PROMPT="""你是严谨的问答助手。只依据下面的「资料」回答问题; 资料里没有的内容就说「资料中未提及」,不要编造。 资料: {context} 问题:{question} 请用中文回答,并在结尾用 [来源N] 标注你用到的资料段编号。"""defask(question:str):retriever=load_retriever()docs=retriever.invoke(question)context="\n\n".join(f"[来源{i+1}]{d.page_content}"fori,dinenumerate(docs))llm=make_llm()msg=PROMPT.format(context=context,question=question)resp=llm.invoke(msg)print("\n=== 答案 ===\n"+resp.content)print("\n=== 命中来源 ===")fori,dinenumerate(docs):src=d.metadata.get("source","?")print(f"[来源{i+1}]{src}")if__name__=="__main__":importsys q=sys.argv[1]iflen(sys.argv)>1else"这些资料讲了什么?"ask(q)先设置 Key 再运行:
setDEEPSEEK_API_KEY=sk-xxxx# macOS/Linux: export DEEPSEEK_API_KEY=sk-xxxxpython ask.py"我的文档里关于X是怎么说的?"你会看到一段只基于你文档的答案,外加它实际命中的来源文件。这就是一个完整的 RAG 问答。
五、常见报错与解决(收藏级)
报错 1:allow_dangerous_deserialization相关报错
- 根因:新版 FAISS 加载本地索引默认禁止反序列化。
- 解法:
FAISS.load_local(..., allow_dangerous_deserialization=True),仅对你自己建的索引开启。
报错 2:首次运行卡在下载嵌入模型 / 连接超时
- 根因:
BAAI/bge-small-zh-v1.5首次需下载。 - 解法:耐心等一次;下完会缓存到本地,之后秒加载。可配置 HuggingFace 国内镜像加速下载。
报错 3:KeyError: 'DEEPSEEK_API_KEY'
- 根因:环境变量没设到当前终端会话。
- 解法:在「同一个」终端里先
set/export再运行脚本,别开两个窗口。
报错 4:答案总是「资料中未提及」
- 根因:切分块太大或检索 k 太小,相关内容没被召回。
- 解法:把
chunk_size调小到 300–400,k调到 6–8,重建索引再试。
报错 5:中文文档加载报 UnicodeDecodeError
- 根因:文件不是 UTF-8。
- 解法:本文已在 loader 指定
encoding="utf-8";若仍报错,把源文件另存为 UTF-8。
六、验证成功的标志
ingest.py输出了 chunk 数量并保存了faiss_index/;ask.py能针对你文档里的内容给出正确答案,并列出命中来源;- 问一个文档里没有的问题,它会回答「资料中未提及」而不是编造。
三条都满足,你的专属知识库问答就跑通了。
七、从 Demo 到生产:下一步
这个最小 RAG 还能往上加:换更强的重排模型提精度、把 FAISS 换成可持久化的向量数据库、给问答套个 Web 界面。这些我会在后续文章里讲,关注大鹏AI教育,持续更新 AI 实战。
完整代码:本文的ingest.py与ask.py已在上文逐段给全,直接复制即可跑通,无需额外下载。
建议收藏:下次搭知识库问答直接照这套改。卡在哪一步,把报错原文贴评论区,我帮你看。