1. 为什么 Java 工程师转 AI Agent 有天然优势这两年身边不少写 Java 的朋友都在焦虑同一件事AI Agent 这么火自己是不是要被时代甩下去了。我的判断恰恰相反——Java 工程师转 AI Agent起点比大多数人都高只是很多人没意识到自己手里已经握着什么牌。先把概念对齐。AI Agent不是简单的“调个大模型接口返回一段文本”而是一个能自主感知输入、规划步骤、调用工具、观察结果、再决定下一步的闭环系统。它和普通 Chatbot 的本质区别在于“行动能力”Chatbot 只会说Agent 会做。而“会做”这件事落到工程上就是一堆服务编排、状态管理、异常重试、并发控制、可观测性——这些恰好是 Java 后端工程师干了十几年的活。我见过太多 Python 背景的算法同学模型调得飞起但一让他把 Agent 部署成能扛住生产流量的服务线程池、连接池、超时熔断、幂等设计全抓瞎。反过来Java 工程师缺的往往只是“大模型这一层”的认知Prompt 怎么组织、工具怎么描述、上下文怎么裁剪、多轮推理怎么收敛。这一层是可以在几周内补上的而工程能力是几年攒出来的。所以这篇东西我打算讲透三件事Agent 的底层原理到底是怎么回事Java 生态里LangChain4j和Spring AI这两条主流路线怎么选、怎么落地以及ReAct这种“边想边做”的模式在 Java 里怎么实现、怎么扛并发。适合有 Java 基础、想切进 AI Agent 方向但不知道从哪下手的同学也适合已经在写 Agent 但被工程问题卡住的人。提示本文所有代码和配置都基于常见实践整理具体版本 API 可能随迭代变化落地时以你项目锁定的版本为准。2. 先把 AI Agent 的原理拆到能动手的程度2.1 Agent 和普通大模型调用的本质区别普通调用大模型流程是线性的用户输入 → 拼 Prompt → 请求模型 → 拿到文本 → 返回。整个过程是一次性的模型没有“下一步”的概念。Agent 不一样它是一个循环。核心可以抽象成四步感知Perception→ 规划Planning→ 行动Action→ 观察Observation然后拿着观察结果回到规划直到任务完成或达到终止条件。这个循环就是所谓的 Agent Loop。举个具体例子。用户说“帮我查一下北京明天天气如果下雨就提醒我带伞”。普通模型只能回你一句“建议你查一下天气预报”。Agent 会这样跑先规划“我需要调用天气查询工具”行动——调用天气 API观察——返回“明天中雨”再规划“需要给出带伞提醒”最后输出结论。中间可能还涉及多轮工具调用比如先查城市编码再查天气。理解这个循环之后你会发现Agent 的工程难点根本不在模型本身而在于循环怎么控制不失控、工具调用失败怎么办、上下文越来越长怎么裁剪、多个用户并发跑循环怎么隔离状态。这些全是 Java 工程师的主场。2.2 ReAct 模式让模型“边想边做”的标准范式ReAct是 Reasoning Acting 的缩写是目前最主流的 Agent 推理范式。它的核心思想是让模型在每一步都显式输出“思考”和“行动”而不是直接给答案。一个典型的 ReAct 输出长这样Thought: 我需要先查询北京的城市编码 Action: getCityCode Action Input: {city: 北京} Observation: {code: 101010100} Thought: 拿到编码了现在查天气 Action: getWeather Action Input: {code: 101010100} Observation: {weather: 中雨, temp: 18-24℃} Thought: 明天有雨需要提醒带伞 Final Answer: 北京明天中雨气温18-24℃记得带伞。模型每输出一段框架就解析出 Action执行对应工具把结果作为 Observation 塞回上下文再让模型继续。这个“解析-执行-回填”的循环就是 ReAct 的骨架。为什么这个范式好用因为它把“推理”和“行动”解耦了。模型负责想工具负责做框架负责调度。你不需要训练模型只需要把工具描述清楚、把循环控制好。对 Java 工程师来说这就是一个标准的“策略模式 状态机”问题。2.3 工具调用Function Calling的底层机制ReAct 是“文本层面”的推理范式而现代大模型普遍支持的Function Calling是“协议层面”的工具调用能力。两者经常配合使用。Function Calling 的机制是你在请求里带上工具的定义JSON Schema 描述函数名、参数、用途模型如果判断需要调用工具就不再返回自然语言而是返回一个结构化的调用请求比如{name: getWeather, arguments: {city: 北京}}。你的代码解析这个结构执行真实函数把结果再发回去。这里有个关键认知模型本身不执行任何函数它只是“决定调用哪个函数、传什么参数”。真正的执行永远在你的 Java 代码里。这意味着安全性、权限、限流、审计全部由你掌控——这对企业级应用是刚需。工具描述写得好不好直接决定 Agent 的智商。我踩过的坑是工具描述太简略模型经常选错工具参数描述不写清楚格式模型传参乱七八糟。后面会专门讲怎么写工具描述。2.4 记忆与上下文管理Agent 的“工作台”Agent 跑多轮循环上下文会迅速膨胀。每一轮的 Thought、Action、Observation 都要塞进对话历史几轮下来轻松几千 token。如果不管理成本和延迟都会爆炸。记忆一般分三层短期记忆当前任务的对话历史、长期记忆跨会话的用户偏好、知识库、工作记忆当前循环的中间状态。Java 里实现短期记忆最直接的方式就是维护一个消息列表但必须做窗口裁剪或摘要压缩。常见的裁剪策略有三种滑动窗口只保留最近 N 轮、摘要压缩把早期对话让模型总结成一段话、关键信息提取只保留工具调用结果丢掉中间推理。我实测下来滑动窗口 工具结果保留的组合性价比最高简单可靠。3. Java 生态两条路线LangChain4j 与 Spring AI 怎么选3.1 LangChain4j轻量灵活适合快速验证LangChain4j的定位很像 Python 的 LangChain把 Agent、RAG、工具调用、记忆这些概念都做了 Java 封装。它的优点是抽象层次清晰API 直观上手快。一个最小的 Agent 定义大概是这样interface Assistant { String chat(String userMessage); } Assistant assistant AiServices.builder(Assistant.class) .chatLanguageModel(model) .tools(new WeatherTools()) .chatMemory(MessageWindowChatMemory.withMaxMessages(10)) .build(); String answer assistant.chat(北京明天天气怎么样);AiServices是 LangChain4j 的核心它用动态代理把接口方法映射成“带工具和记忆的模型调用”。你只需要定义接口和工具类框架帮你处理 ReAct 循环、工具解析、记忆管理。LangChain4j 的强项在于多路召回和Easy RAG。做知识库问答时它内置了文档加载、切分、向量化、检索的完整链路几行代码就能跑通一个 RAG。如果你要做的是“Agent 知识库”的组合LangChain4j 的开发效率很高。但它也有短板生态相对分散企业级治理能力比如统一的配置中心、监控埋点、多租户隔离需要自己补。另外版本迭代较快API 偶有破坏性变更锁版本很重要。3.2 Spring AI企业级基因适合长期维护Spring AI走的是另一条路——把 AI 能力做成 Spring 生态的一等公民。它的最大价值是“和现有 Spring 项目无缝融合”依赖注入、配置管理、Actuator 监控、事务、AOP 全部复用。Spring AI 里定义一个带工具的 ChatClientBean ChatClient chatClient(ChatClient.Builder builder, WeatherTools weatherTools) { return builder .defaultSystem(你是一个能调用工具的助手) .defaultTools(weatherTools) .build(); }调用时String response chatClient.prompt() .user(北京明天天气怎么样) .call() .content();Spring AI 的优势在于可观测性和可治理性。它天然接入 Micrometer工具调用次数、模型延迟、token 消耗都能打点配置通过application.yml管理多环境切换很自然结合 Spring Security 做工具级权限控制也很顺。关于Spring AI Alibaba社区里经常有人问“是不是停更了”。实际情况是它在持续演进主要价值是打通了国内主流模型平台的适配比如对接百炼上的 Qwen 系列。如果你用的是国内模型Spring AI Alibaba 能省掉不少适配工作。但要注意版本匹配Spring AI 2.0.x 和对应 Alibaba 适配层的版本要对应上否则会出现自动配置不生效的问题。3.3 选型对照表与决策建议维度LangChain4jSpring AI上手速度快API 直观中等需熟悉 Spring 风格与现有 Spring 项目融合一般需手动整合极佳原生集成RAG 能力内置 Easy RAG开箱即用需自行组装灵活度高可观测性需自行埋点原生 Micrometer 支持多模型适配支持广泛通过 starter 适配国内模型靠 Alibaba版本稳定性迭代快需锁版本相对稳健适合场景快速验证、RAG 为主企业级、长期维护、多租户我的建议很直接如果是新项目、要长期维护、团队本来就是 Spring 技术栈选 Spring AI如果是做原型验证、或者核心诉求是 RAG 知识库选 LangChain4j。两者不是非此即彼实际项目里我也见过用 Spring AI 做服务骨架、用 LangChain4j 的检索组件做 RAG 的混搭方案。4. 从零搭一个能跑的 Java Agent4.1 环境准备与依赖配置先明确技术栈JDK 17 起步Spring AI 对 17 支持最好Maven 或 Gradle 都行模型侧需要一个可用的 API Key。Spring AI 的核心依赖dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-openai-spring-boot-starter/artifactId /dependency如果对接国内模型平台换成对应的 starter。配置写在application.ymlspring: ai: openai: api-key: ${AI_API_KEY} base-url: https://your-endpoint/v1 chat: options: model: your-model-name temperature: 0.3这里有个经验temperature 在 Agent 场景不要设太高。Agent 需要稳定地选择工具、输出结构化内容temperature 超过 0.7 后工具选择会变得随机我一般压在 0.2 到 0.4 之间。4.2 定义工具Agent 的“手脚”工具就是普通的 Spring Bean用注解标记Component public class WeatherTools { Tool(description 根据城市名称查询该城市未来天气返回天气状况和温度区间) public WeatherResult getWeather( ToolParam(description 城市名称例如北京、上海) String city) { // 真实调用天气服务 return weatherService.query(city); } }工具描述是重中之重。我总结了几条硬规则描述里写清楚“什么时候用”而不只是“这是什么”。比如“当用户询问天气、气温、是否下雨时使用”。参数描述给出格式示例模型对示例的敏感度远高于抽象说明。一个工具只做一件事。把“查天气和查空气质量”塞进一个工具模型会经常传错参数。返回值尽量结构化避免返回一大段自然语言否则 Observation 会污染上下文。4.3 组装 Agent 与 ReAct 循环Spring AI 的ChatClient已经内置了工具调用循环你不需要手写 while。但如果你想理解底层或者需要自定义循环控制比如限制最大轮数可以手动实现public String runAgent(String userInput, int maxSteps) { ListMessage messages new ArrayList(); messages.add(new SystemMessage(SYSTEM_PROMPT)); messages.add(new UserMessage(userInput)); for (int step 0; step maxSteps; step) { ChatResponse response chatModel.call(new Prompt(messages, toolOptions)); AssistantMessage aiMsg response.getResult().getOutput(); messages.add(aiMsg); if (aiMsg.getToolCalls().isEmpty()) { return aiMsg.getText(); } for (ToolCall call : aiMsg.getToolCalls()) { String result toolExecutor.execute(call); messages.add(new ToolResponseMessage(call.id(), result)); } } return 达到最大步数限制任务未完成; }maxSteps是必须的保险丝。没有它模型可能陷入“调用工具→结果不满意→再调用”的死循环烧钱又烧时间。我一般设 5 到 8 步复杂任务放宽到 10。4.4 记忆管理落地短期记忆用消息窗口MessageWindowChatMemory memory MessageWindowChatMemory.builder() .maxMessages(20) .build();但纯窗口有个问题工具调用的中间结果被裁掉后模型可能“忘记”已经查过的信息导致重复调用。我的做法是对工具结果做单独保留在裁剪时优先保留 ToolResponseMessage优先丢弃早期的 Thought 文本。长期记忆则落到向量库用户的历史偏好、常见问题答案存进去每次对话前做一次相似度检索把 Top-K 结果拼进 System Prompt。这就是 RAG 的思路LangChain4j 的 Easy RAG 把这条链路封装得很省事。5. 扛并发Java Agent 的生产级考验5.1 并发场景下 Agent 的真实瓶颈“AI Agent 怎么扛并发”是搜索热词说明这是真痛点。Agent 的并发瓶颈和普通接口完全不同主要有三个第一模型调用是长耗时 IO。一次带工具调用的 Agent 请求可能涉及 3 到 5 次模型调用每次几百毫秒到几秒总耗时轻松超过 10 秒。这意味着线程会被长时间占用。第二上下文是有状态的。每个用户的对话历史必须隔离不能串。用错共享变量A 用户的工具结果可能出现在 B 用户的上下文里这是灾难级 bug。第三模型侧有速率限制。你的服务能扛住模型平台的 QPS 配额未必扛得住超了就是 429。5.2 线程模型与资源隔离Java 里处理长耗时 IO第一反应应该是异步 虚拟线程。JDK 21 的虚拟线程在 Agent 场景简直是量身定做每个 Agent 循环跑在虚拟线程上阻塞等待模型响应时自动让出载体线程几千并发也不会把平台线程池打爆。try (var executor Executors.newVirtualThreadPerTaskExecutor()) { FutureString future executor.submit(() - agent.run(userInput)); return future.get(30, TimeUnit.SECONDS); }如果还在 JDK 17用CompletableFuture 独立线程池但一定要给 Agent 单独开池别和业务线程池混用否则 Agent 的长任务会把普通接口拖垮。会话状态隔离用ThreadLocal或显式传参都行但我更推荐显式传参——把会话上下文作为方法参数一路传下去避免 ThreadLocal 在异步切换时丢失或串号。5.3 限流、降级与超时设计三层防护缺一不可入口限流用 Sentinel 或 Resilience4j 对 Agent 接口做 QPS 限制保护后端。模型调用超时单次模型调用设 15 到 30 秒超时整个 Agent 循环设总超时 60 秒。降级策略模型不可用时降级到“无工具的纯问答”或返回缓存答案而不是直接报错。CircuitBreaker breaker CircuitBreaker.ofDefaults(agent); SupplierString decorated CircuitBreaker .decorateSupplier(breaker, () - agent.run(input));5.4 成本与延迟优化并发上来了成本就是真金白银。几个实测有效的优化Prompt 缓存System Prompt 固定不变的部分很多模型平台支持缓存能省不少 token。工具结果缓存天气、汇率这类短时间不变的数据缓存 5 分钟避免重复调用。小模型分流意图识别、简单问答用便宜的小模型复杂推理才上大模型。流式输出用 SSE 把模型的流式响应推给前端用户感知延迟大幅下降虽然总耗时没变。6. 常见问题与排查技巧实录6.1 工具调用失败排查表现象可能原因排查方向模型不调用工具工具描述不清、System Prompt 未引导检查描述是否说明使用场景调用工具但参数错误参数描述缺格式示例补充示例加参数校验工具执行报错后模型卡死错误信息未回填或格式不对把错误作为 Observation 回填循环不终止缺 maxSteps 或终止条件加最大步数硬限制上下文超长报错记忆未裁剪加窗口裁剪或摘要压缩6.2 几个我踩过的坑坑一工具抛异常直接中断循环。早期我没做异常捕获工具一报错整个 Agent 就挂了。正确做法是把异常信息包装成 Observation 回填给模型让它自己决定重试还是换方案。坑二System Prompt 写太长。我一度把几十条规则全塞进 System Prompt结果模型注意力被稀释工具选择准确率反而下降。后来精简到核心 5 条效果明显变好。坑三忽略 token 计费。上线第一周账单超预期排查发现是工具结果返回了完整 JSON包含大量无用字段。裁剪返回值后成本降了一半。坑四并发下会话串号。用了一个共享的ChatMemoryBean结果所有用户共享历史。改成每次请求创建独立 memory 实例后解决。6.3 可观测性建设Agent 上线后必须能回答三个问题这次请求调了几次模型、调了哪些工具、每步耗时多少。Spring AI 接 Micrometer 后这些指标都能打点。我还会把完整的 Agent 轨迹每步的 Thought/Action/Observation落到日志出问题时能完整回放。7. 学习路线与后续扩展方向如果你是从 Java 后端转过来我建议的路线是先用 Spring AI 或 LangChain4j 跑通一个带单个工具的 Agent理解 ReAct 循环然后加记忆和 RAG做知识库问答接着上并发和限流把它变成能上生产的服务最后再研究多 Agent 协作、工作流编排这些进阶话题。关于Dify 工作流转成 Spring AI Java 代码这类需求本质是把可视化编排的节点翻译成 Java 的链式调用或状态机。思路是每个节点对应一个Function或Processor节点间的连线对应数据流转条件分支用策略模式实现。这块没有银弹但理解了 Agent Loop 之后翻译工作就是体力活。至于“个人用 AI Agent 做期货交易”这种想法我的态度是谨慎。Agent 能帮你收集信息、做初步分析但金融决策涉及的风险和合规问题远超技术范畴别把 Agent 当成稳赚工具。技术归技术边界要清楚。最后分享一个我自己的体会Java 工程师转 AI Agent最大的障碍从来不是技术而是心态——总觉得自己“不懂 AI”。其实你不需要懂模型怎么训练你只需要懂怎么把模型当成一个能力很强但不太靠谱的同事来管理给它清晰的指令、给它趁手的工具、给它必要的约束、盯着它的每一步。这套管理方法论你写 Java 这些年早就练熟了。