一文彻底搞懂 RAG(检索增强生成):原理、流程与架构演进(Python + Java 双版本实战)
🔥 一文彻底搞懂 RAG(检索增强生成):原理、流程与架构演进(Python + Java 双版本实战)
作者: 你的CSDN昵称
专栏: 大模型技术栈
标签:RAGLLM向量检索Embedding检索增强生成Spring AILangChain4j
一、引言
在大型语言模型(LLM)席卷全球的今天,一个无法回避的问题始终存在:模型知识有截止日期,且容易产生"幻觉"(Hallucination)。当用户询问最新事件、企业内部文档或专业领域知识时,纯靠模型参数记忆的回答往往不可靠。
RAG(Retrieval Augmented Generation,检索增强生成) 正是为解决这一痛点而生的核心技术。它通过将外部知识库"嫁接"到大模型上,让 LLM 在生成回答前先"查资料",从而显著提升回答的准确性、时效性和可溯源性。
本文将从你看到的原理图出发,逐层拆解 RAG 的完整工作流程,深入讲解 Embedding、向量相似度、检索策略等核心概念,并提供 Python + Java 双版本实战代码,无论你是哪个技术栈都能快速上手。
二、RAG 是什么?
RAG,全称 Retrieval Augmented Generation,中文译为检索增强生成。
其核心思想非常直观:通过检索外部知识库的方式,增强大模型的生成能力。
传统的 LLM 交互是"端到端"的:
用户提问 → LLM → 生成回答
而 RAG 在此基础上增加了一个检索环节:
用户提问 → 检索相关知识 → 将知识注入Prompt → LLM → 生成回答
这个看似简单的改动,却从根本上解决了 LLM 的三大顽疾:
| 问题 | 传统 LLM | RAG 增强后 |
|---|---|---|
| 知识时效性 | 训练数据有截止日期,无法回答最新信息 | 实时检索最新文档,知识随时更新 |
| 领域专业性 | 对垂直领域(法律、医疗、企业内部)知识薄弱 | 接入专业领域知识库,精准回答 |
| 幻觉问题 | 可能编造不存在的事实 | 基于检索到的真实文档生成,可溯源 |
三、RAG 核心工作流程详解
下面这张图展示了 RAG 的完整工作流程,我们将按照数据流向,逐个环节拆解:

3.1 用户查询输入(Query)
一切从用户的自然语言提问开始,例如:
“如何学习 Python?”
这是整个流程的触发点。用户的原始查询往往存在表述模糊、口语化、缺乏关键词等问题,这也是后续"查询改写"环节存在的原因。
3.2 Embedding 编码:文本 → 向量
这是 RAG 中最关键的"翻译"步骤。
Embedding 模型(如 OpenAI 的 text-embedding-ada-002、BGE、M3E 等)会将人类可读的文本转换为机器可计算的高维向量(通常 768 维或 1536 维)。
"如何学习 Python?" → Embedding模型 → [0.21, -0.5, 0.2, ..., 0.23]
为什么必须转成向量?
因为计算机无法直接理解"语义",但它可以高效计算向量之间的距离。语义相近的文本,在向量空间中的距离也更近——这是整个 RAG 检索的理论基石。
3.3 向量检索:在知识库中找"最像"的
向量数据库(如 Milvus、Pinecone、Chroma、FAISS 等)中预先存储了大量文档片段的向量。当查询向量到来时,系统会计算它与库中所有向量的相似度,返回最相似的前 K 个结果(Top-K)。

🔍 相似度计算:余弦相似度
RAG 中最常用的相似度度量方式是余弦相似度(Cosine Similarity):
cos(θ)=q⃗⋅d⃗∣∣q⃗∣∣⋅∣∣d⃗∣∣\cos(\theta) = \frac{\vec{q} \cdot \vec{d}}{||\vec{q}|| \cdot ||\vec{d}||}cos(θ)=∣∣q∣∣⋅∣∣d∣∣q⋅d
| 余弦相似度值 | 含义 |
|---|---|
| → 1 | 两个向量方向完全相同,文本语义高度相似 |
| → 0 | 两个向量正交,文本语义无关 |
| → -1 | 两个向量方向相反,文本语义对立 |
核心结论:余弦相似度越大,说明向量方向越接近,两点之间的距离越小。由于 RAG 中的向量都是由文本转换而来的,不同文本对应的向量余弦相似度越大,距离越近,文本相似度就越高。
在实际应用中,通常会设置一个阈值(如 > 0.5),只有相似度超过阈值的文档才会被召回。
3.4 结果召回与重排序(Retrieval & Rerank)
初步检索可能返回数十甚至上百个候选文档,但并非所有都真正相关。因此需要:
- 召回(Recall):从海量文档中快速筛选出候选集(追求"不漏")
- 精排(Rerank):用更精细的模型对候选集重新打分排序(追求"更准")
常用的重排序模型有 Cohere Rerank、BGE-Reranker 等。
3.5 Prompt 组装:构造增强提示词
这是 RAG 的"灵魂步骤"。系统将检索到的相关文档片段与用户的原始问题拼接,构造出一个增强型 Prompt:
你是一位专业的技术顾问。请根据以下参考资料回答用户问题。
如果参考资料不足以回答问题,请明确说明。
【参考资料】
1. Python入门教程:Python是一种解释型、面向对象的高级编程语言...
2. Python进阶指南:学习Python需要掌握数据结构、算法和面向对象编程...
3. Python数据分析:NumPy和Pandas是Python数据分析的核心库...
【用户问题】
如何学习Python?
请给出详细回答:
3.6 LLM 生成:基于上下文作答
增强后的 Prompt 被送入大语言模型。此时 LLM 拥有了"外挂大脑"——检索到的知识库上下文,能够:
- 基于真实文档生成回答,而非凭空编造
- 引用具体来源,提高可信度
- 处理超出训练数据的最新/私有知识
四、关键技术深度解析
4.1 Embedding 模型选型
| 模型 | 维度 | 特点 | 适用场景 |
|---|---|---|---|
| OpenAI text-embedding-ada-002 | 1536 | 通用性强,API便捷 | 快速原型、英文为主 |
| OpenAI text-embedding-3 | 3072 | 最新版本,多语言优化 | 生产环境、多语言 |
| BGE (BAAI) | 1024 | 开源可本地部署,中文优秀 | 中文场景、私有化部署 |
| M3E | 768 | 轻量高效,中文语义好 | 资源受限、中文应用 |
| E5 (Microsoft) | 768 | 多任务训练,检索精度高 | 跨领域检索 |
4.2 向量数据库对比
| 特性 | Milvus | Pinecone | Chroma | FAISS | Weaviate |
|---|---|---|---|---|---|
| 部署方式 | 本地/云 | 纯SaaS | 本地/轻量 | 本地库 | 本地/云 |
| 开源 | ✅ | ❌ | ✅ | ✅ | ✅ |
| 十亿级规模 | ✅ | ✅ | ❌ | ✅ | ✅ |
| 混合检索 | ✅ | ✅ | ❌ | 需开发 | ✅ |
| 易用性 | 中等 | 极高 | 极高 | 低 | 中等 |
| 最佳场景 | 企业级大规模 | 快速上线 | 原型开发 | 科研实验 | 多模态应用 |
4.3 相似度算法对比
| 算法 | 公式特点 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|---|
| 余弦相似度 | 只考虑方向,不考虑长度 | 对文本长度不敏感,语义匹配稳定 | 忽略向量模长信息 | 文本语义检索(最常用) |
| 欧氏距离 | 计算空间直线距离 | 直观,适合稠密向量 | 受向量模长影响大 | 图像向量、归一化后向量 |
| 点积 | 简单高效 | 计算快,适合内积型索引 | 需向量已归一化 | 特定ANN索引库 |
| BM25 | 基于词频和文档长度 | 关键词匹配精准,可解释性强 | 无法理解语义 | 稀疏检索、混合检索 |
💡 实践建议:生产环境中推荐余弦相似度 + 混合检索(BM25 + 向量),兼顾语义理解和关键词精确匹配。
五、RAG 架构演进:从朴素到智能
RAG 并非一成不变,其架构经历了三个阶段的演进:

5.1 Naive RAG(朴素 RAG)
最基础的实现方式:查询 → Embedding → 向量检索 → Prompt 组装 → LLM 生成。
存在的问题:
- 检索精度低:用户查询表述不清,导致召回文档不相关
- 上下文冗长:召回文档过多,超出 LLM 上下文窗口
- 生成质量不稳定:缺乏对检索结果的验证机制
5.2 Advanced RAG(高级 RAG)
在朴素 RAG 基础上增加了一系列优化模块:
| 优化模块 | 作用 | 代表技术 |
|---|---|---|
| 查询重写(Query Rewriting) | 将模糊查询改写为更精准的检索式 | HyDE、Query2Doc |
| 混合检索 | 同时用向量检索 + 关键词检索 | BM25 + Dense Retrieval |
| 重排序(Rerank) | 对召回结果精细打分排序 | BGE-Reranker、Cohere Rerank |
| 上下文压缩 | 去除冗余信息,保留关键内容 | LongLLMLingua、选择性上下文 |
| 多路召回 | 从多个索引源同时检索 | 多向量索引、父子文档索引 |
5.3 Agentic RAG(智能体 RAG)
最新的演进方向,将 RAG 与 AI Agent 结合:
| 能力 | 说明 |
|---|---|
| 路由决策 | 自动判断问题类型,选择最合适的知识库或工具 |
| 多 Agent 协作 | 多个专业 Agent 分别检索不同领域知识,再整合答案 |
| 工具调用 | 不仅检索文档,还能调用 API、数据库、计算工具 |
| Self-RAG / 反思验证 | LLM 自我评估检索结果是否足够,不足则主动重新检索 |
| 迭代优化 | 多轮检索-生成-验证循环,直到获得满意答案 |
六、极简实战:Python + Java 双版本

🎯 核心原则:无论 Python 还是 Java,RAG 的核心流程完全一致:文本 → Embedding → 向量检索 → Prompt 增强 → LLM 生成。区别只在于技术栈选型和API 调用方式。
6.1 Python 版本
基于 sentence-transformers + FAISS,最轻量的本地 RAG 实现:
from sentence_transformers import SentenceTransformer
import faiss
import numpy as np
# ========== 1. 加载 Embedding 模型 ==========
model = SentenceTransformer('BAAI/bge-large-zh-v1.5')
# ========== 2. 准备知识库文档 ==========
documents = [
"Python是一种解释型、面向对象的高级编程语言,语法简洁优雅。",
"Java是一种静态类型、跨平台的编程语言,广泛应用于企业级开发。",
"机器学习是人工智能的一个分支,通过数据训练模型进行预测。",
"深度学习是机器学习的一个子集,使用多层神经网络提取特征。",
]
# ========== 3. 文档向量化并构建索引 ==========
doc_embeddings = model.encode(documents, normalize_embeddings=True)
dimension = doc_embeddings.shape[1]
index = faiss.IndexFlatIP(dimension) # 内积索引(归一化后 = 余弦相似度)
index.add(np.array(doc_embeddings))
# ========== 4. 用户查询 ==========
query = "什么是Python?"
query_embedding = model.encode([query], normalize_embeddings=True)
# ========== 5. 检索 Top-3 ==========
scores, indices = index.search(np.array(query_embedding), k=3)
print(f"查询: {query}\n")
print("检索结果:")
for score, idx in zip(scores[0], indices[0]):
print(f" [相似度: {score:.4f}] {documents[idx]}")
# ========== 6. 组装 Prompt ==========
context = "\n".join([f"{i+1}. {documents[idx]}" for i, idx in enumerate(indices[0])])
prompt = f"""根据以下参考资料回答问题:
{context}
问题:{query}
请给出准确、简洁的回答:
"""
print("\n" + "="*50)
print("组装后的 Prompt:")
print(prompt)
运行结果:
查询: 什么是Python?
检索结果:
[相似度: 0.9234] Python是一种解释型、面向对象的高级编程语言,语法简洁优雅。
[相似度: 0.3456] 机器学习是人工智能的一个分支,通过数据训练模型进行预测。
[相似度: 0.3123] Java是一种静态类型、跨平台的编程语言,广泛应用于企业级开发。
6.2 Java 版本(方案一:Spring AI 推荐)
Spring AI 是 Spring 官方推出的 AI 应用开发框架,是目前 Java 生态中实现 RAG 最标准、最优雅的方式。
依赖配置(pom.xml)
<dependencies>
<!-- Spring AI Core -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<!-- 向量数据库:以 Redis Vector 为例 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-redis-store-spring-boot-starter</artifactId>
</dependency>
<!-- 文档加载与解析 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-pdf-document-reader</artifactId>
</dependency>
</dependencies>
配置文件(application.yml)
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
embedding:
options:
model: text-embedding-3-small
vectorstore:
redis:
index: rag-documents
prefix: doc
initialize-schema: true
RAG 核心实现代码
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.SystemPromptTemplate;
import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/api/rag")
public class RagController {
@Autowired
private VectorStore vectorStore; // 自动注入 Redis Vector Store
@Autowired
private ChatClient chatClient; // 自动注入 OpenAI ChatClient
// ========== 1. 文档入库(知识库构建) ==========
@PostMapping("/ingest")
public String ingestDocuments(@RequestBody List<String> texts) {
// 将文本转换为 Document 对象并写入向量库
List<Document> documents = texts.stream()
.map(text -> new Document(text))
.collect(Collectors.toList());
vectorStore.add(documents);
return "成功入库 " + documents.size() + " 条文档";
}
// ========== 2. RAG 问答 ==========
@GetMapping("/ask")
public String ask(@RequestParam String question) {
// Step 1: 向量检索 —— 查询相似度最高的 Top-3 文档
SearchRequest searchRequest = SearchRequest.builder()
.query(question)
.topK(3)
.similarityThreshold(0.5) // 相似度阈值过滤
.build();
List<Document> relevantDocs = vectorStore.similaritySearch(searchRequest);
// Step 2: 提取检索到的上下文
String context = relevantDocs.stream()
.map(Document::getContent)
.collect(Collectors.joining("\n---\n"));
// Step 3: 组装增强 Prompt
String systemPrompt = """
你是一位专业的技术顾问。请严格根据以下参考资料回答用户问题。
如果参考资料不足以回答问题,请明确说明"根据现有资料无法回答"。
【参考资料】
{context}
""";
SystemPromptTemplate promptTemplate = new SystemPromptTemplate(systemPrompt);
Prompt prompt = promptTemplate.create(Map.of("context", context));
// Step 4: 调用 LLM 生成回答
String answer = chatClient.prompt(prompt)
.user(question)
.call()
.content();
// 返回带溯源信息的回答
String sources = relevantDocs.stream()
.map(doc -> "- " + doc.getContent().substring(0, Math.min(50, doc.getContent().length())) + "...")
.collect(Collectors.joining("\n"));
return "【回答】\n" + answer + "\n\n【参考来源】\n" + sources;
}
}
使用方式
# 1. 向知识库添加文档
curl -X POST http://localhost:8080/api/rag/ingest \
-H "Content-Type: application/json" \
-d '["Python是一种解释型编程语言...", "Java广泛应用于企业级开发..."]'
# 2. 提问
curl "http://localhost:8080/api/rag/ask?question=什么是Python?"
6.3 Java 版本(方案二:LangChain4j 轻量版)
如果你不想用 Spring Boot,LangChain4j 提供了更轻量的纯 Java API:
依赖(pom.xml)
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
<version>0.31.0</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-embeddings-bge-small-zh</artifactId>
<version>0.31.0</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>0.31.0</version>
</dependency>
纯 Java RAG 实现
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.Metadata;
import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.embedding.bge.small.zh.BgeSmallZhEmbeddingModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.store.embedding.EmbeddingMatch;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
import java.util.List;
public class SimpleRagExample {
public static void main(String[] args) {
// ========== 1. 初始化 Embedding 模型(本地运行,无需 API Key) ==========
EmbeddingModel embeddingModel = new BgeSmallZhEmbeddingModel();
// ========== 2. 初始化内存向量存储(生产环境可替换为 Milvus/Redis) ==========
EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
// ========== 3. 知识库文档入库 ==========
String[] documents = {
"Python是一种解释型、面向对象的高级编程语言,语法简洁优雅。",
"Java是一种静态类型、跨平台的编程语言,广泛应用于企业级开发。",
"机器学习是人工智能的一个分支,通过数据训练模型进行预测。",
"深度学习是机器学习的一个子集,使用多层神经网络提取特征。"
};
for (String text : documents) {
TextSegment segment = TextSegment.from(text, new Metadata());
Embedding embedding = embeddingModel.embed(segment).content();
embeddingStore.add(embedding, segment);
}
System.out.println("✅ 知识库入库完成,共 " + documents.length + " 条文档\n");
// ========== 4. 用户查询 ==========
String query = "什么是Python?";
System.out.println("🔍 用户查询: " + query + "\n");
// ========== 5. 查询向量化 + 相似度检索 ==========
Embedding queryEmbedding = embeddingModel.embed(query).content();
List<EmbeddingMatch<TextSegment>> matches = embeddingStore
.findRelevant(queryEmbedding, 3); // Top-3
// ========== 6. 打印检索结果 ==========
System.out.println("📚 检索结果:");
StringBuilder context = new StringBuilder();
for (int i = 0; i < matches.size(); i++) {
EmbeddingMatch<TextSegment> match = matches.get(i);
System.out.printf(" [%d] 相似度: %.4f | %s%n",
i + 1, match.score(), match.embedded().text());
context.append(match.embedded().text()).append("\n");
}
// ========== 7. 组装 Prompt 并调用 LLM(可选) ==========
String prompt = String.format("""
根据以下参考资料回答问题:
%s
问题:%s
请给出准确、简洁的回答:
""", context, query);
System.out.println("\n" + "=".repeat(50));
System.out.println("📝 组装后的 Prompt:");
System.out.println(prompt);
// 如需调用 LLM,取消下面注释(需要配置 OpenAI API Key)
/*
OpenAiChatModel chatModel = OpenAiChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("gpt-3.5-turbo")
.build();
String answer = chatModel.generate(prompt);
System.out.println("\n🤖 LLM 回答:\n" + answer);
*/
}
}
6.4 Python vs Java 实现要点对比
| 对比项 | Python | Java |
|---|---|---|
| Embedding 模型加载 | sentence-transformers 一行代码 |
BgeSmallZhEmbeddingModel 或 Spring AI 自动配置 |
| 向量存储 | FAISS / Chroma 轻量库 | Redis Vector / PGVector / Milvus(企业级) |
| 框架成熟度 | LangChain / LlamaIndex 生态最丰富 | Spring AI / LangChain4j 快速追赶中 |
| 部署方式 | 脚本运行 / FastAPI 服务 | Spring Boot 微服务 / 企业级架构 |
| 学习曲线 | 更平缓,AI 生态最完善 | 需要 Spring 基础,但企业集成度更高 |
| 推荐场景 | 算法实验、快速原型、研究 | 企业级应用、现有 Java 系统接入 |
七、总结
RAG 的本质是给大模型装上"外接大脑"。它通过三个核心步骤实现知识增强:
- 向量化:用 Embedding 模型将文本语义映射到高维向量空间
- 相似检索:通过余弦相似度等度量,在向量库中找到语义最相关的文档
- 提示增强:将检索结果注入 Prompt,引导 LLM 基于真实知识生成回答
从 Naive RAG 到 Advanced RAG 再到 Agentic RAG,这一技术栈正在快速进化。无论你是 Python 开发者还是 Java 开发者,掌握 RAG 原理都是每一个大模型应用开发者的必修课。
📌 推荐阅读
- 《LangChain 实战:从入门到精通》
- 《Spring AI 官方文档》:https://docs.spring.io/spring-ai/reference/
- 论文:Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks (Lewis et al., 2020)
- 论文:Self-RAG: Learning to Retrieve, Generate, and Critique through Self-Reflection (Asai et al., 2023)
如果这篇文章对你有帮助,欢迎点赞 👍、收藏 ⭐、评论 💬,你的支持是我持续创作的动力!
更多推荐


所有评论(0)