你有没有过这种冲动：网站有几百篇文章，想做一个「站内 AI 助手」，于是把**全部文章正文**拼进 system prompt，再问问题？

我最初也是这么干的。直到账单出来、回答开始胡说八道、长文章直接超出上下文窗口——才意识到这是条弯路。

这篇教程把 RAG（Retrieval-Augmented Generation，检索增强生成）讲透：**为什么不要「全塞进 prompt」，正确的姿势是什么，怎么用硅基流动免费的两个模型（嵌入 `BAAI/bge-m3` + 重排 `BAAI/bge-reranker-v2-m3`）搭出又准又省钱的问答系统。**

想白嫖这两个免费模型，可以用这个注册链接：<https://cloud.siliconflow.cn/i/MBwLMSrY>

---

## 一、什么是 RAG（Why）

**RAG = Retrieval-Augmented Generation（检索增强生成）**：在让大模型生成答案之前，先**从外部知识库里检索出最相关的资料**，把这些资料连同问题一起交给大模型，让它「带着资料」回答。

它的核心思想一句话：**让模型「现查现答」，而不是指望它把全世界的 knowledge 都背在参数里。**

### 为什么会出现 RAG？

大模型本身有几个天生的天花板：

- **知识有截止日期**：模型只在训练数据时间点之前「懂」，之后的事一概不知。
- **看不到你的私有数据**：公司文档、你的博客、客户聊天记录，模型训练时根本没见过。
- **上下文窗口有限**：哪怕有 200K 上下文，也装不下整个知识库。
- **会一本正经地胡说（幻觉 / Hallucination）**：资料里没有的内容，它也会编得头头是道。

2020 年 Meta 等提出的 *Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks* 论文，就是为了让模型在回答时「先查资料」，从而缓解上述问题。后来随着向量数据库和 embedding 模型成熟，RAG 成了落地 LLM 应用最主流的范式。

### 它解决了什么问题 / 与传统大模型回答的区别

| | 传统大模型回答 | RAG 增强回答 |
|---|---|---|
| 知识来源 | 训练时「背」进去的参数 | 实时检索的外部资料 |
| 时效性 | 停在训练截止日 | 资料更新即生效 |
| 私有数据 | 看不到 | 能检索到 |
| 可溯源 | 无法引用出处 | 能给出资料来源 |
| 幻觉 | 容易编造 | 有资料约束，显著降低 |

一句话：**传统大模型是「凭记忆考试」，RAG 是「开卷考试」。**

---

## 二、为什么需要 RAG

重点说痛点，这恰恰是 RAG 存在的理由：

1. **大模型知识会过时**：2024 年的模型答不了 2026 年的新政策、新 API。
2. **容易产生幻觉（Hallucination）**：没有资料时，模型会自信地编造事实、链接、数字。
3. **无法直接访问企业私有数据**：内部 Wiki、合同、工单，模型根本不知道。
4. **Prompt 太长，Token 成本高**：把全站文章塞进 prompt，每次提问都重发几百万 token。
5. **无法引用资料来源**：用户无法核实「这句话到底出自哪里」，不信任。

RAG 把「记忆」和「查资料」解耦——模型负责推理和表达，知识存放在外面随时可更新。

---

## 三、RAG 的工作流程

一张流程图就能说清：

```mermaid
flowchart LR
  Q[用户问题] --> E[Embedding 向量化]
  E --> V[(Vector Database 向量库)]
  V --> R[Retriever 检索 Top-K]
  R --> RR[Reranker 重排 可选]
  RR --> L[LLM 生成答案]
```

放到文字里就是：

```
用户问题
   ↓
Embedding（向量化：把问题变成向量）
   ↓
Vector Database（向量数据库里存着所有资料的向量）
   ↓
Retriever（检索：找出和问题向量最相似的若干段）
   ↓
Reranker（重排，可选：对召回结果按真实相关性重新打分）
   ↓
LLM（带着最相关的资料生成答案）
```

**每一步的作用：**

