新闻详情

新闻详情

首页 / 资讯中心 / 详情

RAG 创建实战:从零搭一个能回答问题的知识库

发布时间:2026/9/30 13:08:17来源:尧图网络
RAG 创建实战:从零搭一个能回答问题的知识库
1. 引言今天不聊概念直接上手。我带你从零搭一个 RAGRetrieval-Augmented Generation检索增强生成系统让大模型能基于你自己的文档回答问题。整个过程我会按真实操作的口吻来写每一步都告诉你我做了什么、踩了什么坑、怎么排查。先交代一下我的环境Python 3.10Windows 11用 OpenAI 兼容接口本地也可以用 Ollama 跑开源模型。代码我尽量写得能直接复制运行。本文的最终成果一个能直接复制运行、可复用的 RAG 脚本——你只要把docs/里的资料换成自己的就能让大模型基于你的知识库回答问题。适用读者有 Python 基础、想快速搭建 RAG 的开发者。阅读完你将获得什么从原理到踩坑的完整实战路径以及一套开箱即用的代码照着敲就能跑通。2. 原理与大纲先花两分钟把原理讲清楚后面动手才不会懵。RAG 说白了就一句话先检索再生成。大模型本身记不住你的私有资料那就先把资料切成块、转成向量存起来用户提问时先从向量库里捞出最相关的几块拼进 prompt 一起喂给模型让它「看着资料回答」。整个流程拆开就是四步加载把文档读进来切块把长文档切成小块向量化存储把块转成向量存进向量库检索生成提问时检索相关块拼给模型生成答案下面这张图把整个 RAG 流程串起来后面每一步都对应图里的一个环节用户提问加载文档切分文档向量化存储向量库 ChromaDB检索相关块拼进 Prompt大模型生成答案返回回答下面按这个顺序一步步来。先看大纲引言原理与大纲准备工作装依赖准备文档数据切分文档生成向量并存入向量库构建检索链完整跑通一个可复用的脚本实现方式对比踩坑记录总结2. 准备工作装依赖打开终端先建个虚拟环境免得把系统 Python 搞乱python-mvenv rag_env rag_env\Scripts\activate# Windows# source rag_env/bin/activate # Linux/Mac然后装依赖。我用的核心库是 LangChain 0.3 系列、ChromaDB 做向量库、以及 OpenAI 的 SDKpipinstalllangchain langchain-community langchain-openai chromadb openai python-dotenv装完验证一下版本防止版本不兼容python-cimport langchain; print(langchain.__version__)我这边输出的是0.3.x。如果你装到 0.2 或更早建议升级到 0.3因为后面有些 API 写法不一样。3. 准备文档数据RAG 的第一步是「喂数据」。我准备了几篇 Markdown 格式的技术笔记放在docs/目录下。你也可以用 PDF、TXT、网页后面我会说怎么换加载器。先写一个加载文档的脚本。这里我用 LangChain 的目录加载器一次性把整个文件夹读进来fromlangchain_community.document_loadersimportDirectoryLoader,TextLoader loaderDirectoryLoader(docs,glob**/*.md,loader_clsTextLoader,loader_kwargs{encoding:utf-8},)docsloader.load()print(f加载了{len(docs)}个文档)这里有个坑Windows 下如果文档是 GBK 编码TextLoader默认用 UTF-8 读会报UnicodeDecodeError。我一开始就踩了后来在loader_kwargs里显式指定encodingutf-8才解决。如果你的文档是别的编码改成对应的就行。4. 切分文档加载进来的文档可能很长直接塞给向量库效果很差所以要先切块。切块的大小和重叠度直接影响检索质量我一般这样配fromlangchain_text_splittersimportRecursiveCharacterTextSplitter splitterRecursiveCharacterTextSplitter(chunk_size500,chunk_overlap50,separators[\n\n,\n,。,,, ,],)chunkssplitter.split_documents(docs)print(f切分成{len(chunks)}个块)chunk_size500表示每块约 500 字符chunk_overlap50让相邻块有 50 字符重叠避免把一句话从中间切断导致语义丢失。separators里我加了中文标点这样中文文档切得更自然。5. 生成向量并存入向量库接下来把每个块转成向量存进 ChromaDB。这一步是 RAG 的核心——把文本变成机器能算相似度的数字。我用 OpenAI 的 embedding 模型fromlangchain_openaiimportOpenAIEmbeddingsfromlangchain_community.vectorstoresimportChroma embeddingsOpenAIEmbeddings(modeltext-embedding-3-small)vectorstoreChroma.from_documents(documentschunks,embeddingembeddings,persist_directory./chroma_db,)print(向量库创建完成已持久化到 ./chroma_db)跑完你会看到./chroma_db目录下生成了索引文件。persist_directory指定持久化路径这样下次启动不用重新算向量。如果你没有 OpenAI 的 key也可以用本地模型。我试过用 Ollama 跑nomic-embed-text效果也还行fromlangchain_community.embeddingsimportOllamaEmbeddings embeddingsOllamaEmbeddings(modelnomic-embed-text)6. 构建检索链向量库建好了现在把它接进大模型。这里我用 LangChain 的RetrievalQA链它会把「检索 生成」串起来fromlangchain_openaiimportChatOpenAIfromlangchain.chainsimportRetrievalQA llmChatOpenAI(modelgpt-4o-mini,temperature0)qa_chainRetrievalQA.from_chain_type(llmllm,chain_typestuff,retrievervectorstore.as_retriever(search_kwargs{k:4}),)answerqa_chain.invoke(什么是 RAG)print(answer[result])k4表示每次检索取最相似的 4 个块喂给模型。chain_typestuff表示把所有检索结果直接拼进 prompt适合块数不多的情况。7. 完整跑通一个可复用的脚本上面几步拆开讲实际用的时候我习惯合成一个脚本方便反复跑。下面是我最终用的版本importosfromdotenvimportload_dotenvfromlangchain_community.document_loadersimportDirectoryLoader,TextLoaderfromlangchain_text_splittersimportRecursiveCharacterTextSplitterfromlangchain_openaiimportOpenAIEmbeddings,ChatOpenAIfromlangchain_community.vectorstoresimportChromafromlangchain.chainsimportRetrievalQA load_dotenv()# 1. 加载loaderDirectoryLoader(docs,glob**/*.md,loader_clsTextLoader,loader_kwargs{encoding:utf-8})docsloader.load()# 2. 切分splitterRecursiveCharacterTextSplitter(chunk_size500,chunk_overlap50,separators[\n\n,\n,。,,, ,])chunkssplitter.split_documents(docs)# 3. 向量化 存储embeddingsOpenAIEmbeddings(modeltext-embedding-3-small)vectorstoreChroma.from_documents(documentschunks,embeddingembeddings,persist_directory./chroma_db)# 4. 检索 生成llmChatOpenAI(modelgpt-4o-mini,temperature0)qa_chainRetrievalQA.from_chain_type(llmllm,chain_typestuff,retrievervectorstore.as_retriever(search_kwargs{k:4}),return_source_documentsTrue,)whileTrue:queryinput(请输入问题输入 exit 退出)ifquery.lower()exit:breakresultqa_chain.invoke(query)print(\n回答,result[result],\n)# 打印来源文档方便追溯答案出处print(--- 来源文档 ---)fori,docinenumerate(result[source_documents],1):sourcedoc.metadata.get(source,未知来源)snippetdoc.page_content[:100]print(f[{i}] 来源{source})print(f 片段{snippet}...)print().env文件里放你的 API keyOPENAI_API_KEYsk-xxxx9. 实现方式对比上面用的是 LangChain ChromaDB 这一套也是目前最主流的组合。但 RAG 的实现路径不止一条我把我试过的几种列出来优缺点都摆一摆你按自己的场景挑。方式一LangChain ChromaDB本文用的优点生态成熟、文档多、上手快切块、向量化、检索一条龙都封装好了缺点依赖较重LangChain 版本升级 API 容易变ChromaDB 单机够用数据量大或要并发时吃力方式二LlamaIndex FAISS优点对「索引」这件事做得更细支持多种索引结构检索精度高缺点概念比 LangChain 多学习曲线陡一点FAISS 是内存索引重启要重新加载方式三纯手写embedding 向量检索 prompt 拼接优点最轻量没有框架包袱每一步都看得懂、可控缺点要自己处理切块、持久化、检索逻辑代码量上去了维护成本高方式四RAGFlow / Dify 这类平台优点可视化配置拖拽就能搭适合快速验证和给非技术同事用缺点定制性差想改底层逻辑就受限数据量大时性能不一定好怎么选我的建议是想快速跑通、验证想法用方式一对检索精度要求高、愿意折腾试方式二想彻底搞懂原理强烈建议手写一遍方式三团队里非技术人多再考虑方式四。怎么选我的建议是想快速跑通、验证想法用方式一对检索精度要求高、愿意折腾试方式二想彻底搞懂原理强烈建议手写一遍方式三团队里非技术人多再考虑方式四。四种方式放在一起对比优缺点和适用场景一目了然方式优点缺点适用场景方式一LangChain ChromaDB生态成熟、文档多、上手快切块、向量化、检索一条龙都封装好了依赖较重LangChain 版本升级 API 容易变ChromaDB 单机够用数据量大或要并发时吃力快速跑通、验证想法个人或小团队起步方式二LlamaIndex FAISS对「索引」这件事做得更细支持多种索引结构检索精度高概念比 LangChain 多学习曲线陡一点FAISS 是内存索引重启要重新加载对检索精度要求高、愿意折腾的进阶场景方式三纯手写最轻量没有框架包袱每一步都看得懂、可控要自己处理切块、持久化、检索逻辑代码量上去了维护成本高想彻底搞懂原理、学习 RAG 内部机制方式四RAGFlow / Dify 平台可视化配置拖拽就能搭适合快速验证和给非技术同事用定制性差想改底层逻辑就受限数据量大时性能不一定好团队里非技术人多、需要快速交付原型四种方式的定位差异用一张图看得更清楚方式四RAGFlow / Dify可视化、拖拽即用定制性差方式三纯手写最轻量、可控代码量大、维护成本高方式二LlamaIndex FAISS索引精细、精度高概念多、内存索引方式一LangChain ChromaDB生态成熟、上手快依赖较重、单机够用按场景选择8. 踩坑记录这一节把我实际遇到的问题列出来你遇到类似情况可以直接对照坑 1编码问题现象加载文档报UnicodeDecodeError解决loader_kwargs{encoding: utf-8}或改成文档实际编码坑 2检索结果答非所问现象模型回答跟问题对不上解决调大k值或减小chunk_size让块更聚焦也可以检查文档切分是否把关键信息切断了坑 3向量库重复写入现象每次跑脚本都往同一个./chroma_db追加导致检索结果重复解决重建前先删掉旧目录或者用Chroma(persist_directory..., embedding...)加载已有库而不是重新from_documents坑 4LangChain 版本 API 变化现象RetrievalQA或Chroma导入报错解决确认langchain是 0.3.xlangchain-community和langchain-openai都装了11. 总结到这里一个能用的 RAG 系统就跑通了。核心流程就四步加载文档 → 切块 → 向量化存储 → 检索生成。你只要把docs/里的内容换成自己的资料就能让大模型基于你的知识库回答问题。最后用一张图回顾整个核心流程加载文档切块向量化存储检索生成回答说到底RAG 的本质就一件事给大模型配一个「外挂记忆」。模型记不住你的私有资料那就把资料变成可检索的向量提问时先捞出来再让它回答。不管用 LangChain、LlamaIndex 还是手写绕来绕去都是「检索 生成」这两个动作。理解了这一点换什么框架都只是换工具核心思路不变。下一步你可以试试换 PDF 加载器、接入本地模型、或者把检索结果和引用来源一起返回。有问题欢迎在评论区交流。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

