AI在线 AI在线

我的RAG开源项目300+star了,十分适合新手入门(日志级详细拆解)

三个月前,我在 Github 上开源的一个 RAG 练手项目,目前已经有了 327 个 star,总共解决了 22 个 issues。 结合过去几个月的项目实践,我重新对项目做了轻量化重构,降低资源消耗与部署门槛。 项目地址:,五脏俱全。

我的RAG开源项目300+star了,十分适合新手入门(日志级详细拆解)

三个月前,我在 Github 上开源的一个 RAG 练手项目,目前已经有了 327 个 star,总共解决了 22 个 issues。结合过去几个月的项目实践,我重新对项目做了轻量化重构,降低资源消耗与部署门槛。

图片

项目地址:https://github.com/weiwill88/Local_Pdf_Chat_RAG

麻雀虽小,五脏俱全。总体来说,这是一个轻量级但组件完整的本地化 RAG 智能问答平台。可以通过 Gradio Web UI 直观体验混合检索、重排序、递归查询及联网搜索等高级 RAG 策略,更能从源码层面学习和实践 RAG 的完整流程与优化技巧。BTW,也支持 API 的调用方式.

图片

这篇试图说清楚,项目的各个核心组件构成,日志分段拆解含义,以及进阶和扩展方向参考,欢迎感兴趣的盆友基于此项目进行探索和贡献。

以下,enjoy:

1、项目定位

在接触如 Dify、RAGFlow 这类高度封装的 RAG 框架之前,复现和二开这个项目,可以:

熟悉 RAG 核心组件:实际体验文本加载、切分、向量化、向量存储与检索(本项目使用 FAISS)、LLM 集成等关键环节。

理解 RAG 基本流程:从底层脚本层面观察数据如何在 RAG 系统中流转和处理。

进行初步优化与测试:尝试调整参数、替换模型、优化提示词等,直观感受不同策略对结果的影响。

掌握这些基础后,能更有的放矢地使用高级 RAG 框架的 API 进行针对性调优或定制开发。

2、核心优化

这部分要介绍的项目轻量化改造,主要也是为了让初学者盆友更好的抓住 RAG 的核心脉络,避免过早陷入数据库管理和配置的细节中。

当理解了核心流程后,再过渡到如 ChromaDB 或其他生产级向量数据库,就能更好地理解这些数据库所解决的问题和提供的价值。

2.1旧版依赖问题

在上一个版本的 issues 中,有挺多用户反馈依赖安装时间过久,几个主要的“重量级”组件及其依赖项是导致安装时间较长的主要原因:

图片

torch 和 transformers

这两个库是 sentence-transformers 的核心依赖。sentence-transformers 用于生成文本嵌入(向量化)以及进行结果重排序(通过交叉编码器)。torch 是一个庞大的深度学习框架,而 transformers 包含了许多预训练模型和工具。这些是现代 NLP 和 RAG 系统的基石,因此体积较大。

onnxruntime

这是 chromadb 的一个依赖。chromadb 在内部可能使用 ONNX Runtime 来执行其默认的嵌入模型或其他优化计算,即使项目代码中指定了使用 sentence-transformers 来生成嵌入。onnxruntime 本身是一个跨平台的机器学习模型执行引擎,体积也不小。

Langchain

虽然原项目目前主要使用它的文本分割器 (RecursiveCharacterTextSplitter),但完整安装 langchain 会引入不少间接依赖。

2.2轻量化改造

针对 Langchain 的优化

项目主要使用了 langchain 的文本分割功能,考虑到 langchain 已经将许多组件模块化,所以可以仅安装文本分割器模块,并相应修改代码中的导入语句。

针对向量数据库

ChromaDB 虽然功能较为全面,但在某些场景下,尤其是对于本地运行和初学者而言,其依赖和服务可能相对“重”一些,会涉及到更多的后台进程和磁盘空间占用。

FAISS-CPU 是一个专注于高效向量相似性搜索的 C++库,Python 绑定通常更为轻量,依赖更少,尤其是在 CPU 版本下,不需要额外的数据库服务运行,直接在内存中进行索引和搜索。这使得项目更容易在普通个人电脑上快速启动和运行。

注:针对嵌入和重排序模型 (sentence-transformers, torch, transformers),这部分是 RAG 系统效果的核心,轻量化难度较大,且容易牺牲模型性能,所以暂时不做处理。

3、核心组件拆解

项目虽然经过了轻量化改造,但依然包含了构建一个完整 RAG 系统的所有核心组件。学习和理解下述组件的运作方式,对于入门 RAG 技术很重要。

图片

3.1文档加载与解析:

使用 pdfminer.six 从 PDF 文件中提取文本内容,理解如何从不同格式的非结构化数据源中提取原始文本,这是 RAG 流程的第一步。熟悉不同的解析库及其优缺点,能为后续处理多种数据源打下基础。

3.2文本切分:

使用 langchain_text_splitters (如 RecursiveCharacterTextSplitter) 将长文本分割成小的数据块 (chunks)。理解文本切分对于 RAG 的重要性。合适的切分策略能确保每个数据块既包含足够的上下文,又不超过后续处理(如向量化模型输入长度、LLM 上下文窗口)的限制。学习不同的切分方法(如按字符数、按句子、递归等)及其适用场景。

图片

3.3文本向量化 :

使用 sentence-transformers 库加载预训练的句向量模型(如 moka-ai/m3e-base),将文本块转换为高维向量。这是 RAG 的核心之一。理解文本向量化的概念,即如何将语义信息编码为计算机可以理解和比较的数字表示。

熟悉不同的向量化模型及其特点(如多语言支持、特定领域优化、向量维度等),并了解如何选择合适的模型。

3.4向量存储与索引 :

使用 faiss-cpu 构建向量索引 (IndexFlatL2),并在内存中存储和管理这些向量及其与原始文本块的关联(通过我们自己维护的 faiss_contents_map, faiss_metadatas_map, faiss_id_order_for_index)。

理解向量数据库/搜索引擎的基本原理,即如何高效地存储大量向量,并根据查询向量快速找到最相似的 K 个向量。通过 FAISS,可以直观感受到索引构建、相似度计算(如 L2 距离)的过程。学习不同的索引策略对检索效率和精度的影响。

3.5检索:

语义检索:用户问题向量化后,在 FAISS 索引中执行 search 操作,获取最相似的文本块。

关键词检索:使用 rank_bm25 实现 BM25 算法,根据关键词匹配度进行检索。

混合检索:结合语义检索和 BM25 的结果,进行加权合并。

理解不同的检索策略。语义检索关注意义的相似性,关键词检索关注字面匹配。混合检索则试图结合两者优点,提高召回率和相关性。学习如何评估和调整不同检索策略的权重。

3.6上下文重排序:

使用 sentence-transformers 加载交叉编码器 (CrossEncoder) 模型,对初步检索到的上下文片段进行重新打分和排序,选出与问题最相关的片段。

理解在初步检索后,如何进一步优化上下文的相关性。交叉编码器通常比双编码器(用于向量化的模型)在相关性判断上更精确,但计算量也更大,因此常用于对少量候选结果的精排。

3.7提示工程与大语言模型交互 :

构建合适的提示 (Prompt),将用户问题和检索到的相关上下文整合后,提交给大语言模型 (LLM)。通过 requests 与本地 Ollama 服务或云端 SiliconFlow API 进行交互,获取 LLM 生成的答案。

递归检索:利用 LLM 分析当前结果,判断是否需要生成新的查询以进行更深入的探索。

理解 LLM 在 RAG 中的核心作用——基于提供的上下文生成答案。学习如何设计有效的提示词,以引导 LLM 更好地利用检索到的信息。体验与不同 LLM(本地/云端)集成的过程。递归检索则展示了更高级的 RAG 模式,即如何让 LLM 参与到信息检索的迭代优化中。

3.8用户界面:

使用 Gradio 构建交互式的 Web 界面。虽然不是 RAG 核心算法的一部分,但一个好的界面能极大地方便用户与 RAG 系统交互、测试和调试。学习 Gradio 这类工具可以快速搭建原型。

4、运行日志拆解

下文会清晰地追踪 RAG 系统处理问题的每一步,各位仔细阅读下,有助于更好理解各组件的功能和协同方式。

4.1应用启动与用户界面初始化 (Gradio)

复制
(venv) PS D:\Projects\Ongoing\开源项目\local_pdf+Chat_rag> python rag_demo_pro.py
Gradio version: 5.29.0
D:\Projects\Ongoing\开源项目\local_pdf+Chat_rag\rag_demo_pro.py:1703: UserWarning: You have not specified a value for the `type` parameter. Defaulting to the 'tuples' format for chatbot messages, but this is deprecated and will be removed in a future version of Gradio. Please set type='messages' instead, which uses openai-style dictionaries with 'role' and 'content' keys.
  chatbot = gr.Chatbot(
INFO:httpx:HTTP Request: GET https://api.gradio.app/pkg-version "HTTP/1.1 200 OK"
* Running on local URL:  http://0.0.0.0:17995
INFO:httpx:HTTP Request: GET http://localhost:17995/gradio_api/startup-events "HTTP/1.1 200 OK"
INFO:httpx:HTTP Request: HEAD http://localhost:17995/ "HTTP/1.1 200 OK"
* To create a public link, set `share=True` in `launch()`.

图片

python rag_demo_pro.py: 这是启动整个 RAG 应用的主命令。radio version: 5.29.0: 显示了 Gradio 库版本,它负责构建用户交互界面。

UserWarning... chatbot = gr.Chatbot(...): Gradio 提示其聊天机器人组件参数 type 的未来变更。INFO:httpx:HTTP Request...: Gradio 启动过程中的网络请求,如检查版本等。

Running on local URL: http://0.0.0.0:17995 : Gradio 服务成功启动,用户可通过此地址访问 Web UI。

4.2数据初始化/清理

复制
INFO:root:成功清理历史FAISS数据和BM25索引

在处理新文档前或应用启动时,系统会清理旧的 FAISS 向量索引和 BM25 关键词索引,确保基于当前文档进行问答,避免数据混淆。

涉及组件:FAISS 索引管理、BM25 索引管理。

4.3文档处理、向量化与 FAISS 索引构建

复制
Batches: 100%|████████████████████████████████████████████████████████████| 1/1 [00:02<00:00,  2.71s/it]
INFO:root:FAISS索引构建完成,共索引 9 个文本块

此阶段包括了从 PDF 提取文本、将文本切分成小块(chunks)、然后使用 sentence-transformers 模型(如 moka-ai/m3e-base)将这些文本块批量转换为向量。Batches: 100%...: 显示文本块向量化的进度。

INFO:root:FAISS 索引构建完成...: 表明所有文本块的向量已成功存入 FAISS (IndexFlatL2) 索引。此处示例中,PDF 被处理成了 9 个文本块。

涉及组件:pdfminer.six (PDF 解析)、langchain_text_splitters (文本切分)、sentence-transformers (向量化)、faiss-cpu (向量索引)。

4.4BM25 关键词索引构建

复制
Building prefix dict from the default dictionary ...
DEBUG:jieba:Building prefix dict from the default dictionary ...
Loading model from cache C:\Users\10440\AppData\Local\Temp\jieba.cache
DEBUG:jieba:Loading model from cache C:\Users\10440\AppData\Local\Temp\jieba.cache
Loading model cost 6.168 seconds.
DEBUG:jieba:Loading model cost 6.168 seconds.
Prefix dict has been built successfully.
DEBUG:jieba:Prefix dict has been built successfully.
INFO:root:BM25索引更新完成,共索引 9 个文档

系统为相同的文本块构建 BM25 关键词索引,以支持后续的混合检索。Building prefix dict...: jieba 分词库正在初始化并加载词典,这是处理中文文本进行 BM25 计算的前提。

INFO:root:BM25 索引更新完成...: 表明针对这 9 个文本块的 BM25 索引已创建。

涉及组件:rank_bm25 库、jieba 分词库。

4.5用户提问与递归检索启动 (第一轮)

复制
INFO:root:递归检索迭代 1/3,当前查询: 发动机冒蓝烟的故障原因分析

用户通过 Gradio 界面输入问题“发动机冒蓝烟的故障原因分析”。系统启动递归检索流程,配置的最大迭代次数为 3,这是第一轮的开始。

涉及组件:Gradio UI、递归检索控制逻辑。

4.6联网搜索(可选,第一轮)

复制
INFO:root:网络搜索返回 5 条结果,这些结果不会被添加到FAISS索引中。

如果启用了联网搜索,系统会使用 SerpAPI 根据当前查询从互联网获取实时信息。这些结果作为临时上下文,当前版本不存入 FAISS。

涉及组件:SerpAPI 集成、requests 库。

4.7查询向量化 (第一轮)

复制
Batches: 100%|████████████████████████████████████████████████████████████| 1/1 [00:00<00:00,  3.53it/s]

用户的查询(或其变体)被送入 sentence-transformers 模型转换为查询向量,用于在 FAISS 中进行语义相似度搜索。

涉及组件:sentence-transformers 模型。

4.8检索结果重排序(第一轮)

复制
Some weights of DistilBertForSequenceClassification were not initialized from the model checkpoint at sentence-transformers/distiluse-base-multilingual-cased-v2 and are newly initialized: ['classifier.bias', 'classifier.weight', 'pre_classifier.bias', 'pre_classifier.weight']
You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.
INFO:sentence_transformers.cross_encoder.CrossEncoder:Use pytorch device: cpu
INFO:root:交叉编码器加载成功
Batches: 100%|████████████████████████████████████████████████████████████| 1/1 [00:07<00:00,  7.42s/it]

初步通过 FAISS 和 BM25 检索到的候选文本块,会由交叉编码器 (CrossEncoder) 进行更精确的相关性打分和重排序。

Some weights...: Hugging Face Transformers 库关于交叉编码器底层模型部分权重新初始化的提示。INFO:...Use pytorch device: cpu: 交叉编码器在 CPU 上运行。Batches: 100%...7.42s/it: 显示重排序过程及其耗时。

涉及组件:sentence-transformers (CrossEncoder 模型)。

4.9LLM 交互:判断是否需要递归查询及生成新查询 (第一轮后)

复制
INFO:root:使用SiliconFlow API分析是否需要进一步查询
INFO:root:生成新查询: 新查询(如果需要):
1. 涡轮增压器故障是否会引起发动机冒蓝烟?
2. 曲轴箱通风系统(PCV阀)故障如何导致烧机油?
3. 气门油封老化与冒蓝烟的具体关联是什么?
4. 使用错误粘度的机油的烧机油风险有哪些?

图片

系统将第一轮检索的上下文及原始问题提交给大语言模型 (LLM,此处为 SiliconFlow API)。LLM 分析后判断需要进一步探索,并生成了一系列更具体的新查询点,以指导下一轮检索。

涉及组件:LLM (SiliconFlow API/Ollama)、提示工程。

4.10递归检索 (第二轮)

复制
INFO:root:递归检索迭代 2/3,当前查询: 新查询(如果需要):
1. 涡轮增压器故障是否会引起发动机冒蓝烟?
2. 曲轴箱通风系统(PCV阀)故障如何导致烧机油?
3. 气门油封老化与冒蓝烟的具体关联是什么?
4. 使用错误粘度的机油的烧机油风险有哪些?
INFO:root:网络搜索返回 5 条结果,这些结果不会被添加到FAISS索引中。
Batches: 100%|█████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 15.57it/s] 
Batches: 100%|█████████████████████████████████████████████████████████████████████████████| 1/1 [00:06<00:00,  6.47s/it]

系统进入第二轮递归检索,使用 LLM 生成的新查询。重复进行联网搜索、查询向量化、混合检索(隐含)、重排序等步骤。

涉及组件:同第一轮的检索、向量化、重排序组件。

4.11LLM 交互:再次判断与生成新查询 (第二轮后)

复制
INFO:root:使用SiliconFlow API分析是否需要进一步查询
INFO:root:生成新查询: 新查询:  
1. 活塞环磨损或断裂如何导致发动机冒蓝烟?
2. 气门油封老化与烧机油的因果关系及检测方法
3. 气缸壁划伤是否会引起过量机油进入燃烧室?
4. 高粘度与低粘度机油选择错误对烧蓝烟现象的具体影响差异
5. 废气再循环系统(EGR)故障是否可能间接引发烧机油问题?


理由:
- **角度扩展**:现有信息聚焦于PCV阀、涡轮增压器和基础油品问题(如低粘度),但未覆盖活塞环/气门油封等机械磨损核心因素。需补充机械结构失效的关联分析。
- **技术细化**:针对已知的“粘度过低”提示,需明确不同粘度机油的适用场景与异常消耗阈值(如高温剪切性能)。
- **系统关联性**:EGR系统虽不直接涉及润滑回路,但其堵塞可能导致异常燃烧压力变化间接加剧窜油现象。

第二轮检索后,再次调用 LLM。LLM 进一步分析并生成了更细化、更深入的新查询及理由,展示了其分析和引导能力。

涉及组件:LLM (SiliconFlow API/Ollama)、提示工程。

4.12递归检索 (第三轮 - 最后一轮)

复制
INFO:root:递归检索迭代 3/3,当前查询: 新查询:
1. 活塞环磨损或断裂如何导致发动机冒蓝烟?
2. 气门油封老化与烧机油的因果关系及检测方法
3. 气缸壁划伤是否会引起过量机油进入燃烧室?
4. 高粘度与低粘度机油选择错误对烧蓝烟现象的具体影响差异
5. 废气再循环系统(EGR)故障是否可能间接引发烧机油问题?


