Java开发者AI入门实战:Spring AI与LangChain4j构建RAG与Agent
1. Java 开发者切入 AI 的真实路径拆解1.1 为什么 Java 开发者不需要从零学 Python我做了十多年 Java 后端这两年身边问得最多的问题就是“要不要转 Python 才能搞 AI”。实测下来这个判断本身就是个误区。Java 生态在 AI 工程化落地这一层已经长出了一套相当完整的工具链尤其是Spring AI和LangChain4j这两个框架成熟之后Java 开发者完全可以留在自己熟悉的技术栈里做 AI 应用。核心逻辑在于AI 应用分两层一层是模型训练和微调那确实是 Python 的主场另一层是模型调用、编排、RAG 检索增强、Agent 调度、企业系统集成这一层本质上是工程问题而工程问题恰恰是 Java 的强项。企业里绝大多数 AI 需求比如智能客服、知识库问答、文档摘要、NL2SQL 查询、流程自动化都属于第二层。所以路线图的第一条原则是不要为了 AI 去重学一门语言而是把 AI 能力接进你已有的 Java 工程能力里。你已有的 Spring Boot、MyBatis、Redis、消息队列、微服务治理经验在 AI 应用里全部用得上甚至比算法背景的人更值钱因为 AI 应用最终要落到高并发、事务一致性、可观测性这些硬骨头上面。1.2 一条可执行的四周入门路线我把入门拆成四个阶段每个阶段都有明确的产出物避免“学了一堆概念但写不出东西”。阶段时间核心目标产出物第一阶段第 1 周跑通模型调用一个能对话的 Spring Boot 接口第二阶段第 2 周掌握提示词与结构化输出能返回 JSON 的智能接口第三阶段第 3 周搭建 RAG 知识库基于私有文档的问答服务第四阶段第 4 周引入 Agent 与工具调用能查数据库/调接口的智能体这个顺序不能乱。很多人一上来就啃 RAG 和 Agent结果连模型返回的流式响应怎么处理都没搞明白遇到问题根本无从排查。先把最基础的“请求-响应”链路打通后面每一层都是在它上面叠加。1.3 工具链选型的取舍逻辑工具链这块我踩过的坑比较多直接给结论。模型接入层Spring AI 和 LangChain4j 二选一或者都用。Spring AI 的优势是和 Spring Boot 无缝集成配置化程度高适合已经在用 Spring 体系的团队LangChain4j 的抽象更贴近 LangChain 的设计哲学链式编排、记忆管理、RAG 组件更丰富适合做复杂编排。我的建议是主用 Spring AI 做基础接入复杂 RAG 场景引入 LangChain4j两者可以在同一个项目里共存。本地模型运行Ollama 是零基础最友好的选择一条命令拉起模型OpenAI 兼容接口直接对接。适合开发调试和隐私敏感场景。向量数据库入门阶段用内存向量库或者 Redis 就够了别一上来就上 Milvus、Qdrant 这些重型组件运维成本会把你的学习热情耗光。编排框架LangGraph4j 适合需要状态机和循环控制的 Agent 场景但入门阶段用不上等你的 RAG 跑通了再考虑。提示选型时优先考虑“能不能在本地五分钟跑起来”而不是“功能是不是最全”。入门阶段最大的敌人是环境配置不是功能缺失。2. Spring AI 与 LangChain4j 核心能力对比实操2.1 Spring AI 的最小可运行示例先看 Spring AI因为对 Spring 开发者来说它上手最快。核心依赖就一个 starter配置里填上模型地址和密钥即可。dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-openai-spring-boot-starter/artifactId version1.0.0/version /dependency配置文件里指定模型端点如果你用 Ollama 本地跑base-url 指向本地端口就行。spring: ai: openai: base-url: http://localhost:11434 api-key: dummy chat: options: model: qwen2.5:7b temperature: 0.7然后注入ChatClient就能用了。这里有个细节ChatClient是 Spring AI 推荐的门面类比直接用ChatModel更顺手支持流式、系统提示词、结构化输出。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(); } }这段代码跑起来你就已经跨过了 AI 应用的第一道门槛。注意defaultSystem的设定系统提示词决定了模型的角色和行为边界很多人忽略这一步导致模型回答风格飘忽不定。2.2 LangChain4j 的链式编排能力LangChain4j 的写法更接近“组装流水线”的思路。它的核心接口是ChatLanguageModel和AiServices后者能把一个 Java 接口自动实现成 AI 调用。interface Assistant { SystemMessage(你是一个 Java 技术顾问只回答 Java 相关问题。) String chat(UserMessage String question); } ChatLanguageModel model OpenAiChatModel.builder() .baseUrl(http://localhost:11434/v1) .apiKey(dummy) .modelName(qwen2.5:7b) .build(); Assistant assistant AiServices.create(Assistant.class, model); String answer assistant.chat(Spring AI 和 LangChain4j 怎么选);这种声明式接口的好处是业务代码里看不到任何 AI 相关的样板逻辑接口定义即契约。LangChain4j 的记忆管理也做得更细MessageWindowChatMemory可以控制上下文窗口大小避免 token 超限。2.3 两者的关键差异与共存策略维度Spring AILangChain4j集成方式Spring Boot 自动配置手动构建或 Spring 集成抽象层次偏底层贴近 Spring 风格偏高层链式编排丰富RAG 组件内置基础 RAG组件更全支持多种检索器结构化输出支持基于 Converter支持基于 JSON Schema学习曲线Spring 开发者几乎零成本需要理解其抽象模型实际项目里我的做法是基础对话、结构化输出用 Spring AIRAG 检索、多轮记忆、工具调用用 LangChain4j。两者共享同一个模型端点互不冲突。这样既享受了 Spring 的工程便利又拿到了 LangChain4j 的编排能力。注意两个框架的依赖版本要留意尤其是底层 HTTP 客户端和 JSON 库的版本冲突建议用 Maven 的 dependencyManagement 统一锁定。3. RAG 知识库从零搭建的完整流程3.1 RAG 到底解决了什么问题RAG 这个词被说烂了但很多人没搞清它的本质。大模型的知识截止到训练时间而且不知道你公司的内部文档。RAG 的思路是在提问之前先从你的私有知识库里检索出相关片段拼进提示词里一起发给模型。模型基于这些片段回答而不是靠它自己的记忆。这解决了三个问题知识时效性、私有数据访问、幻觉抑制。但它不是银弹RAG 的效果高度依赖检索质量检索不准后面全白搭。3.2 文档切分与向量化的关键参数RAG 的第一步是把文档切成小块再转成向量存进向量库。切分策略直接决定检索效果。DocumentSplitter splitter DocumentSplitters.recursive( 500, // 每块最大字符数 50 // 块间重叠字符数 ); ListDocument documents FileSystemDocumentLoader.loadDocuments( Paths.get(/data/docs), splitter );500 和 50 这两个数字不是随便定的。块太大检索出来的内容包含太多无关信息稀释了相关性块太小语义不完整模型拿到的上下文断裂。重叠区是为了防止关键信息正好被切在边界上。我的经验是技术文档用 500-800法律合同用 300-500代码文档按方法粒度切。向量化用嵌入模型本地可以用 Ollama 的nomic-embed-text效果够用且免费。EmbeddingModel embeddingModel OllamaEmbeddingModel.builder() .baseUrl(http://localhost:11434) .modelName(nomic-embed-text) .build(); EmbeddingStoreTextSegment store new InMemoryEmbeddingStore(); EmbeddingStoreIngestor ingestor EmbeddingStoreIngestor.builder() .documentSplitter(splitter) .embeddingModel(embeddingModel) .embeddingStore(store) .build(); ingestor.ingest(documents);3.3 检索增强的组装与提示词设计检索到相关片段后要把它拼进提示词。这一步的提示词设计很讲究直接给模板。String promptTemplate 基于以下参考资料回答问题。如果资料中没有相关信息明确说资料中未提及不要编造。 参考资料 {{context}} 问题{{question}} ;“不要编造”这句话必须写否则模型会习惯性地用通用知识补全导致答案看起来合理但和你的文档无关。这是 RAG 幻觉的主要来源之一。检索器可以配置相似度阈值和返回条数EmbeddingStoreContentRetriever retriever EmbeddingStoreContentRetriever.builder() .embeddingStore(store) .embeddingModel(embeddingModel) .maxResults(5) .minScore(0.7) .build();maxResults给 5 是平衡点太多会撑爆上下文太少可能漏掉关键信息。minScore是相似度下限低于这个分数的片段直接丢弃宁可说“不知道”也不要给错误答案。3.4 提升 RAG 命中率的实战技巧RAG 效果不好九成出在检索环节。我整理了几个实测有效的优化手段。查询改写用户的问题往往口语化直接拿去检索效果差。先用模型把问题改写成更规范的检索语句再检索。这一步能明显提升命中率。混合检索纯向量检索对关键词不敏感比如产品型号、专有名词。加上 BM25 关键词检索做融合效果提升明显。重排序检索出 20 条用一个重排序模型挑出最相关的 5 条。这一步计算量不大但对最终质量影响很大。元数据过滤给文档块打上来源、时间、分类标签检索时先按元数据过滤再向量检索能大幅缩小范围。提示RAG 调优不要凭感觉要建立评估集。准备 50-100 个问题和标准答案每次调整参数后跑一遍看命中率和准确率的变化。没有评估的调优就是瞎调。4. Agent 与工具调用进阶实践4.1 从 RAG 到 Agent 的能力跃迁RAG 是“查了再答”Agent 是“想了再做”。Agent 能自主决定调用哪些工具、按什么顺序调用、要不要循环。比如用户问“上个月销售额最高的产品库存还剩多少”Agent 需要先查销售数据再查库存最后汇总。LangChain4j 的工具调用机制很直观用注解标记方法即可public class SalesTools { Tool(查询指定月份的销售数据) public String querySales(P(月份格式 yyyy-MM) String month) { // 实际查数据库 return salesService.queryByMonth(month); } Tool(查询指定产品的库存数量) public int queryStock(P(产品名称) String productName) { return stockService.getStock(productName); } }然后把这个工具类注册给 AI 服务Assistant assistant AiServices.builder(Assistant.class) .chatLanguageModel(model) .tools(new SalesTools()) .build();模型会自动判断什么时候调用哪个工具你不需要写任何调度逻辑。这就是 Agent 的核心价值把决策权交给模型把执行权留给自己。4.2 工具调用的安全边界设计工具调用很强大但也很危险。模型可能调用你不希望它调用的方法或者传入恶意参数。必须做几层防护。第一层是权限控制工具方法内部要校验调用者身份不能因为模型说“查所有用户数据”就真的全查出来。第二层是参数校验模型生成的参数可能格式错误或超出范围方法入口要做严格校验。第三层是操作审计所有工具调用都要记日志方便追溯。Tool(删除指定订单) public String deleteOrder(P(订单号) String orderId) { // 危险操作必须二次确认 if (!securityContext.hasPermission(ORDER_DELETE)) { return 无权限执行此操作; } if (!orderId.matches(^ORD\\d{10}$)) { return 订单号格式错误; } auditLog.record(deleteOrder, orderId, currentUser()); return orderService.delete(orderId); }注意涉及写操作、删除操作的工具一定要加权限校验和审计日志。模型被提示词注入攻击时这些防护是最后一道防线。4.3 Agentic RAG 的编排思路Agentic RAG 是把 RAG 和 Agent 结合起来Agent 自主决定要不要检索、检索什么、检索几次。比如一个复杂问题Agent 可能先检索一次发现信息不够改写查询再检索最后综合回答。LangGraph4j 适合做这种有状态的编排它把流程建模成图节点是操作边是转移条件。但入门阶段不建议直接上先用简单的循环逻辑实现String answer ; for (int i 0; i 3; i) { ListTextSegment segments retriever.retrieve(question); answer generateAnswer(question, segments); if (isAnswerSufficient(answer)) { break; } question rewriteQuery(question, answer); }这个简单的循环已经能覆盖大部分 Agentic RAG 场景。不要为了用框架而用框架能解决问题的代码就是好代码。5. 常见问题排查与避坑经验5.1 模型调用层面的典型故障连接超时本地 Ollama 首次加载模型会慢第一次请求超时很正常。把超时时间设长一点或者提前预热模型。返回乱码多半是编码问题检查 HTTP 客户端的字符集配置确保 UTF-8。token 超限上下文太长导致报错。要么缩短提示词要么换更大上下文的模型要么做历史消息截断。流式响应中断SSE 连接被网关或代理切断。检查 Nginx 的proxy_buffering配置流式场景要关掉缓冲。5.2 RAG 效果不佳的排查顺序RAG 答非所问按这个顺序排查先看检索结果把检索到的片段打印出来看是不是相关。不相关就是检索问题。再看切分粒度片段语义是否完整有没有被切碎。然后看嵌入模型换一个嵌入模型试试不同模型对中文的支持差异很大。最后看提示词提示词有没有明确要求基于资料回答。这个顺序很重要很多人一上来就改提示词但问题其实出在检索环节。5.3 高频问题速查表现象可能原因排查方向模型不回答一直转圈连接超时或模型未加载检查端点连通性预热模型回答内容与文档无关检索未命中打印检索结果调整切分和阈值回答包含编造信息提示词未约束加入“不要编造”指令提高 minScore工具调用失败参数格式错误检查 P 描述加参数校验多轮对话丢失上下文记忆未配置配置 ChatMemory控制窗口大小响应速度慢模型太大或上下文太长换小模型精简提示词5.4 我踩过的几个真实坑坑一以为向量库越重越好。一开始上了 Milvus 集群结果运维成本高得离谱后来换成 Redis 向量检索性能完全够用。入门阶段内存向量库或 Redis 足矣。坑二忽略嵌入模型的语言适配。用了一个英文为主的嵌入模型中文检索效果惨不忍睹。换成支持中文的模型后命中率直接翻倍。坑三提示词写得太长。以为提示词越详细越好结果模型被大量指令干扰反而抓不住重点。提示词要精炼把最关键的约束放前面。坑四不做评估就上线。凭感觉觉得效果不错上线后用户反馈一堆问题。后来建了评估集每次改动都跑一遍才把质量稳住。提示AI 应用的调试和传统应用不一样它的输出是不确定的。所以日志要记全把每次请求的提示词、检索结果、模型输出都存下来出问题时才有据可查。6. 工程化落地的几个关键考量6.1 数据一致性与事务边界Java 开发者做 AI 应用有个天然优势就是对事务和数据一致性的敏感度。AI 应用里模型调用是外部依赖不能放在数据库事务里。正确做法是先完成数据库操作并提交再调用模型或者先调模型拿到结果再开事务写库。如果业务要求“模型调用和写库要么都成功要么都失败”那就需要补偿机制。记录调用状态失败时重试或回滚。这块用你熟悉的 Saga 模式或者本地消息表就能解决。6.2 成本控制与缓存策略模型调用是按 token 计费的量大了成本很可观。几个控制手段相同问题缓存结果用问题文本的哈希做 key精简提示词去掉冗余描述分级模型简单问题用小模型复杂问题用大模型限制上下文长度历史消息做滑动窗口。Cacheable(value ai-answers, key #question.hashCode()) public String ask(String question) { return chatClient.prompt().user(question).call().content(); }缓存要注意失效策略知识库更新后相关缓存要清掉否则会返回过期答案。6.3 可观测性建设AI 应用的监控比传统应用复杂因为多了模型这一层。需要监控的指标包括调用次数、平均延迟、token 消耗、失败率、检索命中率、用户反馈。把这些指标接进你现有的监控体系用 Micrometer 打点Prometheus 采集Grafana 展示。日志方面每次调用要记录请求 ID、用户 ID、提示词、检索片段、模型输出、耗时、token 数。这些数据不仅是排查问题的依据也是后续优化的数据基础。6.4 后续可扩展的方向RAG 跑通之后可以往几个方向扩展。多模态支持图片和文档的混合检索GraphRAG用知识图谱增强检索的关联性NL2SQL让模型直接生成 SQL 查询数据库工作流编排把多个 AI 能力串成自动化流程。但我的建议是先把一个场景做深做透再考虑扩展。AI 应用最怕的就是功能堆了一堆每个都不好用。选一个真实痛点把它做到 90 分比做十个 60 分的功能有价值得多。我在实际项目里的体会是Java 开发者做 AI 最大的障碍不是技术而是心态。总觉得自己不懂算法就做不了 AI其实 AI 应用开发 80% 是工程问题剩下 20% 的算法细节框架已经帮你封装好了。你要做的是把 AI 能力当成一个普通的第三方服务用你熟悉的工程方法去集成、去治理、去优化。这条路我走通了你也一样可以。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →