← 返回首页
技术笔记#python

RAG 搜索技术学习指南:从原理到项目实战

2026-10-09·1 次浏览

RAG 搜索技术学习指南:从原理到项目实战

一、什么是 RAG?

RAG 的全称是 Retrieval-Augmented Generation,中文通常翻译为检索增强生成。

简单来说,RAG 是一种让大语言模型先查找相关资料,再根据查找到的资料生成答案的技术。

假设你有一个包含 500 页内容的 PDF 文档,现在你想问 AI:

“这个项目使用了什么数据库?数据库连接失败应该如何处理?”

如果直接向普通大语言模型提问,它可能不知道你的项目具体使用了什么数据库,甚至可能编造一个答案。

而使用 RAG 后,系统会先在你的 PDF 文档中搜索与问题相关的内容,然后把搜索结果交给大语言模型,让模型根据这些资料回答问题。

因此,RAG 的核心思想可以概括为:

先检索,再生成。

1.1 RAG 解决了什么问题?

传统大语言模型存在几个问题:

  1. 知识存在局限:模型不一定知道你的个人文档、企业内部资料或最新信息。
  2. 容易产生幻觉:当模型缺少可靠信息时,可能生成看似合理但实际上错误的答案。
  3. 知识更新不方便:如果资料发生变化,重新训练模型往往成本较高。
  4. 私有知识利用困难:模型无法自动读取你电脑上的所有文件。

RAG 可以在一定程度上缓解这些问题。它允许系统从外部知识库中检索资料,并将检索结果作为模型生成答案的依据。

需要注意,RAG 并不能彻底消除幻觉。检索结果可能不准确,模型也可能误解资料,因此仍然需要评估和验证。

1.2 RAG 的典型应用场景

  • 智能客服:检索产品说明书、售后政策和常见问题。
  • 企业知识库:搜索企业内部文档和技术规范。
  • 代码助手:搜索项目代码、接口文档和开发规范。
  • 学习助手:针对教材、课件和课程资料回答问题。
  • 文档问答:上传 PDF、Word、TXT 等文件后进行提问。

二、RAG 的整体工作流程

一个典型的 RAG 系统可以分为两个阶段:知识库构建阶段和用户问答阶段。

2.1 知识库构建阶段

首先,需要把原始文档转换为可以搜索的知识库。

主要步骤如下:

  1. 文档加载:读取 PDF、Word、TXT、Markdown 等文件。
  2. 文本切分:把长文档拆分成较小的文本块。
  3. 向量化:使用 Embedding 模型把文本转换为向量。
  4. 建立索引:将文本、向量和相关元数据保存到向量数据库或搜索引擎中。

2.2 用户问答阶段

当用户提出问题时,系统执行以下操作:

  1. 接收用户问题。
  2. 将问题转换为向量,或进行关键词检索。
  3. 从知识库中搜索最相关的文本块。
  4. 将问题和检索到的文本组合成提示词。
  5. 把提示词交给大语言模型。
  6. 返回答案,必要时附上资料来源。

整个过程可以用下面的流程表示:

用户问题 → 检索模块 → 知识库 → 相关资料 → 大语言模型 → 最终答案

其中,检索模块负责“找资料”,大语言模型负责“理解资料并组织答案”。

三、RAG 的核心技术

3.1 文档切分(Chunking)

为什么需要切分文档?

假设有一本 100 页的技术手册。如果每次提问都把整本手册发送给大语言模型,不仅可能超过上下文长度限制,还会增加成本,并使无关信息干扰答案。

因此,需要把文档拆分成多个文本块,也就是 Chunk。

例如,原文为:

“Spring Boot 是一种基于 Spring 框架的开发工具。它能够简化项目配置,并提供自动配置机制。开发者可以通过配置文件管理数据库连接参数。”

切分后可以得到:

  • Chunk 1:Spring Boot 是一种基于 Spring 框架的开发工具。
  • Chunk 2:它能够简化项目配置,并提供自动配置机制。
  • Chunk 3:开发者可以通过配置文件管理数据库连接参数。

实际项目中,一般不会简单地按句子切分,而是结合字符长度、Token 数量、段落结构或语义边界进行切分。

