本文定位:这是一篇面向即将学习 RAG(Retrieval-Augmented Generation,检索增强生成)的开发者的前置知识指南。RAG 是当前 AI 应用中最实用的技术之一,但它涉及多个跨领域概念——向量、Embedding、向量数据库、文本分块、相似度检索等。本文将这些概念逐一拆解,用通俗语言 + 图表 + 代码示例帮你建立完整的知识框架,为后续的 RAG 实战打下坚实基础。

适合谁读

  • 已掌握 LLM 基础调用(如 ChatModel),准备深入 RAG 的 Java/Spring 开发者
  • 对"向量"、"Embedding"等概念一知半解,想要系统梳理的同学

目录


1. 为什么需要 RAG?——LLM 的三大痛点

在学习 RAG 之前,首先要理解它要解决什么问题。大语言模型(LLM)虽然强大,但存在三个致命短板:

痛点 具体表现 举例
知识过时 训练数据有截止日期,不知道最新信息 问"2025年Spring AI最新版本是什么?"→ 回答错误或不知道
幻觉(Hallucination) 不知道的内容会一本正经地编造 问"你们公司的退款政策是什么?"→ 编一个看起来合理但完全虚构的政策
知识边界 不了解私有数据、企业内部文档 问"我们项目的技术架构是什么?"→ 无从得知

RAG 的核心思路

┌─────────────────────────────────────────────────────────┐
│                                                         │
│  传统 LLM:用户问题 ───────────────→ LLM ──→ 回答      │
│                      (只靠训练时的知识)                │
│                                                         │
│  RAG:用户问题 → 【先检索相关知识】→ 知识+问题 → LLM → 回答  │
│                   (从知识库中找到最相关的内容)          │
│                                                         │
└─────────────────────────────────────────────────────────┘

一句话理解 RAG:开卷考试。LLM 不再只靠"记忆"(训练数据)答题,而是允许它翻阅"参考资料"(检索到的文档),然后基于参考资料回答问题。


2. RAG 全局架构概览

在深入每个概念之前,先看 RAG 的完整架构,建立全局认知:

┌─────────────────────── 离线阶段(Indexing)──────────────────────┐
│                                                                  │
│  原始文档                                                        │
│  (PDF/Word/Markdown/数据库...)                                   │
│       │                                                          │
│       ▼                                                          │
│  ① 文档加载(Document Loading)                                  │
│       │                                                          │
│       ▼                                                          │
│  ② 文本分块(Chunking / Splitting)                              │
│       │                                                          │
│       ▼                                                          │
│  ③ 向量化(Embedding)                                           │
│     "每个文本块" → Embedding 模型 → "一个向量 float[1536]"       │
│       │                                                          │
│       ▼                                                          │
│  ④ 存入向量数据库(Vector Store)                                │
│     向量 + 原文 + 元数据 → 持久化存储                            │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘

┌─────────────────────── 在线阶段(Querying)──────────────────────┐
│                                                                  │
│  用户提问:"Agent 是怎么调用工具的?"                             │
│       │                                                          │
│       ▼                                                          │
│  ⑤ 问题向量化(Query Embedding)                                 │
│     用户问题 → Embedding 模型 → 查询向量                         │
│       │                                                          │
│       ▼                                                          │
│  ⑥ 向量相似度检索(Similarity Search)                           │
│     在向量数据库中找到 Top-K 最相似的文档块                      │
│       │                                                          │
│       ▼                                                          │
│  ⑦ 构建增强 Prompt(Augmented Prompt)                           │
│     系统提示词 + 检索到的文档内容 + 用户问题                     │
│       │                                                          │
│       ▼                                                          │
│  ⑧ LLM 生成回答(Generation)                                   │
│     基于检索到的知识生成准确、有据可依的回答                     │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘

上面的每一步都涉及一个或多个前置知识,下面逐一展开。


3. 什么是向量(Vector)?

向量是 RAG 的数学基石,理解向量才能理解后续的一切。

3.1 向量的直觉理解

