什么是 RAG?
RAG(Retrieval-Augmented Generation,检索增强生成)是当前企业级 LLM 应用中最重要的技术架构。它通过将外部知识库与大语言模型结合,让 AI 能够基于最新、最准确的信息生成回答。
为什么需要 RAG?
LLM 的局限性
大语言模型虽然强大,但存在几个关键问题:
graph TB
A[LLM 的局限性] --> B[知识截止日期]
A --> C[幻觉问题]
A --> D[缺乏私有数据]
A --> E[无法溯源]
B --> B1[训练数据有截止时间
无法获取最新信息] C --> C1[可能生成看似合理
实际错误的内容] D --> D1[无法访问企业内部
文档和知识] E --> E1[无法说明答案来源
难以验证准确性] style A fill:#ffebee,stroke:#c62828,stroke-width:3px style B fill:#fff3e0,stroke:#e65100,stroke-width:2px style C fill:#fff3e0,stroke:#e65100,stroke-width:2px style D fill:#fff3e0,stroke:#e65100,stroke-width:2px style E fill:#fff3e0,stroke:#e65100,stroke-width:2px
无法获取最新信息] C --> C1[可能生成看似合理
实际错误的内容] D --> D1[无法访问企业内部
文档和知识] E --> E1[无法说明答案来源
难以验证准确性] style A fill:#ffebee,stroke:#c62828,stroke-width:3px style B fill:#fff3e0,stroke:#e65100,stroke-width:2px style C fill:#fff3e0,stroke:#e65100,stroke-width:2px style D fill:#fff3e0,stroke:#e65100,stroke-width:2px style E fill:#fff3e0,stroke:#e65100,stroke-width:2px
| 问题 | 说明 | 影响 |
|---|---|---|
| 知识截止 | 模型只知道训练时的数据 | 无法回答最新问题 |
| 幻觉 | 模型"编造"不存在的信息 | 输出不可信 |
| 无私有数据 | 不了解企业内部知识 | 无法处理业务问题 |
| 无法溯源 | 不知道答案从哪来 | 难以审计和验证 |
RAG 如何解决这些问题
RAG 的核心思想非常直观:先检索,再生成。
graph LR
A[用户提问] --> B[检索相关文档]
B --> C[将文档作为上下文]
C --> D[LLM 基于上下文生成]
D --> E[带引用的回答]
style A fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
style B fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
style C fill:#fff3e0,stroke:#f57c00,stroke-width:2px
style D fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
style E fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
RAG 的核心流程
一个完整的 RAG 系统包含两个主要阶段:索引阶段和查询阶段。
索引阶段(离线)
graph TB
subgraph 索引阶段
A[原始文档] --> B[文档加载]
B --> C[文本切分]
C --> D[向量化 Embedding]
D --> E[存入向量数据库]
end
A1[PDF] --> A
A2[Word] --> A
A3[Markdown] --> A
A4[网页] --> A
style A fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
style E fill:#c8e6c9,stroke:#388e3c,stroke-width:3px
查询阶段(在线)
graph TB
subgraph 查询阶段
Q[用户问题] --> Q1[问题向量化]
Q1 --> Q2[向量检索]
Q2 --> Q3[获取相关文档]
Q3 --> Q4[构建 Prompt]
Q4 --> Q5[LLM 生成回答]
Q5 --> Q6[返回答案+引用]
end
DB[(向量数据库)] --> Q2
style Q fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
style Q6 fill:#c8e6c9,stroke:#388e3c,stroke-width:3px
style DB fill:#fff3e0,stroke:#f57c00,stroke-width:2px
代码示例:最简 RAG 系统
下面用 Python 实现一个最简单的 RAG 系统,帮助你理解核心流程:
"""
最简 RAG 系统示例
演示 RAG 的核心流程:索引 → 检索 → 生成
"""
from openai import OpenAI
client = OpenAI()
# ============================================
# 第一步:准备知识库(模拟文档)
# ============================================
documents = [
{
"id": 1,
"title": "公司年假政策",
"content": "员工入职满1年可享受5天年假,满3年享受10天,满5年享受15天。年假需提前3天申请。"
},
{
"id": 2,
"title": "报销流程",
"content": "员工报销需在费用发生后30天内提交,金额500元以下主管审批,500元以上需部门经理审批。"
},
{
"id": 3,
"title": "远程办公政策",
"content": "员工每周可申请2天远程办公,需提前1天在系统中申请,主管审批后生效。"
},
]
# ============================================
# 第二步:创建向量索引
# ============================================
def get_embedding(text: str) -> list[float]:
"""获取文本的向量表示"""
response = client.embeddings.create(
model="text-embedding-3-small",
input=text
)
return response.data[0].embedding
def cosine_similarity(a: list[float], b: list[float]) -> float:
"""计算余弦相似度"""
dot_product = sum(x * y for x, y in zip(a, b))
norm_a = sum(x ** 2 for x in a) ** 0.5
norm_b = sum(x ** 2 for x in b) ** 0.5
return dot_product / (norm_a * norm_b)
# 为所有文档创建向量
print("正在创建文档向量...")
for doc in documents:
doc["embedding"] = get_embedding(doc["content"])
print(f"已为 {len(documents)} 篇文档创建向量索引")
# ============================================
# 第三步:检索相关文档
# ============================================
def retrieve(query: str, top_k: int = 2) -> list[dict]:
"""检索与查询最相关的文档"""
query_embedding = get_embedding(query)
# 计算相似度并排序
scored_docs = []
for doc in documents:
score = cosine_similarity(query_embedding, doc["embedding"])
scored_docs.append({"doc": doc, "score": score})
scored_docs.sort(key=lambda x: x["score"], reverse=True)
return scored_docs[:top_k]
# ============================================
# 第四步:生成回答
# ============================================
def generate_answer(query: str) -> str:
"""RAG 完整流程:检索 + 生成"""
# 检索相关文档
results = retrieve(query, top_k=2)
# 构建上下文
context = "\n\n".join([
f"【{r['doc']['title']}】\n{r['doc']['content']}"
for r in results
])
# 构建 Prompt
prompt = f"""请根据以下参考资料回答用户的问题。
如果参考资料中没有相关信息,请坦诚说明。
请在回答中标注信息来源。
## 参考资料
{context}
## 用户问题
{query}
## 回答"""
# 调用 LLM 生成
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}],
temperature=0.3
)
return response.choices[0].message.content
# ============================================
# 测试
# ============================================
question = "我工作两年了,能请几天年假?"
print(f"\n问题:{question}")
print(f"\n回答:{generate_answer(question)}")
输出示例:
问题:我工作两年了,能请几天年假?
回答:根据公司年假政策,员工入职满1年可享受5天年假。
您工作两年,已满1年但未满3年,因此您目前可以享受5天年假。
待您工作满3年后,年假将增加至10天。
请注意,年假需提前3天申请。
——来源:《公司年假政策》
RAG vs 其他方案
RAG vs 微调(Fine-tuning)
| 对比维度 | RAG | 微调 |
|---|---|---|
| 知识更新 | 实时更新,修改文档即可 | 需要重新训练 |
| 成本 | 低,只需向量数据库 | 高,需要 GPU 训练 |
| 可溯源 | 可以引用来源文档 | 无法追溯来源 |
| 适用场景 | 知识密集型问答 | 风格/格式学习 |
| 实施周期 | 天级别 | 周级别 |
| 幻觉控制 | 受限于检索结果,更可控 | 仍可能产生幻觉 |
RAG vs 长上下文(Long Context)
| 对比维度 | RAG | 长上下文 |
|---|---|---|
| 数据量 | 支持海量数据 | 受限于上下文窗口 |
| 成本 | 只传递相关片段 | 每次传递全部内容 |
| 精度 | 精确检索相关段落 | 可能"大海捞针" |
| 延迟 | 检索+生成 | 长文本处理较慢 |
| 适用场景 | 大规模知识库 | 少量文档精读 |
graph TB
A{你的需求是什么?} --> B{数据量大吗?}
A --> C{需要实时更新吗?}
A --> D{需要学习风格吗?}
B -->|大于100MB| E[选择 RAG]
B -->|小于100MB| F[可考虑长上下文]
C -->|是| E
C -->|否| G{预算充足吗?}
D -->|是| H[选择微调]
D -->|否| E
G -->|是| H
G -->|否| E
style E fill:#c8e6c9,stroke:#388e3c,stroke-width:3px
style H fill:#fff3e0,stroke:#f57c00,stroke-width:2px
style F fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
RAG 的应用场景
1. 企业知识库问答
最常见的应用,让员工通过自然语言查询公司内部文档。
2. 客服机器人
基于产品文档和 FAQ 自动回答客户问题。
3. 法律/合规检索
在海量法规文件中快速找到相关条款。
4. 技术文档助手
帮助开发者快速查找 API 文档和代码示例。
5. 医疗辅助
基于医学文献辅助诊断建议(需严格审核)。
本章小结
- RAG 通过"先检索,再生成"的方式解决 LLM 的知识局限
- RAG 系统包含索引阶段(离线)和查询阶段(在线)两个核心流程
- 相比微调和长上下文,RAG 在成本、可更新性、可溯源性方面具有优势
- RAG 是当前 85% 企业 LLM 应用的核心架构
下一章:我们将深入了解 RAG 的系统架构,学习如何设计一个生产级的 RAG 系统。