
1. 为什么 Java 开发者转 AI 有天然优势先把一个误区说清楚Java 开发者入门 AI不是从零开始学一门新语言而是把已有的工程能力迁移到一个新场景里。我身边不少做 Spring Boot 后端的朋友一听到“AI”“大模型”“RAG”就觉得是 Python 的天下自己插不上手。实际情况恰恰相反——当 AI 应用从“跑个 demo”走向“上生产”Java 那套东西反而成了稀缺能力。你想想一个 RAG 知识库项目真正难的地方在哪不是调一次模型接口而是文档怎么切、向量怎么存、检索命中率怎么调、多轮对话上下文怎么管、并发请求怎么限流、模型超时怎么降级、密钥怎么管理、日志怎么追踪。这些全是后端工程师每天在干的事。模型调用本身说白了就是一次 HTTP 请求Java 用HttpClient或者框架封装的客户端都能搞定。所以这篇内容我打算按“一个 Java 后端如何一步步把 AI 能力接进自己项目”的思路来写。核心关键词会围绕Java、Spring AI、LangChain4j、RAG、AI Agent这几个展开。适合两类人看一类是有 Java 基础、想往 AI 方向靠的后端另一类是已经在做业务系统、想把 AI 集成进去但不知道从哪下手的开发者。哪怕你只写过 CRUD只要理解 Spring Boot 的套路后面的内容都能跟上。我自己的路径大概是这样先用 Spring AI 跑通一次对话理解“模型调用”这件事的本质然后引入 LangChain4j 做 RAG把公司文档变成可检索的知识库最后再往 Agent 方向走让模型能调用工具。这条路我踩过不少坑下面按阶段拆开讲。2. 入门前的认知准备与技能盘点2.1 你已有的 Java 功底哪些能直接用很多 Java 开发者低估了自己。你在做业务系统时积累的这些能力在 AI 应用里几乎原样可用依赖注入与配置管理Spring 的Bean、ConfigurationProperties用来管理模型客户端、向量库连接、API Key比 Python 脚本里到处写全局变量规范得多。HTTP 客户端与重试模型接口本质是 HTTP你熟悉的超时、重试、熔断Resilience4j直接套上去。线程池与异步批量 embedding、并发检索CompletableFuture和虚拟线程JDK 21能显著提速。数据访问向量库虽然有专门的 SDK但很多场景你还是要和 MySQL、Redis 打交道存会话、存元数据、做缓存这些是你的主场。可观测性Micrometer、Actuator、链路追踪AI 应用上线后最缺的就是这些。反过来说你需要补的主要是三块提示词工程的基本感觉、向量与检索的原理、AI 框架的 API 习惯。前两块是概念第三块是动手都不难。2.2 需要补的三块新知识第一块是提示词。别把它想玄乎本质就是“怎么把任务描述清楚”。你要学会的是给模型设定角色、给几个示例few-shot、约束输出格式比如要求返回 JSON。这些在 Java 里就是拼字符串但拼得好不好直接决定效果。第二块是向量与检索。核心概念就几个文本经过 embedding 模型变成一串浮点数向量语义相近的文本向量距离近检索就是找距离最近的几条。理解了这个RAG 就懂了一半。至于余弦相似度、HNSW 索引这些用到再查。第三块是框架 API。Spring AI 和 LangChain4j 的设计哲学不同前者更“Spring 味”后者更“链式编排”。下面会分别讲。提示不要一上来就啃论文。先把一个能跑的最小闭环做出来遇到不懂的概念再回头查效率高得多。2.3 环境与工具清单我建议的最小环境是这样工具用途备注JDK 17 或 21运行环境21 的虚拟线程对并发调用友好Maven / Gradle构建按团队习惯选Spring Boot 3.x应用骨架Spring AI 要求 3.2Ollama本地跑模型零成本试错不依赖外部服务Docker跑向量库Qdrant、Milvus 都有官方镜像IDE开发IDEA 对 Spring 支持最好本地先用 Ollama 拉一个小模型比如 qwen 系列的小参数版本跑通对话等逻辑验证完再换成线上模型服务。这样调试成本最低也不会因为调用额度心疼。3. 框架选型Spring AI 还是 LangChain4j3.1 两个框架的定位差异这是被问得最多的问题。我的结论是它们不是二选一而是看你的项目形态。Spring AI 的定位是“把 AI 能力做成 Spring 生态里的一等公民”。它的 API 风格和你写JdbcTemplate、RestTemplate一模一样自动配置、starter 依赖、ChatClient链式调用。如果你的项目本来就是 Spring Boot引入 Spring AI 几乎零学习成本配置写在application.yml里客户端注入进来就能用。LangChain4j 的定位更偏“AI 应用编排”。它把 RAG、Agent、工具调用这些模式抽象得很细AiServices可以用接口 注解的方式声明一个 AI 服务RetrievalAugmentor把检索流程拆成可替换的组件。做复杂 RAG 和 Agent 时它的表达力更强。3.2 选型对照表维度Spring AILangChain4j上手成本低Spring 开发者无缝中需要理解其抽象与 Spring 集成原生自动配置良好需手动装配RAG 能力有够用更细组件可替换Agent / 工具调用支持支持模式更丰富社区活跃度高官方维护高社区驱动适合场景业务系统集成 AI独立 AI 应用、复杂编排3.3 我的实际选择建议如果你只是想在现有系统里加个“智能问答”“文档摘要”“字段抽取”直接用 Spring AI别折腾。它的ChatClient加Advisor机制足够覆盖大部分需求。如果你要做的是一个独立的 RAG 知识库产品检索流程要反复调优或者要做多步 Agent 编排LangChain4j 的组件化设计会让你少写很多胶水代码。我做过一个项目就是两者混用Spring AI 管对话入口和配置LangChain4j 管检索链路各取所长。注意不要因为“哪个更火”就选哪个。框架是工具先明确你要解决的问题再倒推选型。4. 第一阶段用 Spring AI 跑通第一次对话4.1 依赖与配置先建一个标准的 Spring Boot 3.2 项目加依赖dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-ollama-spring-boot-starter/artifactId /dependency然后在application.yml里配置spring: ai: ollama: base-url: http://localhost:11434 chat: options: model: qwen2.5:7b temperature: 0.7temperature控制输出的随机性做事实问答调低0.1~0.3做创意生成调高0.7~1.0。这个参数我调过很多次做知识库问答时设 0.2 左右最稳太高容易“编”。4.2 最小可运行代码RestController public class ChatController { private final ChatClient chatClient; public ChatController(ChatClient.Builder builder) { this.chatClient builder .defaultSystem(你是一个严谨的技术助手回答要准确不确定时明确说不确定。) .build(); } GetMapping(/chat) public String chat(RequestParam String message) { return chatClient.prompt() .user(message) .call() .content(); } }这段代码跑起来你就完成了从 0 到 1。defaultSystem设的是系统提示词相当于给模型定人设。别小看这一句它直接影响回答风格。我试过不设系统提示词模型回答会很“飘”加了约束之后稳定很多。4.3 流式输出与多轮对话实际产品里用户等不了模型一次性返回。流式输出用stream()替代call()GetMapping(value /chat/stream, produces MediaType.TEXT_EVENT_STREAM_VALUE) public FluxString chatStream(RequestParam String message) { return chatClient.prompt() .user(message) .stream() .content(); }多轮对话需要维护历史消息。Spring AI 提供了ChatMemory配合MessageChatMemoryAdvisor使用this.chatClient builder .defaultAdvisors(new MessageChatMemoryAdvisor(new InMemoryChatMemory())) .build();InMemoryChatMemory只适合单机测试生产环境要换成基于 Redis 或数据库的实现否则重启就丢历史多实例部署还会串会话。实操心得会话 ID 一定要显式传。默认按会话隔离如果你不传多个用户的对话可能混在一起。我早期就踩过这个坑测试时两个人同时问回答串了。5. 第二阶段用 LangChain4j 搭建 RAG 知识库5.1 RAG 到底在解决什么问题模型的知识有截止日期也不知道你公司的内部文档。RAG检索增强生成的思路很朴素先去你的知识库里找相关内容把找到的内容塞进提示词再让模型基于这些内容回答。打个比方模型是个博学但没看过你公司手册的顾问。RAG 就是每次提问前先派个助理去手册里翻出相关几页递给顾问顾问再结合这几页回答。这样答案既准确又可溯源。RAG 的完整链路是文档加载 → 切分 → 向量化 → 存储 → 检索 → 重排 → 拼提示词 → 生成。每一环都有坑下面逐个说。5.2 文档切分最容易被忽视的关键环节切分chunking决定了检索质量的上限。切太大检索出来的内容冗余模型抓不住重点切太小语义不完整检索不到。我的经验参数块大小500~800 字符。中文按字符算英文按 token 算。重叠块大小的 10%~20%。防止一句话被切断导致语义丢失。按语义切优先按段落、标题切别硬按固定长度切。LangChain4j 提供了DocumentSplitterDocumentSplitter splitter DocumentSplitters.recursive(600, 100); ListTextSegment segments splitter.split(document);recursive会优先按段落、句子切实在不行才按字符切比固定长度切分合理得多。5.3 向量化与存储向量化就是把文本变成向量。用 embedding 模型EmbeddingModel embeddingModel OllamaEmbeddingModel.builder() .baseUrl(http://localhost:11434) .modelName(nomic-embed-text) .build(); EmbeddingStoreTextSegment store new QdrantEmbeddingStore.Builder() .host(localhost) .port(6334) .collectionName(knowledge) .build();把切分后的片段存进去for (TextSegment segment : segments) { Embedding embedding embeddingModel.embed(segment).content(); store.add(embedding, segment); }注意embedding 模型和对话模型是两回事。embedding 模型只负责把文本转向量不能用来对话。选型时要看它的向量维度维度不同不能混用换模型意味着要重新灌库。5.4 检索与生成检索就是拿用户问题去向量库找最相似的几条Embedding queryEmbedding embeddingModel.embed(question).content(); ListEmbeddingMatchTextSegment matches store.findRelevant(queryEmbedding, 5);5是返回条数也就是 topK。这个值要调太小可能漏掉关键信息太大引入噪声。我一般从 5 开始试看命中情况再调。把检索结果拼进提示词String context matches.stream() .map(m - m.embedded().text()) .collect(Collectors.joining(\n\n)); String prompt 基于以下资料回答问题如果资料中没有相关信息明确说不知道不要编造。 资料 %s 问题%s .formatted(context, question);这句“不要编造”很关键。不加约束模型会拿自己的知识硬答RAG 就白做了。5.5 用 AiServices 简化编排LangChain4j 的AiServices可以把上面这套流程声明成一个接口interface KnowledgeAssistant { SystemMessage(基于提供的资料回答不确定就说不确定。) String answer(UserMessage String question); } KnowledgeAssistant assistant AiServices.builder(KnowledgeAssistant.class) .chatLanguageModel(chatModel) .contentRetriever(EmbeddingStoreContentRetriever.builder() .embeddingStore(store) .embeddingModel(embeddingModel) .maxResults(5) .minScore(0.7) .build()) .build();minScore是相似度阈值低于这个分数的结果直接丢弃。这个参数能有效过滤无关内容我一般设 0.6~0.75具体看 embedding 模型的分布。6. 第三阶段从 RAG 走向 AI Agent6.1 Agent 和 RAG 的区别RAG 是“查了再答”Agent 是“想清楚再决定做什么”。Agent 能调用工具查数据库、调接口、算数、发邮件。模型根据用户意图自己决定调哪个工具、调几次。举个场景用户问“上个月销售额多少和去年同期比怎么样”。RAG 答不了因为数据在数据库里。Agent 会先调“查销售额”工具拿到两个数再调“计算同比”工具最后组织语言回答。6.2 工具调用的实现LangChain4j 里用注解声明工具class SalesTools { Tool(查询指定月份的销售额) double querySales(P(月份格式 yyyy-MM) String month) { return salesRepository.sumByMonth(month); } }注册到 AiServicesSalesAssistant assistant AiServices.builder(SalesAssistant.class) .chatLanguageModel(chatModel) .tools(new SalesTools()) .build();模型会自动判断是否需要调用工具。这里有个坑工具描述要写清楚。模型靠描述决定调不调、怎么调。描述含糊模型要么不调要么传错参数。我一般把参数含义、格式、边界都写进Tool和P里。6.3 Agentic RAG两者结合实际项目里纯 RAG 和纯 Agent 都不够。Agentic RAG 的思路是把检索本身也做成一个工具让 Agent 决定要不要检索、检索几次、要不要换个关键词再检索。比如用户问“我们产品的退款政策是什么和竞品比有什么优势”。Agent 会先检索自家退款政策再检索竞品信息最后对比。这种多步检索固定流程的 RAG 做不了。实现上把ContentRetriever包装成一个Tool让模型自主调用。LangChain4j 的RetrievalAugmentor也支持更复杂的查询转换和路由但那是进阶内容先把基础跑通再说。7. 常见问题与排查技巧实录7.1 检索命中率低的排查思路这是 RAG 最常遇到的问题。按这个顺序查现象可能原因排查方法完全检索不到向量库没数据 / 维度不匹配查库记录数确认 embedding 模型一致检索到但无关切分太碎 / topK 太大调大块大小减小 topK相关但排后面相似度算法 / 无重排加 rerank 模型中文效果差embedding 模型不擅长中文换多语言或中文优化的模型我遇到最多的是切分问题。文档切得太碎一句话被切成三段检索出来语义不完整。后来改成按标题层级切效果立竿见影。7.2 模型“胡说”怎么治三个手段叠加用提示词约束明确要求“只基于资料回答不知道就说不知道”。降低 temperature事实类问答设 0.1~0.3。加引用要求模型在答案里标注来源片段方便核对。如果还不行说明检索环节有问题模型拿到的资料本身就不对先回去查检索。7.3 性能与成本优化缓存相同问题直接返回缓存结果embedding 结果也可以缓存。批量 embedding灌库时批量调用比一条条调快很多。异步检索多个检索源并行查用CompletableFuture合并。模型分级简单任务用小模型复杂任务用大模型。实操心得灌库是个体力活几万条文档跑 embedding 要很久。我一般先拿几百条验证流程确认切分和检索效果满意了再全量灌。否则切分策略一改全量重灌时间全浪费了。7.4 会话与并发问题多实例部署时InMemoryChatMemory会导致会话丢失。换成 Redis 存储key 用会话 ID。并发调用模型接口要注意限流模型服务通常有 QPS 限制超了会报错。用 Resilience4j 的RateLimiter和Retry包一层比裸调稳得多。8. 学习路线与资源建议8.1 分阶段路线图我把路线分成四段每段都有明确的产出物第一段1~2 周跑通对话。产出一个能对话的 Spring Boot 接口支持流式输出和多轮。第二段2~3 周搭 RAG。产出一个能基于本地文档回答的知识库检索命中率可接受。第三段2~3 周加工具调用。产出一个能查数据库、调接口的 Agent。第四段持续调优与工程化。产出可观测、可限流、可降级的生产级应用。别跳阶段。我见过有人第一段没跑通就上 RAG结果检索出问题根本分不清是检索的锅还是模型的锅。8.2 官方文档与社区Spring AI 和 LangChain4j 的官方文档都写得不错示例代码可以直接抄。遇到问题先查文档再查 GitHub Issues最后再问社区。这两个项目的迭代都很快注意看版本号不同版本 API 可能不兼容。8.3 我踩过的几个坑第一个坑是版本冲突。Spring AI 早期版本和 Spring Boot 3.2 有兼容问题升级时一定要看 release notes。第二个坑是 embedding 模型换版本。换模型后向量维度变了旧数据全部作废必须重灌。所以选 embedding 模型要慎重别频繁换。第三个坑是提示词里的变量注入。用户输入直接拼进提示词可能被“提示词注入”攻击比如用户输入“忽略以上指令”。要做输入清洗和转义别裸拼。9. 把 AI 能力真正落进业务系统技术跑通只是第一步真正难的是怎么和业务结合。我的体会是从高频、低风险、可验证的场景切入。高频意味着有真实需求低风险意味着出错影响可控可验证意味着你能判断效果好坏。比如内部文档问答、工单自动分类、日志摘要都是不错的起点。别一上来就做面向用户的智能客服出了问题兜不住。集成方式上我倾向于把 AI 能力做成独立的服务通过接口暴露给业务系统。这样模型升级、提示词调整都不影响主业务也方便单独扩容和监控。业务系统只管调接口不关心背后用的是哪个模型。监控这块至少要记录请求量、响应时间、token 消耗、检索命中率、用户反馈。没有这些数据你根本不知道系统好不好优化也无从下手。我一般用 Micrometer 打点接到现有的监控体系里和业务指标放一起看。最后说一句AI 应用的效果很大程度取决于数据质量。文档乱、格式杂、更新不及时再好的模型也救不了。花时间整理知识库比反复调提示词收益高得多。