尧图精选

Java开发者AI应用开发实战:Spring AI与LangChain4j从入门到RAG落地

🕒 发布时间:2026/10/1 19:19:39 📁 来源:尧图网络
1. 从写业务代码到跑通第一个AI应用Java人到底卡在哪做了七八年Java后端Spring Boot那套东西闭着眼睛都能写CRUD、事务、缓存、消息队列哪个不是手到擒来。可一提到AI很多人的第一反应是这玩意儿不是Python的天下吗。我身边不少同行都是这个状态业务代码写得飞起但面对大模型、向量数据库、RAG这些词总觉得隔着一层纱不知道从哪里下手。其实这个认知本身就是最大的障碍。Java在AI应用层的位置跟Python完全不是一回事。Python强在模型训练、算法实验、数据处理那是AI的研发侧。但AI要真正落地到企业系统里要跟订单、库存、用户、权限这些业务逻辑长在一起要保证高并发下的稳定性要能接入现有的微服务架构——这恰恰是Java的主场。你不需要去训练模型你需要的是把大模型的能力嵌进你已有的系统里这件事Java不但能做而且做得比Python更稳。这篇内容就是写给那些有Java基础、想切入AI应用开发但不知道路怎么走的开发者。我会把整条路线拆开从语言选型、框架对比、RAG落地、工具链搭建到实际踩过的坑全部讲清楚。不是泛泛而谈的科普而是我实际跑过一遍之后总结出来的路径。看完你至少能明确一件事下一步该装什么、学什么、写什么。关键词里提到的Spring AI、LangChain4j、RAG、Agentic RAG这些我都会在对应的章节里展开。先把整体地图铺开再逐个攻破。2. 先搞清楚Java在AI技术栈里站哪个位置2.1 训练侧和应用侧的分工别搞混了很多人一上来就想学PyTorch、学模型微调方向就偏了。AI技术栈大致可以分成三层最底层是模型训练和算法研究中间层是模型服务和推理部署最上层是AI应用开发。Java开发者的机会在第三层偶尔涉及第二层。训练侧需要的是数学功底、GPU集群、深度学习框架这是算法工程师的活。应用侧需要的是工程能力、系统设计、业务理解这是Java开发者的强项。你要做的事情是调用大模型的API或者本地部署的模型服务把模型输出跟业务数据结合起来构建出对用户有价值的功能。打个比方模型就像一个刚毕业的博士生知识渊博但不懂你公司的业务。Java开发者要做的是给这个博士生配一套办公系统——告诉他去哪里查资料RAG、怎么用工具Function Calling、按什么流程办事Agent编排。这套办公系统才是Java的主战场。2.2 Java做AI应用的三个核心优势第一个优势是工程化能力。Python写个Demo很快但要做成7x24小时稳定运行的服务要考虑连接池、线程安全、熔断降级、可观测性这些Java生态有成熟到令人发指的解决方案。AI应用本质上还是一个应用逃不开这些工程问题。第二个优势是类型安全。大模型的输出是不确定的但你的业务逻辑需要确定的输入。Java的强类型系统能在编译期就拦住很多问题配合Spring AI或者LangChain4j的结构化输出功能可以把模型的自由文本输出映射成强类型的Java对象这在生产环境里太重要了。第三个优势是生态整合。你现有的系统是Java写的数据库连接、消息队列、缓存、权限体系全是Java生态。用Java做AI集成不需要跨语言调用不需要维护两套技术栈运维成本直接砍半。2.3 需要补的课其实没你想的那么多从Java转AI应用开发需要补的知识主要是这几块大模型的基本概念Token、上下文窗口、温度参数、Prompt Engineering、向量和嵌入Embedding是什么、向量检索怎么工作、RAG的基本流程文档切分、向量化、检索、增强生成、以及至少一个Java AI框架的熟练使用。这些概念听起来吓人但本质上都是工程问题。Embedding就是把文本变成一串浮点数向量检索就是算余弦相似度RAG就是先查资料再回答问题。你不需要理解Transformer的注意力机制怎么算就像你不需要理解MySQL的B树怎么分裂也能写出高效的SQL一样。3. 框架选型Spring AI和LangChain4j到底怎么选3.1 两个框架的定位差异这是被问得最多的问题。我的结论是如果你已经在用Spring Boot优先选Spring AI如果你需要更灵活的编排能力或者不在Spring生态里选LangChain4j。但实际情况往往更复杂下面展开说。Spring AI的定位是Spring生态的AI抽象层。它的设计哲学跟Spring Data、Spring Cache一脉相承——提供统一的抽象接口底层可以切换不同的模型提供商。你写代码的时候面向ChatClient、EmbeddingClient这些接口编程具体用OpenAI还是Ollama还是通义千问改个配置就行。这种抽象带来的好处是供应商锁定风险低坏处是某些模型特有的高级功能可能用不上。LangChain4j的定位更偏向AI应用编排框架。它的灵感来自Python的LangChain提供了Chain、Agent、Memory、Tool等更丰富的抽象。如果你要做复杂的多步骤推理、工具调用、对话记忆管理LangChain4j的表达能力更强。但它的API变动相对频繁一些版本升级时需要注意兼容性。3.2 版本选择与依赖引入的实操细节Spring AI在2.0版本之后API逐渐稳定建议直接用最新的稳定版。Maven依赖的核心是spring-ai-bom和具体的starter。这里有个坑Spring AI的版本跟Spring Boot的版本有对应关系不是随便搭配都能跑。比如Spring AI 1.0.x对应Spring Boot 3.4.x升级的时候要一起升。dependencyManagement dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-bom/artifactId version1.0.0/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagementLangChain4j的依赖结构不太一样它是按功能模块拆分的。核心是langchain4j然后根据需要引入langchain4j-open-ai、langchain4j-ollama、langchain4j-spring-boot-starter等。这种模块化设计的好处是按需引入不会把整个框架都拖进来。dependency groupIddev.langchain4j/groupId artifactIdlangchain4j/artifactId version0.35.0/version /dependency dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-open-ai/artifactId version0.35.0/version /dependency注意LangChain4j的版本号在0.x阶段迭代很快升级时务必看Release Notes有些接口改名了但文档没跟上容易踩坑。3.3 一个决策表帮你快速定方向维度Spring AILangChain4j生态绑定Spring Boot深度集成框架无关可独立使用抽象层次偏底层贴近模型API偏上层提供Chain/Agent抽象学习曲线对Spring开发者平缓需要理解新概念多模型支持通过统一接口切换通过不同模块支持RAG支持内置Advisor机制内置RetrievalAugmentor社区活跃度背靠Spring官方增长快社区驱动迭代快适合场景企业级Spring应用集成AI复杂AI编排、非Spring项目我个人的做法是新项目如果已经在Spring Boot体系里直接用Spring AI省心。如果是独立的AI服务或者需要做很复杂的Agent编排用LangChain4j。两个框架并不是互斥的同一个项目里也可以混用但没必要为了混用而混用。4. RAG落地从文档到可用的知识库4.1 RAG到底解决了什么问题大模型有两个硬伤一是知识有截止日期训练数据之后发生的事情它不知道二是它不知道你企业的私有数据。RAGRetrieval-Augmented Generation检索增强生成就是来解决这两个问题的。RAG的核心思路很朴素用户提问的时候先去知识库里检索相关内容把检索到的内容作为上下文一起发给大模型让大模型基于这些上下文来回答。这样既解决了知识时效性问题又解决了私有数据问题还顺带降低了大模型胡编乱造的概率。整个流程拆开就是四步文档加载、文档切分、向量化存储、检索增强生成。每一步都有讲究下面逐个说。4.2 文档切分最容易被低估的环节很多人做RAG效果不好第一反应是换模型、换向量库其实问题往往出在文档切分上。切分粒度太粗检索出来的内容包含大量无关信息大模型被干扰切分粒度太细上下文不完整大模型理解不了。我的经验是切分粒度控制在500到1000个Token之间相邻块之间保留10%到20%的重叠。重叠的目的是防止一个完整的语义被切断。比如一段话正好在切分点被分成两半没有重叠的话检索到前半段就丢了后半段的信息。Spring AI里用TokenTextSplitter来做这件事TokenTextSplitter splitter new TokenTextSplitter(500, 100, 5, 10000, true); ListDocument chunks splitter.apply(documents);参数含义分别是目标块大小、最小块字符数、最小块行数、最大块大小、是否保留分隔符。实际调的时候目标块大小和重叠量是最关键的两个参数。LangChain4j里对应的是DocumentSplittersDocumentSplitter splitter DocumentSplitters.recursive(500, 100); ListTextSegment segments splitter.split(document);实操心得如果你的文档是结构化的比如Markdown、HTML优先按标题层级切分而不是按固定长度切。按语义结构切分的效果远好于按字符数切分。Spring AI的MarkdownDocumentReader和LangChain4j的各个DocumentParser都支持这种模式。4.3 向量化与向量库选型文档切分完之后需要把每个文本块通过Embedding模型转成向量存到向量数据库里。Embedding模型的选择直接影响检索质量。常见的选项有OpenAI的text-embedding-3-small、通义千问的text-embedding-v2、以及本地可以跑的BGE系列模型。如果数据敏感度不高用云服务的Embedding API最省事。如果数据不能出内网那就本地部署Ollama加BGE模型。Ollama的部署非常简单装好之后拉个模型就能用ollama pull nomic-embed-text向量数据库的选择就更多了。简单场景用内存向量库Spring AI的SimpleVectorStore、LangChain4j的InMemoryEmbeddingStore就够数据量大了再换Milvus、Qdrant、PgVector这些。我的建议是除非你确定数据量会很大否则先用内存向量库把流程跑通后面再换。过早引入重型向量数据库只会增加调试成本。PgVector是个被低估的选项。如果你已经在用PostgreSQL直接装个pgvector扩展就能当向量库用不需要额外维护一套数据库。对于中小规模的RAG应用这个方案性价比极高。4.4 检索策略从朴素检索到混合检索最基础的检索就是向量相似度检索把用户问题也转成向量然后找最相似的K个文本块。但纯向量检索有个问题它对关键词匹配不敏感。比如用户搜一个特定的产品编号向量检索可能找不准但关键词检索一找一个准。所以生产环境里更推荐混合检索向量检索加关键词检索两路结果合并后重排序。Spring AI提供了VectorStoreRetriever和各种Advisor来实现这个流程LangChain4j有EmbeddingStoreContentRetriever和ReRankingContentAggregator。检索数量TopK的设置也有讲究。设太小可能漏掉关键信息设太大无关信息会干扰大模型。一般从5开始调根据实际效果增减。如果发现大模型回答时经常漏掉某些信息就加大TopK如果回答里经常混入无关内容就减小TopK或者加一个相似度阈值过滤。4.5 一个最小可用的RAG示例用Spring AI搭一个最简单的RAG核心代码大概长这样Configuration public class RagConfig { Bean public VectorStore vectorStore(EmbeddingModel embeddingModel) { SimpleVectorStore store SimpleVectorStore.builder(embeddingModel).build(); // 加载文档并写入 ListDocument docs new TokenTextSplitter().apply( new TextReader(resource).get() ); store.add(docs); return store; } Bean public ChatClient chatClient(ChatClient.Builder builder, VectorStore vectorStore) { return builder .defaultAdvisors(new QuestionAnswerAdvisor(vectorStore)) .build(); } }这段代码做了三件事把文档切分后存入向量库、配置ChatClient、挂上QuestionAnswerAdvisor。之后调用chatClient的时候它会自动完成检索-增强-生成的流程。这就是Spring AI的Advisor机制的好处把RAG的逻辑封装成了可插拔的组件。LangChain4j的写法略有不同需要显式构建RetrievalAugmentorRetrievalAugmentor augmentor DefaultRetrievalAugmentor.builder() .contentRetriever(EmbeddingStoreContentRetriever.builder() .embeddingStore(store) .embeddingModel(embeddingModel) .maxResults(5) .minScore(0.7) .build()) .build(); Assistant assistant AiServices.builder(Assistant.class) .chatLanguageModel(model) .retrievalAugmentor(augmentor) .build();两种写法思路一致只是API风格不同。Spring AI更声明式LangChain4j更组装式。5. 工具链搭建本地开发和调试环境怎么配5.1 本地模型运行环境开发阶段不建议直接调云API一是费钱二是网络延迟影响调试效率三是有些实验性的Prompt不想发到外面。本地跑模型用Ollama是最省事的选择。Ollama装好之后拉一个7B左右的模型就够开发用了ollama pull qwen2.5:7b ollama pull nomic-embed-textqwen2.5:7b做对话nomic-embed-text做Embedding。这两个组合在消费级显卡上就能跑16G内存的机器也勉强能带动。如果机器配置更低可以用qwen2.5:3b效果差一些但开发调试够用。Spring AI接入Ollama只需要加依赖和配置spring: ai: ollama: base-url: http://localhost:11434 chat: options: model: qwen2.5:7b temperature: 0.7 embedding: options: model: nomic-embed-textLangChain4j接入OllamaOllamaChatModel model OllamaChatModel.builder() .baseUrl(http://localhost:11434) .modelName(qwen2.5:7b) .build(); OllamaEmbeddingModel embeddingModel OllamaEmbeddingModel.builder() .baseUrl(http://localhost:11434) .modelName(nomic-embed-text) .build();5.2 调试与可观测性AI应用最难调试的地方在于同样的输入输出可能不一样。传统的断点调试基本失效你需要的是完整的调用链日志。Spring AI提供了ChatClient的日志功能加上Advisor的日志可以看到完整的Prompt、检索到的文档、模型的原始输出。LangChain4j有ChatModelListener接口可以挂载各种监听器。我习惯在开发阶段把每次调用的完整Prompt和响应都打到日志里格式化成可读的文本。这样出问题的时候能快速定位是检索环节的问题还是生成环节的问题。生产环境再关掉详细日志只保留关键指标。关键指标包括每次请求的Token消耗、检索耗时、生成耗时、检索到的文档数量和相似度分数。这些指标能帮你判断系统瓶颈在哪里。如果检索耗时占比高考虑优化向量库索引如果生成耗时高考虑换更小的模型或者优化Prompt长度。5.3 测试策略AI应用的测试跟传统应用不一样。传统应用是确定性输入对应确定性输出AI应用是概率性的。你不能断言输入A必须输出B但你可以断言输出B必须包含某些关键信息或者输出B不能包含某些违规内容。我的做法是分两层第一层是单元测试Mock掉模型调用只测试检索逻辑、Prompt组装逻辑这些确定性的部分。第二层是集成测试用真实模型跑一批预设的问题人工检查或者用另一个模型来评估输出质量。LangChain4j提供了AiServices的测试支持可以很方便地Mock掉模型。Spring AI也有对应的测试工具。关键是要把模型调用和业务逻辑隔离开让业务逻辑可以独立测试。6. 从RAG到Agent能力进阶的路径6.1 什么时候需要AgentRAG解决的是知识问答问题但很多场景不只是问答。比如用户说帮我查一下上个月的销售数据然后生成一份报告这需要模型先调用数据库查询工具拿到数据后再调用文档生成工具。这种多步骤、需要调用外部工具的场景就需要Agent。Agent的核心是让模型自己决定下一步做什么。你给它一组工具Tool它根据用户的问题决定调用哪个工具、传什么参数、拿到结果后怎么处理。这比RAG复杂得多但能力也强得多。6.2 Function Calling的实现方式Spring AI里通过Tool注解来定义工具Component public class SalesTools { Tool(description 根据月份查询销售数据) public SalesData querySales(ToolParam(description 月份格式yyyy-MM) String month) { // 实际查询逻辑 return salesService.queryByMonth(month); } }然后在ChatClient里注册这些工具ChatClient chatClient builder .defaultTools(salesTools) .build();模型在对话过程中会自动判断是否需要调用工具需要的话会生成工具调用请求Spring AI负责执行工具并把结果返回给模型模型再基于结果生成最终回答。LangChain4j的工具定义类似用Tool注解public class SalesTools { Tool(根据月份查询销售数据) public SalesData querySales(P(月份格式yyyy-MM) String month) { return salesService.queryByMonth(month); } }6.3 Agentic RAGRAG和Agent的结合Agentic RAG是最近很热的一个方向。传统RAG是检索一次然后生成Agentic RAG是让模型自己决定检索什么、检索几次、什么时候检索够了。比如用户问一个复杂问题模型可以先检索一次发现信息不够再换个关键词检索或者调用其他工具补充信息最后综合所有信息生成回答。这种模式对复杂查询的效果明显更好但实现复杂度也更高Token消耗也更大。LangChain4j在这方面提供了比较丰富的抽象可以通过AiServices配合RetrievalAugmentor和Tool来实现。Spring AI的Advisor机制也能支持但需要自己写更多的编排逻辑。我的建议是先把基础RAG跑通效果稳定了再考虑Agentic RAG。不要一上来就搞最复杂的架构容易在调试上耗尽耐心。7. 实际落地中踩过的坑和应对方案7.1 中文分词的坑做中文RAG的时候TokenTextSplitter按Token切分但中文的Token计算跟英文不一样。一个中文字可能对应1到2个Token具体取决于分词器。如果按英文的经验设置块大小中文文档切出来的块会偏小语义不完整。我的做法是中文文档的块大小设置成英文的1.5到2倍。比如英文用500 Token中文就用800到1000 Token。同时增加重叠量中文用150到200 Token的重叠。另外如果用的是OpenAI的Tokenizer来算中文Token结果会偏大因为OpenAI的Tokenizer对中文的支持不是最优的。用国产模型的Tokenizer会更准但Spring AI和LangChain4j默认用的都是OpenAI的Tokenizer。这个差异在调试的时候要注意。7.2 向量维度不一致的问题换Embedding模型的时候向量维度会变。比如从OpenAI的1536维换成BGE的768维之前存的向量就全部作废了。如果向量库里的数据没有清空重建检索的时候会报维度不匹配的错误。这个坑在开发阶段很容易踩因为经常换模型做对比。我的建议是向量库的集合名称里带上模型标识比如docs_openai_1536和docs_bge_768换模型的时候用新的集合不要复用。这样虽然占点存储空间但省去了很多调试麻烦。7.3 大模型输出格式不稳定的处理让大模型输出JSON的时候它有时候会加一些额外的解释文字有时候JSON格式不对有时候字段名大小写不一致。这些都会导致解析失败。Spring AI提供了BeanOutputConverter可以把模型输出直接映射成Java对象BeanOutputConverterSalesReport converter new BeanOutputConverter(SalesReport.class); String format converter.getFormat(); // 把format加到Prompt里告诉模型按这个格式输出 SalesReport report converter.convert(modelOutput);LangChain4j也有类似的功能通过AiServices的返回值类型自动处理。但不管用哪个框架都要做好解析失败的兜底处理。我的做法是解析失败时重试一次重试还失败就返回一个默认值或者错误提示不要让整个请求挂掉。7.4 检索命中率低的排查思路RAG效果不好的时候按这个顺序排查先看检索到的文档是不是相关如果不相关问题在检索环节如果相关但回答不好问题在生成环节。检索环节的问题通常是Embedding模型不适合当前语言或领域、切分粒度不合适、TopK设置不合理、相似度阈值太高或太低。生成环节的问题通常是Prompt模板不好、上下文太长导致模型迷失在中间、模型本身能力不够。我一般会先把检索到的文档打印出来人工检查。如果检索结果明显不相关就调Embedding模型和切分策略如果检索结果相关但回答不好就调Prompt和模型。这个排查顺序能省很多时间。7.5 成本控制的几个实用技巧Token是要花钱的尤其是用云API的时候。几个实用的省钱技巧一是缓存Embedding结果同样的文本不要重复计算二是控制上下文长度检索到的文档不要一股脑全塞进去按相似度排序后取TopK三是用更小的模型做简单任务复杂任务才用大模型四是设置max_tokens限制输出长度防止模型啰嗦。Spring AI和LangChain4j都支持这些配置关键是要有意识地去设置。我见过不少项目上线后才发现Token消耗远超预期回头再优化就很被动。8. 学习路线和资源推荐8.1 分阶段的学习路径第一阶段1到2周理解大模型的基本概念跑通一个最简单的对话Demo。用Spring AI或者LangChain4j调通Ollama能发消息收回复就行。这个阶段的目标是消除陌生感。第二阶段2到3周理解RAG的完整流程搭一个能用的知识库问答。重点搞懂文档切分、Embedding、向量检索这三个环节。这个阶段的目标是能独立完成一个RAG应用。第三阶段3到4周学习Function Calling和Agent让应用能调用外部工具。这个阶段的目标是能处理需要多步骤推理的复杂场景。第四阶段持续深入Prompt Engineering、检索优化、性能调优。这些是需要在实践中不断积累的没有速成的方法。8.2 值得看的资源Spring AI的官方文档写得不错尤其是Advisor和RAG部分有完整的示例代码。LangChain4j的文档相对零散一些但GitHub上的examples目录很有参考价值。Ollama的官方文档很简洁基本看一遍就能上手。PgVector的README也写得很清楚照着做就能跑起来。至于大模型本身的知识不建议一上来就看论文。先看一些工程实践类的博客和教程把概念建立起来有兴趣再深入原理。8.3 一个建议从解决实际问题开始学AI应用开发最快的方式是找一个你工作中真实存在的问题用AI去解决它。比如你经常需要查文档就做一个文档问答你经常需要写周报就做一个周报生成助手。有真实场景驱动学习动力和效果完全不一样。纯粹为了学而学很容易在概念里打转。带着问题去学每个知识点都能立刻验证进步快得多。9. 我个人的一些体会从Java转AI应用开发这一年多最大的感受是这件事没有想象中那么难但也没有想象中那么简单。难的不是技术本身而是思维方式的转变。传统开发是确定性的输入A必然输出BAI应用是概率性的同样的输入可能得到不同的输出。接受这种不确定性学会跟不确定性共处是每个Java开发者转AI要过的第一关。另一个体会是不要追求一步到位。我见过太多人一上来就想搭一个完美的RAG系统结果在向量库选型、模型对比、参数调优上耗了几周最后连一个能跑的Demo都没做出来。正确的做法是先跑通最小闭环再逐步优化。先让系统能回答问题再让它回答得更好。最后Java在AI应用层的优势会越来越明显。随着AI从炫技走向落地工程能力的重要性会超过算法能力。Java开发者在这个转变中占的位置比很多人以为的要好得多。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →