
Rod Johnson 用一本书干掉了 EJB,催生了 Spring。二十多年后,他把同一套方法论搬到了 AI Agent 领域:Embabel,一个为 JVM 设计的智能体框架,核心思路是用 Java 的类型系统和路径规划算法,解决 LLM 在企业场景中「90% 可用、10% 崩溃」的可靠性难题。
为什么 Python 不够
Johnson 用了十年以上的 Python,写过大量机器学习代码。他承认 Python 容易上手,但指出两个硬伤:缺乏可见性(visibility)支持,泛型系统原始。对企业级软件来说,更致命的是现有代码资产几乎全在 JVM 上。事务管理、消息总线、安全框架、数据库连接池,这些基础设施在 Java 生态中已经打磨了二十多年。
当 LLM 需要与企业的系统记录源(system of record)深度集成时,Python 能调用的工具链远不如 JVM 丰富。Johnson 的判断十分明确:「解决这些问题所需要的技能,JVM 社区比 Python 社区更加具备。」
GOAP:让规划脱离 LLM
Embabel 最有辨识度的设计是规划层(Planning Step)。目前主流 Agent 框架的做法分两种:Crew AI 用顺序嵌套的流程控制,LangGraph 要求开发者手动搭建状态机。状态机的问题在于系统只能执行预定义路径,任何调整都需要改动逻辑代码并重新部署。
Embabel 引入了 GOAP(Goal Oriented Action Planning)算法。这套算法最初为游戏 AI 设计,在 F.E.A.R. 等游戏中实现了 NPC 的动态行为决策。Embabel 的工作模型围绕四个核心概念:
- Action(行为):智能体执行的具体步骤,带有前置条件和预期后置条件
- Goal(目标):智能体试图达成的结果,同样带有前置条件
- Condition(条件):执行行为或判定目标达成前需要评估的状态
- Domain Model(领域模型):支撑整个流程的对象模型,可以包含业务行为
运行时,GOAP 算法根据当前世界状态(已满足的条件)搜索通往目标的行动路径。每个 Action 完成后,系统重新评估状态并重新规划。这就是 OODA 循环(观察、调整、决策、行动)的工程化实现。
关键区别在于:规划过程由非 LLM 的确定性算法完成,而非让大模型自己决定下一步做什么。「你给它相同的世界状态和目标,它每次都会生成同样的计划。」Johnson 强调,这跟「背后藏着三千亿个参数、无法解释为何那样决策」的 LLM 规划有本质不同。
当某个 Action 执行失败(比如数据源访问异常、信息提取不成功),系统自动切换路径寻找替代方案。开发者不需要写 if-else 分支来处理每个可能的失败场景,框架会基于可用 Action 的前置条件自动重规划。
三种执行模式
Embabel 的 AgentPlatform 提供三种执行模式,确定性从高到低排列:
Focused 模式:用户代码显式请求某个 Agent 的特定功能,传入输入数据。适合事件驱动的代码流,比如收到 Kafka 消息后触发特定处理流程。确定性最高,行为可预测。
Closed 模式:平台对用户意图进行分类,从已注册的 Agent 中选择一个合适的来处理。Agent 选择是动态的,但一旦选定,只有该 Agent 内部定义的 Action 会执行。
Open 模式:平台评估用户意图后,使用所有可用资源(所有 Goal 和 Action)构建临时 Agent 来达成目标。这是最强大的模式,系统可以组合不同提供者的功能,甚至发现开发者没有预设的执行路径。但确定性最低。开发者可以通过 GoalChoiceApprover 接口限制目标选择范围。
即使在 Open 模式下,系统执行的每一个 Action 仍然是开发者明确定义的。框架不会凭空创造新行为,但可以在已知行为之间发现新的组合路径。
类型系统即护栏
Embabel 把 Java 的类型系统当作 LLM 的约束层。当 Action 的返回类型是 Java Record 或 POJO 时,框架将字段上的 Jakarta EE 验证注解(如 @NotNull、@Size、@Pattern)自动注入到 LLM 的 prompt 中。模型在生成响应之前就清楚什么样的数据结构是合法的。
如果 LLM 返回的数据未通过验证,框架将错误信息回传给模型并要求重新生成。LLM 在这个架构中成为了应用类型系统的参与者,而非外挂的黑盒端点。
模型选择同样是设计层面的考量。Embabel 支持在单个工作流的不同步骤中使用不同的 LLM。简单的信息提取用 GPT-4.1-mini 降低成本,需要复杂推理的步骤切换到更强的模型。这种「按步骤选择模型」的设计比全局配置单个模型更经济。
代码示例:注解驱动的 Agent
Embabel 的 API 设计刻意贴近 Spring MVC 的编程体验。用 @Agent 标注类,@Action 标注方法,@AchievesGoal 声明行为的目标达成关系。依赖注入、事务管理、AOP 切面等 Spring 能力全部可用。
@Agent(description = "根据星座查找相关新闻")
public class StarNewsFinder {
private final HoroscopeService horoscopeService;
public StarNewsFinder(HoroscopeService horoscopeService) {
this.horoscopeService = horoscopeService;
}
@Action
public StarPerson extractStarPerson(UserInput input, Ai ai) {
return ai.withLlm(OpenAiModels.GPT_41)
.createObjectIfPossible(
"从用户输入中提取姓名和星座: " + input.getContent(),
StarPerson.class);
}
@Action(toolGroups = {CoreToolGroups.WEB})
public RelevantNewsStories findNewsStories(
StarPerson person, Horoscope horoscope, Ai ai) {
return ai.withDefaultLlm()
.createObject(prompt, RelevantNewsStories.class);
}
@AchievesGoal(description = "生成基于星座和新闻的趣味报告")
@Action
public Writeup writeup(StarPerson person,
RelevantNewsStories stories, Ai ai) {
// 使用更便宜的模型完成最终输出
return ai.withLlm(OpenAiModels.GPT_41_MINI)
.createObject(prompt, Writeup.class);
}
}开发者不需要手动定义执行顺序。GOAP 规划器会根据 StarPerson、Horoscope、RelevantNewsStories 等领域对象的数据流自动推断出执行路径:先提取用户信息,再获取运势,然后搜索新闻,最终生成报告。
意图完整性链
为了控制 LLM 生成代码的可靠性,Embabel 引入了意图完整性链(Intent Integrity Chain)机制。整个流程从 prompt 构建开始,依次经过规范生成、规范审核、测试用例编译,最终进入代码生成。每个环节都可以嵌入人工审查或自动化验证。
测试集以只读形式锁定预期行为。LLM 的角色被聚焦在「反复生成代码直到全部通过测试」。当测试全部通过时,框架可以确认生成的代码与审核过的规范保持一致。
MCP 与 A2A 支持
Embabel 基于 Spring AI 构建,继承了 Spring AI 的 MCP(Model Context Protocol)支持。开发者可以将 MCP 工具集暴露给 Agent 使用,但 Johnson 对「把两百个工具丢给一个 LLM」的做法持明确反对态度。他主张精简聚焦的工具集,配合合理边界控制,才能实现企业级 AI 需要的确定性、成本和安全三重目标。
框架还实现了 Google A2A(Agent-to-Agent)服务器,支持多智能体之间的通信协议。未来计划支持联邦化(Federation),允许不同 Embabel 系统之间的规划层共享远程 Action 和 Goal。
工具权限分级
LLM 的工具访问权限被分为多个层级。开发者可以定义哪些工具对模型可见、哪些只读、哪些需要运行时权限验证。以代码生成 Agent 为例,文件系统访问被拆分为读取和写入两类。写入操作执行前,系统会先验证前置条件(比如项目是否成功构建),只有条件满足才放行。
这种设计把安全控制从「信任 LLM 不乱来」转移到了框架层面的硬性约束。
快速上手
通过 GitHub 模板创建项目,已有 Maven 和 OpenAI API Key 的情况下,一分钟内可以跑起第一个 Agent:
- Java 模板:
github.com/embabel/java-agent-template - Kotlin 模板:
github.com/embabel/kotlin-agent-template
框架代码 95% 使用 Kotlin 编写,同时提供完整的 Java 互操作性。Apache 2.0 协议开源,Maven 坐标为 com.embabel.agent:embabel-agent-api。目前 GitHub 上超过 4000 star,70 位贡献者参与开发。
更完整的示例可以参考 Tripper 旅行规划 Agent(github.com/embabel/tripper),它展示了多步骤规划、Web 工具集成、结构化输出等能力的组合使用。
定位与生态
Johnson 对 Embabel 的定位非常明确:目标直指「最好的 Agent 框架」,不局限于 JVM 平台。虽然当前实现跑在 JVM 上,但核心概念(Action、Goal、Condition、GOAP 规划)是平台无关的。框架概念不依赖 JVM 特性,未来可能扩展到 TypeScript 和 Python。
在 JVM 生态内部,Embabel 与 Spring AI 的关系类似 Spring MVC 与 Servlet API 的关系。Spring AI 提供底层 LLM 调用能力,Embabel 在其之上提供更高层次的 Agent 抽象。这种分层设计让开发者可以在需要精细控制时直接使用 Spring AI,在需要快速构建 Agent 流程时使用 Embabel 的高层 API。
框架的商业模式参照 SpringSource 模型:开源核心 + 商业实体提供企业级支持。目前有五位全职工程师投入开发。
适用场景判断
Embabel 适合的场景特征:
- 企业系统中已有的 Java/Kotlin 代码资产需要接入 AI 能力
- Agent 工作流需要确定性和可测试性(金融、医疗、合规领域)
- 多步骤流程需要在失败时自动重规划而非直接报错
- 需要在不同步骤中使用不同 LLM 以优化成本
如果一个项目的 AI 需求只是简单的 chatbot 或单次文本生成,引入 Agent 框架的复杂度收益不大。Embabel 的价值在多步骤、多工具、需要与现有系统集成、对执行可靠性有要求的场景中才会充分体现。