RAG 简介

RAG 是什么?

RAG(Retrieval-Augmented Generation) 在调用 LLM 之前,先从你自己的文档里找出相关片段,再把片段和问题一起交给模型。生成仍然是语言模型;「公司制度、产品 FAQ、昨天刚改的接口」则来自检索,而不是来自预训练记忆。

没有检索时,模型只能靠训练数据和提示词里塞进去的原文。上下文窗口再大,也不适合把整座知识库每次都贴进去;私有数据也不会出现在公开权重里。

问题 ──► 检索(向量库 / 关键词)──► 相关块 ──► 提示词 + LLM ──► 回答

为什么需要 RAG?

痛点RAG 怎么帮
幻觉要求模型只根据检索到的块说话,并引用出处
私有知识制度、工单、内部 Wiki 不必先微调进权重
新鲜度改 Markdown / 改表 → 重新切块嵌入即可,不必重训
可审计能回答「这段话来自哪一文件哪一块」

不适合硬上 RAG 的情况:

  • 全文只有两三页,直接放进提示词更简单
  • 你要的是写作风格或领域技能,而不是查事实 → 考虑微调(见 Hugging Face 微调
  • 毫秒级延迟、且语料几乎不变 → 有时缓存或规则引擎更合适

RAG、微调、长上下文

手段擅长代价
长上下文单次任务、文档短Token 贵;知识不能跨会话复用
RAG大规模、常更新的事实库要维护切块、嵌入、索引、评估
微调格式、语气、任务技能数据与训练成本高;改事实要再训

三者可以组合:用 RAG 提供事实,用微调固定输出格式,用长上下文装「这一轮检索到的块」。本课只把 RAG 链路讲清楚。


本课立场:原则,不是某一个框架

同一条流水线可以出现在:

形态本站课程
Python 自己写(本课)切块函数 + 嵌入 API + Chroma / pgvector / Qdrant
框架封装LangChain RAGLlamaIndex
控制台Dify 知识库
本地嵌入Ollama Embeddings

学会原则之后,换框架只是换 Loader / Retriever 的类名;向量库选型(本地文件、跟 Postgres 走、独立服务)仍然是同一组问题。


核心词汇

含义
Chunk(块)检索的最小文本单位,通常几百到一千 token
Embedding(嵌入)把文本变成固定维浮点向量;语义近则向量近
Vector store存向量 + 原文 + 元数据,并做近邻搜索
Retrieve按问题向量(或关键词)取 top-k 块
Rerank对粗召回结果再打分,把真正相关的提前
GenerationLLM 阅读块后作答

索引(离线)和查询(在线)必须用同一个嵌入模型。换模型 = 整库重嵌。中文语料不要只看英文榜单,用你自己的 FAQ 测。


一条最小直觉

下面不用任何向量库,只说明「近邻」是什么。生产请用后面章节的 ANN 索引。

from numpy import dot
from numpy.linalg import norm

def cos(a, b) -> float:
    return float(dot(a, b) / (norm(a) * norm(b)))

docs = ["退款在到货 7 日内申请。", "客服在线时间 09:00–18:00。"]
# 假向量:真实系统里这里是 embedding API 的返回值
vecs = [[0.9, 0.1], [0.1, 0.9]]
q = [0.85, 0.2]
best = max(range(len(docs)), key=lambda i: cos(q, vecs[i]))
print(docs[best])

单位长度向量上,余弦与点积等价。嵌入模型(OpenAI 或 Ollama)通常已做归一化,以厂商文档为准。


下一步

  • 流水线 — 把上表连成一张图
  • 切块 — 块切坏了,后面全是噪声
  • Embeddings — 云端或本地,都不需要 GPU

评论