C++ stack与queue底层原理、性能对比与高阶应用 2026/9/30 14:52:09

C++ stack与queue底层原理、性能对比与高阶应用

C的stack和queue,可能是初学者最快上手的一对容器:一个后进先出,一个先进先出,push进去再拿出来,规则简单到几乎不用思考。但如果你只把它们当成“存东西的盒子”,后面遇到单调栈、滑动窗口最大值、线程安全…

阅读更多 →
数据中心网络Overlay三件套与sFlow监控实战解析 2026/9/30 14:52:08

数据中心网络Overlay三件套与sFlow监控实战解析

简介:华为技术有限公司发布的《数据中心技术红宝书》合集文档,面向企业数据中心架构、运维及网络技术人员,系统讲解Segment Routing、TRILL与sFlow三项关键技术。其中Segment Routing部分重点介绍其改进机制、工作流程与优势;TRIL…

阅读更多 →
校园网三层架构设计与VLAN/IP双轨规划实战 2026/9/30 14:52:08

校园网三层架构设计与VLAN/IP双轨规划实战

简介:本资源是一份面向高校网络工程专业师生及信息化建设从业者的《校园网设计》完整技术文档,聚焦教育场景下的网络规划与落地实践,系统解决教学、科研、行政及生活多维度的网络需求建模与架构设计问题。文档以Word格式(.doc&…

阅读更多 →
KOS服务器网络配置实战:bond、VLAN与静态路由完整指南 2026/9/30 14:52:08

KOS服务器网络配置实战:bond、VLAN与静态路由完整指南

上个月接手了一批预装 KeyarchOS(浪潮信息云峦操作系统,简称 KOS)的服务器,业务方要求当天晚上完成网络初始化:两块网卡做 bond、按机房拓扑划两个 VLAN、配好默认路由和 DNS。说实话,第一次独自动这套系统…

阅读更多 →
企业上云如何锁定三年成本?京东云服务器长期特惠选购与运维指南 2026/9/30 14:52:08

企业上云如何锁定三年成本?京东云服务器长期特惠选购与运维指南

1. 为什么我建议企业直接买3年的京东云服务器 很多企业用户看到“买3年长期特惠”这个词,第一反应是:一次性付3年钱,资金压力是不是太大了?我做过不少企业上云方案,坦白讲,对于有稳定业务、长期需要对外提供…

阅读更多 →
VMware Lab Platform讲师实战指南:Instructor Console与labctl深度用法 2026/9/30 14:52:00

VMware Lab Platform讲师实战指南:Instructor Console与labctl深度用法

简介:本资源是VMware官方发布的《VMware Lab Platform Instructor Guide》教学指导手册,专为高校及企业IT培训讲师设计,解决实验室环境统一管理、学生进度实时监控与实操干预等核心教学痛点。手册系统覆盖Instructor Console操作全流程&#…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