- **Embedding**：把自然语言变成一串数字（向量），让「语义相似」可以被「数学距离」衡量。
- **Vector Database**：存放所有资料的向量，支持「按向量找最近邻」的高效检索。
- **Retriever**：用问题的向量去库里做最近邻搜索，粗筛出候选（如 15 段）。
- **Reranker**：把「问题 + 每个候选」拼起来重新打分，精排出真正最相关的（如 5 段）。**这是质量的关键一步。**
- **LLM**：只消费 top-N 资料，生成带出处的答案。

---

## 四、RAG 的核心组件

### 1. Embedding（嵌入模型）

把文本映射成固定维度的稠密向量。维度常见的有 768 / 1024 / 1536。中文场景首选 **BAAI/bge-m3**（1024 维，中英文都强），在硅基流动上**免费**。

**那「向量」到底是什么？**

一句话：**向量就是一串数字，代表一段文本在「语义空间」里的坐标。**

想象一张地图：每篇文章、每句话都是一个点，语义相近的句子在地图上离得近，不相关的离得远。但文字本身没法直接算「距离」，所以嵌入模型把它变成一串定长的数字，比如 1024 维的 `[0.12, -0.03, 0.87, …]`。这串数字就是那句话的「坐标」。

- 维度越高，能表达的语义越细腻（1024 维比 384 维装得下更多细微差别）。
- 「语义相似」≈「向量距离近」：用**余弦相似度**（两个向量夹角的余弦）衡量，越接近 1 越相关，越接近 0 越不相关。

**大模型「读」的是向量吗？——这是个常见误解**

不是。要把两件事分清楚：

1. **向量只用来「检索」**：检索阶段，系统把问题也变成向量，去向量库里找「离得最近」的几个文本片段。这一步全是数学计算（算距离、排序），大模型不参与。
2. **真正喂给大模型的是「原文」**：检索完成后，系统把对应的**原始文本片段**（注意，不是那串数字）拼进 prompt，大模型读的是这些文字，再据此生成答案。

> 所以更准确的说法是：**向量负责「找得准」，大模型负责「读得懂」。** 向量是给检索器用的「地址」，不是给大模型读的「内容」。也是因为这个分工，RAG 才能用很便宜的模型就答得准——大模型看到的只是精挑细选出来的几段文字。

### 2. Chunk（文本切分）

把长文档切成小段（chunk）。RAG 的检索粒度是 chunk，不是整篇文档。切得太粗→召回不精准；太细→语义被切碎。常见甜区是 **300~500 字**。

### 3. Vector Database（向量数据库）

专门存向量、支持 ANN（近似最近邻）检索的数据库。可选 Qdrant / Milvus / Chroma / FAISS，或直接在 Postgres 里用 **pgvector** 扩展（本博客用的就是它）。

### 4. Retriever（检索器）

负责「问题向量 → 候选 chunk」的粗筛。核心是余弦相似度 / 内积 / 欧氏距离。

### 5. Reranker（重排模型）

Cross-Encoder 结构，比单纯余弦准得多。把 `query + 候选` 一起喂进去打分。**BAAI/bge-reranker-v2-m3** 在硅基流动上同样**免费**。

### 6. LLM（生成模型）

最后消费 top-N 资料生成答案。因为只看到几段，所以**可以用更便宜的模型**，成本骤降。

它们如何配合：**嵌入模型**负责「入库」和「查」时的向量化；**向量库+检索器**负责粗筛；**重排模型**负责精排；**LLM** 负责表达。前三者决定「找得准」，最后一个决定「答得好」。

---

## 五、RAG 的优势

- **回答更准确**：带着真实资料回答，而不是凭空编。
- **降低幻觉**：有资料约束，编造空间被压缩。
- **可引用来源**：每条答案能附上出处段落，用户可核实。
- **知识实时更新**：往库里加新文档即可，不用动模型。
- **降低 Token 消耗**：只送 top-N 段（几千 token），不是全库。
- **可使用更便宜的生成模型**：因为上下文短而精，小模型也答得不错。
- **企业数据无需重新训练模型**：知识在外面，模型参数不动。

---

## 六、RAG 与微调（Fine-tuning）的区别

这是高频搜索话题，一张表说清：

| 维度 | RAG | 微调（Fine-tuning） |
|---|---|---|
| 知识更新 | 快（加文档即生效） | 慢（需重新训练） |
| 是否修改模型 | 不改参数 | 修改模型权重 |
| 实时更新知识 | 支持 | 不支持，需重训 |
| 成本 | 低（主要是检索+少量生成） | 高（训练算力+数据标注） |
| 适合场景 | 知识库 / 检索问答 | 让模型学会某种「能力 / 风格」 |

> **重点**：很多企业实际采用 **「RAG + 微调」组合**——用 RAG 提供最新、可溯源的知识，用微调让模型掌握特定的表达风格或任务格式。不是二选一。

---

## 七、如何搭建一个 RAG

完整流程：

1. **准备文档**：博客文章、PDF、Wiki、工单等原始资料。
2. **文本切分（Chunk）**：按语义切成 300~500 字的小段。
3. **Embedding**：用 bge-m3 把每段变成向量。
4. **写入向量数据库**：`chunk + 向量 + 元数据` 入库。
5. **用户提问**：问题进来。
6. **检索**：问题向量化后，在库里召回 Top-15。
7. **重排（可选但推荐）**：用 bge-reranker 重排，取 Top-5。
8. **交给 LLM 回答**：把 Top-5 拼进 prompt，生成答案并附来源。

---

## 八、常见开源方案（生态一览）

**框架**

- LangChain（最流行，组件多）
- LlamaIndex（数据接入与索引见长）
- Haystack（企业级 pipeline）

**Embedding 模型**

- BGE（`BAAI/bge-m3` 等，中英文强，硅基流动免费）
- Jina Embeddings
- Nomic Embed

**向量数据库**

- Qdrant（Go 写，性能好，易部署）
- Milvus（大规模分布式）
- Chroma（轻量，开发友好）
- FAISS（Meta 的向量检索库，常作底层引擎）

**Reranker**

- BGE Reranker（`BAAI/bge-reranker-v2-m3`，免费）
- Jina Reranker

---

## 九、如何优化 RAG（最容易忽略、却最有价值）

1. **Chunk 大小怎么选**：300~500 字是常见甜区；超长文档可先按标题/段落结构切。
2. **Chunk 是否需要重叠（Overlap）**：建议留 10%~20% 重叠，避免一句话被切断导致语义丢失。
3. **Hybrid Search（混合检索）**：向量检索（语义）+ 关键词检索（BM25 / 全文索引）融合（RRF），召回率明显更高。本博客资源站就是「向量 + ilike 词法」双路 RRF 融合。
4. **Metadata Filter（元数据过滤）**：先按时间、分类、作者过滤，再检索，能大幅降噪（比如只搜「2026 年的教程」）。
5. **Top-K 如何设置**：召回 15~20、重排后取 5，是稳妥起点；太长反而引入噪声。
6. **是否需要 Reranker**：几乎总是「需要」——它能把余弦召回的误排纠正回来，质量提升肉眼可见。
7. **如何降低 Token 成本**：只送重排后的 Top-5；生成模型选便宜的；嵌入/重排用免费模型。
8. **如何提高召回率**：混合检索 + 元数据过滤 + 合理 chunk + overlap + 重排，四管齐下。

---

## 十、RAG 的应用场景（适合什么场景）

- **企业知识库**：员工问制度、流程、产品文档。
- **AI 客服**：检索历史工单与 FAQ，给出准确答复。
- **PDF 问答**：上传合同 / 论文 / 手册，直接问内容。
- **API 文档助手**：开发者问「这个接口怎么调」，定位到对应段落。
- **法律咨询**：检索法条与判例（须人工复核，不可直接采信）。
- **医疗知识助手**：检索指南与文献（同理，辅助而非替代专业判断）。
- **教育平台**：按教材章节答疑、出练习题。
- **博客问答**：就像本博客的「就这篇文章问 AI」——读者对某一篇提问，模型只基于该文作答。

---

## 十一、常见误区

