news 2026/10/14 5:21:21

Java Agent不用卷Python:GOAP+Spring AI打造确定性企业级Agent

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java Agent不用卷Python:GOAP+Spring AI打造确定性企业级Agent

最近一年多,我身边不少做Java的朋友都有同一个焦虑:看到AI Agent相关的开源项目、招聘需求、技术博客,几乎全是Python的天下,好像不转语言就要被这波浪潮淘汰。某团队去年在技术选型会上还被建议优先招Python工程师做Agent方向,结果几个人用基于提示词编排的方案折腾了半年,Demo演得挺好,一接真实业务就碎成一地。这让我开始认真琢磨一个问题:企业级Agent到底缺的是语言生态,还是工程确定性?

后来我注意到两个变化,一个是Spring社区开始认真回应LLM应用层的需求,框架层面的支持陆续补位;另一个是GOAP这类经典规划算法被重新拿出来,用来替代脆弱的提示词编排。两个变化凑在一起,恰好给Java企业打开了一条并不需要卷Python的Agent落地路线。今天这篇就围绕这两点展开,把原理、对比、实操和边界讲透。

1. 为什么说Java做Agent的路一直被低估了

1.1 Python抢走了光环,Java扛住了交付

先别急着吵语言优劣,聊聊事实。Python在AI领域的地位主要来自算法库和研究生态,模型训练、微调、数据探索这些场景,确实没几个语言能比Python顺手。但企业里的Agent项目,真正吃资源的地方往往不是训练,而是系统集成。

一个典型的B端Agent场景是什么?读取工单、判断紧急程度、调用客户系统查合同、写工单备注、触发审批流、给责任人发通知、记录操作日志。这些动作每一个都要对接企业内部已有的系统,Java在这条链路里积累了二十年的能力:Spring全家桶的依赖注入和事务管理、成熟的ORM体系、完善的连接池和重试机制、严格的类型系统和编译期检查。

而这些恰恰是Python生态相对弱的地方。Python写一个调用OpenAI接口的脚本只要20行,但把它变成一个能受控运行、能被审计、能接进企业权限体系的服务,需要补的东西就多了。不是不能补,而是补完之后,你已经等于用Python重新造了一个弱化版的Spring框架。

我见过不少团队在Python侧给Agent做配置中心、做接口鉴权、做链路追踪,费了很大劲,最后发现这些能力Java侧全是现成的。那为什么不直接站在Java的存量能力上做Agent?

1.2 大模型应用层换了赛道:从造模型到装整车

还有一个更底层的逻辑变化。早几年AI项目的核心竞争力是模型本身,谁能训出更好的模型谁就赢。那个时候做应用的人能做的很少,加载别人训练的模型已经算有技术含量了。

现在不一样。通用大模型的能力已经溢出到“够用”的程度,行业里拼的已经不是再训练一个模型,而是怎么把现成的大模型可靠地装进业务流程里。这个变化我习惯用一个类比:以前是造发动机,现在是装整车。

装整车的核心问题是什么?是发动机(大模型)和底盘(企业系统)怎么匹配,是刹车(安全控制)、仪表盘(可观测性)、方向盘(业务规则)怎么设计。这些恰恰是Java工程师最熟悉的东西。大模型这个“发动机”确实多半来自Python社区,但把它装进企业这辆“车”里,Java的工程化能力反而成了主战场。

所以我一直觉得,所谓“Java不适合做AI”是个伪命题,只是过去几年AI的聚光灯一直打在模型侧,应用侧工程化的价值被严重低估了。

2. GOAP:把Agent决策从概率拉回确定

2.1 GOAP到底是什么

GOAP全称Goal-Oriented Action Planning,目标导向行为规划,最早是游戏AI里用的一套决策算法。游戏里的NPC要决定下一步干嘛,不能光靠写一堆if else,那会把人逼疯,于是就有了这么个思路:

把NPC会做的所有事情抽象成一个个“动作”,每个动作都有三个关键要素:前置条件、效果、代价。然后给NPC一个“目标状态”,规划器从当前状态出发,不断挑选动作、应用效果,直到目标状态达成,输出一条动作序列。

举个例子。一个游戏NPC的目标是“获得武器”,可用的动作有“去铁匠铺”、“购买铁矿”、“铸造武器”,每个动作有前置条件(比如“购买铁矿”需要身上有钱)和效果(比如“身上有铁矿”)。规划器把这些动作拼装成一条可行路径,NPC照着执行就行。

有意思的是,GOAP当时发明出来就是为了替代脆弱的文本分支逻辑。游戏里的分支脚本一多就爆炸,GOAP却能把行为决策变成结构化搜索。这个历史和今天提示词编排遇到的问题如出一辙。

2.2 和提示词编排硬碰硬,GOAP赢在哪

现在主流的Agent实现方式,不管叫什么名字,本质都是提示词编排:把任务目标、工具列表、业务规则、输出要求全塞进提示词里,让大模型自己决定调用哪些工具、按什么顺序调用。

这种方式在小规模Demo里表现得非常惊艳,但一旦进入企业真实场景,问题就开始暴露。我做了一个对照,把两者从工程视角摊开来看:

维度提示词编排GOAP规划
决策确定性概率输出,同样输入可能得到不同计划确定性规划,相同状态得到相同计划
可测试性只能做端到端测试,断言自然语言结果给定世界状态即可断言动作序列
可观测性只能看token输出,难以追踪决策根据规划过程是显式数据,每一步都可回放
变更成本改业务规则要改提示词,易影响全局新增动作即新增类,不影响已有动作
约束能力靠提示词“央求”模型遵守规则前置条件硬性约束,不满足就不能选
失败模式静默出错,规则遗漏时直接走偏无解时明确返回,可进入兜底逻辑

我重点说说失败模式这点。提示词编排的Agent在复杂分支下会“忘记”某些条件,因为它本质是在用概率拟合逻辑规则,而逻辑规则是不允许“大概满足”的。你可以在提示词里写十遍“必须先检查用户身份再执行操作”,模型可能前三十次都遵守,第三十一次就跳过了。这种不确定性在To C场景还能接受,在金融、政企、生产系统里意味着事故。

GOAP则完全不同。前置条件不是建议,是硬约束。规划器根本不会选择一个前置条件不满足的动作,除非你先执行别的动作把条件补上。这种机制保证行为逻辑和代码一样可控。

2.3 LLM的定位变了:从拍板的人变成递情报的人

这里需要澄清一点,走GOAP路线不代表抛弃大模型。恰恰相反,大模型在GOAP架构里承担一个不可替代的角色:状态理解。

GOAP的规划器需要“世界状态”作为输入,但企业场景里的状态往往藏在非结构化文本里。客户发来一段话:“这个订单我等了三天了,再不到货我就退货,还要投诉你们。”这句话里藏着哪些状态?客户情绪是愤怒、订单延迟超过三天、有退货和投诉风险。让传统代码去解析这个信息要写大量规则,让大模型来解析就是一次对话的事。

于是LLM的定位就从“拍板做决策的人”变成了“递情报的情报员”。它负责把自然语言翻译成结构化状态,比如客户情绪等级、紧急程度、涉及产品线、是否触发SLA违约金。而真正决定“下一步做什么”的,是GOAP规划器,它在确定性的状态数据上做确定性的规划。

这个分工我认为才是企业级Agent该有的样子:大模型负责理解世界,引擎负责承担责任。把决策权从大模型手里拿回来,交给确定性算法,但保留大模型感知非结构化信息的能力。

3. Spring生态出手,Java Agent路线终于闭环

3.1 Spring AI到底做了什么

如果说GOAP解决了决策确定性的问题,那Spring AI解决了Java侧接入大模型的最后一公里。

Spring AI不是要跟深度学习框架抢地盘,它做的是把大模型接入这件事彻底Spring化。它提供了几个关键能力:统一的ChatClient接口,屏蔽不同模型提供商的差异;结构化输出转换,能把大模型返回的文本直接映射成Java对象;工具调用抽象,把Java方法暴露成大模型可调用的工具;还有一些模板管理和模型配置的能力。

几个能力叠加起来意味着什么?意味着你写一个调用大模型的模块,跟在Spring里写一个调用数据库的Service没什么区别。配置走配置文件,依赖走依赖注入,返回结果是被类型检查过的对象,而不是需要自己parse的字符串。

在我实际项目里,这个体验差异非常大。过去在Java里接大模型,要么自己封装HTTP请求,要么用Python侧提供的网关,要么引入一个很重的第三方SDK,总是感觉游离在Spring体系之外。用Spring AI之后,Agent代码和业务代码终于长在一棵树上。

3.2 Agent组件变成Bean之后发生的三件好事

GOAP里的Action,一旦被纳入Spring容器管理,工程价值是质变的。我至少体会到三个好处。

第一,动作实现类可以直接注入企业已有的基础设施。一个动作要查客户合同,直接注入Repository;要发消息,直接注入MQ的Template;要调外部系统,直接注入FeignClient。这不是功能问题,是开发效率问题。写Agent动作就跟写一个普通Service方法一样顺手。

第二,AOP切面可以统一处理横切关注点。审计日志、租户隔离、分布式锁、操作人上下文,这些企业级能力都可以通过注解和切面挂在动作执行过程上,而不用在业务代码里重复写。我在项目里就做过一个审计切面,每个Agent动作执行前后自动记录状态快照,出了问题一查日志就知道Agent当时看到了什么、做了什么。

第三,Spring的测试体系直接复用。动作是Bean,就可以用MockBean替换掉外部依赖做单元测试;规划器是Service,就可以在测试容器里塞各种世界状态断言动作序列。Agent的单元测试终于不再是“跑一遍提示词看看结果像不像话”。

3.3 Java路线和Python路线的对照

不用回避Python路线,它在有些场景确实是优势局,但把企业Agent的全流程拉出来看,两条路线的优劣势很不一样。

维度Java + Spring AI + GOAPPython + 提示词编排
团队复用现有Java工程师直接上手需要重新组建AI团队
系统集成原生对接企业存量系统依赖桥接层,容易变成双语言维护黑洞
治理能力配置中心、监控、权限全齐多数方案要自行搭建
决策可控性GOAP确定性保证依赖模型发挥,稳定性靠调Prompt
算法前沿不擅长模型训练和微调模型生态最丰富,紧跟研究
交付速度前期框架搭建略重,中后期稳定加速原型极快,进入生产后运维成本上升

这个表不是用来踩Python的,Python在训练和探索阶段的优势目前没有替代方案。但“训练模型”和“用模型做Agent”是两个物种,Java在后者的系统工程环节里,优势被严重低估了很久。

4. 手把手:用Spring AI + GOAP搭一个工单处理Agent

理论讲了这么多,直接上实操。我以一个工单处理Agent为例,把GOAP的核心代码和Spring AI的接入方式完整走一遍。

4.1 先把动作集定义好

先定义AgentAction接口,包含规划需要的元信息和执行方法。

