
很多 Java 后端开发者想把大模型接入现有业务,第一反应往往是去学 Python、看 LangChain。但是真正放到生产环境里,多数据源管理、微服务鉴权、事务一致性这些工程问题,用 Python 桥接一套不仅运维成本翻倍,而且很难与现有的 Spring Boot 技术栈打通。
实际上,如果你只需要做企业知识库或者智能客服,检索增强生成(RAG) 是目前成本最低、确定性最高的方式。Spring 官方推出的 Spring AI,把大模型交互抽象成了我们最熟悉的套路:就像操作 `JdbcClient` 或 `RestClient` 一样,通过统一的接口来操作模型和向量数据库。
下面我结合线上项目的实际落地过程,直接讲讲怎么用 Spring AI 构建一套能跑在生产环境的企业级 RAG 系统。
核心步骤一:文档清洗与分块(ETL 阶段)
很多项目检索不准确,问题往往不在模型,而是在最前面的文档处理上。先做文档加载,然后做文本切分,最后做向量入库,这是标准的数据处理流程。
Spring AI 提供了 `DocumentReader`、`DocumentTransformer` 和 `DocumentWriter` 三个核心接口。
1.先做文档读取:对于 Word、PDF 等复杂格式,使用 `TikaDocumentReader`;对于技术文档或 Markdown,直接用 `MarkdownDocumentReader`。
2.然后做文本分块:不能按字数生硬截断。如果一句话被切成两半,向量计算出来的语义就会彻底失真。推荐使用 `TokenTextSplitter`。
在配置切分参数时,建议根据不同业务文档做精细化配置:
| 切块策略 | 推荐块大小(Chunk Size) | 重叠大小(Overlap) | 适用场景 | 优缺点对比 |
|---|---|---|---|---|
| 细粒度切块 | 200 ~ 300 Tokens | 30 ~ 50 Tokens | 常见问题解答(FAQ)、参数规格表 | 检索命中率高,但是上下文容易缺失 |
| 平衡切块 | 500 ~ 800 Tokens | 50 ~ 100 Tokens | 企业规章制度、操作手册、API 文档 | 企业级知识库首选,兼顾语义完整度与召回准确度 |
| 粗粒度切块 | 1200 ~ 1500 Tokens | 150 ~ 200 Tokens | 深度技术报告、长篇案例分析 | 上下文完整,但是会引入无关噪音,增加 Token 消耗 |
避坑要点:重叠区域(Overlap)必须保留。如果完全不重合,处于切分边界的关键实体和因果关系就会丢失。通常将 Overlap 设置为块大小的 10% 到 15%。
核心步骤二:向量存储选型
向量数据库负责把切好的文本块变成 Embedding 向量并做相似度查询。Spring AI 抽象了统一的 `VectorStore` 接口,写代码时面对的是统一 API,换底层数据库只需要改 Maven 依赖和 YAML 配置。
目前主流的存储方案有以下几种:
| 选型方案 | 查询延迟 | 运维成本 | 事务与元数据过滤能力 | 生产建议 |
|---|---|---|---|---|
| PostgreSQL (PGVector) | 中等(10~50ms) | 低(复用现有 PG) | 极强(原生 SQL 联合查询与过滤) | 中小规模首选。数据量在五百万以下,直接用原有 PG 加装扩展,零新增运维组件。 |
| Milvus | 低(<10ms) | 高(需独立维护集群) | 中等(元数据过滤支持标量字段) | 亿级大规模向量检索首选。适合专职搜索团队和高并发场景。 |
| Redis (Vector Search) | 极低(<5ms) | 低(复用现有 Redis) | 较弱(内存成本高,过滤较简单) | 适合高频热点知识检索、会话级临时记忆缓存。 |
| Elasticsearch | 中等(15~60ms) | 中等(已有 ES 体系) | 强(天然支持 BM25 与向量混合) | 团队已重度依赖 ES 检索时,可直接平滑扩充密集向量能力。 |
如果你的业务原本就用 PostgreSQL,强烈建议直接上 PGVector。因为企业知识库必须做权限隔离,PGVector 允许你直接在 SQL 里把业务权限表、组织架构和向量距离联合过滤,省去了在应用层拼装过滤器的麻烦。
核心步骤三:配置检索与 Advisor
单纯把用户问题拿去做向量检索,在企业级场景往往不够用。因为用户输入的查询经常包含具体业务专有名词、工单编号或拼写错误,纯向量比对经常会出现语义漂移。
Spring AI 的核心设计是 Advisor(切面增强器)。它在调用大模型之前,自动拦截请求、做向量检索、把召回的文档塞进 Prompt,再发给模型。
在具体实现中,要按以下顺序组装:
1.先做元数据过滤:防止跨租户越权。使用 `FilterExpressionBuilder` 给每次请求绑定租户标识或部门 ID。例如:
Filter.Expression filter = new FilterExpressionBuilder()
.eq("tenant_id", currentTenantId)
.build();
2.然后做混合检索:不能单靠向量余弦相似度。先把用户查询分流:一边走 PGVector 的相似度匹配,一边走关系型数据库或 ES 的关键字精确搜索(BM25),最后使用互惠排名融合(RRF)算法计算最终得分。这样做更好,因为业务用户搜索特定错误码或人员名称时,字面匹配比模糊的语义关联更可靠。
3.加入重排(Rerank)机制:向量召回往往取 Top 20 个候选块,但是大模型上下文窗口塞太多文档会产生“中间迷失”现象。把候选块扔给一个轻量的本地 Cross-Encoder 重排模型(例如 bge-reranker),打分后只筛选出 Top 3 到 Top 5 真正相关的文本送入 Prompt。
4.通过 ChatClient 绑定 Advisor:
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(
new QuestionAnswerAdvisor(vectorStore, SearchRequest.builder()
.topK(5)
.similarityThreshold(0.72) // 核心阈值控制
.filterExpression(filter)
.build())
)
.build();
关键参数提示:相似度阈值(similarityThreshold)务必配置在 0.70 到 0.75 之间。如果设置太低,会引入大量无关内容干扰模型判断;如果设置高于 0.85,稍微换个说法就会检索为空。
生产落地的三个核心避坑点
从跑通 Demo 到实际上线,通常会遇到以下三个生产问题:
1.大模型幻觉与拒绝回答策略
很多业务方无法接受模型胡编乱造。你需要在 Prompt 模板中加入显式约束:“仅依据以下给出的参考文档回答问题。如果文档中未提及答案,请直接回答‘知识库中未找到相关信息’,严禁自行推测。”这样做能把企业场景下的虚假输出概率压到最低。
2.流式输出(SSE)与异步阻断
知识库回答通常较长,如果等模型全部生成完再返回,接口耗时可能高达数秒甚至十几秒,前端体验极差。必须使用 Flux 响应式流式输出。
Spring AI 的 `ChatClient.stream()` 原生支持 `Flux`,直接对接 Spring MVC 的 `ServerSentEvent` 或 WebFlux,模型吐出一个字就往前端推一个字,把首字响应延迟(TTFT)控制在 800ms 以内。
3.模型调用的超时与降级保护
大模型 API 外部依赖非常不稳定。网关超时、限流、网络抖动经常发生。绝对不能裸调。必须在 Spring Boot 中配合 Resilience4j,为每一次 `ChatClient` 调用配置严格的超时时间(建议连接超时 3 秒,读取超时 30 秒)、线程隔离以及降级兜底逻辑。当模型无响应时,直接返回缓存结果或转接人工通道。
后端落地大模型其实并不神秘。不要被各种新名词吓住,剥离掉表面的概念,其本质就是一个带有数据转换管线(ETL)、外挂特殊索引数据库(Vector)、并结合切面机制(AOP/Advisor)的标准 Spring 架构。只要严格把控文档预处理质量、配好混合检索与元数据过滤,用熟悉的 Java 编程方式,完全能稳定承载起企业级的智能业务需求。
原创文章,作者:七点互动,如若转载,请注明出处:https://ai.qidianhudong.com/aikonw/3938.html