理由:
- **角度扩展**:现有信息聚焦于PCV阀、涡轮增压器和基础油品问题(如低粘度),但未覆盖活塞环/气门油封等机械磨损核心因素。需补充机械结构失效的关联分析。
- **技术细化**:针对已知的“粘度过低”提示,需明确不同粘度机油的适用场景与异常消耗阈值(如高温剪切性能)。
- **系统关联性**:EGR系统虽不直接涉及润滑回路,但其堵塞可能导致异常燃烧压力变化间接加剧窜油现象。
INFO:root:网络搜索返回 5 条结果,这些结果不会被添加到FAISS索引中。
Batches: 100%|█████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 11.48it/s] 
Batches: 100%|█████████████████████████████████████████████████████████████████████████████| 1/1 [00:04<00:00,  4.05s/it]

进入最后一轮递归检索,重复之前轮次的步骤。在此轮结束后,系统会将所有收集到的、经过筛选的上下文信息,与原始问题一起,提交给 LLM 以生成最终答案(此部分日志未完全显示)。

涉及组件:同前几轮的检索、向量化、重排序组件,以及最终的 LLM 答案生成。

5、进阶与扩展方向

项目作为一个入门级的 RAG 实现,为后续的迭代和功能扩展提供了良好的基础。以下是各位一些可以考虑的进阶方向:

5.1更精细化的文本切分策略

当前的RecursiveCharacterTextSplitter是通用策略。可以研究并实现基于语义的切分(如使用模型判断句子边界或主题连贯性)、或针对特定文档类型的结构化切分(如解析 Markdown 标题、表格等)。

5.2高级 FAISS 索引与管理

目前使用的是基础的IndexFlatL2。可以尝试更高级的 FAISS 索引类型,如IndexIVFPQ,以优化大规模数据下的检索速度和内存占用。同时,研究如何更优雅地支持对 FAISS 中向量的删除和更新(例如,使用IndexIDMap)。

5.3多元数据源接入

目前主要处理 PDF 和可选的网络搜索。可以扩展支持导入其他格式的本地文档(如.txt,.md,.docx),或者接入外部 API(如 Notion、Confluence 等知识库)。

5.4查询改写与意图识别:

在进行检索前,使用 LLM 对用户的原始查询进行改写(如纠错、同义词扩展、澄清模糊表述)或识别用户真实意图,可以提高检索的精准度。

5.5上下文管理与压缩

当检索到的相关片段过多,超出 LLM 的上下文窗口限制时,需要有效的上下文压缩策略(如筛选最重要片段、总结次要片段)来保证信息质量。

5.6更复杂的重排序模型/策略

除了当前的交叉编码器和基于 LLM 打分,可以尝试集成更先进的重排序模型,或实现多阶段重排序策略。

5.7答案生成效果评估与追溯:

引入简单的评估机制(如用户反馈、答案与来源的相似度计算)和更清晰的答案来源追溯展示,帮助分析和改进系统表现。

6、写在最后

Anyway,动手实践的手搓方式来理解底层机制,是为后续深入学习和使用更高级框架的重要铺垫。

相关资讯

从RAG到QA-RAG:整合生成式AI以用于药品监管合规流程

图片引言聊天机器人的进步近期生成式AI的进展显著增强了聊天机器人的能力。 这些由生成式人工智能驱动的聊天机器人在各个行业中的应用正在被探索[Bahrini等人,2023年;Castelvecchi,2023年;Badini等人,2023年],其中制药行业是一个显著的关注领域。 在药物发现领域,最近的研究表明,由生成式人工智能驱动的聊天机器人在推进药物发现方面可以发挥重要作用[Wang等人,2023年;Savage,2023年;Bran等人,2023年]。
5/8/2025 2:22:00 AM
Wolfgang

理解 RAG 第九部分:针对 RAG 微调 LLM

在“理解 RAG”系列的前几篇文章中,我们重点探讨了检索增强生成的各个方面。 文章中,我们重点介绍了与大型语言模型 (LLM) 集成的检索器组件,该组件用于检索有意义且真实的上下文知识,从而提升 LLM 输入的质量,并最终提升其生成的输出响应。 具体来说,我们学习了如何管理传递给 LLM 的上下文长度、如何优化检索,以及如何利用向量数据库和索引策略来有效地检索知识。
5/20/2025 6:00:00 AM
晓晓

揭秘 RAG:为什么说它是让大语言模型(LLM)更聪明的秘密武器?

现在人工智能(AI)很火,尤其是像 ChatGPT 这样的大语言模型(LLM),它们能聊天、写文章、写代码,感觉无所不能。 但有时候,它们也会犯一些小错误,比如信息过时了,或者一本正经地胡说八道(这叫“幻觉”),或者你问它一些你们公司内部的事情,它就完全不知道了。 为了解决这些问题,科学家们想出了一个聪明的办法,叫做RAG。
4/25/2025 10:03:12 AM
用户007
  • 1