数学定义:向量是一个有序的数字列表(数组),每个数字称为一个"维度"。

二维向量:[3, 4]              → 平面上的一个点
三维向量:[1, 2, 3]           → 三维空间中的一个点
高维向量:[0.23, -0.45, 0.89, 0.12, ..., 0.67]  → 768维空间中的一个点

通俗理解:你可以把向量想象成一个人的"特征描述卡"。

张三的特征卡(用数字描述):
├─ 身高维度:175(cm)
├─ 体重维度:70(kg)
├─ 年龄维度:25(岁)
└─ 收入维度:15000(元/月)

→ 向量表示:[175, 70, 25, 15000]

两个"特征卡"越接近,说明两个人越相似。文本向量也是同样的道理——只不过维度从4个变成了768个或1536个,每个维度编码了文本的某个语义特征。

3.2 为什么用向量表示文本?

计算机天然擅长处理数字,不擅长直接理解文字。把文本转成向量后:

能力 文本形式 向量形式
比较相似度 ❌ "猫"和"喵星人"字面完全不同 ✅ 向量距离很近(语义相同)
数学运算 ❌ 无法对文字做加减乘除 ✅ 可以计算距离、做聚类
快速检索 ❌ 全文搜索依赖关键词匹配 ✅ 向量索引毫秒级返回
跨语言 ❌ "猫"和"cat"字面无关 ✅ 多语言模型中向量接近

核心公式

语义相近的文本 → 向量在空间中距离近
语义不同的文本 → 向量在空间中距离远

用一个直观的例子:

"猫"     → [0.23, -0.45, 0.89, 0.12, ...]
"小猫咪" → [0.25, -0.42, 0.85, 0.15, ...]    ← 距离很近!
"狗"     → [0.18, -0.38, 0.72, 0.20, ...]    ← 距离较近(都是动物)
"汽车"   → [-0.71, 0.33, 0.02, -0.56, ...]   ← 距离很远(不同领域)

4. 什么是 Embedding(文本向量化)?

Embedding 就是把文本转换成向量的过程和技术。

4.1 Embedding 模型的工作原理

┌──────────────────────────────────────────────────┐
│                  Embedding 模型                   │
│                                                  │
│  输入:一段文本(字符串)                          │
│        "Spring AI 的 Tool Calling 机制"           │
│           │                                      │
│           ▼                                      │
│  内部处理:                                       │
│    1. 分词(Tokenization)                        │
│    2. 通过 Transformer 神经网络编码               │
│    3. 提取语义特征                                │
│    4. 压缩为固定长度的浮点数组                     │
│           │                                      │
│           ▼                                      │
│  输出:一个固定维度的向量                          │
│        [0.012, -0.034, 0.078, ..., 0.056]        │
│         \_______________ _______________/         │
│                        V                         │
│                 1536 个浮点数                      │
│              (维度取决于模型)                     │
└──────────────────────────────────────────────────┘

关键点:无论输入文本是 10 个字还是 500 个字,Embedding 模型的输出永远是固定长度的向量。这就是"压缩编码"——把变长文本压缩成定长数字。

4.2 Embedding 模型 vs Chat 模型

这是初学者最容易混淆的两个概念:

对比维度 Embedding 模型 Chat 模型(LLM)
输入 文本 文本(对话)
输出 固定长度的 float 数组 自然语言文本
目的 把文本编码成可计算的数字 理解意图并生成回答
用途 语义搜索、RAG 检索 对话、写作、推理
举例 text-embedding-3-small gpt-4oglm-4
能否对话 ❌ 不能 ✅ 可以
成本 极低(约 Chat 的 1/100) 较高
// Chat 模型:输入文本 → 输出文本
String answer = chatModel.call("什么是RAG?");
// answer = "RAG是检索增强生成..."(自然语言)

// Embedding 模型:输入文本 → 输出向量
float[] vector = embeddingModel.embed("什么是RAG?");
// vector = [0.012, -0.034, 0.078, ...](浮点数组)

