本文介绍了RAG(检索增强生成)技术,旨在解决大语言模型知识截止到训练数据、无法处理私有知识及易产生“幻觉”的问题。RAG通过离线建立知识库索引和在线检索生成两个阶段,有效提升模型回答问题的准确性和相关性。文章详细阐述了文档加载解析、文本分块、向量化、向量数据库存储等离线索引步骤,以及问题向量化、向量检索、重排序、构造Prompt和LLM生成回答等在线查询流程。最后,通过一个完整的Spring AI示例,展示了如何实现RAG问答系统,并提出了生产环境中的注意事项。对于想要提升大模型应用能力的小白和程序员来说,本文提供了一套实用且易于上手的解决方案,值得收藏学习。
1
RAG 概述
大语言模型的知识停留在训练数据截止的那一刻,之后就不知道了。这带来几个问题:
- 训练结束后发生的事,模型一概不知
- 公司内部文档、产品手册、政策条款这些私有知识不在训练数据里,模型没法基于它们回答问题
- 模型不知道答案的时候,可能会编造一些听起来像那么回事但实际是错的内容(也就是"幻觉")
RAG 是解决这些问题的一个成熟方案。整个流程分两个阶段,离线流程建立索引和在线流程检索生成:
-
建立索引:构建知识库,只需执行一次。
-
检索生成:每次问答实时执行

2
离线索引阶段(Indexing)
离线索引阶段把原始知识库加工成 AI 可检索的向量格式,存到向量数据库里。这个阶段一般只需跑一次,知识更新了再重跑。
- 2.1 文档加载与解析
文档加载器从各种数据源读取原始文档,转成纯文本。Spring AI 里用 DocumentReader 接口来做这件事。
常见数据源:
| 数据源类型 | 示例 | 解析难点 |
|---|---|---|
| PDF、Word、PPT | 产品手册、会议记录 | 表格、图片、复杂排版 |
| 网页 | 在线文档、新闻 | HTML 标签清理、正文提取 |
| 数据库 | 结构化业务数据 | 转换为自然语言描述 |
| 图片/扫描件 | 合同扫描件 | OCR 识别文字 |
Spring AI 有个 TikaDocumentReader,集成了 Apache Tika,能自动识别文件类型并提取文本:
Resource resource = new ClassPathResource("docs/product-manual.pdf");
List<Document> documents = new TikaDocumentReader(resource).get();
纯文本文件(.txt、.md)也可以用
TextDocumentReader,更轻量。
- 2.2 文本分块
分块策略直接影响检索质量。向量数据库的工作单位是文档块(chunk),块太大检索时会带入大量不相关内容,块太小又可能丢掉关键信息。
为什么要分块?整篇文档作为一块检索结果太粗,单句话作为一块上下文又不够。另外模型的上下文窗口有限,每次请求的 token 数量也直接影响 API 费用。
常见分块策略:
| 策略 | 做法 | 优点 | 缺点 |
|---|---|---|---|
| 固定大小分块 | 每 512/1024 个 token 切一刀 | 简单、块大小均匀 | 可能切断句子或段落 |
| 按段落/章节分块 | 根据换行符、标题等自然边界切分 | 保持语义完整 | 块大小不均匀,长段落可能仍过大 |
| 递归分块 | 先按大边界切,太长再按小边界继续切 | 平衡语义和大小 | 实现稍复杂 |
| 语义分块 | 用模型判断语义边界,语义变化处切分 | 效果最好 | 计算成本高 |
| 滑动窗口 | 相邻块之间有重叠部分(overlap) | 保留跨块上下文,提高召回率 | 存储冗余增加 |
Spring AI 提供了 TokenTextSplitter,基于 token 数量切分,尽量保留句子边界:
TokenTextSplitter splitter = TokenTextSplitter.builder()
.withChunkSize(800) // 每块约800个token
.withMinChunkSize(400) // 最小块大小,低于此值的不切分
.build();
List<Document> chunks = splitter.apply(documents);
实践经验:先用小模型(如 qwen-turbo)把原始文本重写成带 Markdown 标题(#、##)的结构化格式,再按"目标 500 tokens + 尽量在段落/句子/句号分隔符处断开"的方式切分,最后设置 50 tokens 的重叠保证召回质量。
- 2.3 向量化
向量化把文本块转换成高维向量,语义相近的文本在向量空间中距离也近。这个过程用 EmbeddingClient 完成。
举个例子:
"苹果公司发布了新iPhone" → [0.12, -0.34, 0.56, ..., 0.78] (1536维向量)
"Apple推出最新款手机" → [0.11, -0.33, 0.55, ..., 0.77] (非常接近!)
"今天吃了一个苹果" → [0.67, 0.23, -0.41, ..., 0.15] (距离较远)
常用 Embedding 模型:
| 模型 | 维度 | 特点 |
|---|---|---|
| OpenAI text-embedding-3-small | 1536 | 效果好,成本低 |
| OpenAI text-embedding-3-large | 3072 | 效果最佳,成本较高 |
| BAAI/bge-large-zh | 1024 | 中文效果优秀,开源 |
| m3e | 768 | 轻量中文嵌入 |
| jina-embeddings-v3 | 1024 | 多语言支持 |
- 2.4 存入向量数据库
向量数据库存储向量和原始文本,支持高效的相似度检索。Spring AI 通过统一的 VectorStore 接口抽象了和各向量数据库的交互。
常用向量数据库:
| 数据库 | 类型 | 适用场景 |
|---|---|---|
| Chroma | 轻量、嵌入式 | 本地开发、小规模 |
| FAISS | Meta 开源,单机高性能 | 百万级向量,单机部署 |
| Milvus | 分布式 | 大规模生产环境 |
| Pinecone | 云托管 | 开箱即用,免运维 |
| Weaviate、Qdrant | 自托管/云 | 功能丰富 |
Spring AI 对每种数据库都有对应的 starter 依赖,比如:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-chroma-store-spring-boot-starter</artifactId>
</dependency>
写入向量数据库的代码就一行:
vectorStore.add(chunks);
VectorStore 内部会自动调 EmbeddingClient 为每个 Document 生成向量,再存到后端。
3
在线查询阶段(Querying)
在线查询阶段在每次用户提问时实时执行,完成"检索 → 增强 → 生成"的流程。
- 3.1 问题向量化
用户的问题也要用同一个 Embedding 模型转成向量,才能和知识库里的向量做相似度比较。注意必须是同一个模型。原因很简单:不同模型的"词典"不一样,同一段文本用不同模型转出来的向量也对不上。
String userQuestion = "iPhone 16 有什么新功能?";
List<Double> queryEmbedding = embeddingClient.embed(userQuestion);
- 3.2 向量检索
相似度检索就是在向量数据库里找到和问题向量最相似的 Top-K 个文本块。Spring AI 通过 VectorStore.similaritySearch() 实现:
List<Document> results = vectorStore.similaritySearch(
SearchRequest.builder()
.query(userQuestion)
.topK(5) // 返回最相似的5个块
.similarityThreshold(0.75) // 相似度阈值,低于此值的不返回
.build()
);
相似度计算方式有几种:
-
余弦相似度最常用,值越接近 1 越相似;
-
欧氏距离算向量空间中的直线距离,值越小越相似;
-
点积归一化后等价于余弦相似度。
有时候会结合关键词检索(如 BM25 算法)做混合检索(Hybrid Search),兼顾语义匹配和精确匹配。Spring AI 的
VectorStore接口目前主要支持向量检索,混合检索需要自己实现。
- 3.3 重排序
向量检索返回的 Top-K 结果里可能混进一些相关性不高的内容。重排序用专门的模型(如 bge-reranker、Cohere Rerank)对召回结果重新打分,过滤掉噪音。这一步可选,但生产环境一般都推荐加上。
初始召回5个块 → Reranker重新打分 → 保留最相关的3个
好处是可以先用较大的 Top-K(比如 20)召回足够多的候选,再通过 Reranker 精排到最终的 Top-3,兼顾召回率和精确率。
Spring AI 没有内置 Reranker,可以自己集成 CrossEncoder(比如 HuggingFace 的 BAAI/bge-reranker-base)。
- 3.4 构造 Prompt
最后要把检索到的文本块拼到 Prompt 里,和用户问题一起送给大模型。Spring AI 的 QuestionAnswerAdvisor 可以自动完成这一步。
它内置的 Prompt 模板大致是这样的:
用户问题:{userText}
参考文档:
1. **{document1.content}**
2. **{document2.content}**
...
请基于以上参考文档回答问题。如果参考文档中没有相关信息,请明确告知"根据现有资料无法回答"。
如果想更精细地控制,比如要求模型引用来源、输出特定格式,可以自定义 PromptTemplate:
你是xxx,作为xxx,你将根据用户的对话,基于你的记忆为用户提供准确的信息和指导。
你的记忆
---------------------
{context_str}
---------------------
用户问题: {query_str}
要求:
- 严格基于相关信息的内容进行回答,禁止编造
- 引用来源时使用 [segment_id:编号] 格式
- 若没有相关信息,明确告知用户
你的回答:
在 Spring AI 里,可以自定义 QuestionAnswerAdvisor 并重写 doGetUserTextAdvice 方法来实现,或者直接用 ChatClient 的 .system() 和 .user() 手动拼。
- 3.5 LLM 生成回答
最后把构造好的 Prompt 发给大模型,模型基于检索到的上下文生成回答,也可以按要求标注来源。
String answer = chatClient.prompt()
.user(finalPrompt)
.call()
.content();
4
完整 RAG 示例
环境准备
-
JDK 17+,Maven/Gradle
-
大模型 API Key(OpenAI 或通义千问)
-
准备一份测试用的知识库文件,比如
knowledge.txt
knowledge.txt 示例内容:
Spring AI是一个基于Spring框架的人工智能应用开发框架。
它提供了统一的API抽象,支持OpenAI、Azure、通义千问等多种模型。
Spring AI的核心特性包括:聊天客户端API、模型切换支持、工具调用、ETL管道和RAG检索增强等。
检索增强生成技术让模型能够基于私有知识库回答问题,有效减少幻觉。
Maven 依赖配置
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.1.7</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-tika-document-reader</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-advisors-vector-store</artifactId>
</dependency>
</dependencies>
配置 Embedding 模型
加上 embedding 配置,就能自动注入 EmbeddingModel 的 Bean:
spring:
application:
name: spring-ai-tutorial
ai:
openai:
api-key: ${OPENAI_API_KEY} # 通过环境变量或启动参数传入
base-url: https://dashscope.aliyuncs.com/compatible-mode # DashScope OpenAI兼容端点
chat:
options:
model: qwen3.6-plus # 通义千问模型名称
temperature: 0.7 # 控制输出随机性,范围0~2,越低越确定性
memory:
repository:
jdbc:
initialize-schema: always
embedding: # 配置后可以注入 EmbeddingModel 的 Bean
options:
model: text-embedding-v4 # 嵌入模型
配置 VectorStore 和 ChatClient
用 SimpleVectorStore 内存版:
package com.springai.guide.config;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RagDemoConfig {
@Bean
public VectorStore vectorStore(EmbeddingModel embeddingModel) {
return SimpleVectorStore.builder(embeddingModel).build();
}
@Bean
public ChatClient chatClient(ChatClient.Builder builder, VectorStore vectorStore) {
return builder
// 传入 vectorStore,Advisor 就知道从哪里检索知识
.defaultAdvisors(QuestionAnswerAdvisor.builder(vectorStore).build())
.build();
}
}
QuestionAnswerAdvisor 是 Spring AI 提供的专门用于 RAG 的 Advisor。它在用户提问时先从向量数据库检索相关文档,把文档作为上下文注入到 prompt 中,让大模型基于这些知识来回答。设置成默认 Advisor 后,每次通过这个 ChatClient 发起对话都会自动走 RAG 流程,不用每次手动指定。
初始化知识库(离线索引)
package com.springai.guide.config;
import org.springframework.ai.document.Document;
import org.springframework.ai.reader.tika.TikaDocumentReader;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class KnowledgeBaseInitializer implements CommandLineRunner {
private final VectorStore vectorStore;
public KnowledgeBaseInitializer(VectorStore vectorStore) {
this.vectorStore = vectorStore;
}
@Override
public void run(String... args) throws Exception {
// 1. 文档加载与解析
Resource resource = new ClassPathResource("knowledge.txt");
if (!resource.exists()) {
System.out.println("警告: knowledge.txt 文件不存在,跳过知识库初始化");
System.out.println("提示: 如需使用RAG功能,请在 src/main/resources 目录下创建 knowledge.txt 文件");
return;
}
List<Document> documents = new TikaDocumentReader(resource).get();
// 2. 文本分块
TokenTextSplitter splitter = TokenTextSplitter.builder()
.withChunkSize(200)
.withMaxNumChunks(500)
.withMinChunkLengthToEmbed(10)
.build();
List<Document> chunks = splitter.apply(documents);
// 3. 向量化并存入向量数据库(VectorStore 自动完成)
vectorStore.add(chunks);
System.out.println("知识库初始化完成,共加载 " + chunks.size() + " 个文档块");
}
}
测试 RAG 问答
@RestController
@RequestMapping("/api/rag")
public class RagTestController {
private final ChatClient chatClient;
public RagTestController(ChatClient chatClient) {
this.chatClient = chatClient;
}
@GetMapping("/ask")
public String ask(@RequestParam String question) {
return chatClient.prompt()
.user(question)
.call()
.content();
}
}
5
生产环境注意事项
RAG 从 Demo 到生产还有一些问题要处理,后续 RAG 专栏会深入讲:
| 问题 | 说明 | 解决方向 |
|---|---|---|
| 文档解析质量 | PDF 表格、复杂排版、扫描件 OCR 准确率 | 用专用解析库(如 pdfplumber、OCR 服务) |
| 分块策略选择 | 不同类型文档应该用不同策略 | 按文档类型配置不同的 chunk_size 和 overlap |
| 检索质量 | 向量检索不总是返回最相关的结果 | 查询改写、HyDE、混合检索 |
| 重排序 | 初始召回结果包含噪音 | 集成 CrossEncoder 模型精排 |
| 向量数据库选型 | 内存版不适合生产 | 用 Milvus、Qdrant、Pinecone 等 |
| 成本控制 | 向量化和 LLM 调用都有成本 | 缓存常见问题、优化 chunk 数量 |
总结:这章把 RAG 的两个阶段(离线索引和在线查询)过了一遍,也跑通了一个完整的 RAG 系统。后续 RAG 专栏会继续深入优化技巧和实战。
大模型的知识又多又杂,到底怎么学?
做这行久了,被问最多的问题就一个:大模型的知识又多又杂,我到底先学啥?翻了一堆资料,看啥都像重点,结果啥都没学进去。今天把我自己一路摸出来的顺序捋一遍,零基础、应届生、转行的都适用。跟着走,至少方向不乱、不瞎忙,学完拿得出手。
第一阶段(10天):初阶应用
这一阶段就一个目标:把大模型真正"玩明白",不是只会聊天那种,而是能调教它、能用代码把大模型和业务接起来。
- 大模型 AI 能干什么?
- 大模型是怎样获得「智能」的?
- 用好 AI 的核心心法
- 大模型应用业务架构
- 大模型应用技术架构
- 代码示例:向 GPT-3.5 灌入新知识
- 提示工程的意义和核心思想
- Prompt 典型构成
- 指令调优方法论
- 思维链和思维树
- Prompt 攻击和防范
- …
第二阶段(30天):高阶应用
这阶段正式进实战,目标很实在:做出两个能拿出手的东西——一个私有知识库,一个 agent 对话机器人。
-
为什么要做 RAG
-
搭建一个简单的 ChatPDF
-
检索的基础概念
-
什么是向量表示(Embeddings)
-
向量数据库与向量检索
-
基于向量检索的 RAG
-
搭建 RAG 系统的扩展知识
-
混合检索与 RAG-Fusion 简介
-
向量模型本地部署
-
…
走完这 30 天,Python 或 JavaScript 背景的基本能独立做一套 RAG 应用,简历上也敢写"大模型应用开发"了。
第三阶段(约20天):动手微调
学到这,你已经开始 “造” 模型了 —— 通过微调,搞出垂直领域的专用小模型。
- 为什么要做 RAG
- 什么是模型
- 什么是模型训练
- 求解器 & 损失函数简介
- 小实验2:手写一个简单的神经网络并训练它
- 什么是训练/预训练/微调/轻量化微调
- Transformer结构简介
- 轻量化微调
- 实验数据集的构建
- …
恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。
到此为止,大概2个月的时间。你从 “只会用” 变成 “能造” 的 AI 小子。那么你还想往下探索吗?
想要入局AI大模型赛道、抢占行业红利的朋友,微信扫描下方优快云官方认证二维码,即可100%免费领取全套学习资料!
第四阶段(20天):商业闭环,部署落地
技术学完,落地才算数。这阶段带你搞明白大模型怎么真正跑起来、用起来。
- 硬件选型
- 带你了解全球大模型
- 使用国产大模型服务
- 搭建 OpenAI 代理
- 热身:基于阿里云 PAI 部署 Stable Diffusion
- 在本地计算机运行大模型
- 大模型的私有化部署
- 基于 vLLM 部署大模型
- 案例:如何优雅地在阿里云私有部署开源大模型
- 部署一套开源 LLM 项目
- 内容安全
- 互联网信息服务算法备案
- …
想要入坑大模型的朋友,给大家准备了一份2026 年最新 AI 大模型全套学习资料:
1、大模型系统化学习路线

2、大模型学习视频教程

3、大模型学习书籍&电子文档

4、AI大模型最新行业报告

5、大模型项目实战&配套源码

6、2026大模型大厂面试真题

7、为什么要学习大模型?
我国在A大模型领域面临人才短缺,数量与质量均落后于发达国家。2023年,人才缺口已超百万,凸显培养不足。随着AI技术飞速发展,预计到2025年,这一缺口将急剧扩大至400万,严重制约我国AI产业的创新步伐。加强人才培养,优化教育体系,国际合作并进是破解困局、推动AI发展的关键。


8、适合谁学?
- 传统后端 / Java / 前端开发,想转型 AI 应用
- 大学生、应届生,想拿更好的 offer
- 产品经理、运营,想武装职业竞争力
- 技术负责人,想给团队落地提效
学习是反人性的,但回报是真金白银。技术会更新,赛道会切换,但只要你先动手,机会就永远站在你这边。
9、这些资料真的有用吗?
这份资料由我和鲁为民博士(北京清华大学学士和美国加州理工学院博士)共同整理,现任上海殷泊信息科技CEO,其创立的MoPaaS云平台获Forrester全球’强劲表现者’认证,服务航天科工、国家电网等1000+企业,以第一作者在IEEE Transactions发表论文50+篇,获NASA JPL火星探测系统强化学习专利等35项中美专利。本套AI大模型课程由清华大学-加州理工双料博士、吴文俊人工智能奖得主鲁为民教授领衔研发。
资料内容涵盖了从入门到进阶的各类视频教程和实战项目,无论你是小白还是有些技术基础的技术人员,这份资料都绝对能帮助你提升薪资待遇,转行大模型岗位。


想要入局AI大模型赛道、抢占行业红利的朋友,微信扫描下方优快云官方认证二维码,即可100%免费领取全套学习资料!
好了,就写到这。路线是死的,人是活的,卡住了随时来问我。觉得有用就点个收藏,别让它进收藏夹吃灰——动起来比啥都强。
本文系统讲解RAG(检索增强生成)技术,涵盖离线索引(文档加载、文本分块、向量化、向量数据库存储)和在线查询(问题向量化、向量检索、重排序、Prompt构造、LLM生成)两大核心阶段。基于Spring AI框架提供完整可运行示例,并指出生产环境关键注意事项,帮助开发者构建准确、可控、可落地的大模型知识增强应用。
1136

被折叠的 条评论
为什么被折叠?



