Java工程师转型AI Agent实战:Spring AI与LangChain4j核心指南

发布时间:2026/10/5 12:30:03
Java工程师转型AI Agent实战:Spring AI与LangChain4j核心指南 1. Java 工程师转型 AI Agent 的底层逻辑与路径选择1.1 为什么 Java 工程师转 AI Agent 有天然优势很多 Java 工程师一听到“转型 AI”就心里发怵觉得自己没学过 Python、没碰过 PyTorch、没读过 Transformer 论文是不是要从零开始我一开始也这么想但真正上手做了几个 Agent 项目之后发现事情完全不是这样。AI Agent 的本质是什么说白了就是一个能“思考-行动-观察-再思考”的循环系统。它需要调用大模型做推理需要调用工具去执行任务需要管理对话记忆需要处理并发请求需要做权限控制需要记录日志和监控。你把这些拆开看哪一样不是 Java 工程师天天在干的事大模型推理那一层确实 Python 生态更成熟但 Java 这边现在有LangChain4j和Spring AI两个框架已经把最脏最累的活干完了。你要做的不是训练模型而是把模型能力编排进业务流程里。这恰恰是 Java 工程师最擅长的事情——写业务逻辑、做系统集成、保证服务稳定。我见过太多 Python 背景的算法同学模型调得飞起但一让他做工程化落地就头疼并发怎么扛事务怎么保证服务怎么治理这些恰恰是 Java 工程师的舒适区。所以转型的关键不是补算法短板而是把已有的工程能力映射到 AI Agent 这个新场景里。1.2 转型路径的三种选择与取舍从 Java 转 AI Agent市面上大概有三条路我按投入产出比排个序。第一条路是Spring AI 路线。如果你已经在用 Spring Boot 做后端这是最顺滑的。Spring AI 的 API 设计完全遵循 Spring 的编程习惯ChatClient、EmbeddingClient、VectorStore这些抽象接口用起来跟JdbcTemplate一样自然。你不需要学新语言不需要换构建工具Maven 加个依赖就能跑起来。缺点是 Spring AI 相对年轻某些高级 Agent 模式比如复杂的多 Agent 协作支持得还不够细。第二条路是LangChain4j 路线。LangChain4j 是 Python LangChain 的 Java 移植版概念几乎一一对应ChatLanguageModel、EmbeddingModel、EmbeddingStore、AiServices。它的优势是 Agent 相关的抽象更完整比如ToolSpecification、hallucination检测、RAG 的多路召回都有现成实现。如果你要做的是偏“智能体”而非“智能问答”的东西LangChain4j 的起点更高。第三条路是纯手写路线。不依赖任何框架直接用 HTTP 客户端调大模型的 REST API自己实现 ReAct 循环。这条路我不推荐新手走但如果你要深度定制 Agent 的行为逻辑或者要嵌入到已有的非 Spring 系统里手写反而最灵活。我有个做期货交易辅助工具的朋友就是纯手写因为他需要对每一次工具调用做极细粒度的风控拦截框架的抽象反而碍事。我的建议是先用 Spring AI 跑通一个最小可用 Agent再用 LangChain4j 补 Agent 特有的能力。两者并不冲突可以在同一个项目里共存。1.3 一个必须想清楚的问题你的 Agent 到底解决什么问题我见过太多人一上来就问“怎么搭建 AI Agent”但问他 Agent 要干什么答不上来。这是典型的拿着锤子找钉子。AI Agent 不是万能药。它适合的场景有明确特征任务步骤不固定、需要根据中间结果动态调整、涉及多个工具或数据源的编排。比如“帮我查一下上个月销售额如果同比下降超过 10% 就发邮件给区域负责人并附上下降原因分析”——这种任务用传统 if-else 写死也能做但一旦规则变了就要改代码。Agent 的价值在于用自然语言描述任务由模型动态决定调用哪些工具、按什么顺序调用。反过来如果你的任务是“每天凌晨把 A 表数据同步到 B 表”这种确定性极强的批处理用 Agent 就是杀鸡用牛刀老老实实写定时任务更稳。所以转型第一步不是学框架而是找到你业务里那个“规则经常变、步骤不固定、需要跨系统协调”的场景。找到它你的转型就有了锚点。2. 核心概念拆解ReAct、工具调用与记忆机制2.1 ReAct 模式Agent 的“思考-行动”循环到底怎么跑ReAct 是 Reasoning Acting 的缩写是目前绝大多数 AI Agent 的底层运行模式。它的核心思想特别朴素让模型在每一步都先“想一想”该干什么然后“动手”去干干完看结果再想下一步。我用一个实际例子来说明。假设你让 Agent 回答“北京今天适合穿什么衣服”。ReAct 循环是这样的第一步模型思考我需要知道北京今天的天气。于是它输出一个“行动”——调用天气查询工具参数是城市北京。第二步系统执行工具调用拿到结果“北京今天晴气温 5-15 度北风 3 级”。第三步模型观察这个结果继续思考5-15 度偏凉需要穿外套。于是它输出最终答案“建议穿薄羽绒服或风衣内搭长袖。”这个循环在代码里就是一个 while 循环直到模型输出“最终答案”或者达到最大迭代次数。听起来简单但魔鬼在细节里。第一个细节是提示词设计。你得在系统提示里明确告诉模型你有哪几个工具可用、每个工具的参数格式是什么、什么时候该调用工具、什么时候该直接回答。这个提示词写得好不好直接决定 Agent 的智商。第二个细节是工具调用的解析。模型输出的工具调用请求是自然语言或 JSON你需要解析成实际的函数调用。Spring AI 和 LangChain4j 都提供了Tool注解或ToolSpecification来简化这个过程但底层逻辑你得清楚。第三个细节是循环终止条件。必须有最大迭代次数限制否则模型可能陷入死循环反复调用同一个工具。我一般设 5-8 次超过就强制返回当前结果并记录告警。2.2 工具调用Agent 的“手脚”怎么接工具调用是 Agent 从“聊天机器人”变成“能干活的智能体”的关键。没有工具调用模型只能基于训练数据回答问题有了工具调用它就能查数据库、调 API、发邮件、操作文件。在 Spring AI 里定义一个工具非常简单Component public class WeatherTools { Tool(description 查询指定城市的实时天气) public String getWeather(ToolParam(description 城市名称) String city) { // 实际调用天气 API return weatherApi.query(city); } }然后在构建 ChatClient 时注册这个工具ChatClient chatClient ChatClient.builder(chatModel) .defaultTools(new WeatherTools()) .build();LangChain4j 的做法类似用Tool注解标注方法然后在AiServices接口里声明。但这里有几个坑我必须提醒你。坑一工具描述写得太简略。模型是根据工具描述来决定要不要调用的。如果你只写“查询天气”模型可能不知道什么时候该用。要写清楚“当用户询问某城市天气、气温、是否适合出行时调用此工具”。坑二工具参数类型太复杂。模型对简单类型String、int、boolean的解析准确率最高。如果你传一个嵌套对象模型很容易生成格式错误的参数。我的经验是工具参数尽量扁平化复杂结构拆成多个简单参数。坑三工具执行没有超时和熔断。Agent 调用工具是自动的如果某个工具响应很慢或者挂了整个 Agent 循环就会卡住。必须给每个工具调用加超时比如 3 秒和熔断连续失败 3 次就暂时禁用。2.3 记忆机制让 Agent 记住上下文没有记忆的 Agent 就像金鱼每轮对话都从零开始。记忆机制解决的就是这个问题。记忆分两种短期记忆和长期记忆。短期记忆就是当前对话的历史消息。Spring AI 的ChatMemory接口默认实现是InMemoryChatMemory把消息存在内存里。但生产环境你不能用内存因为服务重启就丢了而且多实例部署时会话不共享。我一般用 Redis 做短期记忆存储key 是会话 IDvalue 是消息列表设置 30 分钟过期。长期记忆则是跨会话的知识。比如用户上次说“我对花生过敏”这次点餐时 Agent 应该记得。长期记忆通常用向量数据库实现把重要信息 embedding 后存进去每次对话时检索相关记忆注入提示词。LangChain4j 在这方面提供了ChatMemoryStore和EmbeddingStore的组合方案Spring AI 也有VectorStore抽象。但我要说的是记忆不是越多越好。你把所有历史消息都塞进提示词token 消耗巨大不说还会稀释当前问题的注意力。我的做法是短期记忆保留最近 10 轮对话长期记忆只存用户明确表达的偏好和事实检索时取 top 3 相关记忆。3. 从零搭建一个可落地的 Java AI Agent3.1 环境准备与依赖选型我以 Spring Boot 3.x Spring AI 为例走一遍完整搭建流程。选 Spring AI 是因为它对 Java 工程师最友好而且和现有 Spring 生态无缝集成。首先JDK 版本至少 17推荐 21。Spring AI 用到了很多新特性JDK 17 是底线。Maven 依赖方面核心是这几个dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-openai-spring-boot-starter/artifactId version1.0.0-M6/version /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-redis-store-spring-boot-starter/artifactId version1.0.0-M6/version /dependency如果你用的是国内的大模型服务比如百炼、智谱把spring-ai-openai换成对应的 starter 即可。Spring AI 的抽象层设计得很好换模型提供商只需要改配置代码基本不动。配置文件里至少要配这些spring: ai: openai: api-key: ${AI_API_KEY} base-url: https://api.example.com chat: options: model: qwen-plus temperature: 0.7 max-tokens: 2000这里temperature设 0.7 是个经验值。做 Agent 任务时温度太高会导致模型“胡思乱想”调用不该调的工具温度太低又会让它过于死板遇到稍微变化的任务就不知道变通。0.7 是我试下来比较平衡的值。3.2 定义 Agent 的工具集与系统提示词工具集的设计直接决定 Agent 的能力边界。我建议按“领域”来组织工具类每个类负责一组相关操作。比如做一个“运维助手 Agent”工具类可以这样分ServerTools查服务器状态、重启服务、查日志DatabaseTools执行查询、查表结构、查慢查询AlertTools发告警、查告警历史、静默告警每个工具方法的描述要写得像给新人看的操作手册。我举个例子Tool(description 根据服务名查询该服务最近N分钟的ERROR级别日志条数。 当用户询问服务是否异常、有没有报错时使用此工具。 参数serviceName必须是已知的服务名minutes范围1-1440) public int countErrorLogs( ToolParam(description 服务名称如 order-service) String serviceName, ToolParam(description 查询最近多少分钟默认30) int minutes) { // 实现逻辑 }系统提示词是 Agent 的“人格设定”。我一般包含这几部分你是一个运维助手负责帮助工程师排查线上问题。 你可以使用以下工具查日志、查服务器状态、查数据库、发告警。 排查问题时先查日志确认错误类型再查服务器状态确认资源是否正常最后给出结论。 如果工具返回结果不足以判断可以继续调用其他工具但最多调用 5 次。 不要编造工具没有返回的信息。如果无法确定原因如实告知用户。这段提示词里“先查日志再查服务器”是给 Agent 的排查策略“最多 5 次”是防止死循环“不要编造”是抑制幻觉。每一条都是踩过坑之后加上的。3.3 实现 ReAct 循环与工具调用编排Spring AI 从 1.0.0-M6 开始ChatClient已经内置了工具调用的自动编排。你只需要这样写String response chatClient.prompt() .user(order-service 最近半小时有没有报错) .tools(new ServerTools(), new DatabaseTools()) .call() .content();框架会自动处理“模型请求调用工具 - 执行工具 - 把结果喂回模型 - 模型继续推理”这个循环。但如果你想自定义循环逻辑比如加风控拦截、加人工确认就需要手动实现。手动实现的骨架大概是这样public String runAgent(String userInput, int maxIterations) { ListMessage messages new ArrayList(); messages.add(new SystemMessage(SYSTEM_PROMPT)); messages.add(new UserMessage(userInput)); for (int i 0; i maxIterations; i) { ChatResponse response chatModel.call(new Prompt(messages)); AssistantMessage assistantMessage response.getResult().getOutput(); if (assistantMessage.hasToolCalls()) { for (ToolCall toolCall : assistantMessage.getToolCalls()) { // 风控拦截点 if (!riskChecker.allow(toolCall)) { messages.add(new ToolResponseMessage(操作被风控拦截)); continue; } String result toolExecutor.execute(toolCall); messages.add(new ToolResponseMessage(result)); } } else { return assistantMessage.getContent(); } } return 达到最大迭代次数未能完成任务; }这个骨架里riskChecker就是你的风控入口。比如涉及“重启服务”“删除数据”这类高危操作可以在这里拦截转人工确认。3.4 并发场景下的 Agent 稳定性设计“AI Agent 怎么扛并发”是个高频问题。我的答案是Agent 本身是无状态的扛并发的关键在外部资源管理。Agent 的一次完整运行涉及三类资源大模型 API、工具背后的服务、记忆存储。大模型 API 通常有 QPS 限制。你不能让 1000 个请求同时打过去必须加限流。我用 Resilience4j 的RateLimiter做客户端限流配置成和 API 提供方的限制一致。超出的请求排队等待而不是直接失败。工具背后的服务可能是数据库、内部 API。这些服务本身有连接池限制Agent 调用时要注意复用连接池不要每次调用都新建连接。另外工具调用要加超时我一般设 3 秒超过就返回“工具超时”让模型决定是重试还是换方案。记忆存储用 Redis 时要注意大 key 问题。对话历史如果很长不要整个 list 一把梭可以按消息 ID 分片存储或者只存最近 N 条。还有一个容易被忽略的点Agent 循环的耗时。一次 ReAct 循环可能调用 3-5 次大模型每次 2-5 秒总共就是 10-25 秒。如果你的接口是同步的用户会等很久。我的做法是改成异步提交任务返回 taskId前端轮询或走 SSE 推送结果。4. 实战避坑与高频问题排查4.1 模型“不听话”的几种典型表现与对策Agent 开发中最让人抓狂的就是模型不按预期行事。我总结了几种典型情况。情况一该调工具的时候不调直接编答案。比如问“今天天气”模型不调天气工具直接说“今天晴天”。这是幻觉的典型表现。对策是在系统提示里强调“涉及实时数据必须调用工具”同时在工具描述里写清楚触发条件。如果还不行可以在用户输入前加一个预处理步骤用规则或小模型判断是否需要工具需要的话在提示词里强制要求。情况二调了工具但参数传错。比如把“order-service”传成“order_service”。对策是工具参数尽量用枚举或白名单校验在工具实现里做参数规范化。另外可以在提示词里给出参数示例。情况三陷入循环反复调同一个工具。比如查日志没查到就一直查。对策是设最大迭代次数同时在提示词里加“如果连续两次调用同一工具且结果相同应停止并告知用户”。情况四工具返回结果太长模型处理不了。比如查日志返回了 1000 行。对策是在工具实现里做截断和摘要只返回关键信息。我一般限制工具返回不超过 2000 字符。4.2 常见问题速查表问题现象可能原因排查方法解决方案Agent 不调用工具工具描述不清、提示词未强调打印模型原始输出看是否有 tool_calls完善工具描述提示词加强制要求工具调用参数错误参数类型复杂、缺少示例查看工具调用日志中的参数扁平化参数提示词加示例循环不终止无最大迭代限制、工具返回空统计迭代次数设 maxIterations空结果时提示模型响应时间过长同步调用、模型慢打点各阶段耗时改异步加超时换更快的模型并发下报错API 限流、连接池耗尽看限流和连接池指标客户端限流扩大连接池记忆混乱历史消息过多、多会话串扰检查会话 ID 隔离限制历史条数Redis 按会话隔离4.3 我踩过的三个印象最深的坑第一个坑工具方法抛异常导致整个 Agent 崩溃。早期我没在工具执行层加 try-catch某个工具抛了 NPE整个请求 500。后来我在toolExecutor里统一捕获异常把异常信息作为工具返回结果喂回模型让模型决定怎么办。这样即使工具挂了Agent 也能优雅降级。第二个坑Redis 记忆没有设过期时间。上线跑了一周Redis 内存爆了。后来所有记忆 key 都加了 TTL短期记忆 30 分钟长期记忆 7 天。另外做了内存监控告警。第三个坑提示词里的工具列表和实际注册的工具不一致。我改代码加了个工具忘了更新提示词结果模型不知道新工具存在一直用旧工具凑合。后来我把工具列表做成动态生成从注册的工具里自动拼提示词杜绝了不一致。4.4 从 Demo 到生产的最后一公里Demo 跑通只要一天但上线要做的还很多。可观测性每次 Agent 运行要记录完整轨迹——用户输入、每轮模型输出、工具调用参数和结果、最终答案、总耗时。这些日志是排查问题的唯一依据。我一般用结构化日志方便后续分析。成本控制大模型调用是按 token 计费的。一个 Agent 任务可能消耗几千 token。要做预算控制比如单次任务 token 上限、单用户日限额。另外缓存高频问题的答案能省不少钱。安全防护Agent 能调工具就意味着它能产生副作用。必须做权限控制——哪些用户能用哪些工具、高危操作要不要二次确认、工具调用要不要审计。我见过一个案例Agent 被诱导调用了删除数据的工具幸好有审计日志才追回来。灰度发布新 Agent 上线先小流量灰度观察成功率、耗时、成本指标没问题再全量。别一上来就全量出了事回滚都来不及。5. 转型路上的学习路线与资源取舍5.1 分阶段学习路线我按自己的经验把 Java 工程师转 AI Agent 分成三个阶段。第一阶段1-2 周跑通最小闭环。目标是用 Spring AI 或 LangChain4j 做一个能调用 1-2 个工具的 Agent。重点理解 ChatClient、Tool、ChatMemory 这三个核心概念。这个阶段不要追求功能多追求的是“跑通”。第二阶段3-4 周补齐 Agent 特有知识。重点学 ReAct 模式、RAG检索增强生成、多路召回、向量数据库。LangChain4j 的Easy RAG模块是很好的入门材料。这个阶段要动手做一个带知识库的问答 Agent。第三阶段1-2 月工程化与生产化。重点学并发控制、可观测性、成本优化、安全防护。这个阶段最好的学习材料是你自己的生产环境——把前两个阶段做的东西真正部署上去接受真实流量的考验。5.2 资源取舍哪些该看哪些可以跳过网上 AI Agent 的资料铺天盖地但质量参差不齐。我的筛选标准是优先看官方文档和源码其次看有完整代码的实战教程最后才看概念科普。Spring AI 和 LangChain4j 的官方文档质量都很高而且有大量示例代码。遇到不懂的类直接看源码比看二手教程快得多。概念性的东西比如 Transformer 原理、注意力机制Java 工程师转型做 Agent 开发其实不需要深究。你是用模型的人不是训模型的人。知道 token、temperature、context window 这些概念就够了。至于 Python 生态的 LangChain、AutoGPT 这些可以了解其设计思想但不必深入代码。Java 生态的对应实现已经足够用了。5.3 一个容易被忽略的能力提示词工程很多 Java 工程师觉得提示词工程“不算技术”这是大错特错。在 Agent 开发里提示词就是你的核心业务逻辑。同样的模型、同样的工具提示词写得好坏效果天差地别。我建议把提示词当代码来管理版本控制、A/B 测试、效果评估。我一般会维护一个提示词库每个提示词有版本号、适用场景、效果指标。改提示词要走评审改完要跑回归测试。提示词写作的核心原则就几条指令明确、格式清晰、给示例、设边界。别写模棱两可的话别让模型猜你的意图。6. 关于转型这件事我最后想说的转型不是把 Java 扔掉去学 Python而是把 Java 的工程能力迁移到 AI Agent 这个新场景。你的并发经验、事务经验、服务治理经验在 Agent 生产化阶段全是宝贝。缺的那块拼图——大模型交互、ReAct 循环、向量检索——补起来并不难因为有 Spring AI 和 LangChain4j 这样的框架帮你兜底。我自己的体会是前两周最痛苦因为概念全是新的跑个 Demo 都能遇到一堆环境问题。但一旦跑通第一个闭环后面就是滚雪球。因为 Agent 开发的本质还是软件工程而软件工程是你的主场。如果你现在还在观望我的建议是今天就去建一个 Spring Boot 项目加一个 Spring AI 依赖写一个能查天气的 Agent。不用想太多先跑起来。跑起来之后你自然知道下一步该学什么。