4.3 主流 Embedding 模型对比

模型 提供商 维度 最大 Token 特点
text-embedding-3-small OpenAI 1536 8191 性价比高,推荐
text-embedding-3-large OpenAI 3072 8191 精度更高,成本更高
text-embedding-ada-002 OpenAI 1536 8191 旧版,仍在广泛使用
embedding-3 智谱 AI 2048 8192 中文效果好
BAAI/bge-large-zh BAAI 1024 512 开源,中文专优
mxbai-embed-large Ollama 1024 512 本地部署,免费
nomic-embed-text Ollama 768 8192 本地部署,长文本

选型建议

  • 中文场景优先选择智谱 embedding-3 或开源 bge-large-zh
  • 英文场景优先选择 OpenAI text-embedding-3-small
  • 预算有限或数据敏感,选择 Ollama 本地部署方案

5. 相似度计算——向量之间怎么比"像不像"?

有了向量之后,如何判断两个向量(即两段文本)的语义是否相近?这就需要"相似度计算"。

5.1 余弦相似度(Cosine Similarity)

最常用的相似度度量方式。

直觉理解:两个向量之间"夹角"的余弦值。夹角越小(方向越一致),余弦值越接近 1,表示越相似。

              B 向量
             /
            / θ(夹角)
           /
          /
─────────────────── A 向量

余弦相似度 = cos(θ)
- θ = 0°   → cos(0°) = 1.0   → 完全相同
- θ = 90°  → cos(90°) = 0.0  → 完全无关
- θ = 180° → cos(180°) = -1.0 → 完全相反

数学公式(了解即可):

            A · B           Σ(Ai × Bi)
cos(θ) = ─────── = ──────────────────────
          |A|×|B|   √(Σ Ai²) × √(Σ Bi²)

代码示例

/**
 * 计算两个向量的余弦相似度
 * @param vectorA 向量A
 * @param vectorB 向量B
 * @return 相似度值,范围 [-1, 1],越接近1越相似
 */
public static double cosineSimilarity(float[] vectorA, float[] vectorB) {
    double dotProduct = 0.0;
    double normA = 0.0;
    double normB = 0.0;
    for (int i = 0; i < vectorA.length; i++) {
        dotProduct += vectorA[i] * vectorB[i];
        normA += vectorA[i] * vectorA[i];
        normB += vectorB[i] * vectorB[i];
    }
    return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
}

实际效果

"猫咪很可爱" vs "小猫真萌"       → 余弦相似度 ≈ 0.92(很相似)
"猫咪很可爱" vs "今天天气不错"     → 余弦相似度 ≈ 0.15(不相关)
"猫咪很可爱" vs "我讨厌猫"        → 余弦相似度 ≈ 0.45(有关联但语义不同)

5.2 欧氏距离(Euclidean Distance)

直觉理解:两个点之间的"直线距离"。距离越小,越相似。

在二维空间中:
A = (1, 2),  B = (4, 6)
欧氏距离 = √((4-1)² + (6-2)²) = √(9+16) = 5.0

特点:不仅考虑方向(像余弦),还考虑向量的长度(幅度)。

5.3 点积(Dot Product)

直觉理解:两个向量对应维度相乘再求和。同时包含了方向和长度信息。

A = [1, 2, 3],  B = [4, 5, 6]
点积 = 1×4 + 2×5 + 3×6 = 4 + 10 + 18 = 32

5.4 三种方法怎么选?

方法 取值范围 含义 适用场景 RAG 中的使用频率
余弦相似度 [-1, 1] 方向一致性 文本语义匹配 ⭐⭐⭐⭐⭐ 最常用
欧氏距离 [0, +∞) 绝对距离 图像特征、聚类 ⭐⭐
点积 (-∞, +∞) 方向+长度 推荐系统 ⭐⭐⭐

小结:RAG 场景一般用余弦相似度,因为我们关心的是语义方向是否一致,而不是向量的绝对大小。Embedding 模型输出的向量通常已经归一化,此时余弦相似度和点积的结果等价。


