2 小时搞定 RAG 智能客服:Spring Boot + DeepSeek + Qdrant 最小闭环实践
原文链接2 小时搞定 RAG 智能客服:Spring Boot + DeepSeek + Qdrant 最小闭环实践
原文链接:https://mp.weixin.qq.com/s/rw9vxk4-Bl_J60wCy0cnsw 作者:yeffky 发布时间:2026-06-21
摘要
Java 生态纯 RAG 最小闭环实践——Spring Boot + DeepSeek + Qdrant + Ollama bge-m3。两条管线(写入 + 检索)各 3 步,核心 Java 代码不超过 500 行。原汁原味的 Java 方案,不需要 Python/LangChain。
架构总览
前端 (Vue.js + Element UI)
↓ HTTP
Spring Boot 后端
├── AI Agent(五层架构)
├── RAG 引擎(摄取+检索)
└── 业务服务(订单/商铺)
↓ ↓
DeepSeek LLM API Qdrant + Ollama(向量库+Embed)
写入管线:3 步灌文档
Step 1:Markdown 结构感知切分
MarkdownSplitter 核心能力:
- 按 H2/H3 标题层级切分,保持语义完整
- 代码块和表格占位符保护(切完再还原),不会被切散
- 每个切片携带标题路径(如
帮助中心 > 退款政策 > 申请流程) - 段落→句子→字符三级兜底策略
为什么不用 LangChain TextSplitter? 它不认识 Markdown 结构,FAQ 文档切在代码块中间检索就废了。结构化文档必须用结构化切分。
Step 2:bge-m3 向量化
Ollama 一键拉起,OpenAI 兼容格式,5 行代码切换 provider。选 bge-m3 的原因:中文 FAQ 检索准确率远高于通用 text-embedding 模型。
Step 3:Qdrant 一行 Docker
docker compose up -d
纯 REST API,零 SDK 依赖,RestTemplate 写完整个客户端——集合管理、向量 upsert、相似检索、按来源删除。
写入管线串联:文档 Markdown → MarkdownSplitter 切片 → bge-m3 向量化 → Qdrant 存储
检索管线:检索 + 生成
// 用户问题 → 向量化 → Qdrant 余弦相似度检索 Top-5 → 格式化上下文 → 喂给 LLM
关键设计:检索和格式化分离,方便后续加缓存、加重排序、加多轮对话上下文压缩。
Agent 工具化调用
通过 LangChain4j @Tool 注解把 RAG 检索变成 Agent 工具箱里的一把利器:
@Tool("从知识库中检索信息。当用户询问平台规则、使用帮助时调用")
public String searchKnowledge(String query) { ... }
LLM 自己决定何时调用工具——不需写 if-else 路由。
填坑:DeepSeek 不认 role=function
问题: LangChain4j 0.31 把工具执行结果序列化为 role=function,但 DeepSeek API 只接受 role=tool。症状:Agent 调了工具后 LLM 返回 400。
最优方案:写一个 HTTP 代理(60 行代码),在 JSON body 层正则替换 role=function → role=tool,再转发 DeepSeek:
LangChain4j → localhost:8081/api/deepseek-proxy (代理)
→ replace "role":"function" → "role":"tool"
→ forward to api.deepseek.com
为什么代理更好?
- 工具调用走标准
role=tool协议,@Tool 能力完整恢复 - 对 LangChain4j 和 DeepSeek 完全透明
- MCP、function calling 扩展不受限制
- 只需改一行配置:
deepseek.base-url: http://localhost:8081/api/deepseek-proxy/v1
RAG vs 普通 LLM 效果对比
| 对比维度 | 普通 LLM | RAG 增强 |
|---|---|---|
| 商家信息 | 泛泛而谈,可能是编的 | 引用知识库原文 |
| 订单查询 | 编造订单号(幻觉) | Agent Tool 查真实数据 |
| 知识更新 | 必须重新训练/微调 | 重新摄入文档即可 |
核心要点
- 最小 RAG 闭环 = 写入管线 + 检索管线,各 3 步,Java 代码不超过 500 行
- Markdown 文档必须用结构感知切分,普通字符切分会翻车
- Qdrant REST API 足够,不需要 SDK
- DeepSeek + LangChain4j 兼容问题用 HTTP 代理一劳永逸