本地RAG系统: introduction
本地检索增强生成(RAG)允许您使用本地运行的模型来查询自己的文档:您的文件会被分割,并通过嵌入模型转换为向量,然后在每次提问时,仅将最相关的片段添加到模型的提示中。整个过程无需任何数据离开计算机,无论是索引阶段还是回答阶段。
本篇入门介绍解释了本地 RAG 的工作原理、基于 Ollama 构建它所需的最小技术栈、无代码方案,以及使用 LlamaIndex 的 Python 示例,尤其着重说明了大多数初次尝试失败的环节:分块、语言、检索和 PDF。文中也说明了何时 RAG 并不是合适的解决方案。
#本地 RAG:定义及您对它的期待
RAG 指检索增强生成:首先从文档库中检索相关段落,然后让模型基于这些段落生成回答。本地一词明确表示,从文档读取、嵌入计算、存储到生成的每一步均在你的设备上完成。这是私有模型最实用的场景:针对合同、笔记或内部知识库提出问题,回答会明确引用其来源。
| 组件 | 角色 | 示例 |
|---|---|---|
| 文档阅读器 | 从 PDF、Word、Markdown、HTML 中提取干净的文本 | LlamaIndex 的读取器、Docling |
| 分块器(chunker) | 将文本切分为长度合适的片段 | 按令牌或按结构进行分割 |
| 嵌入模型 | 将每段文本转换为向量 | embeddinggemma, qwen3-embedding, all-minilm(由 Ollama 推荐) |
| 向量数据库 | 存储向量并查找最相近的向量 | ChromaDB, Qdrant, FAISS, pgvector |
| 生成模型 | 根据段落撰写回答 | 由 Ollama 或 LM Studio 提供服务的模型 |
#为何采用RAG而非直接将全部内容发送给模型?
你的文档,你的 AI:基于你的 PDF、笔记和邮件的可靠本地 RAG——无需向云端发送任何内容。
- 在线空间,终身可用
- PDF + 文件
- 30 天内退款
首先想到的办法:把所有文档复制到提示词中。但这会遇到两个限制。上下文窗口有上限:300 个 PDF 文件包含数百万个 token,远超本地模型所能接受的范围。而且,即使一份文档能放进上下文窗口,模型的表现也会下降:一项代表性研究(斯坦福大学 Liu 等人)表明,当有用信息位于长上下文的中间时,模型性能可能显著下降,即使是专为长上下文设计的模型也不例外。这种现象称为 lost in the middle(“中间信息丢失”)。
RAG只向模型传递针对问题选出的几个段落,从而避开这两个问题。模型读取的是几百个有针对性的token,而不是几万个用处不大的token,计算成本和延迟也因此更低。关键在于做好检索。
用一个示例计算来说明数量级:300 份 PDF,每份 20 页、每页约 600 个 token,总计 360 万个 token,是本地模型常设的 8,000 token 上下文窗口的数百倍。按每段 400 个 token 切分后,约有 9,000 个片段。针对一个问题,从中选取五个片段,也就是 2,000 个 token:模型只读取整个语料库的 0.06%,但如果检索成功,读到的就是与问题相关的那 0.06%。
#两分钟理解核心概念:嵌入与距离
嵌入(embedding)是一组数字,用于表示文本的语义。讨论相同主题的两个文本即使使用不同的词汇,其向量也相近。Ollama 的文档将嵌入描述为可存储于向量数据库中的数值向量,可通过余弦相似度进行检索,或用于 RAG 系统,其长度取决于模型,通常在 384 到 1024 维之间
问题会由同一个模型转换为向量,然后与所有已索引的文本片段进行比较,返回最相近的片段。初学者容易踩的坑是:建立索引和处理问题时使用的嵌入模型必须完全相同。LlamaIndex 的文档在重新加载索引的示例中也提醒了这一点:使用与构建索引时相同的 embed_model 很重要。
#RAG的结构:两个阶段
#阶段 1:索引,每个文档仅执行一次
- 01导入读取文件(PDF、Word、Markdown、HTML),并从中提取干净的文本。这是最容易被低估的步骤。
- 02分段处理将文本切分成片段:片段要足够小,以保证精确性,也要足够大,以保留完整含义。每个片段 200 至 500 个 token 是常见的起点。
- 03Embedding用嵌入模型处理每个文本片段,例如使用命令 ollama run embeddinggemma 或 API /api/embed。
- 04存储将向量与原始文本及元数据(文件名、页码、日期)一同保存。
#阶段 2:查询,每次提问时执行
- 01问题嵌入使用与建立索引时相同的模型。
- 02搜索用余弦相似度衡量向量的接近程度,找出向量最接近的 N 个文本片段。
- 03提示组装构建一条消息,其中包含摘录,以及要求回答时引用来源、在摘录中找不到答案时明确说明的指令。
- 04生成将此提示发送至本地模型,由其生成回复。
#最小技术栈与无代码方案
要搭建一个能正常工作的本地 RAG 系统,四个组件就足够了:一个通过 Ollama 提供服务的生成模型、一个嵌入模型、一个向量数据库,以及连接它们的一层。处理法语时,请选择多语言嵌入模型;Ollama 的页面推荐了三种(embeddinggemma、qwen3-embedding、all-minilm),它们的向量维度不大,因此可以在笔记本电脑上运行。
| 路径 | 努力 | 控制 | 适用于 |
|---|---|---|---|
| LM Studio,Chat with Documents | 将 .pdf、.docx 或 .txt 文件拖入对话中 | 低:自动在全文和 RAG 之间切换 | 对几个文件进行快速测试 |
| AnythingLLM | 可选择嵌入模型和向量数据库的应用 | 中等 | 无开发人员的小型团队 |
| Open WebUI | 连接到 Ollama 的网页界面,知识库 | 中等 | 日常使用笔记库 |
| Python 中使用 LlamaIndex 或 Haystack | 需要编写代码 | 高:切分、检索、评估 | 定制项目或需要部署的项目 |
如果不想编写代码,LM Studio 中的 RAG 指南和 AnythingLLM 指南分别详细介绍了相应的方案;NotebookLM 及其本地替代方案指南则涵盖了“notebook lm rag”这一查询。
#Python管道,分步说明
下面的示例遵循 LlamaIndex 官方教程中使用本地模型的方案:先使用目录读取器、嵌入模型和通过 Ollama 提供服务的模型,再使用查询引擎。请先安装 llama-index-llms-ollama 和 llama-index-embeddings-huggingface 包。请根据您已下载的模型调整模型名称。
首次运行会计算所有嵌入向量,耗时长短取决于数据量和机器。为避免全部重新计算,请使用 index.storage_context.persist 保存索引,然后使用 load_index_from_storage 重新加载,并继续使用同一个嵌入模型。正如教程所说明的,context_window 参数会限制内存消耗。
#导致初期尝试失败的陷阱
- 简单划分会破坏结构
- 在表格中间断开会导致内容不可读。请使用支持标题和表格结构的分割工具,或先用Docling转换文档。
- 嵌入模型的语言很重要
- 主要使用英语数据训练的嵌入模型,在检索法语文本片段时表现较差。请选用多语言模型,并先用 10 个真实问题进行测试,再为整个语料库建立索引。
- 单一top-k很少适用
- 文档片段太少会使回答内容贫乏;太多则会让模型难以应对。请根据文档的性质调整,并用您已知答案的问题进行验证。
- 检索不当会导致看似笃定却错误的回答
- 如果给模型提供不相关的片段,它可能会编造出看似笃定的回答。请先衡量片段的相关性。
- PDF 文件容易带来处理陷阱
- 双栏布局、页脚、表格、扫描件:很大一部分工作是在数据导入过程中进行清洗。扫描版PDF需要先进行OCR,再做任何其他处理。
- 混合嵌入模型
- 使用一个模型进行索引、另一个模型进行查询,会得到荒谬的结果,且无错误信息。
#何时不使用RAG
| 情况 | 最佳方案 | 为什么 |
|---|---|---|
| 不到二十页 | 所有内容全部输入上下文 | 更简单,不会遗漏任何段落;当文档能完整容纳时,LM Studio 也是这样做的 |
| 关于结构化数据的事实性问题(2024 年营业额) | SQL 查询或数据提取脚本 | RAG 检索的是文本,而不是精确的计算结果 |
| 针对整个语料库的综合问题 | 分层摘要后,再对摘要提出问题 | RAG 只检索少量段落,而不是完整的整体概览 |
| 文档持续被修改 | 增量索引,或关键词搜索 | 每次变更都重新索引的成本高于直接查询 |
| 学习特定风格或格式 | Fine-tuning | RAG 提供事实,而非写作方式 |
详细说明fine-tuning与RAG对比的指南中,重点介绍了RAG方案。
#硬件与隐私:什么数据保留在您本地
在完全本地运行的 RAG 系统中,文档、向量和问题都会留在机器上,前提是每个组件也都在本地运行:嵌入模型由 Ollama 提供服务或从磁盘加载,向量数据库以文件形式存储或作为本地服务运行,生成模型也在本地运行。请检查是否有组件调用在线服务:如果误选了云端嵌入模型或云端生成模型,您的文本片段就会被发送到外部。
硬件方面,资源需求最大的是生成模型:采用 Q4 量化时,80 亿至 90 亿参数的模型需要约 5 GB 内存,此外还要加上上下文所需的内存。这里的上下文会变大,因为其中包含摘录片段;如果增加片段数量,请预留余量。嵌入处理本身的资源需求较低;大型语料库的初次索引仍是最耗时的操作,但只需进行一次。关于无 GPU 运行 LLM 的指南说明了各种 RAM 容量分别能支持什么。
#接下来呢?改进顺序如下
基础 RAG 往往能很好地回答简单问题。要进一步改进,投入产出比最高的顺序是:先按文档结构进行切分,再采用混合检索(向量检索加上基于关键词的 BM25 检索,以免漏掉合同编号这样的精确词项),然后使用重排序器重新排列最先检索到的结果,最后用一组约五十个您已知答案的问题进行评估。不做测量,每次改动的效果就都只是主观印象。
什么是本地 RAG?+
RAG 和微调之间的区别是什么?+
处理法语时应选择哪种嵌入模型?+
本地 RAG 需要 GPU 吗?+
建立索引时,文本片段应有多长?+
如何判断RAG的响应是否正确?+
有反馈、发现了错误,或想补充说明?请告诉我们,让这份指南对每个人都更有帮助。