做了13年Java,我今年终于把自己掰成了AI Agent开发者。过程比想象中顺,也比想象中坑。先说结论:你不需要先花三个月啃Python,90%的Java老兵转型失败,不是死在语言上,而是死在一个共同的认知陷阱里——把Agent当普通API调。这篇复盘会把那个坑彻底拆开,再把从技术选型到落地的完整路径摆出来,希望能给同样在观望的Java后端一点参考。
先说下我自己的背景,方便大家对号入座。我一直在做传统企业级后端,Spring Boot、Spring Cloud、消息队列、定时任务、分布式事务,这些东西写了十多年,自认对“稳定的系统”有一套肌肉记忆。转型的起因,是公司内部要做一个能自动查库存、查订单、回复客户问题的智能助手,让我去调研。我一开始也想走常规路线:要不要先学Python?要不要研究PyTorch?后来被现实狠狠教育了一轮——大模型本身对编程语言一视同仁,它要的只是HTTP请求和JSON。真正卡住我的,反而是那些多年Java开发养成的“确定性思维”。
这篇复盘不是什么学术指南,就是一次完整的实战记录:从认知层的误区拆解,到工具选型、代码骨架、调试排错,再到三个月的学习路径。我尽量把每一步都写清楚,尤其是那些常规文档里不会告诉你的细节。
1. 先破认知:转型AI Agent的门槛根本不是Python
1.1 为什么Java老兵一上来就想学Python
这个思维惯性太普遍了。打开社区,十篇AI教程里九篇是Python,示例代码全是import torch、from transformers import pipeline,搞得好像不学Python就进不了AI的门。再加上身边搞算法的同事张嘴就是Python,更是加重了这种错觉。
但这里要分清楚一个概念:算法岗在做的事,和业务应用开发在做的事,完全是两回事。
算法岗要训练模型、调参、做实验,Python的数据科学生态确实不可替代。但你要做的AI Agent,是“把已经训练好的大模型集成到业务系统里”,核心工作是写业务逻辑、设计对话流程、封装工具接口、处理数据流转。这些工作,Java能干,而且干得相当好。
我做了个简单对比,大家感受一下:
| 能力需求 | Python生态 | Java生态 | 你的真实处境 |
|---|---|---|---|
| 调用大模型API | requests一把梭 | HttpClient/RestClient | Java老本行,无障碍 |
| 业务系统集成 | 要写胶水代码 | Spring Boot天然衔接 | Java强项 |
| 高并发与稳定性 | 需要额外设计 | JVM体系成熟多年 | Java强项 |
| 工具函数封装 | 容易写但难治理 | 接口约束+Spring管理 | Java强项 |
| 数据处理与解析 | pandas很爽 | Jackson/Gson足够 | 日常操作 |
| Agent编排框架 | 非常丰富 | 已有可用方案 | 需要适应 |
看清楚了吗?模型调用本质上就是发一个HTTP请求,传一段JSON进去,再拿一段JSON回来。大模型服务商根本不在乎你的请求是Java发的还是Python发的。既然底层通信协议是通用的,那语言壁垒就不该成为转型的第一道坎。
1.2 Agent开发真正要补的三块短板
跳过Python,并不意味着什么都不用学。我转型过程中真正花时间补的,是下面三样东西:
第一,消息结构与会话管理。传统后端接口是“你传参数,我返回结果”,而对话模型要的是messages数组,每个元素带role和content。你得维护一个会话的消息列表,并且管理它在模型上下文窗口里怎么流转。这个思维转变看似简单,做起来很深。
第二,上下文窗口的管理。模型不是无限记忆的,Token就那么多。对话长了,你得做滑动窗口、做摘要压缩、做关键信息提取。传统后端讲究“数据存库”,Agent讲究“把重要数据留在上下文里”。这个取舍,是Java老兵最容易想歪的地方。
第三,工具调用(Function Calling)机制。这是Agent最强的能力之一:模型根据用户问题,自己决定调用你封装的某个Java方法,把参数填好,然后拿着你的返回值继续生成回答。这等于让模型在你的业务系统里“按需取数”。这个机制的调通,是Agent从“玩具”走向“能干活”的关键。
1.3 90%的人挂在同一个坑:把Agent当成普通API接口调
前面铺垫了这么多,该说那个坑了。
很多Java老兵转型后的第一版Agent,写出来是这样的:先接收用户输入,然后硬编码一个System Prompt,再拼上最近几轮对话,丢给模型,拿到回答,返回给用户。看起来没错,对吧?但遇到稍微复杂的业务就废了:用户问“帮我查一下上周三的销量,顺便对比下今天上午的”,模型直接乱答,或者答非所问,甚至一本正经地编数据。
问题出在哪?你用写普通API的思路在写Agent。普通API是“输入-处理-输出”流水线,逻辑是确定性的,参数是规范的,过程是完全可控的。但Agent的本质是“输入-模型推理-可能调用工具-再推理-输出”,整个过程有模型自己的判断在里面。你把判断流程写死在if/else里,一旦模型的行为超出你的预设分支,整个系统就崩了。
我见过太多同行踩这个坑:为了控制模型输出,写了十几层条件判断,结果换一个模型版本,输出格式全变,代码推倒重来。这让我彻底明白了一件事:Agent开发的核心不是“写好控制逻辑”,而是“给模型铺好路,让它自己走”。你要用Prompt约束行为,用工具描述引导决策,用输出格式规范结果——这套玩法,和传统的“代码控制一切”完全不是一个思路。
所以,别再纠结Python了。真正的门槛,是把思维从“确定性编码”切换成“概率性编排”。
2. 技术选型:Java生态做Agent的几套可行方案
2.1 用最土的姿势接入大模型API
选型之前,先把最底层的姿势练好。我是不建议一上来就上重型框架的,因为框架会掩盖很多细节,出了问题你完全无从排查。先用最原始的方式把链路打通,比什么都重要。
我当时用的是Spring Boot内置的RestClient,直接调用大模型服务的对话接口。核心代码非常简单,就是一个HTTP POST请求,带一个JSON body,解析JSON response:
RestClient restClient = RestClient.create(); Map<String, Object> messageMap = new HashMap<>(); messageMap.put("role", "user"); messageMap.put("content", "今天杭州天气怎么样?"); Map<String, Object> requestBody = new HashMap<>(); requestBody.put("model", "your-model-id"); requestBody.put("messages", List.of(messageMap)); requestBody.put("temperature", 0.7); requestBody.put("stream", false); String response = restClient.post() .uri("https://your-api-endpoint.example.com/v1/chat/completions") .header("Authorization", "Bearer " + apiKey) .contentType(MediaType.APPLICATION_JSON) .body(requestBody) .retrieve() .body(String.class); // 下一步就是解析 response 里的 choices[0].message.content这一步的意义是让你亲眼看清楚:模型API没有魔法,就是一个RestClient能搞定的远程服务。把这一步跑通,你对“调用大模型”这件事的神秘感就消除了大半。
跑通同步接口之后,我强烈建议立刻学习流式输出。因为真实业务里,用户等不了你3到5秒的完整生成时间。流式接口的返回体是text/event-stream,一大段JSON被拆成很多小块,每一块都是类似data: {...}的文本。解析方式也很直接:逐行读取,遇到data:开头就解析后面的JSON,直到出现结束标记。
我用WebClient做流式接收,然后把收到的内容逐段推给前端。这段链路不要省,几乎所有上线了的Agent应用都要靠流式输出来撑体验。
2.2 Java生态的Agent编排框架怎么选
底层打通之后,你会发现每次都要自己拼messages、维护会话状态、处理多轮工具调用,代码开始变散。这时候就需要编排框架了。当时我调研了几类方案,简单列个对比:
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 纯手写Java编排 | 学习阶段、极简Agent | 链路完全透明,改造成本低 | 每加一个能力都要自己造轮子 |
| Java版Agent编排框架 | 生产级业务Agent | 内置消息管理、工具注册、循环控制 | 需要熟悉框架的抽象概念 |
| Python生态框架 | 快速原型验证 | 生态最丰富、案例最多 | 与Java系统集成成本高、维护分散 |
我最后选了Java生态里一个社区活跃度比较高的编排框架,原因很现实:团队全是Java背景,上了Python框架就意味着系统里有两条技术栈,后续维护要两拨人。而Java版框架虽然案例少一些,但它和Spring Boot的整合非常顺,依赖注入、配置管理都能直接用。
这里给我的建议是:如果你的场景只是“调用模型+固定Prompt”,手写就够了;如果你的Agent要接多个工具、有复杂的多轮推理,再考虑上编排框架。别盲目追新,能用代码解决的问题,就不要引入额外依赖。
2.3 记忆与知识库:向量数据库接入
Agent要能回答业务问题,光靠模型本身的通用知识不够,得把企业内部的文档、商品信息、历史工单等内容灌进去。这就要用到“检索增强生成”,也就是常说的RAG流程:把文档切片转成向量,存进向量数据库;用户提问时,把问题也转成向量,去库里搜最相似的一批片段,再把这些片段拼进Prompt,让模型基于它们回答。
Java生态里可以选的向量数据库方案不少。我的选型标准就三条:
- 有没有官方或社区维护的Java SDK
- 部署形态能不能融入现有的运维体系
- 数据量级别够不够用
我当时选了支持Java SDK的某款向量库,把它跑在Docker容器里,几百上千个集合、百万级向量都扛得住。接入过程没有想象中那么复杂,核心就是两件事:插入向量时把文档ID、内容、向量一起存进去,查询时传一个用户问题的向量,拿回TopK个匹配片段。
这里提醒一句:别一开始就追求“完美RAG”,什么混合检索、重排序、多路召回,都是后话。先把“切片-向量化-检索-拼Prompt”这条主链路跑通,再去谈优化。很多团队第一步就把方案做得太重,结果连基础检索效果都没验证好。
2.4 工程化细节:超时、重试、限流与异步
Java老兵搞AI Agent,最大的优势在工程化。但这块也最容易翻车,因为大模型API的行为和传统接口真的不一样。
先说超时。模型生成动辄几秒甚至几十秒,如果你还在用默认的2秒超时,线上会直接炸。我把连接超时设成3秒,读超时设成60秒,流式场景下因是长连接,又把空闲超时单独做了处理。这个参数不用照抄,要根据你的模型服务实际情况调。
再看重试。模型服务偶尔会返回429限流、502网关错误,这些是常态。我写了个带重试的调用封装:对429做指数退避重试,对5xx最多重试两次,对业务层错误直接抛异常,不盲目重试。重试时机和次数一定要控制好,否则一个接口被限流,你的线程池会被重试任务直接打满。
限流也很关键。模型服务按QPS和Token双重限流,你的后端接口要是突然来了流量高峰,上游直接给你返回429。我在接入层做了个简单的令牌桶,把请求速率限制在模型服务允许的区间内,宁可让客户端稍等,也不触发上游限流。
最后说异步。Agent的完整处理链路通常包含多轮模型推理和多次工具调用,整体耗时很长。如果每个请求都占用一个Servlet线程,线程池很快会耗尽。我把长耗时链路放到线程池里异步执行,用CompletableFuture串起多个独立调用,前端则通过流式接口分段拿到结果。这一块是Java工程师的舒适区,务必发挥出来。
3. 从零到一:一个Java版AI Agent的完整落地记录
3.1 场景定位:某客服知识库助手
光讲选型不落地,等于纸上谈兵。我说个具体的模拟项目,代号就叫“某客服知识库助手”。
业务背景很简单:客服人员每天要面对大量用户咨询,内容涉及商品信息、订单状态、退款规则、物流时效等。大多数问题重复且机械,但需要查多个系统才能回答。传统做法是做一套关键词问答机器人,效果大家都懂,稍微换个问法就失灵。目标就是做一个能理解自然语言、自动查数据、生成回复的Agent,嵌入到客服后台的工作台里。
这个场景选得比较典型:既有知识库检索(RAG),又有结构化数据查询(Function Calling),还有多轮对话维护(会话管理),覆盖了Agent开发的大部分核心能力点。
3.2 Agent核心流程:从意图识别到工具调用循环
整个Agent的执行流程,用大白话说是这样的:
- 接收用户问题,连同系统Prompt、历史消息一起发给模型
- 模型判断:这个问题我能直接答,还是需要调用工具
- 如果需要工具,模型返回一个结构化的“工具调用请求”,包含工具名和参数
- 后端根据工具名找到对应的Java方法,传入参数并执行
- 把执行结果作为一条新消息发给模型
- 模型基于工具返回继续推理,可能再次调用工具,也可能直接生成最终回答
- 循环直到模型不再请求工具,输出最终回复
这个“模型-工具-模型”的循环,就是Agent区别于普通API调用的核心机制。我在框架里用一个while循环来实现:
public String runAgent(String userInput) { // 1. 把用户问题追加到会话历史 messages.add(Map.of("role", "user", "content", userInput)); while (true) { // 2. 调用模型,开启工具开关 ChatResult result = chatModel.call(messages, toolDefinitions); // 3. 模型返回工具调用请求 if (result.hasToolCalls()) { for (ToolCall call : result.getToolCalls()) { // 4. 根据工具名执行Java方法 ToolResponse resp = toolRegistry.execute(call.getName(), call.getArguments()); // 5. 把执行结果作为工具消息追加回会话 messages.add(Map.of("role", "tool", "name", call.getName(), "content", resp.toJson())); } continue; // 6. 把工具结果交给模型继续推理 } // 7. 模型不再请求工具,拿到最终回答 String answer = result.getContent(); messages.add(Map.of("role", "assistant", "content", answer)); return answer; } }这段代码看起来不长,但里面藏着几个非常容易出错的细节。比如hasToolCalls()的判断,不同模型服务返回的字段结构不一样,有的叫tool_calls,有的叫function_call,参数格式也有差异。我在适配层做了统一转换,上层代码永远只看到一种结构,这个抽象能省掉后面大量的兼容工作。
3.3 工具函数怎么写:让模型学会用你的Java方法
工具调用是整个Agent能不能真正干活的命门。很多Java老司机卡在这里,不是因为不会写Java方法,而是不知道“怎么让模型知道这个方法存在、什么情况下调用、参数该怎么传”。
我定义了一个简单的工具接口,所有可被模型调用的方法都实现它:
public interface ChatTool { // 工具名称,模型用这个名字发起调用 String getName(); // 工具描述,告诉模型这个方法能干什么 String getDescription(); // 参数结构,用JSON Schema描述每个参数的含义和类型 Map<String, Object> getParameterSchema(); // 实际执行逻辑,入参是模型填好的JSON字符串 String execute(String argumentsJson); }以查询订单状态为例,这个工具的定义是这样:
@Component public class QueryOrderTool implements ChatTool { @Override public String getName() { return "query_order_status"; } @Override public String getDescription() { return "根据订单号查询订单当前状态,适用于用户询问订单到哪了、是否发货、是否签收等场景"; } @Override public Map<String, Object> getParameterSchema() { return Map.of( "type", "object", "properties", Map.of( "orderId", Map.of( "type", "string", "description", "用户的订单号,例如 JD123456789" ) ), "required", List.of("orderId") ); } @Override public String execute(String argumentsJson) { JsonNode args = objectMapper.readTree(argumentsJson); String orderId = args.get("orderId").asText(); OrderVO order = orderService.queryByOrderId(orderId); return objectMapper.writeValueAsString(order); } }写工具的要点其实就三个:
第一,描述要写人话。getDescription这个字段是给模型看的,写得越清楚,模型判断得越准。你写“查询订单状态”,模型只知道有这功能;你写“根据订单号查询订单状态,适用于用户问发货、签收等问题”,模型就知道触发条件了。
第二,参数Schema要写得细。参数描述直接影响模型填参的准确度。我见过有人把参数描述写成空的,结果模型频繁漏参、传错类型。后来老老实实给每个参数写了示例值,准确性提升明显。
第三,返回结构要简单。工具返回给模型的内容,不要在Java对象里带一堆冗余字段。模型会拿这些数据继续生成自然语言,数据太多会干扰它的判断,还占Token。返回前尽量精简,只留必要信息。
3.4 Prompt工程化:不是写作文,是画框子
很多Java开发者写Prompt,习惯性地把它当成“写给AI看的一段说明文字”,想到哪写到哪。实战之后我发现,Prompt更像一种编程语言,要有结构、有规则、有边界。
我写System Prompt的模板大致长这样:
你是某公司的智能客服助手,你的任务是基于给定的知识库内容和工具查询结果,回答用户问题。 工作原则: 1. 只依据给定的资料和工具查询结果回答,不编造事实。 2. 如果知识库和工具都无法回答,直接说“我暂时无法回答这个问题”,不要强行解释。 3. 回答要简洁、口语化,控制在80字以内,除非用户明确要求详细说明。 4. 涉及订单、物流等时效性信息,必须调用工具查询,禁止凭记忆作答。 5. 如果用户问题不清晰,先追问清楚,不要猜。 常用工具说明: - query_order_status:查询订单状态 - query_logistics_info:查询物流轨迹这套模板的经验是:Prompt不是在教模型“怎么想”,而是在约定“什么能做、什么不能做、什么情况下做”。把边界画清楚了,模型的输出稳定性会上升一个量级。
除了System Prompt,少样本示例也值得投入。我会在Prompt里附加一两个“用户说A,你调用工具B并回答C”的完整例子。模型学会这个套路之后,遇到类似场景就知道照着做了。
4. 实战避坑:Java版Agent开发中那些排到崩溃的问题
4.1 上下文爆炸:回答越来越离谱,费用越烧越高
症状很典型:Agent跑了几十轮对话之后,回答质量急剧下降,开始胡言乱语,而且每次请求的Token消耗大幅上升,账单肉眼可见地涨。原因很简单,我把所有历史消息都无脑塞进了模型。
排查过程其实不难,打印出每次请求的messages数量就明白了。对话超过20轮,历史消息可能就有好几千Token,加上用户新问题,直接顶到模型的上下文上限。
解决办法是状态压缩。我做了一个会话管理器,保留System Prompt和最近6轮对话,更早的历史内容,定期让模型做一次摘要,把摘要当作一条系统消息放到最前面。这样模型的记忆不丢,Token消耗还稳住了。这个方案不是完美的,但胜在简单可维护。
4.2 工具调用失效:模型就是不查库,张嘴就答
有一种情况让我印象很深:工具定义得好好的,Prompt也写了“涉及订单信息必须调工具”,但模型就是要自己编答案,完全不触发工具调用。
我一开始以为是模型能力不够,后来把模型返回的原始日志翻出来一看,才发现是工具描述的问题——我把查询工具的触发条件写得太模糊,模型在“用户问的是订单状态”和“用户问的是物流信息”之间不知道自己该触发哪个方法。
解决方式是把工具描述改得更具体,并且给参数加上触发示例。比如query_order_status的描述里明确写了“仅当用户提供订单号或者主动询问订单状态时使用”,同时在Prompt示例里加了一个完整的工具调用示范。这两步做完,工具的触发率从50%左右提升到了90%以上。
4.3 工具参数解析失败:模型返回了非法JSON
这个坑几乎避不开。模型输出的JSON偶尔会带着多余的文字,比如回一个前导说明再输出JSON,或者花括号括号不匹配,直接导致Jackson解析报错。第一次遇到这种问题,我差点想把模型训练集给改了。
后来处理手段分三层:
- 提示层面:在System Prompt里明确要求“只输出JSON,不要任何解释文字”,并给了一个严格示例
- 解析层面:写一个容错解析工具,自动剔除多余的说明文字,提取第一条合法的JSON结构
- 兜底层面:如果解析确实失败,就把错误信息返回给模型,让它重新生成参数,最多重试一次
三层加下来,参数解析失败的比率降到了可接受范围。顺便说一句,模型返回的JSON最好用Jackson的readTree解析,比先绑定DTO类更灵活,因为你根本不知道模型会给你塞什么额外字段。
4.4 响应太慢:用户等不起,怎么办
Agent比传统接口慢,这是物理规律。因为模型推理要几千毫秒,还可能要来回调好几轮工具。要是不做任何优化,用户点一下按钮,5秒钟不出东西,体验直接崩盘。
我做了两件事:流式输出和任务异步化。
流式输出是我第一时间上的,模型生成的第一个Token差不多1秒内就能到前端,用户看到内容在往外蹦,等待焦虑会大幅缓解。异步化针对的是多步骤复杂任务,比如用户问“最近一周订单退款率多少,顺便对比一下上周”,这种任务需要查多个数据源,耗时可能超过10秒。我把它提交到线程池,返回一个任务ID,前端轮询任务状态,完成后展示结果。
4.5 没有评估指标:改了一版Prompt,怎么知道是变好了还是变差了
这一点我觉得是所有人最容易忽视的。做普通后端,接口正确性可以用单元测试来保证;但Agent的输出是概率性的,没有明确的“对错”。这就导致一个尴尬局面:你改了Prompt,感觉效果变了,但说不清是变好还是变坏。
我的做法是建了一个最小的评测集,二十来条典型的客服问答,覆盖查询订单、物流、退换货、闲聊等场景。每改一版Prompt或工具描述,就跑一遍评测集,人工看一遍回答质量,同时记录工具调用的触发率、参数解析成功率、平均Token数这些硬指标。
这套东西不用做得复杂,一个Excel表格加一个简单的测试脚本就能跑起来。但它的价值很高,没有评测标准,你的Agent就永远只能靠“感觉”来迭代。
5. 从Java老兵到Agent开发者的实用转型路线
5.1 你的Java经验,哪些不是负担而是资产
这个过程里我最大的一点体会是:Java老兵缺的不是技术,而是对“新玩法”的认知。很多经验反而是Agent工程化里最难补齐的部分。
我画了个简单的映射表,希望你能从中看到自己身上的存量价值:
| Java后端既有能力 | AI Agent开发中的对应价值 |
|---|---|
| 面向接口编程 | 设计工具抽象、隔离模型差异 |
| Spring依赖注入 | 管理Agent、工具、记忆模块的组装 |
| 异常处理与重试 | 应对大模型接口的不稳定 |
| 并发与异步编程 | 编排多Agent、处理长耗时请求 |
| 性能分析与调优 | Token成本控制、响应延迟优化 |
| 单元测试意识 | 建立评测集,保证Agent输出质量 |
这些能力不是没用,而是从“主角”变成了“底座”。你过去十年积累的工程化素养,在Agent落地阶段恰恰是最缺的。
5.2 三个月学习计划:不学Python也能走通的路
如果你也准备转型,我建议你按这个节奏来,亲测下来比较顺:
第一周,打底认知。不要写代码,先把大模型对话接口的文档看三遍,搞清楚messages结构、role含义、常用参数。然后自己注册个账号,用Postman调试几次接口,直观感受模型返回。
第二到四周,专攻Prompt。找业务里的真实问题,设计System Prompt,练少样本、思维链这些技巧。这个阶段重点是建立“对话就是编程”的感觉。
第五到七周,吃透Function Calling。这阶段直接决定你Agent的边界。把工具定义、参数Schema、多轮工具调用循环全部跑通,做一个能查数据库、能调第三方接口的最小Agent。
第八到十周,补RAG和记忆管理。文档切片、向量化、检索、拼装Prompt,会话压缩与摘要。这个阶段做完,你已经能应付大部分业务场景了。
第十一到十二周,做一个完整项目。不要用玩具Demo充数,找一个真实业务流程,把它完整Agent化,包括评测集、监控、异常处理。
5.3 学习资料怎么选:别囤课,去啃官方文档
关于学习资料,我的观点可能和很多人不一样:不要囤课,那些所谓的AI入门课程大部分都在讲Python基础和调包,对你的实际帮助很有限。真正值得花时间的,是模型服务商官方文档里关于对话接口、Function Calling、Prompt最佳实践的部分。这些内容每天在更新,课程里的说法很可能已经过时了。
我自己的习惯是:每周精读一份模型服务的更新日志,看看新能力是什么,琢磨一下它能不能解决我当前的业务问题。这个习惯的长期回报非常大,你能比同行早几周用上新能力。
5.4 转型路上的心态建议
最后说点掏心窝的。转型过程中,我一度非常焦虑,觉得自己从“团队里最懂技术的人”变成了“啥都要从头学的新人”。但后来我想明白了一个道理:你不是从零开始,你是从一座山走向另一座山。Java给你的是工程化的肌肉记忆,Agent给你的是新的表达方式,两者结合起来,才是完整的生产力。
具体操作上,有几个建议你参考:
- 先做小项目,做真实需求,别追求完美架构
- 把模型当同事,它答错了记录案例,沉淀成Prompt修订的依据
- 每周末花一下午整理本周踩的坑,这个复盘习惯比看十篇文章都有用
- 尽量参与真实业务系统,别只停留在Demo阶段
我个人在实际操作中还有一个习惯:每次把Agent的一次完整交互日志打印出来,包括完整的Prompt、模型返回、工具调用过程。这些日志排障时就是黄金。出了问题时,一般都能直接定位到是Prompt的问题、工具描述的问题,还是上下文管理的问题。这个习惯帮我省掉了很多排查时间。
转型到今天,回头看那个“该不该学Python”的问题,已经显得非常次要。真正的门槛,是驯服概率性的思维模式,是学会和不确定性共处,是把自己从“一切尽在掌握”的工程师,变成“放手让模型自己跑,但你给它兜好底”的导演。这条路我还在走,但方向已经很清楚:Java老兵的十年功底,在Agent时代不但没过时,反而正在变成一种新的优势。