前言

RAG 是 Retrieval-Augmented Generation 的缩写,直译就是检索增强生成。这个概念这些年很火,但它的基本想法并不复杂:不要让大模型只凭训练参数回答,而是在生成之前先去知识库里检索相关资料,再把资料一起交给模型。

很多企业内部问答、文档助手、代码库问答,本质上都是 RAG。因为这些知识经常更新,而且不一定出现在模型训练数据里。与其每次重新训练模型,不如维护一套可更新的外部知识库。

为什么需要 RAG

大模型擅长语言组织和模式归纳,但它不擅长保证知识一定最新、一定来自某个指定来源。RAG 把外部文档引入生成过程,可以缓解幻觉问题,也能让答案带上出处。

原始 RAG 论文把模型参数里的知识称为 parametric memory,把外部索引里的知识称为 non-parametric memory。这个区分很有用:模型负责理解和表达,知识库负责提供可更新、可追溯的信息。

基本流程

最常见的流程是四步:文档切分、向量化入库、问题检索、带上下文生成。文档切分不要太粗也不要太碎,太粗会把无关内容塞进上下文,太碎又容易丢失完整语义。

检索阶段通常先用向量相似度召回,再用关键词、rerank 或业务规则二次排序。最后把最相关的片段放进 prompt,让模型基于这些片段回答。

开发时容易踩的坑

第一个坑是只关注 embedding 模型,忽略了文档清洗。脏数据、重复段落、标题丢失,会让检索结果很飘。第二个坑是 chunk 设计过于随意,导致召回片段缺上下文。第三个坑是 prompt 没约束好,模型拿不到资料时仍然硬答。

我一般会在 prompt 里明确写:如果资料中没有答案,就回答不知道,并说明缺少什么资料。同时把引用片段 ID 保留下来,方便前端展示出处,也方便调试检索质量。

切片不是随便切

很多 RAG 系统一开始效果差,问题不一定在 embedding 模型,而在文档切片。比如 Markdown 标题丢了,只留下正文,检索结果就会缺少上下文;又比如按固定字数硬切,把一个完整步骤拆成两半,模型拿到的片段自然答不完整。

更稳的做法是保留层级标题,把标题、来源、更新时间一起放进 metadata。技术文档可以按标题、段落和代码块切;制度文档可以按条款切;FAQ 可以一问一答作为最小单元。

{
  "id": "blog-rag-001",
  "title": "AI开发-RAG:让模型回答时先查资料",
  "section": "开发时容易踩的坑",
  "content": "第一个坑是只关注 embedding 模型,忽略了文档清洗...",
  "metadata": {
    "source": "blog",
    "url": "/2026/06/20/AI开发-RAG/",
    "updated_at": "2026-06-20"
  }
}

metadata 不只是附属信息,它会参与过滤和展示。比如用户只想查博客,就用 source 过滤;前端展示答案出处,就用 title 和 url;评估召回质量,也可以根据 section 判断命中的片段是否正确。

一个最小 RAG 示例

下面用 Python 写一个最小流程,省略具体 embedding 服务,只展示工程结构。真正上线时,可以把向量库换成 Milvus、pgvector、Qdrant、Elasticsearch 或云服务。

def retrieve(question, top_k=4):
    query_vector = embed(question)
    return vector_store.search(query_vector, top_k=top_k)

def build_prompt(question, chunks):
    context = "\n\n".join(
        f"[{c['id']}] {c['text']}" for c in chunks
    )
    return f"""你只能根据下面资料回答问题。
如果资料里没有答案,请直接说不知道,并说明缺少什么资料。

资料:
{context}

问题:{question}
回答时请标注引用片段 ID。
"""

def answer(question):
    chunks = retrieve(question)
    prompt = build_prompt(question, chunks)
    return llm.generate(prompt)

这个版本很朴素,但它把关键点放进去了:先检索,再拼上下文,再约束模型必须基于资料回答。很多问题不是靠复杂框架解决的,而是靠这些基础约束一点点收紧。

怎么评估 RAG 好不好

我会把 RAG 评估拆成两层:检索层和生成层。检索层看 top_k 里有没有命中正确片段,常用指标有 recall@k、MRR、nDCG;生成层看答案是否准确、是否忠实于资料、引用是否正确。

cases:
  - question: "报销单最晚什么时候提交?"
    gold_chunks: ["policy-2026-03"]
    expected_keywords: ["7天", "出差结束"]
  - question: "博客 Gitalk 初始化脚本做了什么?"
    gold_chunks: ["blog-gitalk-init"]
    expected_keywords: ["自动初始化", "issue"]

最开始不一定要搭复杂平台,先做几十个手工样本就很有用。改切片、换 embedding、调 rerank 时都跑一遍,系统变好还是变差就不会只靠感觉。

小结

RAG 不是万能补丁,它更像一个工程化套路:把可变知识交给外部检索,把语言生成交给模型。一个好用的 RAG 系统,核心不是“接上向量数据库”这么简单,而是资料质量、召回质量、上下文组织和答案约束共同作用。

参考资料:Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks