☰
Java工程师AI落地实战:Spring Boot整合RAG与AI Agent
2026/10/1 15:11:42 网站建设 项目流程

1. 为什么 Java 工程师做 AI,真正的战场在「落地」

先把结论摆在最前面:Java 工程师切入 AI 领域,最现实、最有价值、也最容易做出成绩的方向,是把大模型能力落地到业务系统里,而不是去卷模型训练。训练大模型这件事,拼的是 GPU 集群、数据规模、算法团队和烧钱能力,这跟绝大多数 Java 工程师的日常技能栈几乎不重叠。但落地不一样,落地拼的是工程能力、系统设计、稳定性保障、接口抽象、性能调优——这些恰恰是 Java 工程师干了十几年的老本行。

我身边有不少做 Java 的朋友,这两年一直焦虑,觉得 AI 来了自己要被淘汰。但实际情况是,我接触到的项目里,真正缺人的岗位不是「训练大模型的算法工程师」,而是「能把大模型接进现有业务系统的后端工程师」。一个典型的 RAG 知识库系统,模型部分可能只占 20% 的工作量,剩下 80% 全是工程活:文档解析、切片策略、向量存储、检索排序、接口封装、缓存、限流、监控、灰度发布。这些活,Java 工程师闭着眼睛都能干,而且干得比算法同学更稳。

所以这篇文章我想聊的不是「怎么训练一个大模型」,而是一个 Java 工程师如何用 Spring Boot 这套熟悉的技术栈,把大模型、RAG、AI Agent 这些能力真正落地到生产系统里。内容会覆盖整体架构思路、核心技术点拆解、完整实操流程、常见坑和排查技巧。适合有 Java 基础、想往 AI 应用方向转型的开发者,也适合正在做 AI 项目但被工程问题卡住的同学。看完你至少能明白:这条路怎么走、坑在哪里、哪些东西值得深挖。

2. 整体架构设计与技术选型思路

2.1 为什么 Java 做 AI 落地反而有优势

很多人有个误区,觉得 AI 项目就该用 Python。这个认知在「训练」阶段是对的,但在「应用落地」阶段就未必了。原因很简单:企业里绝大多数业务系统是 Java 写的。你的订单系统、用户系统、权限系统、风控系统,全是 Spring Boot 那一套。如果 AI 能力要用 Python 单独起一个服务,那就要面对跨语言调用、数据一致性、部署运维、团队协作等一系列额外成本。

我做过一个对比,同样一个 RAG 问答功能,用 Python 单独做服务再让 Java 调用,和直接用 Java 全栈实现,后者的维护成本低太多了。因为:

  • 技术栈统一:不用维护两套依赖、两套部署流程、两套监控体系。
  • 复用现有能力:你现有的鉴权、日志、配置中心、链路追踪,直接就能用。
  • 团队协作顺畅:后端团队不用为了 AI 功能专门学一套 Python 工程体系。
  • 性能可控:JVM 的成熟度、GC 调优、线程模型,都是经过大规模验证的。

当然,这不是说 Python 没用。模型微调、实验性探索、数据处理脚本,Python 依然是首选。但面向生产的服务层,Java 是更稳的选择。这就是我说的「落地」机会——不是跟算法团队抢训练,而是把训练好的能力稳稳地接进业务。

2.2 一套典型的 Java AI 落地架构长什么样

我拿一个实际做过的 RAG 知识库项目举例,整体架构大致分四层:

第一层是接入层,就是 Spring Boot 对外提供的 REST 接口。这一层负责参数校验、鉴权、限流、会话管理。这里有个常见问题:AI 接口该放在现有服务里还是单独起服务?我的经验是,如果 QPS 不高、和业务耦合紧,就放在现有服务里;如果 QPS 高、需要独立扩缩容,就单独起一个 AI 服务。判断标准是看它会不会拖累主业务。

第二层是编排层,这是 Java 工程师的核心战场。它负责把用户的问题、检索到的上下文、系统提示词组装成最终发给大模型的 prompt,然后处理模型的流式返回。这一层用 Spring Boot 的 Service 层就能实现,配合 LangChain4j 这类框架会更省事。

