RAG 检索增强生成

RAG 是 Retrieval-Augmented Generation,中文常译为检索增强生成。普通大模型只靠自己参数里的知识回答;RAG 会先去外部知识库、文档、数据库、网页或企业资料里检索相关内容,再把检索到的内容交给大模型生成答案。

RAG 的好处是什么?

可以回答模型训练后才出现的新信息,可以减少胡编,回答更容易引用来源。

1 向量化模型

Embedding Model 又称语义向量模型,被广泛应用于搜索领域,其目的是将自然形式的数据转化为向量(即连续的数字序列),并用向量之间的距离衡量样本的相关性。

1.1 常见的模型

开源的 Embedding 模型可以通过 sentence-transformers 加载。

安装:

1
pip install sentence-transformers

sentence-transformers 常用模型

常见的有:

  • all-MiniLM-L6-v2
  • paraphrase-multilingual-MiniLM-L12-v2
  • multi-qa-MiniLM-L6-cos-v1

BGE 系列

常见的有:

  • BAAI/bge-small-zh-v1.5
  • BAAI/bge-base-zh-v1.5
  • BAAI/bge-large-zh-v1.5
  • BAAI/bge-small-en-v1.5
  • BAAI/bge-base-en-v1.5
  • BAAI/bge-large-en-v1.5
  • BAAI/bge-m3

E5 系列

  • intfloat/multilingual-e5-small
  • intfloat/multilingual-e5-base
  • intfloat/multilingual-e5-large
  • intfloat/e5-small-v2
  • intfloat/e5-base-v2
  • intfloat/e5-large-v2

openAI 的需要单独安装:

1
pip install openai

OpenAI Embeddings 系列

  • text-embedding-3-small
  • text-embedding-3-large

2 向量数据库

顾名思义,为了存储向量的数据库,著名的有 google 开源的 FAISS。

RAG 所做的内容其实就是从 FAISS 当中检索出相关的资料,再让大模型基于资料去回答。

3 RAG 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import os
import numpy as np
import faiss
from sentence_transformers import SentenceTransformer
from openai import OpenAI


# 1. 准备知识库
docs = [
"RAG 是 Retrieval-Augmented Generation,中文叫检索增强生成。",
"RAG 的核心流程是:先从知识库中检索相关资料,再让大模型基于资料生成答案。",
"Embedding 模型可以把文本转换成向量,语义相近的文本向量距离更近。",
"FAISS 是一个向量检索库,可以快速查找相似向量。",
"在 RAG 中,向量数据库用于保存文档片段的 embedding,并根据用户问题检索相关内容。",
"如果知识库中没有相关资料,RAG 系统应该告诉用户资料中没有答案,而不是编造。"
]

# 2. 加载 embedding 模型
embedding_model = SentenceTransformer("paraphrase-multilingual-MiniLM-L12-v2")

# 3. 把文档转成向量
doc_vectors = embedding_model.encode(docs)
doc_vectors = np.array(doc_vectors).astype("float32")

# 4. 建立 FAISS 索引
dimension = doc_vectors.shape[1]
index = faiss.IndexFlatL2(dimension)
index.add(doc_vectors)

def retrieve(question, top_k=3):
"""根据问题检索最相关的文档片段。"""
question_vector = embedding_model.encode([question])
question_vector = np.array(question_vector).astype("float32")

distances, ids = index.search(question_vector, top_k)

retrieved = []
for doc_id in ids[0]:
retrieved.append(docs[doc_id])

return retrieved

def build_prompt(question, retrieved_docs):
"""把检索结果和用户问题组合成 prompt。"""
context = "\n".join(f"- {doc}" for doc in retrieved_docs)

prompt = f"""
你是一个 RAG 问答助手。

请只根据下面的资料回答问题。
如果资料中没有答案,请回答:资料中没有相关信息。
不要编造资料之外的内容。

资料:
{context}

问题:
{question}
"""

return prompt

def ask_openai(prompt):
"""把 prompt 发给 OpenAI,让大模型生成最终答案。"""
client = OpenAI()

response = client.responses.create(
model=os.getenv("OPENAI_MODEL", "gpt-4.1-mini"),
input=prompt
)

return response.output_text

def main():
question = "RAG 为什么需要向量数据库?"

print("用户问题:")
print(question)

print("\n第一步:检索相关资料")
retrieved_docs = retrieve(question, top_k=3)

for doc in retrieved_docs:
print("-", doc)

print("\n第二步:构造 prompt")
prompt = build_prompt(question, retrieved_docs)
print(prompt)

print("\n第三步:发送给 OpenAI 生成最终回答")
answer = ask_openai(prompt)

print("\n最终回答:")
print(answer)

if __name__ == "__main__":
main()