跳至内容
RAG 检索增强生成

RAG 检索增强生成

模型不知道你公司的内部文档,也记不住昨天刚更新的数据。RAG(Retrieval-Augmented Generation,检索增强生成)就是解决这个问题的主流方案:先检索相关资料,再让模型基于资料作答。这篇讲清楚它的原理、流程和落地要点。

为什么需要 RAG

直接问大模型私有或最新知识,会遇到两个问题:

  • 不知道:训练语料里没有你的内部资料。
  • 会瞎编:不知道又被追问时,模型容易「一本正经地胡说」(幻觉)。

RAG 的思路很朴素:把答案的依据先找出来,塞进提示词,再让模型照着资料回答,并要求它只依据给定资料。这样既补上了知识,又能附带引用、降低幻觉。

相比微调(fine-tuning),RAG 的资料可以随时更新、成本低、可溯源,是「让模型用上自有知识」的首选;微调更适合改变模型的风格或能力,而非灌输事实。

整体流程

RAG 分成离线的「建库」和在线的「问答」两段:

建库(离线):
  文档 ──切块──► chunks ──向量化──► embeddings ──存入──► 向量数据库

问答(在线):
  用户问题 ──向量化──► 在向量库里检索最相似的 chunks
          └──► 把 chunks + 问题拼成提示词 ──► 大模型生成带依据的回答

核心是用向量表示语义:把文本通过 embedding 模型转成一串数字(向量),语义相近的文本向量距离也近。检索时算「问题向量」和「文档向量」的相似度,取最近的几条。

关键步骤拆解

1. 切块(Chunking)

整篇文档太大,要切成小块再向量化。切块质量直接影响检索效果:

  • 块太大:噪声多、容易超出上下文、检索不精准。
  • 块太小:语义被切碎、丢失上下文。
  • 经验值:每块几百 token,块之间留一点重叠(overlap),避免把一句话从中间切断。
  • 尽量按语义边界切(段落、标题、章节),别机械按固定字数。

2. 向量化与存储

用 embedding 模型把每个 chunk 转成向量,连同原文一起存进向量数据库(如 pgvector、Milvus、Qdrant 等),由它负责高效的相似度检索。

3. 检索与拼接提示词

把用户问题也向量化,检索出 Top-K 个最相关的 chunk,拼进提示词。下面用伪代码表示这一步,再调用 Claude 生成:

from anthropic import Anthropic

client = Anthropic()

def answer(question: str) -> str:
    # 1) 检索:从向量库取回最相关的若干片段(此处为示意)
    chunks = vector_store.search(embed(question), top_k=4)
    context = "\n\n---\n\n".join(c.text for c in chunks)

    # 2) 把资料作为依据拼进提示词,并约束「只依据资料作答」
    system = (
        "你是企业知识库助手。只依据 <资料> 中的内容回答;"
        "资料里没有的,就明确说「资料中未提及」,不要编造。"
    )
    user = f"<资料>\n{context}\n</资料>\n\n问题:{question}"

    resp = client.messages.create(
        model="claude-opus-4-8",
        max_tokens=1024,
        system=system,
        messages=[{"role": "user", "content": user}],
    )
    return resp.content[0].text
务必在 system 里强约束「只依据资料作答、缺失就说没有」,这是 RAG 降低幻觉、获得可信回答的关键一句。

落地时的常见坑

  • 检索不到 = 答不对:效果差先别怪模型,多半是切块或检索环节没召回正确资料。先单独评估「检索命中率」。
  • 重排序(Rerank):向量检索召回后,再用一个更精细的 rerank 模型对 Top-K 排序,能明显提升相关性。
  • 评估要分两层:分别评「检索质量」(有没有找到对的资料)和「生成质量」(基于资料答得对不对),别混在一起看。
  • 附上引用:让模型标注每条结论来自哪个片段,方便用户核对,也利于排查。

一句话小结

RAG = 先检索、再生成。它让模型用上你的私有与实时知识,且可溯源、易更新。做好它的关键不在调模型,而在切块、检索与「只依据资料作答」这条硬约束

最后更新于