一文彻底搞懂 RAG — Retrieval‑Augmented Generation

一文彻底搞懂 RAG — Retrieval‑Augmented Generation

本文全面梳理了 RAG(Retrieval‑Augmented Generation) 的核心概念、技术细节与落地实践,适合作为 优快云 的科普/实战教程。阅读完毕后,读者将能够:

  1. 明确 RAG 的整体架构与关键模块;
  2. 基于 Elasticsearch 独立实现“向量检索 → 多路召回 → 重排序 → 生成问答”的端到端流程;
  3. 深入理解向量、相似度、知识图谱召回等技术原理,并掌握常见工程坑位及优化策略。

目录

  1. 何为 RAG?解决什么问题?

  2. RAG 总体流程拆解

  3. 第一层:多路召回(Recall)

    1. 关键词召回(BM25)
    2. 向量召回(语义检索)
    3. 知识图谱/规则召回
    4. Chunk 策略 与候选池合并
  4. 第二层:重排序(Re‑ranking)

  5. Elasticsearch 完整向量检索实战

    1. 索引映射与相似度模型
    2. 数据写入脚本
    3. knn 查询 vs script_score 查询
    4. 向量归一化与分数解释
  6. 深入理解向量相似度的数学原理

  7. 知识图谱召回:结构化语义“跳跃”

  8. 端到端 RAG Demo(Python 完整代码)

  9. 最佳实践与常见坑

  10. 结语与拓展阅读


1. 何为 RAG?解决什么问题?

Retrieval‑Augmented Generation 由 Meta AI 在 2020 年提出,旨在将检索和生成能力结合,以解决大语言模型在实时性、私有数据访问和长尾知识覆盖方面的不足。


2. RAG 总体流程拆解

  1. Query 预处理 → 分词、语言检测、实体识别。
  2. 多路召回 → 关键词、向量、知识图谱等并行召回,汇总候选池。
  3. 粗排(可选) → 简易向量或 BM25 分数过滤,保留 Top‑N(如 500)。
  4. 重排序 → Cross‑Encoder / Rank‑BERT 对 (query, doc) 对精排,输出最终 Top‑k(如 10)。
  5. Prompt 构造 → 将检索结果与用户问题拼接,送入 LLM。
  6. 生成答案 → LLM 基于外部知识生成响应。

3. 第一层:多路召回(Recall)

3.1 关键词召回(BM25)

基于倒排索引的精确匹配,适合短语义明确的查询,速度快、稳定。

3.2 向量召回(语义检索)

将文本切块 → Embedding → 存入 ES dense_vector 字段,使用 knn 查询找 Top‑K 最近邻。

Chunk 是否必要?
场景是否分块说明
长网页 / PDF✅ 必须512 token 限制,且匹配需更细粒度
FAQ / 标题❌ 可以不分文本短,可整体向量化

Chunk 示例(滑动窗口)

def split_to_chunks(text, max_len=150, stride=50):
    words = text.split()
    for i in range(0, len(words), stride):
        yield " ".join(words[i:i+max_len])

3.3 知识图谱/规则召回

通过实体→关系→实体多跳路径补全召回,示例:(高血压)-[:治疗方式]->(降压药)

Cypher 查询示例 (Neo4j)
MATCH p=(q:Entity {name:"高血压"})-[:治疗方式|包含*1..2]-(m)
RETURN m.name LIMIT 50;

3.4 候选池合并

多路结果 → 去重 → 打标签(来源、分数),形成统一候选池。


4. 第二层:重排序(Re‑ranking)

阶段模型优点缺点
首轮召回Bi‑Encoder 向量检索毫秒级误召、漏召
重排序Cross‑Encoder高精度计算慢,仅能处理 Top‑N

Cross‑Encoder 代码示例:

from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch

tokenizer = AutoTokenizer.from_pretrained("cross-encoder/ms-marco-MiniLM-L-6-v2")
model = AutoModelForSequenceClassification.from_pretrained(...)

def rerank(query, docs):
    scores = []
    for doc in docs:
        inputs = tokenizer(query, doc, truncation=True, return_tensors="pt")
        score = model(**inputs).logits.squeeze().item()
        scores.append(score)
    return [doc for doc,_ in sorted(zip(docs,scores), key=lambda x: x[1], reverse=True)]

5. Elasticsearch 向量检索实战

5.1 创建索引映射

PUT rag_chunks
{
  "mappings": {
    "properties": {
      "text": {"type": "text"},
      "vector": {
        "type": "dense_vector",
        "dims": 384,
        "index": true,
        "similarity": "cosine"
      }
    }
  }
}

5.2 数据写入脚本

import requests, json, uuid
from sentence_transformers import SentenceTransformer

model = SentenceTransformer('all-MiniLM-L6-v2')
text = "高血压是一种常见慢性病…"
for chunk in split_to_chunks(text):
    vec = model.encode(chunk, normalize_embeddings=True).tolist()
    doc = {"text": chunk, "vector": vec}
    requests.post("http://localhost:9200/rag_chunks/_doc/"+str(uuid.uuid4()), json=doc)

5.3 knn 查询 vs script_score

knn_query = {
  "knn": {
    "field": "vector",
    "query_vector": query_vec.tolist(),
    "k": 5,
    "num_candidates": 100
  }
}
  • knn:ES 8.x 内置 HNSW,适合大规模;
  • script_score:灵活,可自定义 cosineSimilarity(),适合小数据量或混合打分场景。

5.4 向量归一化与 _score 解释

  • similarity: "cosine"_score∈[-1,1]
  • l2_norm 时,ES 将距离转为 1/(1+distance)

6. 深入理解向量相似度

6.1 余弦相似度

sim ( A , B ) = A ⋅ B ∥ A ∥ ∥ B ∥ \text{sim}(A,B)=\frac{A·B}{\|A\|\|B\|} sim(A,B)=A∥∥BAB

6.2 欧氏距离

d ( A , B ) = ∑ ( a i − b i ) 2 d(A,B)=\sqrt{\sum(a_i-b_i)^2} d(A,B)=(aibi)2

6.3 点积

A ⋅ B = ∑ a i b i A·B=\sum a_ib_i AB=aibi

6.4 Python 实验对比

vec1, vec2 = embed_text("你好"), embed_text("您好")
print(np.dot(vec1, vec2))                    # cosine (已归一化)
print(1 - np.linalg.norm(vec1-vec2)/2)      # 归一化后欧氏距离转相似度

7. 知识图谱召回:结构化语义跳跃

  1. 实体识别 + 链接高血压 → entityID;
  2. 路径扩展:一到两跳获取关联实体;
  3. 反向检索文档:根据实体名称检索 chunk。

优点:补全召回、可解释;缺点:维护成本较高。


8. 端到端 RAG Demo(Python)

# 1. 生成查询向量
query = input("用户问题 > ")
q_vec = model.encode(query, normalize_embeddings=True)

# 2. Elasticsearch KNN 检索
hits = es.search(index="rag_chunks", knn={"field":"vector","query_vector":q_vec.tolist(),"k":20,"num_candidates":200})
chunks = [h['_source']['text'] for h in hits['hits']['

### RAG模型概述 RAGRetrieval-Augmented Generation)是一种融合了检索增强机制的生成型语言模型,由Facebook AI研究院(FAIR)提出。这种架构通过结合传统的基于检索的方法和现代的语言生成技术来提升自然语言处理任务的效果[^3]。 ### 工作原理详解 #### 数据获取阶段 在数据准备过程中,RAG利用外部知识库作为补充资源。当接收到输入查询时,系统首先会在预先构建的知识图谱或其他形式的大规模语料库中执行信息检索操作,找到最有可能帮助完成当前对话或任务的相关片段。 #### 动态上下文集成 不同于静态预训练模式下的纯生成方式,在线检索到的具体实例会被即时融入到解码器端口处,使得每次预测都能依据最新获得的真实世界证据来进行调整优化。这一特性赋予了RAG更强的情境适应能力,尤其是在面对开放领域问答、多轮次交互式聊天等复杂场景下表现尤为突出。 #### 双重评分机制 为了确保最终输出的质量,RAG采用了两步走策略:先是从候选集中挑选出若干高质量的回答选项;再经过一轮细评估后决定最佳回复方案。具体来说就是分别计算每条建议得分——一方面考量它与原始请求之间的匹配度;另一方面也要顾及内部连贯性和逻辑一致性等因素。 ```python def rag_model_inference(query, knowledge_base): retrieved_docs = retrieve_relevant_documents(query, knowledge_base) generated_responses = [] for doc in retrieved_docs: response = generate_response_based_on_document(doc) generated_responses.append(response) best_response = select_best_response(generated_responses) return best_response ``` ### 应用案例分析 实际应用方面,《大模型RAG实战:RAG原理、应用与系统构建》一书中提供了丰富的实践指导和技术细节解析,涵盖了从理论基础到工程实现再到部署上线全流程的内容介绍。对于希望深入了解并掌握这项前沿技术的研究人员而言,这本书籍无疑是一个宝贵的学习资料来源[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值