第三层是检索层,也就是 RAG 的核心。它包含向量化、向量存储、相似度检索、重排序。向量库可以选 Milvus、Qdrant、PgVector,如果数据量不大,PgVector 直接挂在现有 PostgreSQL 上最省事。

第四层是模型层,可以是本地部署的模型,也可以是调用外部 API。这一层对 Java 来说是黑盒,你只需要封装一个统一的客户端接口,把不同模型的差异屏蔽掉。

这四层里,第二层和第三层是 Java 工程师能发挥最大价值的地方,也是决定一个 AI 应用好不好用的关键。模型本身大家用的都差不多,但检索质量、prompt 编排、上下文管理,这些工程细节才是拉开差距的地方。

2.3 技术选型:LangChain4j 还是自己撸

这是很多人纠结的问题。我的建议是:先用 LangChain4j 快速跑通,再根据需求决定要不要自己实现核心部分。

LangChain4j 是 Java 生态里比较成熟的 LLM 应用框架,它把文档加载、切片、向量化、检索、对话记忆这些常用能力都封装好了。用它做原型,一两天就能跑出一个能用的 RAG demo。但它的抽象层比较厚,遇到性能问题或者需要精细控制的时候,你会觉得束手束脚。

我自己的做法是:用 LangChain4j 做文档处理和向量化,但检索和编排部分自己写。因为检索策略、重排序逻辑、prompt 组装这些,往往需要针对具体业务做大量定制,用框架反而绕。而且自己写这部分,代码量其实不大,可控性却高很多。

选型的时候还要考虑一个现实问题:团队的学习成本。如果团队里没人用过 LangChain4j,那引入它反而增加沟通成本。这时候不如用最朴素的 HTTP 客户端 + 自己封装,代码直白,谁都能看懂。

3. 核心细节解析与实操要点

3.1 RAG 的瓶颈到底在哪里

热词里有个「rag瓶颈」,这个问题问得很实在。我做了几个 RAG 项目后,最大的体会是:RAG 的瓶颈几乎从来不在模型,而在检索质量。

具体来说,瓶颈通常出在这几个环节:

第一个是文档切片策略。很多人上来就用固定长度切片,比如每 500 字切一段。这在结构化的文档上还行,但遇到表格、代码、多级标题的文档就废了。我踩过的坑是:一份技术文档里的配置示例被从中间切断,检索出来的片段缺了关键参数,模型给出的答案就是错的。后来我改成按语义结构切片——按标题层级切、按段落切、表格单独成块,效果立刻好很多。

第二个是向量化的质量。同一个文本,用不同的 embedding 模型,检索效果差异巨大。而且中文场景下,很多英文模型效果并不好。选 embedding 模型的时候,一定要用你自己的业务数据做测试,别只看榜单。

第三个是检索的召回和排序。单纯靠向量相似度检索,经常召回一堆「看起来像但没用」的片段。我的做法是混合检索:向量检索 + 关键词检索(BM25),两路结果合并后再用重排序模型精排。这一套下来,召回质量能提升一大截。

第四个是上下文窗口的管理。检索回来一堆片段,不能全塞给模型,否则又慢又贵还容易跑偏。需要做去重、截断、按相关性排序,只保留最相关的几条。

提示:RAG 调优的顺序应该是「先调切片,再调 embedding,最后调检索策略」。很多人一上来就换模型,其实前面两步没做好,换什么模型都白搭。

3.2 文档切片:看似简单,实则最考验功力

切片这件事,我单独拿出来讲,因为它太重要了。一个好的切片策略,能让 RAG 效果提升 30% 以上。

先说切片长度。太短,语义不完整,检索出来答非所问;太长,噪声多,还会挤占上下文窗口。我的经验值是300 到 800 个 token 之间,具体看文档类型。技术文档可以短一点,因为信息密度高;叙述性文档可以长一点,因为需要上下文。

再说重叠策略。相邻切片之间保留一定的重叠(比如 10% 到 20%),可以避免关键信息正好被切在边界上。这个细节很多人忽略,但实测下来很有用。

然后是结构化处理。对于 Markdown、HTML 这类有结构的文档,一定要利用它的结构。我的做法是:

  • 按标题层级切分,每个最小标题下的内容作为一个候选块。
  • 表格单独处理,转成文本描述或者保留原格式。
  • 代码块单独成块,不要和正文混在一起。
  • 列表项如果太长,可以拆开,但要保留父级上下文。

这里有个技巧:给每个切片加上「元数据」,比如它来自哪个文档、哪个章节、什么类型。检索的时候可以按元数据过滤,比如只在某个文档范围内检索。这在多知识库场景下特别有用。

3.3 向量库选型:别一上来就上重型武器

向量库的选择,很多人一上来就想用 Milvus 这种专业级的。但我的建议是:先看数据量,再看团队运维能力。

如果数据量在百万级以下,PgVector 是最省事的选择。它直接挂在 PostgreSQL 上,你现有的数据库运维体系就能覆盖,不用额外学一套东西。而且它支持 SQL 过滤 + 向量检索混合查询,这在业务场景里非常实用。

如果数据量到了千万级,或者需要高并发、低延迟,那可以考虑 Qdrant 或 Milvus。Qdrant 部署简单,API 友好;Milvus 功能全,但运维复杂。

我做过一个对比,供参考:

向量库适用数据量部署复杂度混合查询推荐场景
PgVector百万级以下低强已有 PG,数据量不大
Qdrant千万级中中独立向量服务,追求易用
Milvus亿级高中大规模、高并发

选型的时候还要考虑一个点:你的向量维度。不同 embedding 模型输出的维度不一样,有的 768 维,有的 1536 维,有的 3072 维。维度越高,存储和检索成本越高。选模型的时候要权衡效果和成本。

3.4 Prompt 编排:Java 工程师的隐形战场

Prompt 编排听起来像是「写提示词」,好像没什么技术含量。但实际上,在生产系统里,prompt 编排是一套完整的工程问题。

首先是模板管理。prompt 不能硬编码在代码里,否则改一个字就要重新发版。我的做法是把 prompt 模板放在配置中心或者数据库里,支持热更新。同时给每个模板加版本号,方便回滚和 A/B 测试。

其次是上下文组装。检索回来的片段怎么拼进 prompt,顺序怎么排,要不要加引用标记,这些都有讲究。我的经验是:

  • 最相关的片段放在最前面和最后面,因为模型对首尾内容更敏感。
  • 每个片段加上来源标记,方便模型引用,也方便用户溯源。
  • 明确告诉模型「只根据提供的上下文回答,不知道就说不知道」,减少幻觉。

然后是输出格式控制。生产系统里,模型的输出往往需要结构化,比如 JSON。这时候要在 prompt 里明确格式要求,同时做好解析和容错。模型偶尔会输出格式不对的内容,代码里必须有兜底逻辑。

最后是流式输出。用户体验上,流式输出比等全部生成完再返回好太多。Spring Boot 里可以用 SSE(Server-Sent Events)或者 WebSocket 实现。SSE 更简单,适合单向推送;WebSocket 更灵活,适合双向交互。

4. 完整实操流程与核心环节实现

4.1 环境准备与依赖引入

先说一下基础环境。JDK 建议用 17 或 21,这两个是 LTS 版本,生态支持好。Spring Boot 用 3.x,因为 3.x 对虚拟线程的支持更好,处理大量 IO 等待的 AI 请求时优势明显。

Maven 依赖这块,核心是这几个:

<dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j</artifactId> <version>0.35.0</version> </dependency> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-open-ai</artifactId> <version>0.35.0</version> </dependency> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-pgvector</artifactId> <version>0.35.0</version> </dependency>

如果你用 PgVector,还需要 PostgreSQL 的驱动和 PgVector 扩展。数据库里要先执行CREATE EXTENSION vector;开启向量支持。

注意:LangChain4j 版本迭代很快,API 经常变。引入之前先看官方文档对应版本的用法,别照着旧教程抄,容易踩坑。

4.2 文档入库:从原始文件到向量

文档入库是 RAG 的第一步,也是最容易被低估的一步。完整流程是:加载 → 解析 → 切片 → 向量化 → 存储。

加载环节,要支持多种格式:PDF、Word、Markdown、HTML、纯文本。PDF 解析是最麻烦的,尤其是扫描件和复杂排版。我的建议是,如果 PDF 质量差,先用 OCR 处理一遍,别指望解析库能搞定一切。

解析环节,把文件内容转成纯文本,同时保留结构信息。比如 Markdown 的标题层级、HTML 的标签结构,这些信息在切片时要用到。

切片环节,按前面说的策略来。这里给一段示意代码:

DocumentSplitter splitter = DocumentSplitters.recursive( 500, // 每片最大 token 数 50, // 重叠 token 数 new OpenAiTokenizer() ); List<TextSegment> segments = splitter.split(document);

向量化环节,调用 embedding 模型把文本转成向量。这一步是 IO 密集型的,批量处理的时候要注意并发控制,别把模型服务打挂了。

存储环节,把向量和原文、元数据一起存进向量库。元数据的设计很关键,至少要包含:文档 ID、来源、章节、类型、创建时间。

4.3 检索实现:混合检索 + 重排序

检索是 RAG 的核心。我推荐的方案是混合检索 + 重排序,分三步走。

第一步,向量检索。把用户问题向量化,在向量库里找最相似的 Top K 个片段。K 一般取 20 到 50,宁多勿少,后面还有精排。

第二步,关键词检索。用 BM25 或者数据库的全文检索,找包含关键词的片段。这一步能补上向量检索漏掉的精确匹配。

第三步,合并重排序。把两路结果合并去重,然后用重排序模型(比如 cross-encoder)精排,取 Top N 个(N 一般 3 到 5)作为最终上下文。

这里有个细节:重排序模型的选择。如果不想引入额外的模型服务,可以用简单的规则重排,比如按向量相似度 + 关键词命中数加权。效果不如模型,但胜在简单。

// 混合检索示意 List<TextSegment> vectorResults = vectorStore.search(question, 30); List<TextSegment> keywordResults = keywordSearch(question, 30); List<TextSegment> merged = mergeAndDeduplicate(vectorResults, keywordResults); List<TextSegment> reranked = reranker.rerank(question, merged, 5);

4.4 对话编排与流式返回

检索到上下文后,就要组装 prompt 发给模型了。这一步的核心是对话记忆管理。

多轮对话场景下,不能把历史对话全塞进去,否则上下文会爆。我的做法是:

  • 保留最近 N 轮完整对话。
  • 更早的对话做摘要,压缩成一段简短描述。
  • 检索到的知识片段每轮都重新检索,不缓存。

流式返回用 SSE 实现,Spring Boot 里用SseEmitter就行。关键点是处理好异常和超时,模型服务不稳定的时候,要能优雅降级。

@GetMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public SseEmitter chatStream(@RequestParam String question) { SseEmitter emitter = new SseEmitter(60_000L); executor.execute(() -> { try { // 检索 + 组装 prompt String context = retrieveContext(question); // 流式调用模型 streamingChatModel.generate(prompt, new StreamingResponseHandler() { @Override public void onNext(String token) { emitter.send(token); } @Override public void onComplete() { emitter.complete(); } @Override public void onError(Throwable error) { emitter.completeWithError(error); } }); } catch (Exception e) { emitter.completeWithError(e); } }); return emitter; }

4.5 监控与可观测性

AI 应用和普通应用最大的区别是:它的输出是不确定的。所以监控不能只看接口成功率,还要看输出质量。

我一般会埋这几类指标:

  • 性能指标:检索耗时、模型调用耗时、首 token 延迟、总响应时间。
  • 质量指标:检索命中率、用户反馈(点赞/点踩)、答案引用率。
  • 成本指标:token 消耗量、调用次数、按业务维度的成本分摊。

这些指标用 Micrometer + Prometheus + Grafana 就能搞定。质量指标需要业务侧配合,比如加个反馈按钮。

提示:AI 应用的日志要特别设计。除了常规的请求日志,还要记录检索到的片段、组装的 prompt、模型的原始输出。出问题的时候,这些是排查的关键。

5. 常见问题与排查技巧实录

5.1 检索不准:从切片到重排序逐层排查

检索不准是最常见的问题。我的排查顺序是:

先看切片。把检索到的片段打印出来,看看是不是语义完整。如果片段被切得七零八落,那就是切片策略的问题。

再看 embedding。用几个典型问题测试,看看召回的片段是不是真的相关。如果明显不相关,可能是 embedding 模型不适合你的领域。

然后看检索策略。单纯向量检索效果不好,就上混合检索。混合检索还不行,就加重排序。

最后看 prompt。有时候检索没问题,是 prompt 没引导好,模型没用上检索到的内容。

我整理了一个速查表:

现象可能原因排查方向
召回片段语义不完整切片策略不当调整切片长度和重叠
召回片段不相关embedding 模型不匹配换模型或微调
精确匹配漏召回纯向量检索的局限加关键词检索
相关片段排后面排序策略问题加重排序模型
模型没用检索内容prompt 引导不足优化 prompt 模板

5.2 响应慢:定位瓶颈的三个维度

AI 应用响应慢,通常出在三个地方:检索、模型调用、网络。

检索慢,一般是向量库的问题。检查索引有没有建好,数据量是不是太大,需不需要分片。

模型调用慢,看是模型本身慢还是网络慢。本地模型看 GPU 利用率,外部 API 看网络延迟。首 token 延迟和总生成时间要分开看,前者影响体验,后者影响总耗时。

网络慢,如果是调用外部 API,考虑加个就近的代理节点,或者做请求合并。

优化手段上,缓存是最有效的。相同或相似的问题,直接返回缓存结果。语义缓存(用向量相似度判断问题是否相似)比精确匹配缓存命中率高很多。

5.3 幻觉问题:让模型「知之为知之」

幻觉是 RAG 要解决的核心问题之一。但完全消除不可能,只能尽量减少。

我的做法是:

  • prompt 里明确约束:「只根据以下上下文回答,上下文没有的信息,明确说不知道」。
  • 要求引用来源:让模型在答案里标注引用了哪个片段,方便用户核实。
  • 设置置信度阈值:检索相似度低于阈值时,直接返回「没有找到相关信息」,不调模型。
  • 后置校验:对模型输出做检查,比如答案里的关键实体是否出现在上下文中。

这里有个经验:降低 temperature 能减少幻觉,但会让回答变得死板。生产环境一般设 0.1 到 0.3 之间,具体看场景。

5.4 成本控制:token 就是钱

如果调用外部 API,token 消耗直接等于成本。控制成本的手段有:

  • 精简上下文:只传最相关的片段,别一股脑全塞。
  • 压缩历史对话:老对话做摘要,别原样保留。
  • 缓存:相同问题不重复调用。
  • 分级模型:简单问题用小模型,复杂问题用大模型。
  • 限制输出长度:设置 max_tokens,避免模型啰嗦。

我做过统计,做好缓存和上下文精简后,token 消耗能降 40% 以上。这在规模化场景下是实打实的成本节省。

5.5 并发与稳定性:别让 AI 拖垮主业务

AI 接口的特点是慢且不稳定。如果不做隔离,很容易拖垮整个服务。

我的做法是:

  • 线程池隔离:AI 调用用独立的线程池,不和主业务共用。
  • 熔断降级:模型服务不可用时,快速失败,返回兜底答案。
  • 限流:按用户或按接口限流,防止被刷。
  • 超时控制:设置合理的超时时间,别让请求无限等待。

Spring Boot 里用 Resilience4j 或者 Sentinel 都能实现这些。关键是别让 AI 的慢影响到主业务的快。

6. 一些踩坑之后的个人体会

做了一段时间 Java + AI 落地,有几个体会想分享。

第一,别被「AI」两个字唬住。剥开外壳,它就是一个普通的后端系统,只不过依赖的服务从数据库变成了模型。你现有的工程经验,90% 都用得上。

第二,效果调优是持续过程,不是一锤子买卖。上线只是开始,后面要根据用户反馈不断调切片、调检索、调 prompt。建立一个快速迭代的机制,比一次做到完美更重要。

第三,数据质量决定上限。再好的模型,喂进去垃圾文档,出来的也是垃圾。文档入库前的清洗和结构化,值得花大力气。

第四,保持对新技术的好奇,但别盲目追新。AI 领域每天都有新框架、新模型,但生产系统要的是稳定。选型的时候,成熟度比先进性更重要。

最后分享一个我常用的小技巧:建一个「问题集」,把用户常问的问题和期望答案整理成测试集。每次调整检索或 prompt 后,跑一遍测试集,看效果是变好还是变差。这比凭感觉调参靠谱得多。这个测试集不用很大,几十条就够,但能帮你避免很多「改了一个地方,另一个地方坏了」的尴尬。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询