这是一篇写给 Java 初学者的 RAG 导学。不要急着背 Embedding、Chunk、Point 这些名词,本篇先帮你看懂整个系统,再亲手把最终项目跑起来。
完整代码和分篇教程:https://github.com/bysbsh/ai-rag-learning-guide

这篇要解决什么问题
大模型虽然懂很多通用知识,但它通常不知道:
- 你公司内部的业务规则。
- 你刚写完的项目文档。
- 没有出现在训练数据中的最新资料。
- 某个问题应该引用哪一份真实文档。
如果只把问题交给大模型,它可能凭自身知识回答,也可能编出一个看似合理的答案。
RAG 的做法是:先从你的知识库找资料,再让大模型根据资料回答。
举个例子,知识库中有一段内容:
text
Secret 用来保存密码、令牌和证书等敏感数据。
用户提问:
text
密码、令牌和证书应该保存在哪里?
RAG 系统会先找到 Secret 这段资料,然后把"资料 + 用户问题"一起交给大模型。这样得到的回答有依据,页面还可以同时显示资料来源和相似度。
先看懂整条 RAG 流程
本项目的完整查询过程如下:
text
用户在网页输入问题
↓
Spring Boot 接收问题
↓
bge-m3 把问题转换成 1024 维向量
↓
Qdrant 用问题向量检索相关的知识片段
↓
Java 过滤低分结果,选出最相关的资料
↓
Java 把资料和用户问题组装成 Prompt
↓
qwen3 根据 Prompt 生成回答
↓
页面显示答案、资料来源、相似度和 Point ID
这里有一个容易混淆的点:**Qdrant 不负责回答,qwen3 不负责去 Qdrant 搜索。**中间的 Java 程序负责把它们串联起来。
每个组件分别做什么
| 组件 | 初学者可以这样理解 | 本项目中的作用 |
|---|---|---|
| Ollama | 本地模型运行器 | 下载、加载模型,并提供 HTTP API |
qwen3:14b |
负责读资料和组织语言的大模型 | 根据检索到的资料生成最终回答 |
bge-m3 |
把文本变成数字坐标的 Embedding 模型 | 把问题和知识片段转成 1024 维向量 |
| Qdrant | 专门保存和检索向量的数据库 | 存储知识片段,找出与问题语义最接近的内容 |
| Spring Boot | Java Web 应用框架 | 提供查询、入库、删除 API 和浏览器页面 |
| Markdown | 容易编辑的文档格式 | 充当本教程的原始知识文档 |
| RAG | 一套"先检索,后生成"的流程 | 是整个应用的组合方式,不是某个单独软件 |
学习前需要会什么
不需要先学会 Python,也不需要会训练大模型。你只需要:
- 看得懂基本 Java 类、方法和集合。
- 会在终端中进入目录、执行命令。
- 知道 HTTP 请求和 JSON 是什么即可。
本教程主要在 Apple Silicon Mac 上验证。Java 代码可以在 Windows 和 Linux 上运行,但安装和后台服务命令会有区别。
为什么项目要分成 5 个模块
如果一开始就阅读完整 Spring Boot RAG 代码,你会同时遇到 HTTP、JSON、Prompt、Embedding、向量数据库和 Web API,很难判断每一段代码在解决什么问题。
所以仓库保留了 5 个可独立运行的阶段:
| 模块 | 先解决什么 | 你会学到什么 |
|---|---|---|
01-ollama-basics |
Java 怎样跟大模型说话 | HttpClient、JSON、多轮上下文、System Prompt |
02-embedding-search |
电脑怎样判断两段文字的语义是否接近 | Embedding、1024 维向量、余弦相似度 |
03-markdown-rag |
怎样把本地 Markdown 资料交给大模型 | Chunk、Top-K、相似度阈值、Prompt 组装 |
04-qdrant-rag |
知识多了以后放在哪里 | Qdrant Collection、Point、向量入库和检索 |
05-spring-rag |
怎样让别的程序和用户使用 RAG | Spring Boot API、动态入库、知识工作台 |
学习顺序不是在反复重写同一个程序,而是每次只新增一个概念。
动手:先把最终的 RAG 工作台跑起来
这一部分用于建立直观认识。先看到最终效果,后续再从第 1 篇开始逐层理解代码。
"5 分钟跑通"不包括第一次下载大模型和 Docker 镜像的时间。如果 Java、Ollama 或 Docker 还没有安装,请先阅读下一篇《第 1 篇:macOS 安装和准备 Ollama》。
完成进度
- 1. 下载项目代码
- 2. 检查 Java、Maven、Ollama、Docker 和 jq
- 3. 准备聊天模型和 Embedding 模型
- 4. 启动 Qdrant 向量数据库
- 5. 创建 Collection 并写入示例知识
- 6. 启动 Spring Boot 应用
- 7. 在浏览器中完成第一次 RAG 问答
第 1 步:下载项目
打开终端,执行:
bash
git clone https://github.com/bysbsh/ai-rag-learning-guide.git
cd ai-rag-learning-guide
第一条命令把公开仓库下载到本地,第二条命令进入项目根目录。后面所有命令都默认在这个目录中执行。
检查当前位置:
bash
pwd
ls
ls 的结果中应该能看到:
text
01-ollama-basics
02-embedding-search
03-markdown-rag
04-qdrant-rag
05-spring-rag
pom.xml
README.md
如果看不到这些内容,先不要继续,通常是还没有进入项目根目录。
第 2 步:检查基础环境
bash
java -version
mvn -version
ollama --version
docker version
jq --version
不要只看命令有没有输出,还要检查以下内容:
| 检查项 | 要求 | 为什么 |
|---|---|---|
| Java | 17 或更高 | 项目按 Java 17 编译 |
| Maven | 3.9 或更高 | 负责下载依赖、编译和启动项目 |
| Ollama | 能输出版本号 | 负责在本地运行模型 |
| Docker | Client 和 Server 都有版本 | Qdrant 在 Docker 容器中运行 |
| jq | 能输出版本号 | 只用来格式化和提取 JSON,不参与 RAG 运行 |
教程发布时的验证组合是 Java 17、Maven 3.9、Ollama 0.32、Docker 29.6 和 Qdrant 1.19。你不必追求完全相同的小版本。
常见失败信号:
command not found:软件还没有安装,或没有加入PATH。Cannot connect to the Docker daemon:Docker Desktop 还没有启动。- Java 显示 11:后面可能出现
class file version 61.0错误,需要切换到 Java 17。 - 没有
jq:执行brew install jq。它只影响教程中的 JSON 查看命令,不影响 Java 项目本身。
第 3 步:准备两个模型
bash
ollama pull qwen3:14b
ollama pull bge-m3
ollama list
为什么是两个模型?
qwen3:14b负责生成人能读懂的回答。bge-m3负责把文本转成向量,它不负责聊天。
ollama list 的列表中应该同时出现这两个名称。
24 GB 以下内存的电脑可以先使用 qwen3:8b。这时需要同步修改项目使用的模型名,具体位置参考**《附录:模型切换指南,qwen3 与 bge-m3 怎么换》**。
再检查 Ollama HTTP 服务:
bash
curl http://localhost:11434/api/tags
返回 JSON 就说明 Ollama 服务可以被 Java 访问。如果是 Failed to connect,在 macOS Homebrew 安装方式下可以执行:
bash
brew services start ollama
第 4 步:启动 Qdrant
第一次启动:
bash
docker run -d \
--name qdrant-study \
-p 6333:6333 \
-p 6334:6334 \
-v qdrant-study-data:/qdrant/storage \
qdrant/qdrant:v1.19.0
这条命令看起来很长,实际上只做了 5 件事:
| 参数 | 意义 |
|---|---|
-d |
让容器在后台运行,关闭终端不会停止 |
--name qdrant-study |
把容器命名为 qdrant-study |
-p 6333:6333 |
映射 HTTP 管理接口 |
-p 6334:6334 |
映射 Java SDK 使用的 gRPC 接口 |
-v qdrant-study-data:/qdrant/storage |
使用 Docker Volume 保存数据,重建容器时不至于立即丢失 |
以后容器已经创建,只需要:
bash
docker start qdrant-study
检查容器:
bash
docker ps --filter name=qdrant-study
成功标志是 STATUS 为 Up,并能看到 6333-6334 端口映射。
再检查 Qdrant API:
bash
curl -s http://localhost:6333/collections
第一次可能返回:
json
{
"result": {
"collections": []
},
"status": "ok"
}
collections 是空数组不是错误,只是还没有创建存放向量的 Collection。
第 5 步:创建 Collection 并写入知识
Collection 可以先粗略理解为关系型数据库中的"表"。本项目的 Collection 名称是 kubernetes_chunks。
创建 Collection:
bash
curl -X PUT http://localhost:6333/collections/kubernetes_chunks \
-H 'Content-Type: application/json' \
-d '{
"vectors": {
"size": 1024,
"distance": "Cosine"
}
}'
两个关键配置:
size: 1024:bge-m3生成的每个向量有 1024 个数字。distance: Cosine:Qdrant 使用余弦相似度判断两个向量的方向是否接近。
成功时会看到类似:
json
{"result":true,"status":"ok"}
如果提示 Collection 已经存在,先不要删除它,直接继续入库即可。
然后执行示例入库程序:
bash
mvn -f 04-qdrant-rag/pom.xml compile exec:java \
-Dexec.args=--index
这条命令的含义是:
mvn:运行 Maven。-f 04-qdrant-rag/pom.xml:使用第 4 个模块的 Maven 配置。compile:编译 Java 代码。exec:java:运行该模块的默认主类。-Dexec.args=--index:把--index传给主类,表示这次要入库,而不是查询。
程序会读取 Markdown,按标题拆成 Chunk,调用 bge-m3 生成向量,最后写入 Qdrant。
检查入库结果:
bash
curl -s http://localhost:6333/collections/kubernetes_chunks | \
jq '.result.points_count'
示例知识库应该输出:
text
4
这个 4 不是"4 个向量维度",而是 Qdrant 中有 4 个 Point。每个 Point 代表一个知识 Chunk,它内部的向量仍然是 1024 维。
第 6 步:启动 Spring Boot 应用
bash
mvn -f 05-spring-rag/pom.xml spring-boot:run
第一次运行时 Maven 需要下载依赖,速度取决于网络。当终端出现类似下面的日志时,才表示启动完成:
text
Started SpringRagApplication
保持这个终端窗口运行,然后在浏览器打开:
text
http://localhost:8080
注意:这里的 Spring Boot 默认在前台运行。如果关闭终端或按 Control + C,页面就会无法访问,这是正常现象。
第 7 步:完成第一次 RAG 问答
在页面右侧的问题输入框中输入:
text
密码、令牌和证书应该保存在哪里?
成功时应该同时看到:
- AI 回答中出现
Secret。 - 来源标题中出现
Secret。 - 来源文件是
kubernetes.md。 - 来源旁边显示相似度和 Point ID。
这 4 个结果同时出现,才说明不只是"大模型会聊天",而是整条 RAG 链路已经跑通。
你刚才的一次提问,后台发生了什么
| 阶段 | 实际动作 | 由谁完成 |
|---|---|---|
| 1 | 浏览器把问题发送给 /api/rag/ask |
网页 |
| 2 | 调用 /api/embed 把问题变成 1024 维向量 |
Java + bge-m3 |
| 3 | 使用问题向量在 kubernetes_chunks 中搜索 |
Java + Qdrant |
| 4 | 只保留达到相似度阈值的前几个 Chunk | Java |
| 5 | 把 System Prompt、知识 Chunk 和用户问题组装起来 | Java |
| 6 | 调用 /api/chat 生成最终文字 |
Java + qwen3:14b |
| 7 | 把 answer 和 sources 返回页面 |
Spring Boot |
answer 和 sources 不是模型自带的固定参数,而是这个 Java 项目自己设计的 API 返回结构:
answer来自 qwen3 生成的回答。sources由 Java 根据 Qdrant 的真实检索结果生成。
这样设计的好处是,来源不需要让大模型凭空生成。
快速看懂代码从哪里开始
第一次不需要阅读所有类。先按下面的顺序找入口:
RagController:查看浏览器的问题如何进入 Java。RagService:查看检索、过滤、Prompt 组装和模型调用如何串联。QdrantKnowledgeRetriever和QdrantSearchGateway:查看问题向量如何交给 Qdrant。RagPromptBuilder:查看检索资料如何变成 Prompt。OllamaAnswerGenerator:查看 Java 如何调用 qwen3。
后续章节会把这些类拆开讲解,所以本篇只需要知道它们在整条链路中的位置。
常见问题与排查顺序
| 现象 | 常见原因 | 先执行什么 |
|---|---|---|
localhost:11434 无法访问 |
Ollama 服务未启动 | curl http://localhost:11434/api/tags |
| 提示模型不存在 | 模型未下载或名称不一致 | ollama list |
localhost:6333 无法访问 |
Qdrant 容器未运行 | docker ps --filter name=qdrant-study |
Collection not found |
没有创建 kubernetes_chunks |
重新执行创建 Collection 的 PUT 命令 |
| 页面一直回答"资料不足" | 没有入库,或检索结果低于阈值 | 检查 points_count 是否大于 0 |
| 页面返回 503 | Ollama、Qdrant 或模型不可用 | 依次检查 11434、6333、ollama list |
Port 8080 was already in use |
已有程序占用 8080 | 停止旧服务,或临时更换端口 |
class file version 61.0 |
Maven 实际使用了 Java 11 | 检查 mvn -version 中的 Java version |
排查时不要一次猜所有环节,按下面顺序逐层检查:
text
Ollama 服务
→ 两个模型
→ Qdrant 容器
→ Collection
→ points_count
→ Spring Boot
→ 浏览器
初学者最容易混淆的 6 件事
1. RAG 不是一个需要安装的软件
RAG 是一套流程。本项目用 Java 把 Ollama、bge-m3、Qdrant 和 qwen3 组合成了这套流程。
2. Embedding 模型不会给你生成答案
bge-m3 的任务是输出向量。最终的中文回答由 qwen3:14b 生成。
3. 1024 维不等于有 1024 条知识
1024 维表示一个向量内含 1024 个数字。points_count: 4 才表示 Collection 中有 4 条 Point。
4. Prompt 不是模型中的固定参数
Prompt 是每次调用模型时发给它的指令和上下文。本项目中由 Java 动态组装。
5. Qdrant 中的 ID 不是靠内容相似度自动猜出来的
Point ID 由入库程序生成,用来唯一标识一条数据。相似度用于检索排名,两者用途不同。
6. 向量数据库不是为了让大模型省掉所有 Token
它的核心价值是从大量资料中找到语义相关的少量片段。这会减少不必要的上下文 Token,但"可检索、可扩展、可返回来源"才是更重要的价值。
本篇自测
先不要往下看,尝试自己回答:
qwen3:14b和bge-m3分别负责什么?- 为什么不能只把整个知识库都塞给大模型?
- Qdrant 返回的是最终答案,还是相关知识?
points_count和向量维度有什么区别?- 页面显示的
sources是谁生成的?
参考答案:
- qwen3 生成答案,bge-m3 生成向量。
- 整库内容可能超出上下文限制,增加 Token 和噪声,也不利于提供精确来源。
- Qdrant 返回相关知识,最终答案由 qwen3 生成。
points_count是数据条数,向量维度是每条向量内数字的个数。- Java 程序根据 Qdrant 的真实检索结果组装
sources。
后续学习路线
不要试图一次记住全部概念,按这个顺序学习即可:
- 第 1 篇:安装 Ollama,先学会在本地运行模型。
- 第 2 篇:用 Java HTTP 调用模型,并解析 JSON 结果。
- 第 3-4 篇:实现交互式多轮聊天,理解上下文和 System Prompt。
- 第 5 篇:学习 Embedding 和余弦相似度。
- 第 6-7 篇:先跑通 Markdown RAG,再把向量迁移到 Qdrant。
- 第 8-11 篇:把 RAG 封装成 Spring Boot API,加入动态知识管理和网页。
- 遇到陌生名词时,随时查看第 12 篇术语索引。
模型切换不在主线学习路径中。只有在内存不足、需要提高速度或更换 Embedding 模型时,再查看模型切换附录。
本篇小结
- RAG 是"检索增强生成",核心顺序是先检索、后生成。
- Ollama 运行模型,bge-m3 生成向量,Qdrant 检索知识,qwen3 生成回答,Java 串联整个流程。
- 判断 RAG 是否真正跑通,不能只看到一段 AI 回答,还要能看到真实来源和相似度。
- 本仓库用 5 个独立模块把完整系统逐层拆开,你可以按章节一步步学,不需要一次理解全部代码。
下一篇
本专栏下一篇:《第1篇:macOS 安装和准备 Ollama》
完整代码和后续更新
本专栏的所有示例代码、自动化测试和更细的分篇文档都已开源:
https://github.com/bysbsh/ai-rag-learning-guide
建议 Clone 到本地边读边运行。如果教程对你有帮助,可以点一个 Star;遇到问题可以提交 Issue,发现错误也欢迎提交 PR。
安全提醒:这是本地学习项目,默认没有登录、权限控制、限流和 HTTPS。不要把
8080、6333、6334、11434直接暴露到公网,也不要提交真实密码、令牌、证书或私有文档。