切分时需要考虑两个参数:

Chunk Size: 每个文本块的大小。

Chunk Overlap: 相邻文本块之间的重叠部分。

适当的重叠可以减少切分导致的上下文丢失。例如,某个重要概念的解释恰好位于两个文本块的交界处,重叠区域可以帮助系统保留完整含义。

不过,文本块并不是越大越好,也不是越小越好。过大的文本块会引入较多无关内容,过小的文本块又可能缺少必要上下文。

3.2 Embedding(文本向量化)

Embedding 是 RAG 中非常重要的技术。

计算机无法直接像人类一样理解自然语言的语义,因此通常需要将文本转换成数字向量。

例如:

“如何连接 MySQL 数据库?”

可能被转换成一个包含数百个数字的向量:

[0.12, -0.37, 0.85, ...]

另一个问题:

“MySQL 数据库怎么配置连接?”

也会被转换成一个向量。

如果 Embedding 模型能够较好地理解这两个问题的语义,那么它们对应的向量通常会比较接近。

这样,即使用户输入的关键词与原始文档不同,系统仍然可能找到语义相关的资料。

Embedding 的主要作用是:把文本的语义信息转换为便于计算和比较的向量表示。

需要注意,Embedding 并不是把文字直接翻译成自然语言含义明确的数字。向量中的单个数字通常没有独立、直观的语义解释。

3.3 向量数据库(Vector Database)

向量生成之后,需要将它们保存起来,并支持高效检索。

这就是向量数据库或向量索引发挥作用的地方。

常见方案包括:

  • FAISS:适合学习向量检索原理,也适合本地构建向量索引。
  • Chroma:适合快速搭建轻量级 RAG 应用。
  • Milvus:面向较大规模的向量检索场景。
  • pgvector:让 PostgreSQL 支持向量存储和检索。
  • Elasticsearch:支持关键词检索,也可以结合向量检索。

在学习阶段,可以先使用 FAISS 或 Chroma;后续再学习数据库持久化、过滤条件、权限隔离和混合检索。

3.4 相似度搜索(Similarity Search)

当用户提出问题时,系统会把问题转换为向量,再与知识库中的向量进行比较。

常见的相似度计算方法包括:

  1. 余弦相似度:比较两个向量方向的接近程度。
  2. 点积:计算两个向量的内积,具体表现受向量是否归一化等因素影响。
  3. 欧氏距离:计算两个向量之间的几何距离。

以余弦相似度为例:

\operatorname{sim}(A,B)= \frac{A\cdot B}{\|A\|\|B\|}

其中,A 和 B 是两个向量。

在常见的文本向量检索场景中,系统会根据所选的相似度或距离指标,找到与问题最相关的若干文本块。

例如,用户搜索“如何解决数据库连接失败”,检索结果可能包括:

  • 文档 A:MySQL 连接配置方法。
  • 文档 B:数据库连接池异常处理。
  • 文档 C:数据库用户名和密码配置。

系统可以将这些结果交给大语言模型,生成更完整的回答。

但相似度高不代表内容一定正确。因此,实际项目还需要结合检索质量、相关性阈值和答案验证机制。

3.5 大语言模型生成答案

检索完成后,系统会将检索结果和用户问题一起发送给大语言模型。

例如,系统可以构造如下提示词:

“请根据下面提供的资料回答问题。如果资料中没有相关信息,请明确说明,不要编造答案。

参考资料:

  1. 数据库连接参数配置在 application.properties 文件中。
  2. MySQL 连接失败时,应检查数据库地址、端口、用户名和密码。

用户问题:
MySQL 连接失败应该如何排查?”

模型根据参考资料组织答案,并给出排查建议。

这里需要注意:RAG 不一定要求对大语言模型进行重新训练。它通常通过提示词把检索到的资料提供给模型,从而增强模型回答特定问题的能力。

四、RAG 搜索有哪些实现方式?

RAG 中的检索并不只有一种方式。实际项目中常见的方案包括以下几类。

4.1 关键词检索

关键词检索根据用户输入的词语寻找匹配文档。

例如,搜索:

“Servlet 生命周期”

系统可能找到包含 Servlet、生命周期、init、service 和 destroy 等关键词的文档。

常见技术包括:

  • 倒排索引。
  • TF-IDF。
  • BM25。

BM25 是信息检索领域常用的相关性排序算法,能够根据查询词在文档中的出现情况等因素计算文档得分。

优点是速度快、结果可解释,并且适合查找类名、函数名、错误代码和专有术语。

缺点是对同义表达和语义变化的处理能力相对有限。

4.2 向量检索

向量检索根据文本的语义向量寻找相关内容。

例如:

用户问题:“程序为什么无法访问数据库?”

文档内容:“数据库连接池初始化失败。”

即使两者没有完全相同的关键词,向量检索也有可能识别出它们之间的语义关系。

优点是对自然语言问题和不同表达方式更加灵活。

缺点是可能忽略精确的关键词、编号、专有名称等信息。

4.3 混合检索(Hybrid Search)

混合检索将关键词检索和向量检索结合起来。

例如,用户搜索:

“Tomcat 11 中 JSTL 依赖如何配置?”

关键词检索可以精确匹配 Tomcat 11、JSTL 等术语;向量检索则可以补充查找与依赖配置相关的说明文档。

系统可以分别取得两种检索结果,再使用 RRF 等排序融合方法合并结果,或者采用经过验证的加权融合策略。

混合检索通常比单一检索方式更灵活,但最终效果取决于数据、模型、参数和排序策略,需要通过测试集进行评估。

4.4 重排序(Reranking)

初次检索可能会返回几十条相关性不够高的结果。

重排序的作用是对初次检索的候选文本重新评分,并选出更适合回答当前问题的内容。

常见流程是:

  1. 通过关键词检索和向量检索召回候选文档。
  2. 使用 Reranker 模型对问题与候选文本进行相关性评分。
  3. 将排序靠前的少量文本交给大语言模型。

这种方式能够改善检索结果的相关性,但也会增加计算开销和处理延迟。

五、动手实现一个简单的 RAG 搜索项目

理解原理之后,建议亲自写一个最小可运行的 RAG 项目。

本节使用 Python、Chroma 和 OpenAI API,演示从文本切分到检索、再到生成答案的基本流程。

5.1 安装依赖

创建项目目录:

bash 复制代码
mkdir rag-demo
cd rag-demo
python -m venv .venv

激活虚拟环境后,安装依赖:

bash 复制代码
pip install openai chromadb

Windows PowerShell 可以使用以下命令激活虚拟环境:

powershell 复制代码
.\.venv\Scripts\Activate.ps1

准备好可用的 OpenAI API 密钥,并将其设置到环境变量中。不要把密钥直接写进代码或提交到 Git 仓库。

5.2 编写知识库

新建 knowledge.txt,写入以下内容:

text 复制代码
Spring Boot 是一种基于 Spring 的应用开发框架,
可以简化项目配置,并提供自动配置功能。

MySQL 是一种关系型数据库管理系统。
Java 项目可以通过 JDBC 连接 MySQL 数据库。

Servlet 是 Java Web 技术的重要组成部分,
用于处理客户端请求并生成响应。

Tomcat 是常见的 Java Web 服务器和 Servlet 容器,
可以运行符合其支持规范的 Servlet Web 应用。

这份文件就是我们的原始知识库。

5.3 编写 RAG 程序

新建 rag_demo.py:

python 复制代码
import os
from pathlib import Path

import chromadb
from openai import OpenAI

# 从环境变量读取 API 密钥
api_key = os.getenv("OPENAI_API_KEY")
if not api_key:
    raise RuntimeError("请先设置 OPENAI_API_KEY 环境变量")

client = OpenAI(api_key=api_key)

# 读取本地知识库
text = Path("knowledge.txt").read_text(
    encoding="utf-8"
)

# 简单演示:按固定字符长度切分文本
chunk_size = 120
overlap = 30
chunks = []

step = chunk_size - overlap
for start in range(0, len(text), step):
    chunk = text[start:start + chunk_size].strip()
    if chunk:
        chunks.append(chunk)

# 创建本地向量数据库
db = chromadb.Client()
collection = db.create_collection(
    name="demo_knowledge"
)

# 将文本写入向量数据库
# Chroma 会为文本计算向量并保存
collection.add(
    ids=[f"doc_{i}" for i in range(len(chunks))],
    documents=chunks
)

# 接收用户问题
question = input("请输入问题:")

# 从知识库中检索相关文本
result = collection.query(
    query_texts=[question],
    n_results=min(3, len(chunks))
)

documents = result["documents"][0]

# 组织参考资料
context = "\n\n".join(
    f"[资料 {i + 1}] {doc}"
    for i, doc in enumerate(documents)
)

# 将检索结果交给大语言模型
response = client.responses.create(
    model=os.getenv("OPENAI_MODEL", "gpt-4.1-mini"),
    instructions=(
        "你是一个知识库问答助手。"
        "请优先依据提供的参考资料回答问题。"
        "如果资料不足以支持答案,请明确说明。"
        "不要将没有依据的内容说成事实。"
    ),
    input=f"""
参考资料:
{context}

用户问题:
{question}
"""
)

print("\n检索到的资料:")
for i, doc in enumerate(documents, start=1):
    print(f"{i}. {doc}")

print("\nAI 回答:")
print(response.output_text)

说明:示例使用 Chroma 的默认文本向量化配置,因此需要安装并配置与当前 Chroma 版本兼容的 Embedding 后端。部分安装环境可能需要额外下载模型或配置向量化函数;如果配置了自定义 Embedding,则应在写入和查询时使用同一套兼容的向量化配置。

此外,这里使用的是简化的字符切分方式,主要用于理解流程,并不是生产项目中的最佳实践。

5.4 运行程序

在项目目录中执行:

bash 复制代码
python rag_demo.py

输入问题:

text 复制代码
Tomcat 是做什么的?

系统会先搜索知识库中的相关内容,再把搜索结果交给大语言模型。

预期回答大致会是:

“Tomcat 是一种 Java Web 服务器和 Servlet 容器,可以运行符合其支持规范的 Servlet Web 应用。”

具体答案取决于实际检索结果和所使用的模型。

5.5 这个程序做了什么?

整个程序实际上完成了四件事:

  1. 将本地文本切分为多个文本块。
  2. 将文本块存入向量数据库。
  3. 根据用户问题检索相关文本块。
  4. 把问题和检索结果交给大语言模型生成答案。

这就是一个最基础的 RAG 系统。

六、如何提升 RAG 的搜索质量?

一个能够运行的 RAG 项目并不意味着它已经具有良好的搜索质量。实际开发时,需要重点关注以下问题。

6.1 优化文本切分

不要仅仅为了方便就固定使用某个 Chunk Size。

可以尝试:

  • 按标题和段落切分。
  • 按 Token 数量控制文本块大小。
  • 对相邻文本块设置合理的重叠区域。
  • 为每个文本块保存文件名、章节、页码等元数据。

对于代码文档,可以按函数、类和模块切分;对于技术手册,可以按标题、章节和段落切分。

6.2 选择合适的 Embedding 模型

不同的 Embedding 模型在中文、英文、代码和多语言检索方面的表现可能存在差异。

选择模型时应考虑:

  • 是否支持中文。
  • 是否适合技术文档或代码检索。
  • 向量维度与计算成本。
  • 检索效果与延迟。
  • 是否支持本地运行,以及数据隐私要求。

更换 Embedding 模型后,通常需要重新生成文档向量,并确保查询向量与文档向量兼容。

6.3 使用混合检索

如果知识库中包含大量 Java 类名、数据库字段、错误编号和配置项,单纯使用向量检索可能不够理想。

可以组合 BM25 与向量检索,使系统同时利用精确词语匹配和语义相似性。

6.4 增加 Reranker

当初次检索返回的文本相关性不够高时,可以增加重排序步骤。

不过,Reranker 不能弥补知识库中根本不存在的信息,也不能保证生成答案一定正确。

6.5 优化提示词和引用来源

可以明确要求模型:

  • 优先使用检索资料。
  • 不确定时说明资料不足。
  • 回答时标注引用来源。
  • 不要把推测说成事实。

如果知识库有文件名、章节和页码等元数据,就可以把这些信息一起传递给模型,便于生成可核对的引用。

6.6 建立测试集