6. 文本分块(Chunking)——RAG 质量的第一个关键

文本分块是 RAG 流水线中最容易被忽视但影响最大的环节。

6.1 为什么要分块?

三个原因:

原因一:Embedding 模型有 Token 上限
├─ text-embedding-3-small 最多处理 8191 tokens
├─ bge-large-zh 最多处理 512 tokens
└─ 一篇文档可能有几万 tokens → 必须切分

原因二:检索粒度问题
├─ 如果整篇文档作为一个向量,检索太粗
├─ 用户问"Agent的Tool Calling怎么实现?"
├─ 整篇文档的向量包含了太多无关内容
└─ 小块(如一个段落)的向量更精准地表示局部语义

原因三:LLM 上下文窗口限制
├─ 检索到的文档要塞进 Prompt 送给 LLM
├─ 如果每个块太大,Top-5 就可能超出窗口
└─ 小块可以塞更多来源,回答更全面

6.2 四种常见分块策略

策略一:固定大小分块
原文:[AAAA|BBBB|CCCC|DDDD|EEEE]
       ↓ 每 4 个字符切一刀
块1: [AAAA]
块2: [BBBB]
块3: [CCCC]
块4: [DDDD]
块5: [EEEE]
优点 缺点
实现简单 可能从句子中间切断
块大小均匀 语义完整性无法保证
策略二:按段落/标题分块
原文:
# 第一章 Agent概述       ←── 遇到标题切分
Agent是一种智能体...
它可以自主决策...

# 第二章 Tool Calling    ←── 遇到标题切分
Tool Calling是指...

结果:
块1: "第一章 Agent概述\nAgent是一种智能体...\n它可以自主决策..."
块2: "第二章 Tool Calling\nTool Calling是指..."
优点 缺点
保留文档结构 块大小不均匀
语义完整性好 某些块可能太大或太小
策略三:滑动窗口分块(推荐)
原文:[A B C D E F G H I J]
       ↓ 窗口大小=5,重叠=2
块1: [A B C D E]
块2: [    D E F G H]      ← D、E 重叠
块3: [        G H I J]    ← G、H 重叠
优点 缺点
避免边界语义丢失 存储空间略增(有重叠)
兼顾完整性和粒度 需要调两个参数
业界最常用

Spring AI 中的实现

// TokenTextSplitter 就是滑动窗口分块器
TokenTextSplitter splitter = new TokenTextSplitter(
    500,    // defaultChunkSize: 每块大约 500 tokens
    100,    // minChunkSizeChars: 最小块字符数
    200,    // minChunkLengthToEmbed: 最小需要 Embedding 的长度
    1000,   // maxNumChunks: 最大块数
    true    // keepSeparator: 保留分隔符
);

List<Document> chunks = splitter.split(document);
策略四:语义分块
原文:[关于猫的介绍。猫很可爱。| 今天天气很好。适合出门。]
       ↓ 用模型检测语义边界(话题变化处切分)
块1: "关于猫的介绍。猫很可爱。"
块2: "今天天气很好。适合出门。"
优点 缺点
语义完整性最好 需要额外模型调用,成本高
切分质量最高 速度慢

6.3 分块参数怎么调?

参数 推荐范围 说明
chunk_size 300-500 tokens 太大检索不精准,太小丢失上下文
chunk_overlap chunk_size 的 10%-20% 即 50-100 tokens 的重叠
分隔符 \n\n. 优先在自然断句处切分

经验法则

  • 技术文档:500 tokens,overlap 50
  • 对话记录:200-300 tokens,overlap 30
  • 法律/合同:300-400 tokens,overlap 80(重叠多一些避免条款截断)

7. 向量数据库(Vector Database)——专门为向量设计的存储引擎

7.1 为什么不用 MySQL?

MySQL 能做的:
  SELECT * FROM documents WHERE content LIKE '%Agent%'
  → 关键词匹配,"Agent"和"智能体"匹配不上

MySQL 做不到的:
  "找出和 [0.23, -0.45, 0.89, ...] 这个 1536 维向量最相似的 5 条记录"
  → MySQL 没有高维向量的索引和相似度计算能力
  → 即使暴力遍历,百万级数据要几十秒

向量数据库是专门为高维向量的存储和近似最近邻(ANN)搜索而设计的数据库。

7.2 主流向量数据库对比

数据库 类型 特点 适合场景 Spring AI 支持
Chroma 轻量级嵌入式 零配置,开箱即用 开发测试、小数据量 ChromaVectorStore
Milvus 分布式 高性能,支持十亿级 生产环境、大规模 MilvusVectorStore
Pinecone 全托管 SaaS 无需运维 快速上线、不想管基础设施 PineconeVectorStore
Weaviate 混合搜索 内置向量化,支持语义+关键词 混合搜索场景 WeaviateVectorStore
pgvector PG 扩展 在已有 PostgreSQL 上加向量能力 已有 PG 基础设施 PgVectorStore
Redis Stack 内存 速度极快 实时性要求高 RedisVectorStore
SimpleVectorStore 内存(Spring AI 内置) 零依赖,用于 Demo 学习和测试 ✅ 内置

选型建议

  • 学习入门:SimpleVectorStore(零依赖,内存存储)
  • 开发测试:Chroma(轻量,Docker 一键启动)
  • 生产部署:Milvus 或 pgvector

7.3 向量检索的底层算法

面试中可能被问到,了解即可:

算法 原理 时间复杂度 精度 适用场景
暴力搜索(Flat) 逐一比对所有向量 O(n) 100% 精确 小数据量(<10万)
IVF(倒排文件索引) 先聚类,查询时只搜部分簇 O(n/k) 近似 大数据量
HNSW(层次导航小世界图) 构建多层图索引,图上跳跃搜索 O(log n) 近似(>95%) 最常用,速度/精度平衡最好
PQ(乘积量化) 压缩向量减少内存 O(n) 近似 超大规模,内存有限
HNSW 搜索过程(直觉理解):

层3(最稀疏):  A ─────────── B ──────────── C
                              │
层2:            A ── D ─── B ── E ── C ── F
                              │
层1:            A-D-G-B-H-E-I-C-F-J
                              │
层0(最稠密):  A-D-K-G-L-B-M-H-N-E-O-I-P-C-Q-F-R-J

搜索时:从顶层(稀疏)快速定位大致区域,逐层下降(细化),
        在底层(稠密)找到精确的最近邻。

小结:HNSW 是目前向量检索最主流的索引算法,它通过构建多层图结构实现 O(log n) 的搜索复杂度,在精度和速度之间取得了最佳平衡。

7.4 向量数据库的核心操作

// 伪代码:向量数据库的核心 CRUD

// 1. 写入(Insert)
vectorStore.add(List.of(
    new Document("Spring AI支持Tool Calling", metadata),
    new Document("RAG是检索增强生成", metadata)
));

// 2. 相似度搜索(核心操作)
List<Document> results = vectorStore.similaritySearch(
    SearchRequest.query("Agent如何调用工具?")
        .withTopK(5)                    // 返回最相似的5条
        .withSimilarityThreshold(0.7)   // 相似度阈值,低于0.7的不返回
);

// 3. 删除
vectorStore.delete(List.of("doc-id-1", "doc-id-2"));

8. Token 与上下文窗口——理解 LLM 的"胃口"

8.1 什么是 Token?

Token 是 LLM 处理文本的最小单位,不是字,不是词,而是模型自己的分词结果。

英文:
"Hello world" → ["Hello", " world"] → 2 tokens

中文:
"你好世界" → ["你好", "世界"] → 2 tokens(约 1 个汉字 ≈ 1-2 个 token)

代码:
"System.out.println" → ["System", ".", "out", ".", "print", "ln"] → 6 tokens

