RAG

举报
yd_292659020 发表于 2026/11/03 00:06:48 2026/11/03
【摘要】 RAG 实战指南:让大语言模型不再"幻觉"一篇文章讲透 RAG 的核心原理、架构设计、工程实践与常见踩坑点。 1. 为什么需要 RAG?大语言模型(LLM)很强,但它有三个与生俱来的短板:短板表现后果知识截止训练数据有截止日期,之后的事不知道问"2026年的新政策"会答不上来幻觉不确定时倾向于"编"一个看起来合理的答案误导用户,尤其在专业领域不可溯源输出是概率生成的,无法追踪依据合规审计、...

RAG 实战指南:让大语言模型不再"幻觉"

一篇文章讲透 RAG 的核心原理、架构设计、工程实践与常见踩坑点。

1. 为什么需要 RAG?

大语言模型(LLM)很强,但它有三个与生俱来的短板:

短板 表现 后果
知识截止 训练数据有截止日期,之后的事不知道 问"2026年的新政策"会答不上来
幻觉 不确定时倾向于"编"一个看起来合理的答案 误导用户,尤其在专业领域
不可溯源 输出是概率生成的,无法追踪依据 合规审计、医疗法律场景不可用

RAG(Retrieval-Augmented Generation,检索增强生成)的思路很朴素:先查资料,再回答。把外部知识库当作"开卷考试"的参考书,让模型基于检索到的真实文档来生成答案,而不是纯靠记忆。

一句话总结:

RAG = 检索(找相关文档) + 生成(基于文档回答)

2. RAG 的标准架构

一个完整的 RAG 系统分为两个阶段:

2.1 离线阶段(Indexing / 建库)

原始文档 → 分块(Chunking) → 向量化(Embedding) → 存入向量数据库

分块(Chunking) 是把长文档切成适合检索的小片段。切太大,检索精度低;切太小,上下文丢失。常见策略:

  • 固定长度切分:按 token 数切(如 512 tokens),简单粗暴
  • 语义切分:按段落、标题、句子边界切,保留语义完整性
  • 滑动窗口:块之间有 overlap(如 50 tokens),避免切断关键信息

向量化(Embedding) 是把文本转成高维浮点向量,语义相近的文本在向量空间中距离也近。常用模型:

  • OpenAI text-embedding-3-small / text-embedding-3-large
  • 开源:bge-large-zh、m3e-base、GTE
  • 华为云:盘古嵌入模型

向量数据库 负责存储和高效检索。主流选择:

数据库 特点 适用场景
Milvus 分布式、高性能 大规模生产
Qdrant Rust 编写、轻量 中小项目
Chroma Python 原生、易用 原型开发
pgvector PostgreSQL 扩展 已有 PG 基础
FAISS Facebook 出品、纯索引 本地实验

2.2 在线阶段(Query / 检索生成)

用户提问 → 向量化 → 向量检索 Top-K → 拼接 Prompt → LLM 生成 → 返回答案

用一段伪代码表示核心流程:

def rag_answer(question: str, vector_db, llm, top_k=5) -> str:
    # 1. 把问题转成向量
    query_vector = embed(question)

    # 2. 在向量库中检索最相关的 K 个文档片段
    retrieved_docs = vector_db.search(query_vector, top_k=top_k)

    # 3. 拼接成 Prompt
    context = "\n\n".join([doc.text for doc in retrieved_docs])
    prompt = f"""请根据以下参考资料回答问题。如果资料中没有答案,请说"我不知道"。

参考资料:
{context}

问题:{question}
"""

    # 4. 调用 LLM 生成答案
    answer = llm.generate(prompt)

    # 5. 返回答案 + 引用来源
    return {
        "answer": answer,
        "sources": [doc.metadata for doc in retrieved_docs]
    }

3. 进阶:从朴素 RAG 到高级 RAG

朴素 RAG(Naive RAG)能跑通,但效果往往不够好。以下是三个维度的优化方向:

3.1 检索前优化(Pre-Retrieval)

问题:用户的原始提问可能表述不清、太短或太宽泛。

查询改写(Query Rewriting):用 LLM 把口语化的问题改写成更适合检索的形式。

原始问题:"那个报错怎么解决"
改写后   :"Python ConnectionRefusedError 连接被拒绝的解决方法"

查询扩展(Query Expansion):生成多个语义等价的查询,分别检索后合并结果。

HyDE(Hypothetical Document Embeddings):先让 LLM 生成一个"假设性答案",用这个答案的向量去检索——因为答案和文档的语义分布比问题和文档更接近。

3.2 检索优化(Retrieval)

问题:纯向量检索(ANN)有时会召回语义相近但内容无关的片段。

混合检索(Hybrid Search):向量检索(语义) + BM25 关键词检索(精确),加权融合:

def hybrid_search(query, vector_db, keyword_index, alpha=0.5):
    vec_results = vector_db.search(embed(query), top_k=10)
    bm25_results = keyword_index.search(query, top_k=10)

    # Reciprocal Rank Fusion 融合排序
    fused = rrf(vec_results, bm25_results)
    return fused[:5]

重排序(Re-ranking):召回一批候选(如 20 个),用更精细的模型重排,取 Top-5。常用重排模型:bge-reranker-large、Cohere Rerank。

3.3 检索后优化(Post-Retrieval)

问题:检索到的片段可能信息冗余或矛盾。

上下文压缩:用 LLM 对检索结果做摘要/去重,减少输入 token。

上下文过滤:用一个小模型判断每个片段是否与问题相关,丢弃不相关的。

整体演进路线

Naive RAG → Search RAG → Advanced RAG → Modular RAG
 (基础)     (混合检索)    (全链路优化)    (模块化编排)

4. 工程实践:一个可落地的 RAG 项目结构

rag-project/
├── config/
│   └── settings.yaml          # 模型、向量库、chunk 参数配置
├── data/
│   └── raw/                   # 原始文档(PDF、Markdown、HTML)
├── src/
│   ├── indexing/
│   │   ├── loader.py          # 文档加载
│   │   ├── chunker.py         # 分块策略
│   │   ├── embedder.py        # 向量化
│   │   └── indexer.py         # 写入向量库
│   ├── retrieval/
│   │   ├── vector_search.py   # 向量检索
│   │   ├── keyword_search.py  # 关键词检索
│   │   ├── reranker.py        # 重排序
│   │   └── fusion.py          # 结果融合
│   ├── generation/
│   │   ├── prompt_builder.py  # Prompt 模板
│   │   └── llm_client.py      # LLM 调用
│   └── pipeline.py            # 主流程编排
├── eval/
│   └── metrics.py             # 评估指标
└── requirements.txt

关键配置示例

# config/settings.yaml
embedding:
  model: "bge-large-zh-v1.5"
  dimension: 1024
  batch_size: 32

chunking:
  strategy: "semantic"        # fixed | semantic | sliding
  chunk_size: 512
  overlap: 50

retrieval:
  top_k: 20                   # 召回数量
  rerank_top_k: 5             # 重排后保留
  hybrid_search: true
  vector_weight: 0.7
  keyword_weight: 0.3

vector_db:
  type: "milvus"
  host: "localhost"
  port: 19530
  collection: "knowledge_base"

llm:
  model: "gpt-4o"
  temperature: 0.1            # 低温度,减少发散
  max_tokens: 2048

5. 评估:怎么知道 RAG 效果好不好?

RAG 的评估分两个维度:

5.1 检索质量

指标 含义
Hit Rate Top-K 结果中是否包含正确文档(0 或 1)
MRR(Mean Reciprocal Rank) 正确文档的排名倒数,越接近 1 越好
Recall@K Top-K 召回的 relevant 文档占全部 relevant 的比例

5.2 生成质量

指标 含义
Faithfulness 答案是否忠于检索到的文档(不编造)
Answer Relevance 答案是否切题
Context Relevance 检索到的上下文是否与问题相关

推荐使用 RAGAS 框架(开源),它用 LLM-as-Judge 的方式自动评估以上指标:

from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_relevancy

result = evaluate(
    dataset=test_dataset,
    metrics=[faithfulness, answer_relevancy, context_relevancy]
)
print(result)
# {'faithfulness': 0.87, 'answer_relevancy': 0.92, 'context_relevancy': 0.78}

6. 常见踩坑清单

以下是实际项目中高频出现的问题和解决方案:

坑 1:分块切断了关键信息

现象:检索到了文档片段,但答案被切到两半,LLM 无法回答。

解决:

  • 使用语义分块而非固定长度
  • 设置 overlap(重叠 10%~20%)
  • 对结构化文档(如表格、代码)按结构边界切分

坑 2:向量检索召回不相关内容

现象:Top-5 里有 3 个不相关,稀释了有效信息。

解决:

  • 加重排序模型(Re-ranker)
  • 降低 top_k 召回数,宁少勿滥
  • 用元数据过滤(如先按文档类型、时间范围筛选,再向量检索)

坑 3:Prompt 过长导致 LLM “迷失在中间”

现象:研究表明,LLM 对 Prompt 中间部分的信息利用率低于首尾。

解决:

  • 控制上下文长度(如不超过 4000 tokens)
  • 把最相关的片段放在 Prompt 首尾
  • 用上下文压缩减少冗余

坑 4:多轮对话中上下文丢失

现象:用户第二轮问"那它的价格呢",但 RAG 只检索了"价格"这个词,丢失了第一轮的主体。

解决:用 LLM 做对话历史压缩,把多轮对话改写成一个独立的检索查询:

def rewrite_with_history(question, chat_history):
    prompt = f"""根据对话历史,将用户最新问题改写为一个独立、完整的检索查询。

对话历史:{chat_history}
最新问题:{question}
改写后的查询:"""
    return llm.generate(prompt)

坑 5:知识库更新后向量不同步

现象:文档更新了,但向量库里还是旧内容。

解决:

  • 建立增量更新机制(文档 hash 变化时重新索引)
  • 设置文档的 updated_at 元数据,定期扫描变更
  • 考虑用 CDC(Change Data Capture)监听文档变更事件

7. RAG vs Fine-tuning:什么时候用哪个?

这是一个高频问题。简而言之:

维度 RAG Fine-tuning
知识更新 实时,改文档即可 需重新训练
成本 低(无需训练) 高(需要 GPU + 数据标注)
适合场景 事实性问答、知识库查询 风格学习、特定任务格式
可溯源性 有(可返回引用来源) 无
幻觉控制 好(有参考文档约束) 一般

实践中常组合使用:先 Fine-tune 让模型学会特定领域的话术和推理方式,再用 RAG 注入最新知识。

8. 未来趋势

RAG 技术仍在快速演进,几个值得关注的方向:

  1. GraphRAG:用知识图谱替代纯向量检索,支持多跳推理和全局摘要。微软已开源 GraphRAG 项目。

  2. Agentic RAG:让 Agent 自主决定是否检索、检索几次、如何组合信息。从"单次检索"走向"迭代式检索"。

  3. 多模态 RAG:不仅检索文本,还检索图片、表格、视频。文档中的图表信息不再丢失。

  4. 长上下文 vs RAG:随着 LLM 上下文窗口增长到百万 token(如 Gemini),有人质疑 RAG 是否还有必要。但实践表明:长上下文成本高、延迟大,RAG 在效率和成本上仍有优势——把 100 万 token 全塞进去不如精准检索 5000 token。

9. 总结

RAG 的核心价值在于:用检索约束生成,用外部知识弥补模型不足。

搭建一个好的 RAG 系统的关键不在于某个单点技术多先进,而在于整条链路的工程化:

文档质量 → 分块策略 → 嵌入模型 → 检索方法 → 重排序 → Prompt 设计 → LLM 选择 → 评估反馈

每一环差一点,最终效果就会差很多。建议从朴素 RAG 起步,用评估指标驱动迭代优化,逐步引入混合检索、重排序、查询改写等高级技术。


参考资源:


本文写于 2026 年 11 月,RAG 领域发展迅速,部分工具和模型版本可能已有更新。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。