- **RAG ≠ 微调**：一个补知识，一个学能力，别混为一谈。
- **RAG 不会让模型变聪明**：它只是给资料，模型本身能力不变。
- **RAG 不是数据库**：它是「检索 + 生成」的范式，底层才用数据库。
- **RAG 不是搜索引擎**：它最终要生成自然语言答案，不是返回链接列表。
- **RAG 不一定比微调更适合所有场景**：要模型「学会新能力/新风格」还是得微调。
- **Reranker 不是必须的**：但加了通常显著更好，属于「可选但强烈推荐」。
- **Chunk 越大不一定越好**：过大反而稀释相关性、浪费 token。

---

## 十二、实战案例：本博客的「就这篇文章问 AI」

以这个博客为例，真实架构是：

```
Markdown 文章（知识库）
   ↓ 自动切分（按段落 / 标题）
   ↓ bge-m3 生成 Embedding
   ↓ 存入向量库（本博客用 Postgres + pgvector；你也可以用 Qdrant）
   ↓
用户提问
   ↓ bge-m3 向量化问题
   ↓ 向量库召回相关文章片段（Top-15）
   ↓ bge-reranker-v2-m3 重排（Top-5）
   ↓ 调用硅基流动的 DeepSeek（或更便宜的免费模型）生成答案
```

**一次完整的问答流程**（伪代码，可直接落地）：

```ts
// ① 索引阶段（写文章时跑一次）
const chunks = splitByHeading(markdownText);          // 自动切分
const vectors = await embed(chunks);                  // bge-m3 向量化
await db.insert(chunks.map((c, i) => ({ content: c, embedding: vectors[i] })));

// ② 提问阶段
const queryVec = (await embed([question]))[0];        // 问题向量化
const candidates = await db.search(queryVec, 15);     // 向量库召回 Top-15
const ranked = await rerank(question, candidates, 5); // bge-reranker 重排取 Top-5
const context = ranked.map(r => candidates[r.index]).join('\n\n');

// ③ 生成（只送 5 段，便宜又准）
const answer = await chatWithLLM(`
请根据以下资料回答，并标注来源：
${context}

问题：${question}
`);
```

嵌入与重排调用硅基流动的免费模型：

```ts
const SF_KEY = process.env.SILICONFLOW_API_KEY!;

// 嵌入：BAAI/bge-m3（免费，1024 维）
async function embed(texts: string[]): Promise<number[][]> {
  const r = await fetch('https://api.siliconflow.cn/v1/embeddings', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${SF_KEY}` },
    body: JSON.stringify({ model: 'BAAI/bge-m3', input: texts, encoding_format: 'float' }),
  });
  const j = await r.json();
  return j.data.map((d: any) => d.embedding as number[]);
}

// 重排：BAAI/bge-reranker-v2-m3（免费）
async function rerank(query: string, documents: string[], topN = 5) {
  const r = await fetch('https://api.siliconflow.cn/v1/rerank', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${SF_KEY}` },
    body: JSON.stringify({ model: 'BAAI/bge-reranker-v2-m3', query, documents, top_n: topN }),
  });
  return (await r.json()).results; // [{ index, relevance_score }] 已按分数排序
}
```

> 完整 SQL（pgvector 建表 + 余弦召回）和成本对比，见我另一篇短文；核心结论：**嵌入 + 重排都免费，生成模型只看 Top-5（约 3000 token），比「全塞 prompt」省 99%+。**

---

## 小结

RAG 的精髓就一句话：**知识放向量库，提问时只送最相关的几段给大模型。**

- 嵌入用 `BAAI/bge-m3`（免费）
- 重排用 `BAAI/bge-reranker-v2-m3`（免费）
- 向量库用 pgvector / Qdrant
- 生成模型只看 Top-5

照这个结构搭，你的 AI 问答会**更准、更快、便宜一个数量级**。想白嫖这两个免费模型，注册链接：<https://cloud.siliconflow.cn/i/MBwLMSrY>

本文代码可直接复用——事实上这个博客自己的「就这篇文章问 AI」功能，跑的就是同一套管线。