public interface AgentAction { // 动作名称,用于日志和审计 String getName(); // 前置条件:判断当前世界状态是否满足执行条件 boolean canExecute(Map<String, Object> worldState); // 动作效果:执行后对世界状态的变更 Map<String, Object> getEffects(); // 动作代价:规划器择优时会参考 double getCost(); // 实际执行逻辑 void execute(AgentContext context); }

然后是具体动作。比如“升级工单”这个动作,前置条件是工单处于高危状态且未升级过,效果是把状态里level改成escalated:

@Component public class UrgentEscalateAction implements AgentAction { @Override public String getName() { return "urgent_escalate"; } @Override public boolean canExecute(Map<String, Object> state) { return "high".equals(state.get("urgency")) && !"escalated".equals(state.get("level")); } @Override public Map<String, Object> getEffects() { return Map.of("level", "escalated"); } @Override public double getCost() { return 1.0; } @Override public void execute(AgentContext context) { // 注入工单服务,把工单状态改为升级 context.getTicketService().escalate(context.getTicketId(), "SLABreach"); } }

这里有个设计细节容易被忽略:execute里的实际操作逻辑依赖Spring注入的Service,而规划器只看canExecute和getEffects这两个纯函数。也就是说,规划是在“头脑”里推演的,执行是落到真实系统的。两者解耦之后,你甚至可以在不执行任何操作的情况下,安全地预演Agent会怎么做,这对测试和审计很有价值。

4.2 实现一个够用的规划器

GOAP经典实现是反向搜索,从目标状态倒推出动作序列。工程上更常见的做法是从当前状态正向搜索,每次挑一个“最接近目标”的动作执行。我建议先从贪心版本起步,逻辑简单、行为可解释,后续再换A*也不影响动作层定义。

@Service public class GreedyGoapPlanner { private final List<AgentAction> availableActions; public GreedyGoapPlanner(List<AgentAction> actions) { this.availableActions = actions; } public List<AgentAction> plan(Map<String, Object> start, Map<String, Object> goals, int maxDepth) { Map<String, Object> state = new HashMap<>(start); List<AgentAction> plan = new ArrayList<>(); for (int i = 0; i < maxDepth; i++) { if (goalSatisfied(state, goals)) { break; } AgentAction best = selectBestAction(state, goals); if (best == null) { break; } plan.add(best); state.putAll(best.getEffects()); } return plan; } private boolean goalSatisfied(Map<String, Object> state, Map<String, Object> goals) { return goals.entrySet().stream() .allMatch(entry -> entry.getValue().equals(state.get(entry.getKey()))); } private AgentAction selectBestAction(Map<String, Object> state, Map<String, Object> goals) { return availableActions.stream() .filter(action -> action.canExecute(state)) .max(Comparator.comparingDouble(action -> scoreAction(action, goals))) .orElse(null); } private double scoreAction(AgentAction action, Map<String, Object> goals) { double score = 0; for (Map.Entry<String, Object> effect : action.getEffects().entrySet()) { if (effect.getValue().equals(goals.get(effect.getKey()))) { score += 100; } else { score -= action.getCost(); } } return score; } }

这个规划器不到四十行,但已经具备GOAP最核心的能力:动作选择不是写死在代码里,而是由目标和当前状态实时推导。要改变Agent行为,不需要改流程代码,只需要调整动作前置条件或效果。

配上一段单元测试,可以直观看到它的确定性价值:

@Test void shouldEscalateWhenUrgencyHigh() { Map<String, Object> state = Map.of( "urgency", "high", "level", "normal", "customerSentiment", "angry" ); Map<String, Object> goals = Map.of("level", "escalated"); List<AgentAction> plan = planner.plan(state, goals, 5); assertEquals("urgent_escalate", plan.get(0).getName()); }

这样的测试不是端到端的黑盒验证,而是对决策逻辑的精确断言。企业客户看到这样的测试,比看到任何演示都有说服力。

4.3 让LLM只干最擅长的事:提取状态

上面所有规划都依赖一个完整的Map<String, Object>世界状态。真实场景里,这个状态一部分来自结构化数据(比如数据库里的客户等级),另一部分藏在非结构化文本里(比如工单内容、聊天记录),后者就是LLM的主场。

用Spring AI的ChatClient让大模型输出结构化JSON,再绑定成WorldState对象:

@Component public class TicketStateExtractor { private final ChatClient chatClient; private final ObjectMapper objectMapper; public TicketStateExtractor(ChatClient.Builder chatClientBuilder) { this.chatClient = chatClientBuilder.build(); this.objectMapper = new ObjectMapper(); } public WorldState extract(String ticketContent) { String json = chatClient.call(""" 请从工单内容中提取以下状态字段,只输出JSON,不要任何解释: { "urgency": "low|medium|high", "customerSentiment": "calm|concerned|angry", "productLine": "string", "hasSlaBreach": "boolean" } 工单内容: %s """.formatted(ticketContent)); try { return objectMapper.readValue(json, WorldState.class); } catch (JsonProcessingException e) { throw new IllegalStateException("LLM输出无法解析", e); } } }

注意这个调用里完全没有“你下一步应该做什么”这类指令。大模型不决定动作顺序,不决定工具调用,它只做一次翻译:把非结构化文本翻译成结构化状态。这一步是它能力最强、幻觉影响最小的区间。

当然,要防止LLM输出不规范。我给这个模块加了Schema约束和JSON校验,解析失败就直接走人工兜底,不会让畸形状态进入规划器。这是跟纯提示词编排的关键差异:编排方案的错误会在动作链条中间才暴露,而这里在入口就拦截了。

4.4 执行闭环与审计记录

最后把三者串起来。一个工单到达后,先做结构化数据加载和LLM文本抽取,合并成完整世界状态,交给规划器,再逐条执行计划。整个链路被一个Spring管理的AgentService编排:

@Service public class TicketAgentService { private final TicketStateExtractor stateExtractor; private final GreedyGoapPlanner planner; private final TicketRepository ticketRepository; private final AuditRecorder auditRecorder; public void handleTicket(Long ticketId, String content) { Map<String, Object> baseState = ticketRepository.loadStructuredState(ticketId); WorldState extracted = stateExtractor.extract(content); Map<String, Object> worldState = mergeState(baseState, extracted); List<AgentAction> plan = planner.plan(worldState, goalOf(ticketRepository.loadGoals(ticketId)), 10); auditRecorder.recordPlan(ticketId, worldState, plan); for (AgentAction action : plan) { action.execute(new AgentContext(ticketId)); auditRecorder.recordAction(ticketId, action.getName(), worldState); } } }

这里真正值得称赞的是审计切面。企业客户常问一句话:“这个Agent为什么这么做?”提示词编排很难回答这个问题,因为你只能展示一次模型输出。GOAP可以。世界状态、目标、每个动作的前置条件、每一步的决策依据,全都是结构化数据,随时可以回放。

我在项目里遇到客户提出合规审计要求,团队花了最长时间的不是实现Agent逻辑,而是想清楚如何把决策过程可解释地记录下来。那也是我第一次意识到,企业级Agent的生命力其实在于治理能力,而不只是模型能力。

5. 这条路线到底适合谁,不适合谁

5.1 适合场景和不适合场景的清单

没有任何一条技术路线是万能药。我基于实际项目感受,把适合和不适合GOAP方案的场景整理了一下,至少对做技术选型有参考意义。

适合走这条路线的情况有:业务路径有一定的结构化特征,比如工单处理、运维告警、订单跟进、审批辅助;对决策稳定性有硬性要求,不允许同样的输入出现不同结果;业务流程需要审计和追责,每一步行为都要能解释;团队以Java为主,没有独立的AI工程团队。

不太适合的情况也有:目标过于开放、需要大量发散性探索的场景,比如开放式创意生成、自由对话陪伴类Agent;步骤无法抽象成有限有序动作集的场景,像那种每次都要临时发明全新操作的;以及以模型能力为核心卖点的产品,比如你想做一个完全由大模型驱动的角色扮演系统,硬套GOAP反而会限制上限。

我这里有一条判断经验:如果一个Agent的核心价值是“知道该做什么”,那它适合GOAP;如果核心价值是“能说出惊艳的话”,那它还是得靠大模型自由发挥。决策型Agent上确定性引擎,内容型Agent上生成模型,二者不要混为一谈。

5.2 现实中的混合架构怎么切

说到最后,其实很少有人真的只用一种技术栈。我更推荐的是混合架构:Java负责决策编排和系统集成,Python保留给重算法、模型训练、前沿探索类任务。

具体的切割边界我建议这样:确定性决策、状态流转、审计记录、系统调用这些工作留在Java侧;文本向量化、定制模型推理、复杂NLP分析这类需要占用GPU或依赖Python库的工作,独立成Python微服务,通过标准HTTP或消息队列暴露给Java调用。

我做过一个运维告警Agent,告警文本理解部分是一个Python服务做实体识别,决策编排部分完全是Java侧GOAP在管。两套系统各自稳定运行,互不干扰。Python侧只需要承诺“我会把文本里的指标名、阈值、业务线准确提取出来”,不需要知道Agent最终怎么处理告警;Java侧也只需要关心“收到结构化状态之后怎么规划”,不需要理解embedding是怎么算的。

这个架构的好处是,每个团队都在自己的舒适区里工作,不需要逼Java工程师三个月速成Python,也不需要让Python工程师去学Spring事务。

我个人在实际操作中的体会是,AI Agent这波浪潮最让人焦虑的不是技术本身,而是技术路线不确定带来的反复折腾。GOAP搭配Spring AI这条路,给了我一种久违的“一切尽在掌握”的感觉。它没有否定大模型的价值,而是用工程手段把大模型的能力封装进可控边界里。如果你所在的企业已经有成熟的Java基础设施,又有Agent落地需求,不妨先用工单、运维这类流程型场景试水,把规划器跑通,把状态字段定义清楚,你会很快感受到这路线跟提示词编排的差异。这个方向后续还可以继续延伸,比如把规划器从贪心算法升级成A*、引入多Agent协作、或者把GOAP规划结果和强化学习结合起来,都是可以继续玩的空间。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 5:20:49

AI Agent生产级控制面:从评测Harness到稳定运行的关键

上个月复盘内部一个Agent项目时&#xff0c;我看着监控面板皱了半天眉头&#xff1a;离线评测集上准确率明明有九成&#xff0c;可生产环境里&#xff0c;用户一次多轮任务平均要经历接近三次重试&#xff0c;才能换来一个勉强可用的结果。同一个模型&#xff0c;在评测Harness…

作者头像 李华
网站建设 2026/10/14 5:20:18

高性能图像处理库:选型逻辑、加速原理与性能优化实战

“高性能图像处理库”这个话题&#xff0c;我每次遇到都会先泼一盆冷水&#xff1a;别被“高性能”三个字带偏&#xff0c;一上来就去背各种函数的复杂度。很多图像处理慢的场景&#xff0c;根本不是库不够快&#xff0c;而是你用库的方式有问题。就拿最常见的 RGB 转灰度来说&…

作者头像 李华
网站建设 2026/10/14 5:18:47

轻量级Coding Agent:基于Token效率的提示工程实践

1. 项目概述&#xff1a;一个轻量级 Coding Agent 的诞生逻辑“我做了一个 Coding Agent&#xff0c;结果比 Claude Code 少用了 58.7% Token”——这句话刚在技术社区刷屏时&#xff0c;我第一反应不是惊讶&#xff0c;而是立刻点开源码仓库看 commit 记录和 prompt 版本树。不…

作者头像 李华
网站建设 2026/10/14 5:18:30

用多模态大模型把截图变成可编辑PPT:原理、实操与批量自动化

这事儿要从半年前说起。一位做课程的老师发来一张PPT截图&#xff0c;问我能不能把里面的文字改成他团队的名字。我看了下&#xff0c;那张图是从某次分享会上拍的&#xff0c;整体是一张深蓝色背景的方案页&#xff0c;标题、副标题、三个要点框、底下一行小字。我试着用老办法…

作者头像 李华