建议提前准备一批问题,并记录正确答案和对应的原始资料。

可以分别测试:

  • 检索是否找到了正确文档。
  • 正确资料在结果中的排名。
  • 最终答案是否忠实于资料。
  • 不相关问题是否会被错误回答。

例如,可以统计 Recall@K、MRR、nDCG 等检索指标,并使用人工检查或适当的评估工具判断生成答案的正确性。

不要只根据几个问题的回答效果就判断整个系统已经可靠。

七、RAG 和微调有什么区别?

RAG 和微调(Fine-tuning)经常被放在一起讨论,但两者解决的问题并不相同。

对比项目 RAG 微调
核心方式 检索外部知识并提供给模型 使用训练数据调整模型参数
更新知识 通常更新知识库即可 可能需要重新训练或继续训练
引用资料 可以保留文档来源并生成引用 模型本身不自动提供检索来源
主要用途 文档问答、知识搜索、动态资料查询 调整输出风格、任务行为和特定模式
工程组成 文档处理、索引、检索、模型调用 训练数据、训练流程、模型评估
主要成本 检索基础设施和模型调用成本 训练、数据准备和模型维护成本

例如,如果你希望 AI 理解一份经常更新的企业技术手册,通常可以优先考虑 RAG。

如果你希望模型稳定地遵循某种特定输出格式,或者学习特定任务的输入输出模式,可以评估微调是否适合。

两者也可以结合使用:先通过微调改善模型行为,再通过 RAG 提供实时或私有知识。

八、RAG 的常见进阶方向

掌握基础 RAG 后,可以继续学习以下内容:

  1. Query Rewriting:将用户的问题改写成更适合搜索的查询。
  2. Multi-Query Retrieval:生成多个不同角度的查询,扩大召回范围。
  3. Hybrid Search:结合关键词与向量检索。
  4. Reranking:对候选结果重新排序。
  5. Parent-Child Retrieval:用较小的文本块检索,再返回更完整的上下文。
  6. Metadata Filtering:按照文件、日期、部门或权限过滤资料。
  7. Agentic RAG:让模型根据任务决定检索策略,必要时多次检索。
  8. GraphRAG:利用知识图谱或图结构辅助处理实体关系和跨文档问题。

不建议一开始就学习所有高级技术。先建立一个基础系统,再根据实际问题逐步升级,会更容易理解各个模块的作用。

九、RAG 学习路线

对于已经开始学习编程、数据库和后端开发的初学者,可以按照下面的顺序学习。

第一阶段:基础知识

学习 Python、HTTP API、JSON、向量、余弦相似度、Embedding 和大语言模型 API 调用。

第二阶段:实现基础 RAG

完成文档加载、文本切分、向量化、向量检索和答案生成。

第三阶段:提升检索能力

学习 BM25、混合检索、Reranker、元数据过滤和引用来源。

第四阶段:工程化开发

增加文件上传、知识库管理、日志记录、错误处理、用户权限和持久化存储。

第五阶段:完成综合项目

开发一个能够上传课程资料、搜索相关段落、回答问题并标注来源的个人知识库助手。

如果想与 Java 后端结合,还可以把 Python RAG 服务封装成 HTTP API,再由 Spring Boot 调用。这样能够把已有的 Java Web、数据库和后端接口知识应用到 AI 应用开发中。

十、总结

RAG 是构建知识库问答系统的重要技术,其核心是把信息检索和大语言模型生成结合起来。

学习 RAG 时,最重要的是理解各个模块之间的关系:

  • 文档切分决定知识如何组织。
  • Embedding 将文本转换为向量。
  • 检索算法负责寻找相关资料。
  • 重排序负责改善候选结果的排序。
  • 大语言模型根据检索结果生成答案。
  • 评估机制帮助判断整个系统是否真正有效。

推荐的学习顺序是:先完成一个最小可运行的 RAG 项目,再逐步学习混合检索、重排序、引用追踪和系统评估。

真正掌握 RAG,不是只会调用一个向量数据库,而是能够解释为什么系统检索到了这些资料、为什么答案正确或错误,以及如何通过实验改善整个检索与生成流程。

── 完 ──

评论

还没有评论,来说点什么
发表评论
0 / 1000