粗略估算

  • 英文:1 token ≈ 4 个字符 ≈ 0.75 个单词
  • 中文:1 token ≈ 1-2 个汉字
  • 1000 个中文汉字 ≈ 500-1000 tokens

8.2 上下文窗口(Context Window)

上下文窗口是 LLM 一次请求能处理的最大 Token 总数,包括输入 + 输出。

模型 上下文窗口 约等于中文字数
GPT-3.5 4K / 16K tokens 约 8K-16K 字
GPT-4o 128K tokens 约 64K-128K 字
GLM-4 128K tokens 约 64K-128K 字
Claude 3 200K tokens 约 100K-200K 字
DeepSeek V3 64K tokens 约 32K-64K 字

8.3 为什么上下文窗口很大了还需要 RAG?

很多初学者会问:“GPT-4o 有 128K 窗口,直接把所有文档塞进去不就行了?”

答案是不行,原因如下:

原因 说明
成本问题 Token 按量计费,128K 输入一次调用就要花好几块钱。RAG 只检索相关片段(Top-5 约 2K tokens),成本降低 90%+
"大海捞针"问题 研究表明,当输入超长时,LLM 对中间位置的信息关注度下降(Lost in the Middle 现象)。信息越精准,回答越好
延迟问题 输入 Token 越多,首次响应延迟越高。128K 输入可能要等几十秒
知识库规模 企业知识库可能有几百万篇文档,远超任何模型的窗口
动态更新 新文档随时添加到向量数据库,无需重新训练模型

小结:长上下文和 RAG 不是替代关系,而是互补关系。RAG 负责从海量数据中精准检索,长上下文让模型能处理更多检索结果。两者结合才是最优方案。


9. Prompt Engineering 与 RAG 的关系

RAG 的最后一步是把检索到的文档注入 Prompt 中,这就涉及到 Prompt 的构造方式。

RAG 的增强 Prompt 模板

┌──────────────── 增强后的 Prompt ────────────────┐
│                                                  │
│  【系统提示词】                                   │
│  你是一个专业的技术助手。请根据以下参考资料         │
│  回答用户的问题。如果参考资料中没有相关信息,        │
│  请明确告知用户你不知道,不要编造。                 │
│                                                  │
│  【检索到的参考资料】(由 RAG 检索步骤提供)        │
│  ---                                             │
│  [文档1] Agent 通过 Tool Calling 机制自主决策,    │
│  模型会根据用户问题选择合适的工具...               │
│  ---                                             │
│  [文档2] Spring AI 的 @Tool 注解可以将 Java        │
│  方法注册为模型可调用的工具...                     │
│  ---                                             │
│                                                  │
│  【用户问题】                                     │
│  Agent 是怎么调用工具的?                          │
│                                                  │
└──────────────────────────────────────────────────┘

关键设计原则

原则 说明 为什么重要
明确要求基于资料回答 “请根据以下参考资料回答” 减少幻觉,让模型依赖事实
允许说不知道 “如果资料中没有相关信息,请明确告知” 防止编造
标注来源 给每个文档块编号或标注出处 方便用户溯源验证
控制回答格式 “用中文回答”、“分点列出” 提升回答质量

10. Spring AI 中的 RAG 组件映射

如果你使用 Spring AI 框架,以下是 RAG 每个步骤对应的组件:

RAG 步骤 Spring AI 组件 说明
① 文档加载 DocumentReader 支持 PDF、TXT、Markdown、JSON 等格式
② 文本分块 TextSplitter(如 TokenTextSplitter 按 Token 数切分,支持重叠
③ 向量化 EmbeddingModel(如 ZhiPuAiEmbeddingModel 调用 Embedding API 将文本转为向量
④ 存入向量库 VectorStore(如 SimpleVectorStore 支持多种向量数据库
⑤ 查询向量化 EmbeddingModel(同上) 用同一个模型将查询文本转为向量
⑥ 相似度检索 VectorStore.similaritySearch() 返回 Top-K 最相似文档
⑦ 注入 Prompt QuestionAnswerAdvisor 自动将检索结果注入 Prompt
⑧ LLM 生成 ChatModel / ChatClient 基于增强后的 Prompt 生成回答

代码示意(完整 RAG 流程)

// === 离线阶段:构建知识库索引 ===

// 1. 加载文档
DocumentReader reader = new TextReader(new ClassPathResource("knowledge.txt"));
List<Document> documents = reader.get();

// 2. 分块
TokenTextSplitter splitter = new TokenTextSplitter();
List<Document> chunks = splitter.split(documents);

// 3-4. 向量化 + 存入向量库(VectorStore 内部自动调用 EmbeddingModel)
vectorStore.add(chunks);


// === 在线阶段:用户查询 ===

// 5-8. ChatClient + QuestionAnswerAdvisor 自动完成:检索 → 注入 → 生成
ChatClient chatClient = chatClientBuilder
    .defaultAdvisors(new QuestionAnswerAdvisor(vectorStore))  // 核心:RAG Advisor
    .build();

String answer = chatClient.prompt()
    .user("Agent 是怎么调用工具的?")
    .call()
    .content();

// 内部流程:
// user问题 → EmbeddingModel → 查询向量 → VectorStore检索Top-K
// → 拼接到Prompt → ChatModel生成回答

11. RAG 检索质量优化(进阶预览)

基础 RAG 跑通之后,你会发现检索质量往往不够理想。以下是常见的优化方向,作为后续学习的路线图:

优化策略 原理 效果
Query 改写 用 LLM 先扩展/改写用户问题,再检索 提升召回率
HyDE 让 LLM 先"假设性回答",用回答去检索 检索更精准(反直觉但有效)
Reranker(重排序) 检索后用交叉编码器对结果重新打分排序 过滤低质量结果
多路召回 同时用向量检索 + 关键词检索(BM25),合并去重 兼顾语义和关键词匹配
Parent-Child 分块 小块用于检索(精准),返回时给大块(完整上下文) 兼顾精度和上下文
元数据过滤 在向量检索前先按类型、日期等元数据缩小范围 减少噪声
基础 RAG 流程:
  问题 → Embedding → 向量检索 → Top-K → LLM

优化后的 RAG 流程:
  问题 → Query改写 → Embedding → 向量检索 + BM25检索
       → 合并去重 → Reranker重排序 → Top-K → LLM

这些优化在后续的 RAG 实战文章中会逐一详细讲解。


12. 总结

本文覆盖了学习 RAG 之前必须掌握的所有核心前置知识:

知识模块 核心要点 重要程度
向量(Vector) 用有序数字表示语义,语义相近→距离近 ⭐⭐⭐⭐⭐
Embedding 通过预训练模型将文本编码为固定维度向量 ⭐⭐⭐⭐⭐
相似度计算 余弦相似度最常用,衡量语义方向一致性 ⭐⭐⭐⭐
文本分块 滑动窗口分块最推荐,chunk_size 300-500 ⭐⭐⭐⭐⭐
向量数据库 HNSW 索引 + 近似最近邻搜索,毫秒级检索 ⭐⭐⭐⭐
Token 与上下文窗口 理解 LLM 的容量限制,解释 RAG 的必要性 ⭐⭐⭐⭐
Prompt Engineering RAG 的最后一步:检索结果 + 用户问题 → 增强 Prompt ⭐⭐⭐

核心认知

  1. RAG = 检索(R)+ 增强(A)+ 生成(G),本质是给 LLM 做"开卷考试"
  2. 向量是桥梁——连接"人类语言"和"数学计算",让计算机能理解语义
  3. Embedding 是关键技术——将变长文本压缩为定长向量,是 RAG 检索的基础
  4. 分块决定上限——再好的模型、再好的向量数据库,如果分块策略不对,检索结果就不精准
  5. RAG 不是替代长上下文——两者互补,RAG 负责精准检索,长上下文负责处理更多结果

13. 参考资料

Spring AI 官方文档

学术与技术文章

向量数据库官方文档

其他推荐阅读

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