乐于分享
好东西不私藏

后端 AI 实战|SpringBoot+SpringAI+Ollama+MySQL 向量库,搭建仓储知识库智能

后端 AI 实战|SpringBoot+SpringAI+Ollama+MySQL 向量库,搭建仓储知识库智能

作为多年供应链 / WMS 方向 Java 后端开发,结合我过往仓储业务背景,花费两天独立搭建一套轻量化私有化 RAG  问答系统:SpringBoot 3.5.16+ SpringAI1.0 + Ollama 本地大模型 + MySQL9.7 原生向量,单库同时持久化业务文档原文与 Embedding 向量,无需第三方向量中间件,适配企业内网离线场景,最终实现仓储规则自然语言问答,下面完整记录全流程实现、踩坑与架构 选型思考。

一、项目整体架构

1. 架构流程图(自行配图)

前端 SSE 对话页面 → SpringBoot  后端(SpringAI 核心层) → Ollama 本地大模型 (对话大模型 + Embedding 向量化模型) → MySQL9.7(存储业务文档、文本、向量)

2. 各层职责拆解

前端层:极简对话页面,基于 SSE 长连接实现打字机流式输出,解决一次性加载长回答卡顿问题;

后端服务层

SpringAI 封装 Ollama 调用,统一管理对话请求、文本切片、Embedding 向量生成;

RAG 核心逻辑:用户提问→问题向量化→MySQL 向量相似度检索匹配知识库文档→拼接上下文 Prompt 送入大模型→流式返回答案;

大模型层:Ollama 本地离线部署,全程不调用任何付费云端 API,私有化无网络依赖;

存储层:MySQL9.7 原生VECTOR字段存储向量,TEXT 字段存原始业务文档,结构化字段记录文档分类、创建时间,单库保证原文与向量事务一致性。

3. 业务场景定位

面向仓储供应链内部员工,知识库录入仓库管理制度、差旅报销标准、公司基础信息、售后流程等文档;员工通过自然语言提问,自动检索对应业务规则给出回答,替代翻阅零散 Word 文档,提升内部咨询效率。

二、核心技术选型与选型权衡(拔高核心,面试重点)

1. 向量存储:为什么选用 MySQL9.7,放弃 Milvus/Chroma?

优势

零额外运维:现有业务均使用 MySQL,无需部署、维护独立向量服务,降低小团队运维成本;

数据强一致性:业务文档、文本、向量存在同一张数据表,新增 / 修改 / 删除可通过 MySQL 事务原子操作,彻底规避「向量库与业务库数据不同步」的经典 RAG 痛点;

学习成本低:开发无需额外掌握向量库专属 API,全部使用标准 SQL 完成向量检索;

适用边界(客观说明短板,体现架构思考) MySQL 仅支持精确 KNN 全表距离计算,无 HNSW、IVF 等 ANN 近似向量索引,仅适合10 万条以内文档的内部后台系统;若面向 C 端、百万级海量向量高并发检索,仍需 Milvus、PGVector 等专业向量引擎。

对比 PGVector:团队技术栈统一 MySQL,无需额外搭建 PostgreSQL 环境,优先选用 MySQL 原生向量能力。

2. AI  框架:SpringAI 2.0

Spring 官方 AI 集成框架,统一封装各大模型厂商 API,本次对接本地 Ollama;踩坑重点:2.0 版本发生破坏性 API 重构,大量旧类弃用、包路径变更,网上多数教程为旧版本,存在大量兼容问题。

3. 本地大模型:Ollama

离线私有化部署,本地完成对话、文本 Embedding 向量化,无 API 调用费用,适配企业内网、涉密场景,无需申请任何模型 Key。

4. 流式输出:SSE 服务端推送

区别于普通同步接口一次性返回完整文本,采用 SSE 长连接分段推送大模型输出内容,前端实现打字机实时展示效果,提升交互体验。

三、核心功能实现代码

3.1 MySQL9.7 向量数据表结构(附完整 SQL,自行截图)

支持存储文档原文、分类、向量、创建时间,VECTOR (768) 适配主流 Embedding 模型 768 维向量:

CREATE TABLE IF NOT EXISTS knowledge_source (

    id          BIGINT AUTO_INCREMENT PRIMARY KEY,

    category    VARCHAR(64)  COMMENT '数据分类,如 wms / finance / company',

    content     TEXT         NOT NULL COMMENT '原始知识文本',

    created_at  DATETIME     DEFAULT CURRENT_TIMESTAMP

);

CREATE TABLE IF NOT EXISTS vector_store (

    id        VARCHAR(64) PRIMARY KEY,

    content   TEXT,

    metadata  JSON,

    embedding TEXT    -- 向量以 JSON 数组文本存储,如 [0.12,-0.34,...]

);

INSERT INTO knowledge_source (category, content) VALUES

('wms', '商品库存低于安全库存时,必须在24小时内提交补货申请'),

('wms', '入库货物外包装破损、水渍,需生成质检异常单,禁止上架'),

('wms', '拣货作业优先匹配就近库位,同一订单多商品合并拣货,减少动线'),

('wms', '仓库A01存放包装耗材,B02存放大件货物,不可混放'),

('finance', '员工差旅费住宿单日上限300元,超出部分财务不予报销'),

('finance', '采购增值税发票必须匹配对应入库单,票货不一致直接驳回审核'),

('finance', '仓储耗材采购单次金额超过5000元,需要部门经理审批'),

