Java开发者转型AI Agent:不用学Python,用Spring AI直接落地 先给结论我是做Java服务端出身的从毕业开始写后端一写就是十几年。最近半年完整转型做AI Agent开发最大的感受不是“技术有多难”而是很多人根本走不到技术这一步90%的人挂在同一个坑上——他们坚定地认为做AI必须先学Python不学Python就做不了Agent。这个认知错得离谱。我用自己的经历告诉你我一行Python都没写过照样完成了AI Agent从架构设计到落地部署的全流程。Java生态下的Spring AI、LangChain4j这些框架已经非常成熟加上大模型本身通过HTTP API对外提供服务跟编程语言根本不绑定。真正的工作量在于理解Agent的运作原理、掌握工具调用的编排逻辑、学会控制上下文窗口这些东西跟你是不是Java出身没有半点关系。这篇文章把我这半年的实战复盘完整写出来包括认知拆解、架构设计、核心代码、踩坑记录。给所有想转型AI Agent的Java开发者一条可以直接照着走的路。整个内容很长建议先收藏再慢慢看。我现在就把“为什么不用学Python”这件事彻底讲透。1. 先破题为什么90%的人挂在“必须学Python”这个坑上1.1 AI Agent的本质跟Python没有必然关系很多人一提到AI开发脑子里第一个画面就是Python脚本、TensorFlow、PyTorch。这套印象来自深度学习时代那时候确实绕不开Python因为主流框架的训练接口、数据处理生态都在Python那边。但AI Agent是完全不同的东西。Agent的核心是什么是大模型通过“感知 - 决策 - 行动”的循环来完成一个目标。说得再直白一点就是程序把用户的一句话拆解成任务选合适的工具去执行再把结果交回模型继续推理。这套机制的核心是协议、编排和状态管理不是数值计算。大模型怎么接入你调用它本质上就是发一个HTTP请求把消息列表和工具描述发过去然后拿回一段JSON。这个接口人人可用跟语言无关。你把同样的请求用Java发、用Go发、用C#发模型返回的结果一模一样。语言只是一个载体真正的灵魂是接口协议和交互设计。我之前在公司内部做过一个分享现场问大家你们觉得Agent开发里最花时间的部分是什么有人说是训练模型有人说是调参。实际上既不是训练也不是调参而是把业务流程拆成“模型能理解的工具描述”和“模型能顺畅执行的循环逻辑”。这两件事靠的是工程能力和业务理解跟你用哪门语言写出来毫无关系。1.2 Java生态早就补齐了Agent开发的基础设施Java在这个领域并不落后。Spring官方推出的Spring AI框架已经把大模型接入、Prompt模板、工具调用、向量存储这些能力封装成了Spring Boot风格的组件。另外还有LangChain4j它是LangChain思想在Java生态的完整实现模型对话、结构化输出、记忆管理、RAG都覆盖到了。我自己实测下来的感受是Spring AI的优点是跟Spring Boot、Spring Cloud这套技术栈无缝融合如果你的团队本身就在用Spring引入成本极低LangChain4j的优点是Agent相关的抽象更细记忆策略和工具调用的扩展点特别清晰适合做复杂编排。除了框架JVM生态本身处理高并发、连接池、线程池这一套能力是现成的。做Agent应用往往要面对多用户同时对话、工具调用超时、API限流这些场景这恰好是Java从业者的老本行。你不需要重新学一套并发模型直接把自己多年的服务端经验搬过来用就行。1.3 转型的真正门槛是思维方式不是语法13年Java经验给我最大的帮助不是语法熟练度而是长期养成的“拆解问题、建模、落工程”的思维方式。AI Agent开发对后端工程师特别友好的点就在这里它需要你把业务拆成清晰的子任务需要你设计稳定可靠的调用链路需要你做异常处理、超时控制、日志追踪。这套东西跟写交易系统、写订单中心是同一个底层逻辑。转型真正要换的是理解“模型的不确定性”。以前我们写代码同样的输入一定得到同样的输出这叫确定性。但Agent应用里模型可能这次返回工具调用参数、下次直接给答案甚至偶尔给你格式错误的内容。你作为开发者不是去消灭这种不确定而是设计一套循环逻辑去包容它、纠正它、让它最终收敛到正确结果。这个思维转变比学一门新语言的语法要难得多也重要得多。1.4 别把“不用学Python”理解成“Python一无是处”我得先把话说完整避免误导。我说不用学Python针对的是“把Python当成人门前提”这件事。如果你本身就是Python开发者用Python做Agent当然完全没问题这是个人技术栈的选择。但对于13年Java出身的人如果你的目标是快速上手AI Agent开发正确的策略是用你最熟悉的Java直接开始把精力花在理解Agent架构、工具调用编排、上下文管理这些通用能力上。等你把这些核心概念搞通再去看Python代码你会发现它也不过是同一套原理的另一种写法。那时候你学Python的速度会快得多因为你要学的只是语法不是思想。2. 用Java视角拆解一个Agent的最小闭环2.1 五个核心模块每个都对应你熟悉的Java概念一个最简单的Agent拆开来看由五个模块组成模型接入层负责跟大模型API打交道。这层在你眼里就是一个HTTP Client封装跟调用外部REST服务没有本质区别。提示词管理器负责把用户消息、系统指令、历史记录、工具描述组装成模型能理解的Prompt。这部分可以抽象成模板引擎类似你以前用Freemarker拼HTML。工具注册中心把Java方法暴露成模型可以调用的工具。每个工具就是一个带注解的方法方法名、描述、参数Schema都会被序列化成JSON交给模型。记忆管理器负责维护会话历史。它决定哪些消息发给模型、什么时候截断、什么时候做摘要压缩。Agent循环引擎这是灵魂。它负责发起对话、判断模型是否要求调用工具、执行工具、把工具结果再喂回模型直到模型给出最终答案。这套结构放在Java里非常自然。模型接入层就是一个Service工具注册中心就是一个Bean容器记忆管理器就是一个带过期策略的缓存。你会发现之前十几年积累的Spring Bean管理、AOP切面、设计模式经验在这里全都能用上。2.2 Java类型系统在Agent开发中的独特优势市面上很多Agent框架用JSON Schema来描述工具参数。Java在这一块有个天然优势类型系统是强类型的。你写一个方法public String queryWeather(String city, Integer days) { ... }框架可以通过反射自动解析出参数名、参数类型再结合注解中的描述信息生成一份结构严谨的JSON Schema给模型。模型返回的参数在反序列化回Java对象时也不需要你自己写一堆手工校验类型不匹配直接抛异常错误处理链路清晰。特别强调一下枚举类型和嵌套对象的使用。我做过一个模拟项目X里面有个工具需要接收“日期范围”和“排序方式”。我用一个Range对象作为参数把排序方式定义成枚举模型返回的JSON会被自动映射成对象代码极其干净。同样的场景放在Python里你要自己写一堆dict字段校验跑通了还好跑不通时排查成本很高。2.3 一定要绕开的误区把Agent当成一次API调用常见的新手误解是这样的我调一次大模型API把问题发给它拿到结果这不就完成了吗怎么还需要一个“循环”大模型确实可以在一次调用中给出一个完整回答但它做不到的是“自主使用工具”。比如你问它“帮我查一下杭州今天天气然后写一篇适合出行的穿衣建议”如果只调一次API模型只能凭训练知识给你一段话它不会真的去查天气。Agent的循环逻辑是这样的第1轮把用户问题 工具描述发给模型。模型返回一个工具调用指令比如call query_weather({city:杭州})。第2轮程序执行这个Java方法得到真实的天气数据。第3轮把工具执行结果作为一条新消息连同原始问题一起再发给模型。模型拿到真实数据后生成最终的穿衣建议。这就是Agent和普通API调用的本质区别它是一个多轮闭环由程序来控制何时停止。理解这一点你就理解了Agent开发最核心的骨架。剩下的工作不过是在这个骨架上增加记忆、规划、多工具协同等能力。3. 实战Java从零搭建一个带工具调用的Agent3.1 工程骨架与依赖选择我建议直接用Spring Boot 3.x配合Spring AI或者LangChain4j。下面以Spring AI为例Maven依赖核心部分是这样dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model/artifactId version1.0.0/version /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-tool-call/artifactId version1.0.0/version /dependency如果项目用的是Gradle同样有对应的依赖坐标。版本号以官方仓库为准建议跟随最新的稳定版不要停留在旧版本上因为Agent相关API迭代很快旧版本的抽象可能跟前端模型接口不匹配。整个工程结构保持标准的Maven分层就够了controller层接收用户请求service层跑Agent循环tools包放业务工具方法。你可以把它理解成普通的Spring Boot应用只不过多了一个跟大模型对话的中间层。3.2 配置模型Provider第一步是配置模型客户端。在Spring AI中这东西叫ChatClient通过配置类或者application.yml暴露出来。大致配置如下spring: ai: model: provider: example api-key: ${LLM_API_KEY} base-url: https://api.example.com/v1 chat: options: model: llm-model-name temperature: 0.7这里我用的是占位符实际操作时你需要填自己对接的模型服务商提供的地址和密钥。有一点提醒一下不同的服务商对工具调用Function Calling的支持度不一样生产环境选型之前务必先测一遍它的工具调用返回格式是否规范。配置完成之后在业务代码里注入ChatClientService public class AgentService { private final ChatClient chatClient; public AgentService(ChatClient chatClient) { this.chatClient chatClient; } public String chat(String userMessage) { return chatClient.call(userMessage); } }这一步跑通说明你的Java应用已经能跟大模型正常对话。接下来才是核心内容把Java方法变成模型可用的工具。3.3 如何把Java方法暴露给模型做一个Agent光会聊天没有意义必须让它能“动手做事”。Spring AI的做法是提供一个Tool注解你只需要在Java方法上打上注解框架会自动把方法注册成工具并生成模型可读的JSON Schema。下面是我在一个模拟天气查询场景里写的工具方法Component public class WeatherTools { Tool(name query_weather, description 查询指定城市当前天气情况) public WeatherInfo queryWeather( ToolParameter(description 城市名称例如杭州、上海、北京) String city, ToolParameter(description 查询天数1表示今天3表示未来三天) Integer days) { // 这里调用真实的天气服务接口或本地缓存库 WeatherInfo info weatherDataService.fetch(city, days); return info; } }这段代码的关键点有三个。第一Tool里的description很重要。模型是没有“看代码”能力的它只能通过这段描述来理解工具是干嘛的。描述越清晰模型越知道什么时候该调用这个方法。我见过很多新手在这里就写一句“查询天气”模型经常会在不该调用的时候调或者该调用的时候不调。正确做法是把触发条件也写进去比如“当用户询问天气或未来气温时调用”。第二方法参数上的ToolParameter描述同样关键。模型需要根据参数描述来生成正确的JSON参数。比如city参数如果你不说明“这是城市名称”模型可能回传“hz”这种简写导致反序列化失败。第三返回值建议封装成对象。如果返回一个字符串模型也能读懂但结构化对象能减少模型理解负担。我习惯返回一个内部类包含城市、日期、温度、天气状况等字段模型拿到结构化数据之后生成回答的质量明显更高。Spring AI会把这些工具统一注册到工具上下文里在调用ChatClient时一并告知模型“我手上有这些工具你可以按需使用”。具体使用时你需要在初始化ChatClient的时候把工具类传入ChatClient client ChatClient.builder() .defaultSystem(你是一个智能助手可以回答用户问题必要时使用工具获取资料。) .defaultTools(new WeatherTools()) .build();defaultTools里传入的每个Bean都会被扫描并转换成模型能理解的工具定义。这一步做完你的应用就已经具备了“模型 工具”的双层能力。3.4 实现Agent循环对话、判断、行动、再对话有了模型和工具还需要一个循环引擎来驱动整个交互流程。Spring AI的ChatClient上有一个toolCalling的调用方式适合跟前端模型接口做手动编排。不过我更建议先理解循环的底层逻辑我用一段简化代码来展示核心部分public class AgentLoop { private final ChatClient chatClient; private final ToolExecutor toolExecutor; private final int maxIterations 5; public String run(String userMessage) { ListMessage messages new ArrayList(); messages.add(new UserMessage(userMessage)); for (int i 0; i maxIterations; i) { ChatResponse response chatClient.call(new ChatRequest(messages)); if (!response.hasToolCalls()) { return response.getContent(); } ListToolCall toolCalls response.getToolCalls(); for (ToolCall call : toolCalls) { String result toolExecutor.execute(call.getName(), call.getArguments()); messages.add(new ToolResultMessage(call.getId(), result)); } } return 已达最大迭代次数请调整问题或工具描述; } }这个循环的终止条件是“模型不再要求调用工具”。第一轮模型可能给出工具调用指令程序执行完后把结果作为ToolResultMessage加回消息列表然后把整个列表再次发给模型。模型读完工具结果后要么给出最终答案要么继续要求调用下一个工具。maxIterations是一个安全阀。为什么必须有因为模型有概率陷入来回调用工具的循环比如查完天气又查气温查完气温又查当地新闻无限延伸。给一个最大迭代次数可以避免Agent在极端情况下消耗太多API费用。我一般设置5到8根据业务复杂度调整。这里有个实践细节要特别注意每次循环都要带上历史的用户消息和工具结果不能只发最新一条。模型没有记忆它要理解当前状态依赖你每条消息把上下文完整传递。这就是为什么记忆管理那么重要。3.5 加记忆会话窗口与消息截断策略生产环境的Agent不能是无状态的。用户可能连续问多句话比如先问“杭州天气怎么样”再问“那上海呢”。第二个问题如果脱离了之前的会话历史模型根本不知道“那”指的是什么。我会在后端用Redis维护一个sessionId对应的消息列表。每次请求时把历史记录捞出来拼接上用户最新消息一起发给模型。这个列表不能无限长因为上下文窗口有限而且超长消息会显著增加费用和延迟。两个常用的截断策略滑动窗口策略只保留最近N条消息超出部分直接丢弃。适合对话轮次不多、信息连续性要求不高的场景。摘要压缩策略当消息超过阈值时调用模型把已有内容压缩成一个摘要后续对话基于摘要继续。适合长对话、深度探讨的场景。我的建议很简单早期用滑动窗口就够了。N的大小根据模型上下文长度设定比如上下文支持8k token我通常保留最近10到15条消息约3到5k token留出余量给工具描述和生成内容。摘要压缩等业务真正需要时再上省去前期复杂度。4. 我趟过的坑工具调用失败、上下文爆炸、并发控制4.1 工具调用反复失败问题出在参数的“模糊描述”上我在前一个月里最常遇到的现象是模型反复要求调用某个工具但传的参数永远不对。排查了很久最后发现原因既不在模型也不在代码而在工具描述写得太模糊。比如我有一个查订单状态的工具参数是orderId。我最初的描述是“订单号”模型返回的JSON长这样{orderId: 20240601}。但系统里的订单号实际上是带前缀的比如“ORD20240601-001”。模型传了一个不存在的单号查不到数据报错然后它觉得是自己参数没传对又开始改格式重试来回折腾五六轮。解决之道把参数描述写精确把数据格式的约束写进描述。修改后的描述是“用户的订单编号格式为ORD开头包含日期和序号例如ORD20240601-001”。加上这个例子之后模型几乎不再出错。还有一个高频坑模型偶尔会返回一个工具调用的JSON参数但参数类型跟你定义的不一致。比如Integer类型的days它返回了一个字符串“3”。强类型框架反序列化时会报错导致整个循环中断。我的处理方式是在工具执行入口加一个参数解析兜底方法遇到类型不一致时做一次宽松转换尽可能把String转成数字。这个兜底逻辑能让你的Agent从“偶发小故障就能挂掉”变成“稳定运行几周才被真正不可恢复的错误打断”。4.2 上下文爆炸一条消息把几十轮历史全塞进去另一个典型问题是“把全部历史都发给模型”。有段时间我觉得既然模型上下文有8k那我无脑塞就好。结果对话到第30轮时每轮请求光历史消息就占据了6k token模型剩下2k空间生成回答回答质量肉眼可见地下降费用也水涨船高。我用了一个很简单的策略来解决按“系统消息 最近10条消息”的规则截断。系统消息写死了角色设定和工具使用规范永远在第一位后面跟最近的对话轮次。试跑了一周回答质量稳定费用也比原来降了40%左右。进阶一点的做法是给每条消息打时间戳或者轮次序号超出的部分调用模型做摘要。注意摘要本身也需要成本和时间所以建议只在用户主动开启长对话场景时才启用不要在默认链路里加。4.3 高并发场景下的线程池与超时控制Agent应用跟传统接口最大的不同在于一次用户请求内部会发起多轮模型调用每一轮可能还要执行外部工具。一个请求消耗的资源和时间远大于普通的CRUD接口。如果线上直接跑默认线程池很快就会把连接池和下游API的配额打满。我在项目里做了三件事第一把Agent执行的线程池独立出来单独配置核心线程数、最大线程数、队列容量。不要让Agent任务跟普通接口抢线程资源。我给这个线程池设置过比较合理的参数核心线程数16最大线程数32队列容量1000拒绝策略改为由调用方线程执行。第二给每一步都设置超时。模型调用超时设置30秒工具执行超时设置5秒整个Agent循环最外层设置90秒的总超时。为什么外层还要超时因为多轮循环叠加起来非常惊人。同一用户的一轮对话最多允许它跑5轮工具调用到达上限后直接返回当前结果或提示用户换个问法。第三针对同一个用户的会话做串行化控制。用户连点两次“发送”时如果前后两个请求都带同一个sessionId那么后者会等待前者完成避免同一session的历史消息被并发修改导致数据错乱。这个锁我用的是Redis的分布式锁key就是sessionId。4.4 API返回慢、限流与流式输出的取舍大模型API的响应速度远高于传统接口的牺牲但完全不适合对延迟敏感的同步调用场景。如果你做的是内部工具类Agent那么同步等待问题不大如果你做的是用户直接对话的产品强烈建议一开始就上流式输出。流式输出跟普通调用在Java API里差别不大Spring AI提供了stream()方法返回Flux对象。用户体验上用户会感觉模型“边说边写”而不是盯着一个光标转圈圈等10秒。流式输出还能配合SSE协议直接推到前端整个链路Java侧实现很顺畅。还有一个必须考虑的限流。大多数模型服务商都有每分钟请求数限制。Agent循环里一次用户请求可能产生五六次模型调用限流很容易被打爆。我的方案是在Agent层做一次本地令牌桶限流把每分钟模型调用次数控制在配额的一半以下同时在收到限流错误时做指数退避重试。5. 90%的人挂在的那个坑到底挂在哪5.1 坑的真相不是学不会是“学错方向”文章标题说90%的人挂在同一个坑这里我再说透一点这个坑不是技术而是“Python崇拜”。我在各种技术社群里观察到的典型路径是这样一位Java开发者决定转AI然后开始学Python。学语法用了3个月学数据分析库用了2个月装CUDA环境用了1周等到第6个月发现自己还是不会做Agent——因为他只是学了Python语法并没有真正跟大模型API打过一次交道。反过来看如果他在第1周直接用Java调一次大模型接口他会立刻明白原来整条链路就这么简单原来真正的复杂度在业务编排上。然后他会用剩余的时间去啃工具调用、记忆管理、Agent循环第6个月的时候他已经可以交付一个能查天气、查订单、写报告的完整Agent应用了。方向错了越努力越尴尬。方向对了Java的工程底座反而让你比半路出家的Python选手更稳。5.2 为什么Java开发者做Agent有先天优势这几年AI圈涌现出大量Python脚本风格的Agent项目。Demo跑起来很酷一上线就崩。原因往往是没有完整的异常处理、没有超时控制、没有线程隔离、没有日志链路。这些东西在Python快速原型里经常被忽略但在Java服务端开发里是刻在骨子里的自觉。我做Agent生产化改造时把很多时间花在了这几个工程问题上API密钥的权限管理、工具调用的审计日志、会话数据的持久化、模型返回内容的敏感词过滤。这些不是Agent独有而是服务端的老话题。越往后做越能体会Java多年沉淀的价值。另外企业级系统里的存量能力基本都是Java写的。你要做一个能查内部订单、能调内部库存接口的Agent直接用Java方式注册工具一行脚本都不用写就能把老系统的方法暴露给模型。这种“老资产 新能力”的组合是企业落地Agent最常见的路径也是Java开发者最值钱的位置。5.3 避坑速查表我把常见误区整理成一张表对号入座看一下自己是不是正在踩典型表现问题真相正确做法花几个月学Python语法还没调过API把语言当门槛方向跑偏直接用Java调大模型API跑通一个最简单对话以为调一次模型就能完成Agent全部功能没有理解Agent循环的机制先手动实现一轮“消息-工具结果-消息”闭环工具描述写得很简短模型调用频繁出错模型靠描述理解工具不是靠代码把触发条件、参数格式、典型示例写进描述把全部历史消息无脑塞给模型上下文窗口和成本失控用滑动窗口或摘要压缩策略控制消息量线程池和超时配置沿用默认值Agent请求阻塞、下游超时、服务雪崩独立线程池、分层超时、并发串行化控制遇到模型偶尔返回格式错误就怀疑框架不行模型本身有概率性需要代码兜底参数宽松转换、错误重试、最大迭代次数安全阀我在实战中反复验证这张表基本覆盖了新手期的全部主要问题。每一条都有对应的代码层面的解法前文已经全部讲到了。6. Java老兵转型AI Agent的六周路线图6.1 第1周不碰框架手写一次原生调用很多人一上来就引入Spring AI结果被框架的抽象绕晕了。我的建议相反第一周纯粹用JDK自带的HTTP能力或者OkHttp写一个最简单的类发一个POST请求带上消息列表拿到模型返回内容打印出来。不要跳过这一步。手写原生调用能让你建立最朴素的“模型就是接口”的认知。你会亲眼看到请求体长什么样响应体长什么样工具调用参数在响应里是什么格式。有了这个底子后面用框架时框架帮你做的每一件事你都能对上号。推荐做一个小任务让模型回答“今天北京天气怎么样”然后在返回结果里尝试解析出JSON内容。这就够了一周时间非常充足。6.2 第2到3周框架速通跑通工具调用闭环第二周开始引入Spring AI或者LangChain4j把官方文档里的工具调用Demo跑起来。同时注册两三个自定义工具比如一个查天气的、一个做算术的、一个查时间的让模型能够根据用户提问自动选择工具。这个阶段核心目标只有一个让“用户消息-模型判断-工具执行-结果回填-最终回答”这条链路完整跑通。跑通之后你对于Agent的骨架就已经有了肌肉记忆。第三周可以加记忆功能用Redis把会话历史存起来测试多轮对话的效果。6.3 第4到6周做一个小而全的模拟项目光跑通Demo不算会做Agent你必须做一个“小而全”的项目来检验自己的综合能力。以我经验建议做一个会议纪要助手类的模拟项目X就够了接收一段会议录音转写文本调用工具查询参会人信息调用工具查询历史会议纪要最后生成一份结构化摘要和待办事项。这个项目覆盖了长文本输入、多工具调用、上下文管理、结构化输出、结果格式化。全部做下来大概需要三周期间你会把前面踩过的坑重新踩一遍但每一遍都会理解得更深。项目做完后把它部署到一台云服务器上开放一个HTTP接口用手机试一下真实对话效果。看到模型在你设计的工具辅助下正确回答问题时那种感觉跟写了十年CRUD完全不一样。6.4 经验总结每天资源有限时怎么挤时间除了上面这条路线图再分享一个关于“时间投入”的经验。我见过很多Java开发说“我想转AI但工作太忙没时间系统学”。其实不需要辞职不需要每天八小时。我自己的节奏是每天早晚各一小时周末再挪出半天坚持大约两个月就走完了上面整条路线。关键不在于时长而在于“每次都跟真实代码打交道”。哪怕只看十分钟也要打开IDE写两行Java代码调一个接口而不是刷一堆AI概念文和图解。动手写代码的时间占比至少要达到70%。看一百篇“AI Agent入门”文章不如亲手跑通一个工具调用来得实在。7. 转型之后我对Java和AI关系的一点新理解项目做久了我渐渐对“Java老兵转型AI”产生了新的理解。很多人把Java当成“旧”技术把AI当成“新”技术好像两者之间有一道鸿沟。实际做下来我发现这更像是一次能力复用多年积累的需求分析能力、系统设计能力、异常处理能力、运维排查能力全部被迁移到了Agent开发中一件都没浪费。AI Agent目前还处于非常早期的阶段工具调用规范还在演进模型能力还在升级框架API几个月就换个版本。这个领域最大的确定性反而是“工程能力永远稀缺”。无论模型多强总得有人把它接进系统把流程跑通把错误兜住。这些事恰恰是Java开发者最擅长的。最后再分享一个小技巧也是我后来一直坚持的习惯不要一上来就设计复杂的Agent规划流程先把一个最小闭环跑通——一个用户消息、一个工具、一轮循环。闭环通了后面加记忆、加多工具、加流式输出都只是在这个闭环上做增量。这个最小闭环相当于你在新领域打下的第一根桩后面所有的高楼都靠它撑起来。希望这份复盘对你有用。现在就可以打开你的IDEA新建一个Spring Boot项目开始你的Agent第一行Java代码。