☰
Java工程师转型AI Agent实战:从ReAct原理到生产级落地
2026/10/2 4:56:36 网站建设 项目流程

Java 工程师转型 AI Agent 这件事,我从去年下半年开始认真琢磨,到现在带着团队把两个内部智能体推上了生产环境。回头看,这条路最难的其实不是写代码,而是思维方式的切换。做了七八年 Java,习惯了 Controller 调 Service、Service 调 DAO 的确定性链路,突然要面对一个"模型可能返回任何东西"的世界,那种失控感非常真实。但好消息是,Java 生态这两年补课补得很快,LangChain4j、Spring AI 这些框架把大量脏活累活封装掉了,Java 工程师的工程化能力反而是做 Agent 落地时最稀缺的东西。这篇就把我从原理到落地的完整思路拆开讲,包括选型逻辑、核心代码骨架、并发扛压的坑、以及那些文档里不会写的经验。

1. 先想清楚:Java 工程师做 Agent 的独特优势在哪

1.1 不是"转行",是"能力迁移"

很多人把转型 AI Agent 理解成要重新学一套东西,甚至有人跑去从头啃 Python 生态。我的看法是,如果你已经有扎实的 Java 功底,完全没必要推翻重来。Agent 的本质是什么?是一个能感知输入、做决策、调用工具、拿到结果再继续决策的循环系统。这个循环里,真正跟"AI"强相关的只有两件事:一是跟大模型的通信(prompt 组装、响应解析),二是决策逻辑的设计(ReAct 模式那套思考-行动-观察的循环)。剩下的全是工程问题——状态管理、并发控制、错误重试、可观测性、权限校验、数据一致性,这些恰恰是 Java 工程师天天在干的事。

我举个具体的例子。一个电商客服 Agent,用户问"我上周买的那双鞋能退吗",Agent 需要:查订单状态、判断是否在退货窗口期、检查商品类目是否支持退货、生成回复。这里面"判断是否在窗口期"是纯业务逻辑,Java 写起来又快又稳;"理解用户意图并决定调用哪个工具"才是模型干的活。你会发现,一个 Agent 项目里,模型相关的代码可能只占 20%,剩下 80% 都是你熟悉的那套东西。

1.2 Java 生态的 Agent 框架已经能打了

去年年初的时候,Java 做 Agent 确实有点尴尬,LangChain 是 Python 的,想用只能通过 HTTP 调服务。但现在情况完全变了。LangChain4j 和 Spring AI 这两个框架成熟度上来了,基本的 Chain、Tool Calling、RAG、Memory 这些能力都有,而且跟 Spring 生态集成得非常顺。特别是 Spring AI,如果你团队本来就在用 Spring Boot,引入成本极低,依赖注入、配置管理、Actuator 监控这些全都能复用。

我列个简单的对比,方便你判断选哪个:

维度LangChain4jSpring AI
定位独立框架,不绑定 SpringSpring 生态原生
学习曲线中等,概念较多较低,Spring 开发者上手快
模型支持非常广,国内外都覆盖广,国内模型适配在快速补齐
RAG 能力成熟,多路召回等高级特性全基础能力完善,高级特性跟进中
工具调用灵活,注解式声明注解式,跟 Spring 风格一致
适合场景复杂 Agent、多模型混用Spring 体系内的企业应用

我的建议是:如果你是从零起一个新项目,且团队是 Spring 技术栈,直接上 Spring AI,省心。如果你要做比较复杂的 Agent 编排,需要多路召回、多模型切换、复杂的工具链,LangChain4j 的灵活性更好。当然两者也不是互斥的,我见过有项目用 Spring AI 做基础通信层,用 LangChain4j 的某些组件做 RAG 增强。

1.3 市场需求的真实变化

从招聘市场看,现在很多岗位 JD 里开始出现"有 AI Agent 开发经验优先"这样的字眼,但注意,它们要的不是"会调 OpenAI API"的人,而是"能把 Agent 稳定跑在生产环境"的人。这两者的差距,就是 Java 工程师的机会窗口。会写 prompt 的人很多,但能把 Agent 的并发、超时、降级、监控、成本控制都处理好的人,少。我面过几个候选人,聊 ReAct 原理头头是道,问他"Agent 调用工具超时了怎么办""多个用户同时触发同一个 Agent 实例怎么隔离状态",就答不上来了。这些恰恰是工程能力,是你的主场。

2. ReAct 模式:Agent 的"思考骨架"到底怎么运转

2.1 用生活化的方式理解 ReAct

ReAct 这个词拆开就是 Reasoning + Acting,推理加行动。你可以把它想象成一个刚入职的助理,你让他"帮我订一张明天去上海的高铁票"。他不会直接就去订,而是先想:我需要知道出发地、具体时间、座位偏好。然后他可能去查你的日程表(行动),发现你明天上午有个会(观察),于是推断你应该下午出发(推理),再去查下午的车次(行动),看到有几趟(观察),最后选一趟合适的下单(行动)。

这个"想一步、做一步、看结果、再想下一步"的循环,就是 ReAct 的核心。跟传统的"一次性把问题丢给模型要答案"不同,ReAct 允许模型在过程中调用外部工具、获取新信息、修正自己的判断。这也是 Agent 和普通 Chatbot 最本质的区别——Chatbot 只能基于训练时学到的知识回答,Agent 能主动去获取实时信息并采取行动。

2.2 循环的四个阶段拆解

一个标准的 ReAct 循环,在代码层面通常是这样运转的:

第一阶段,Thought(思考)。模型根据当前的任务目标和已有的观察结果,输出一段推理,决定下一步该干什么。这段推理是自然语言,比如"用户想知道订单状态,我需要调用订单查询工具,参数是订单号"。

第二阶段,Action(行动)。从思考结果里解析出要调用的工具名和参数。这一步在代码里通常是解析模型返回的结构化内容(JSON 或者特定格式的文本)。

第三阶段,Observation(观察)。执行工具调用,把返回结果作为新的上下文喂回给模型。这里要注意,工具返回的内容可能很长,需要做截断或摘要,否则上下文会爆炸。

第四阶段,判断是否结束。如果模型认为任务完成了,输出最终答案,循环结束;否则带着新的观察结果回到第一阶段。

用伪代码表示大概是这样:

public String runAgent(String userInput) { List<Message> messages = new ArrayList<>(); messages.add(systemPrompt()); messages.add(userMessage(userInput)); for (int i = 0; i < MAX_ITERATIONS; i++) { // 调用模型,获取思考和行动 AiMessage response = chatModel.generate(messages); messages.add(response); // 判断是否要调用工具 if (response.hasToolCalls()) { for (ToolCall call : response.toolCalls()) { String result = executeTool(call); messages.add(toolResultMessage(call.id(), result)); } } else { // 没有工具调用,说明模型给出了最终答案 return response.text(); } } return "任务超出最大迭代次数,请简化问题"; }

这段代码看着简单,但里面藏着好几个坑。MAX_ITERATIONS设多少合适?设小了任务做不完,设大了可能死循环烧钱。我的经验是 8 到 12 之间,具体看任务复杂度。还有工具执行失败怎么办?直接抛异常会让整个循环崩掉,正确做法是把错误信息也作为观察结果喂回去,让模型自己决定是重试还是换个思路。

2.3 为什么 ReAct 比"一次性问答"更适合复杂任务

我做过一个对比测试,同样一个"帮我分析这份销售数据并给出建议"的任务。用普通的一次性问答,模型只能基于你给的数据做表面分析,如果数据里有个字段它不理解,它就只能瞎猜。用 ReAct 模式,模型可以先调用一个"查询字段含义"的工具,搞清楚每个字段代表什么,再调用"计算同比环比"的工具,最后基于准确的计算结果给建议。准确率差了不止一个档次。

但 ReAct 也不是银弹。它的代价是延迟高、token 消耗大。一个需要 5 轮循环的任务,token 消耗可能是单次问答的 5 到 8 倍。所以我的原则是:简单任务用单次问答,需要多步推理或外部信息获取的才上 ReAct。别为了炫技把所有请求都走 Agent 循环,成本扛不住。

3. 框架选型与第一个可运行 Agent 的搭建

3.1 环境准备里最容易忽略的细节

搭第一个 Agent 之前,有几个准备工作看着不起眼,但没做好后面会反复踩坑。

模型接入方式的选择。国内项目现在主流是接百炼、智谱、DeepSeek 这些平台的模型。Spring AI 和 LangChain4j 都提供了对应的 starter,但要注意版本匹配。我遇到过 Spring AI 某个版本跟某个模型平台的 API 协议对不上,工具调用一直返回格式错误,折腾了半天才发现是版本问题。建议锁定版本后先跑通官方的最小示例,再往项目里集成。

API Key 的管理。千万别硬编码在代码里,也别直接写在 application.yml 里提交到仓库。用环境变量或者配置中心。我见过有团队把 key 提交到公开仓库,第二天就被刷爆了。另外要设置好配额告警,模型调用是按 token 计费的,一个死循环的 Agent 一晚上能烧掉不少钱。

超时和重试配置。模型调用是网络请求,超时是常态。默认超时往往太长,建议连接超时设 5 秒,读取超时设 30 到 60 秒(取决于任务复杂度)。重试策略要谨慎,因为模型调用不是幂等的,盲目重试可能重复扣费或产生重复的工具调用。我的做法是只对网络层面的错误重试,业务层面的错误不重试。

3.2 用 Spring AI 搭一个最小可用的 Agent

假设你用的是 Spring Boot 3.x,引入 Spring AI 的 starter 之后,一个带工具调用的 Agent 大概长这样:

@Configuration public class AgentConfig { @Bean public ChatClient chatClient(ChatClient.Builder builder, OrderTools orderTools, LogisticsTools logisticsTools) { return builder .defaultSystem("你是一个电商客服助手,负责处理订单和物流相关问题。" + "回答要简洁准确,不确定的信息要主动调用工具查询。") .defaultTools(orderTools, logisticsTools) .build(); } }

工具类的定义用注解声明:

@Component public class OrderTools { @Tool(description = "根据订单号查询订单详情,包括状态、金额、下单时间") public OrderDetail queryOrder(@ToolParam(description = "订单号") String orderId) { // 实际的查询逻辑 return orderService.getById(orderId); } @Tool(description = "判断订单是否在退货窗口期内") public boolean isInReturnWindow(@ToolParam(description = "订单号") String orderId) { OrderDetail order = orderService.getById(orderId); return Duration.between(order.getCreateTime(), LocalDateTime.now()) .toDays() <= 7; } }

调用的时候:

@RestController public class ChatController { private final ChatClient chatClient; public ChatController(ChatClient chatClient) { this.chatClient = chatClient; } @PostMapping("/chat") public String chat(@RequestBody ChatRequest request) { return chatClient.prompt() .user(request.getMessage()) .call() .content(); } }

就这么点代码,一个能查订单、能判断退货窗口的 Agent 就跑起来了。框架会自动处理工具调用的循环——模型决定调用哪个工具,框架执行,把结果喂回去,直到模型给出最终答案。这就是我说的"Java 生态已经能打了",大量样板代码都被封装掉了。

3.3 工具设计的三条实战原则

工具是 Agent 的手脚,设计得好不好直接决定 Agent 的能力上限。我总结了三条原则。

原则一:工具粒度要适中。太粗,比如一个"处理订单"的工具包揽所有订单操作,模型很难准确调用;太细,比如把"查询订单"拆成"查询订单状态""查询订单金额""查询订单时间"三个工具,模型要调三次,浪费 token 还容易出错。我的经验是按业务动作划分,一个工具对应一个完整的业务操作。

原则二:描述要写给模型看,不是写给人看。@Tool的 description 是给模型判断何时调用用的,要写清楚"什么场景下用这个工具""参数是什么含义"。我见过有人写"查询订单",太模糊了,模型不知道什么时候该用。写成"根据订单号查询订单的完整信息,适用于用户询问订单状态、金额、下单时间等场景",模型判断准确率明显提升。

原则三:返回值要控制大小。工具返回的内容会进入上下文,返回一个包含几十个字段的完整订单对象,既浪费 token 又可能干扰模型判断。只返回模型需要的信息,或者对返回内容做摘要。我一般会把返回控制在几百个 token 以内。

4. 让 Agent 扛住并发:那些压测时才暴露的问题

4.1 有状态和无状态:第一个要做的架构决策

Agent 跟普通接口最大的不同是它通常是有状态的——多轮对话需要记住上下文。这就带来一个经典问题:状态放哪?

最简单的做法是放内存,用一个 Map 存 sessionId 到对话历史的映射。单机跑没问题,一上多实例就完蛋,用户第一次请求打到 A 机器,第二次打到 B 机器,上下文就丢了。我早期就踩过这个坑,测试环境单机跑得好好的,一上生产多副本就出现"Agent 失忆"。

正确做法是把会话状态外置。用 Redis 存对话历史是最常见的方案,key 用 sessionId,value 存消息列表,设置合理的过期时间。这样任何一台机器都能拿到完整的上下文。但要注意序列化问题,消息对象要能正确序列化和反序列化,特别是包含工具调用信息的那种复杂结构。

还有一种思路是无状态设计,每次请求把完整上下文带上来。适合那种不需要长期记忆的场景,比如一次性的任务处理。好处是水平扩展毫无压力,坏处是客户端要维护上下文,且请求体可能很大。

4.2 模型调用的并发瓶颈与应对

Agent 的响应时间主要花在模型调用上,一次调用几秒到几十秒很正常。如果你的 Agent 一个请求要循环 5 次,那就是几十秒的响应时间。并发一上来,线程池瞬间被打满。

我实测下来,几个有效的应对手段:

第一,异步化。Spring AI 和 LangChain4j 都支持流式响应和异步调用。对于不需要即时返回的场景,把 Agent 调用放到异步线程池里,接口立即返回一个任务 ID,客户端轮询结果。这样能大幅提升吞吐量。

第二,连接池调优。模型调用的 HTTP 客户端连接池要单独配置,不能跟业务接口共用。默认的连接数往往不够,需要根据并发量调整。但也不能无限大,模型平台通常有 QPS 限制,连接开太多反而会触发限流。

第三,分级降级。当系统压力大时,把复杂的 Agent 循环降级成单次问答,牺牲一些能力换取响应速度。这个策略要提前设计好开关,压力来了能一键切换。

第四,缓存。很多 Agent 请求是重复的,比如"退货政策是什么"这种问题。对这类请求做结果缓存,能省下大量模型调用。但要注意,涉及实时数据的请求不能缓存。

4.3 一个真实的并发事故复盘

去年我们上线一个内部知识问答 Agent,上线第二天就出事了。现象是响应越来越慢,最后整个服务卡死。排查下来是这么回事:Agent 的对话历史存在 Redis 里,每次请求都要读取完整历史。有个用户开了个超长会话,历史消息累积到几百条,每次请求都要把这几百条消息序列化后发给模型。这个请求特别慢,占着线程不放,慢慢把线程池耗尽了。

修复方案有三层:一是给对话历史设置长度上限,超过就做摘要压缩,只保留最近几轮和关键信息;二是给单个请求设置总超时,超时就中断,不能让一个请求无限期占用线程;三是把模型调用和业务逻辑的线程池隔离,模型调用慢不能拖垮整个服务。

这个事故给我的教训是:Agent 的"状态"是个隐形炸弹,一定要在设计阶段就想清楚它的生命周期和大小边界。

5. RAG 增强:让 Agent 用上你的私有知识

5.1 为什么 Agent 需要 RAG

模型的知识有截止日期,也不知道你公司的内部文档。用户问"我们产品的退款政策是什么",模型要么瞎编,要么说不知道。RAG(检索增强生成)就是解决这个问题的——先从你的知识库里检索相关内容,把检索结果作为上下文一起发给模型,让模型基于这些真实内容回答。

Agent 和 RAG 是绝配。Agent 可以在需要的时候主动触发检索,而不是每次都把所有知识塞进上下文。比如用户问订单问题,Agent 调用订单工具;用户问政策问题,Agent 调用知识检索工具。按需检索,既准确又省 token。

5.2 检索质量决定 RAG 的上限

RAG 的效果,七分靠检索,三分靠生成。检索不准,模型再强也白搭。我踩过的坑主要在这几个地方:

分块策略。文档不能整篇塞进去,要切成小块。切太大,检索出来的内容包含太多无关信息;切太小,可能把完整的意思切断了。我的经验是按语义切分,而不是按固定字数。比如按段落切,或者用模型辅助判断语义边界。块大小控制在 300 到 500 字比较合适,块之间留一点重叠,避免边界信息丢失。

多路召回。单一检索方式容易漏。LangChain4j 支持多路召回,可以同时用向量检索和关键词检索,然后把结果融合排序。向量检索擅长语义相似,关键词检索擅长精确匹配,两者互补。我实测下来,多路召回比单路召回的准确率能提升 20% 以上。

重排序。初步召回的结果往往不够精准,可以用一个重排序模型对结果重新打分排序,把最相关的排到前面。这一步会增加一点延迟,但对准确率提升明显,值得做。

5.3 把 RAG 接进 Agent 的两种方式

一种是把 RAG 做成一个工具,Agent 需要的时候调用。好处是灵活,Agent 自己判断什么时候该检索。坏处是依赖模型的判断,有时候它该检索却不检索。

另一种是在 Agent 处理前先做一次检索,把结果作为背景知识注入。好处是保证每次都有知识支撑,坏处是可能检索出无关内容干扰模型。

我的做法是两者结合:常规问题走预检索,复杂问题让 Agent 自己决定是否调用检索工具。同时给 Agent 的 system prompt 里明确写"涉及公司政策、产品信息的问题,必须先调用知识检索工具",用提示词引导它的行为。

6. 从 Demo 到生产:上线前必须补的课

6.1 可观测性:看不见的 Agent 最危险

Agent 是个黑盒,模型为什么这么决策,你很难完全搞清楚。所以可观测性特别重要。至少要记录这几样东西:每次请求的完整对话历史、每次模型调用的输入输出和耗时、每次工具调用的参数和结果、整个请求的总耗时和 token 消耗。

这些数据一方面用于排查问题,另一方面用于成本核算。我见过有团队上线一个月才发现某个 Agent 的 token 消耗是预期的十倍,就是因为没做监控。建议把 Agent 的执行链路用 traceId 串起来,跟现有的链路追踪系统打通,这样出问题能快速定位。

6.2 成本控制:别让 Agent 变成吞金兽

模型调用是按 token 计费的,Agent 的循环特性让它特别费 token。控制成本的手段有几个:设置单次请求的 token 上限,超过就中断;对简单问题走轻量模型,复杂问题才用大模型;缓存高频问题的答案;定期分析 token 消耗,找出异常请求。

我还会给每个 Agent 设置日消耗上限,超过就告警甚至限流。这不是抠门,是保证系统可持续。一个失控的 Agent 一晚上烧掉的钱,可能比你一个月预算还多。

6.3 安全与权限:Agent 能做的事要有边界

Agent 能调用工具,就意味着它能执行实际操作。如果工具里有"删除订单""修改用户信息"这种敏感操作,一定要做好权限校验。不能让模型随便就能触发这些操作。

我的做法是:敏感工具调用前必须经过人工确认,或者设置严格的白名单。另外,工具的参数要做校验,防止模型被诱导传入恶意参数。还有 prompt 注入的问题,用户可能在输入里藏指令试图让 Agent 执行非预期操作,这个要在输入层做过滤和检测。

7. 我踩过的几个典型坑和应对思路

7.1 工具调用死循环

现象是 Agent 反复调用同一个工具,停不下来。原因通常是工具返回的结果模型无法理解,或者模型陷入了某种循环推理。应对方法是设置最大迭代次数,同时在 prompt 里明确告诉模型"如果连续两次调用同一工具得到相同结果,应该停止并告知用户"。

7.2 上下文超长导致调用失败

对话轮次多了,上下文越来越长,最后超过模型的上下文窗口限制,调用直接报错。应对方法是做上下文压缩,把早期的对话用模型总结成摘要,只保留最近几轮原文。或者用滑动窗口,只保留最近 N 轮。

7.3 模型返回格式不稳定

让模型输出 JSON,它有时候会多输出一段解释文字,导致解析失败。应对方法是用框架提供的结构化输出能力,或者在 prompt 里严格约束格式,同时代码里做容错解析,解析失败时尝试提取 JSON 部分。

7.4 工具执行超时拖垮整个请求

某个工具调用外部接口特别慢,把整个 Agent 请求卡住。应对方法是给每个工具调用设置独立超时,超时后把超时信息作为观察结果返回给模型,让它决定是重试还是换方案。

8. 给转型路上的 Java 工程师的几句实在话

如果你现在还在观望,我的建议是别等了,直接动手搭一个。不用追求完美,先跑通一个最简单的 Agent,哪怕只是查天气、算数学题。跑通之后你会有很多具体的疑问,带着疑问去学,比看十篇原理文章都管用。

学习路径上,我的建议是先理解 ReAct 的循环逻辑,这是 Agent 的骨架;然后熟悉一个框架(Spring AI 或 LangChain4j 选一个),把工具调用和 RAG 跑通;最后补工程化的东西,并发、监控、成本、安全。前面两块一两周能上手,后面那块才是真正拉开差距的地方,也是你作为 Java 工程师的优势所在。

别被那些"AI 要取代程序员"的论调吓到。至少目前来看,Agent 落地最缺的就是能把系统做稳的工程师。模型能力在快速进步,但把模型能力变成可靠产品的工程能力,进步得慢得多。这个时间差,就是你的机会。

最后分享一个我自己的习惯:每做一个 Agent,我都会建一个"失败案例库",把模型判断错误、工具调用异常、用户反馈不好的案例都记下来。定期回顾这些案例,比看任何教程都能提升你对 Agent 行为的理解。这个习惯坚持了半年,现在设计新 Agent 的时候,很多坑在动手前就能预判到。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询