('aftersale', '客户签收7天内商品无损坏,支持无理由退货'),

('aftersale', '缺货订单需当日联系客户,选择补发或全额退款二选一'),

('company', '公司全称:北京智联仓储科技有限公司,成立于2020年,总部位于北京海淀区'),

('company', '公司目前员工总数350人,其中仓储运营部120人、技术研发部80人...'),

('company', 'CEO张伟、CTO李明、COO王芳,电话:010-88886666...'),

('company', '公司在上海、广州、成都设有分公司...');

3.2 Maven 关键依赖(踩坑点:SpringAI 依赖下载失败解决方案)

SpringAI 官方仓库国内镜像同步延迟高,提供阿里云 镜像加速配置,解决依赖拉取超时、缺失问题,目前因为springAi2.0.0刚上市不久,aliyun服务器目前针对这个版本的jar包不全,所以暂时用旧版稳定版

3.3 SpringAI 整合 Ollama 配置

application.yml Ollama 模型地址、超时配置; 完整 Config 配置类:OllamaChatModel、OllamaEmbeddingModel Bean 注入。

3.4 RAG 核心业务逻辑

文档入库流程:原始文本分段切片 → 调用 Embedding 模型生成向量 → SQL 动态插入 MySQL,文本与向量同步落库;

问答检索流程:用户提问 → 问题向量化 → MySQL 向量相似度召回匹配文档 → 组装上下文 Prompt 传入对话模型 → SSE 流式返回结果。

package com.my.springai.controller;

import com.my.springai.dto.AiQueryDTO;

import com.my.springai.service.RagService;

import com.my.springai.vectorstore.MysqlVectorStore;

import lombok.RequiredArgsConstructor;

import org.springframework.http.MediaType;

import org.springframework.web.bind.annotation.*;

import reactor.core.publisher.Flux;

import java.util.LinkedHashMap;

import java.util.Map;

@RestController

@RequestMapping("/ollama/rag")

@RequiredArgsConstructor

public class RagController {

    private final RagService ragService;

    private final MysqlVectorStore mysqlVectorStore;

    /** 加载本地业务规则文档,分片向量化后存入 MySQL */

    @GetMapping("/load")

    public String loadDoc() {

        return ragService.loadDoc();

    }

    /** 同步问答 */

    @PostMapping("/chat")

    public String ragChat(@RequestBody AiQueryDTO dto) {

        return ragService.chat(dto.getQuestion());

    }

    /** SSE 流式问答,前端 sse-test.html 调用 */

    @GetMapping(value = "/stream/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)

    public Flux<String> streamChat(@RequestParam String question) {

        return ragService.streamChat(question);

    }

    /** 手动上传单据文本,分片入库 */

    @PostMapping("/upload/doc")

    public String uploadDoc(@RequestParam String docText) {

        return ragService.uploadDoc(docText);

    }

    /** 从 knowledge_source 表重新同步数据到向量库 */

    @GetMapping("/sync")

    public String syncFromDb() {

        return ragService.syncFromDb();

    }

    /** 诊断接口:查看向量库状态 */

    @GetMapping("/status")

    public Map<String, Object> status() {

        Map<String, Object> result = new LinkedHashMap<>();

        result.put("向量库文档总数", mysqlVectorStore.count());

        result.put("提示", "如果总数为 0,请先调用 GET /ollama/rag/sync 或重启应用");

        return result;

    }

}

3.5 SSE 流式对话 Controller

标准 SSE 接口实现,分段推送大模型输出,前端持续监听打印回答内容,附带跨域、编码处理逻辑。

最终前端展示的效果图如下:

现有短板

MySQL 无 ANN 向量索引,十万条以上文档向量检索速度大幅下降;

文本切片规则简单,未做递归分割、重叠分块优化,长文档召回精度一般;

无向量缓存,重复提问会重复计算向量,存在性能浪费;

未实现文档增量更新、向量批量刷新能力。

后续迭代优化方向

海量数据场景:拆分存储架构,MySQL 存业务原文,引入 Milvus 做高性能向量检索;

检索优化:增加 Redis 缓存高频问题向量结果,提升重复问答响应速度;

文本处理:完善递归文本分割、关键词增强检索,提升 RAG 召回准确率;

功能扩展:接入文档上传解析(PDF/Word 自动切片入库)、多轮对话记忆、角色权限控制。

七、总结

对于中小企业内部低并发知识库场景,MySQL9.7 原生向量完全可以替代独立向量数据库,大幅简化系统架构,降低运维成本;

SpringAI 大幅降低 Java 后端接入大模型的开发门槛,但版本迭代快,2.0 存在大量不兼容改动,开发时需要对照官方最新文档;

私有化 Ollama+MySQL 的 RAG 方案,适合内网、无外网环境的企业业务 AI 落地,是传统后端向 AI 业务拓展低成本实践路径;

本次实战完整覆盖「文档存储→向量化→向量检索→大模型问答→流式前端交互」整条 RAG 链路,弥补传统 Java 后端缺少 AI 落地实战经验的短板,相关技术、选型思路、踩坑记录均可用于面试沟通。

完整项目开源地址:https://gitee.com/danruoshui/springai-ollama-rag.git;                                https://github.com/316959108/springai-ollama-rag.git

配套资料:MySQL9.7 向量官方文档、SpringAI2.0 官方参考文档;

欢迎交流后端 AI 落地相关问题。