由Spring创始人发布的JVM Agent编排框架,用Kotlin实现但Java调用友好,支持动态规划路径、条件和领域模型,已集成文档对话功能。

Embabel(发音为 Em-BAY-bel)是一个在 JVM 上编写智能体流程的框架,能够将 LLM 提示交互与代码和领域模型无缝混合。支持向目标智能寻路。采用 Kotlin 编写,但对 Java 提供了自然的使用模型。来自 Spring 的创作者。
有问题?通过 Embabel 驱动的 hub 与文档对话——这是一个 Embabel AI 智能体,能够用自然语言回答你关于该框架的问题。
Embabel 用以下概念来建模智能体流程:
Actions(动作):智能体执行的步骤
Goals(目标):智能体试图实现的内容
Conditions(条件):在执行动作或确定目标已达成之前需要评估的条件。每个动作执行后,条件会被重新评估。
Domain model(领域模型):支撑流程并为 Actions、Goals 和 Conditions 提供信息的对象。
Plan(计划):为实现目标而采取的一系列动作序列。计划由系统动态制定,而非由程序员编写。系统在每个动作完成后重新规划,使其能够适应新信息并观察前一个动作的效果。这实际上是一个 OODA 循环。
应用开发者通常不需要直接处理这些概念,因为大多数条件源于代码中定义的数据流,系统可以据此推断前置条件和后置条件。
这些概念构成了该框架相对于其他智能体框架的核心差异:
精密的规划能力。超越有限状态机或带嵌套的顺序执行,引入真正的规划步骤,使用非 LLM 的 AI 算法。这使系统能够执行未经编程预设的任务——通过以新颖的顺序组合已知步骤来实现——并在运行时做出关于并行化和其他行为的决策。
卓越的可扩展性和复用性:由于采用动态规划,添加更多的领域对象、动作、目标和条件可以扩展系统能力,而无需编辑 FSM 定义或现有代码。
强类型和面向对象的好处:Actions、goals 和 conditions 由领域模型提供信息,其中可以包含行为。所有内容均采用强类型,提示和手动编写的代码清晰交互。告别神奇的 Map,享受完整的重构支持。
平台抽象:编程模型与平台内部实现的清晰分离,允许在本地运行,同时可能在生产环境中提供更高的服务质量,且无需修改应用代码。
专为 LLM 混合设计:构建混合 LLM 的应用程序很容易,确保最具成本效益且能力最强的解决方案。这使得系统能够利用不同模型的优势来完成不同任务。特别是,它便于使用本地模型来处理单点任务。这对成本和隐私都很重要。
基于 Spring 和 JVM 构建,可以轻松访问现有企业功能。例如:Spring 可以注入和管理 AI 智能体,包括使用 Spring AOP 来装饰函数。可用的持久化和事务管理解决方案也很健壮。
Spring 可以注入和管理 AI 智能体,包括使用 Spring AOP 来装饰函数。
可用的持久化和事务管理解决方案也很健壮。
从一开始就为可测试性而设计。单元测试和 AI 智能体端到端测试都很容易实现。
Flow 可以通过以下两种方式之一来编写:
一种基于注解的模型,类似于 Spring MVC,使用 Spring stereotype @Agent 注解类型,配合 @Goal、@Condition 和 @Action 方法。
另一种是惯用的 Kotlin DSL,使用 agent { 和 action { 代码块。
无论哪种方式,Flow 都由一个领域模型支持,该模型中的对象可以具有丰富的行为。
我们正在努力实现允许部署自然语言动作和目标。
规划步骤是可插拔的。
默认的规划方法是目标导向动作规划(Goal Oriented Action Planning)。GOAP 是一种在游戏领域流行的 AI 规划算法。它允许基于世界的当前状态和 AI 智能体的目标进行动态决策和动作选择。
目标、动作和规划与 GOAP 是独立的。Embabel 还开箱即用地支持 Utility AI,它可以运行相同的动作,但根据(可能是动态的)效用分数来选择动作,而不是严格的前置条件和后置条件。这对于探索和开放性任务很有价值,当我们不需要实现特定目标而是想最大化整体效用时尤其有用。
框架通过 AgentPlatform 实现来执行。
AI 智能体平台支持以下执行模式:
Focused(聚焦)模式:用户代码请求特定功能。用户代码调用方法来运行特定的 AI 智能体,并传入输入。这非常适合代码驱动的 Flow,例如响应传入事件而调用的 Flow。
Closed(封闭)模式:用户意图(或其他传入事件)被分类以选择 AI 智能体。平台尝试在它知道的所有 AI 智能体中找到合适的 AI 智能体。AI 智能体选择是动态的,但只有特定 AI 智能体内定义的动作才会运行。
Open(开放)模式:评估用户意图,平台利用其所有资源来尝试实现它。平台尝试在它知道的所有目标中找到合适的目标,并从初始状态构建一个自定义 AI 智能体来实现它,包括相关的动作和条件。如果对任何目标的适用性有任何疑虑,平台将不会继续。GoalChoiceApprover 接口为开发者提供了进一步限制目标选择的途径。
Open 模式是最强大的,但也是最不确定的。
在开放模式下,平台能够找到开发者未曾设想过的新路径,甚至可以组合多个提供者的功能。
即使在开放模式下,平台也只执行已指定的单个步骤。(当然,步骤本身可能是 LLM 转换,这种情况下提示词由用户代码控制,但结果仍然是不确定的。)
可能的未来模式:
Evolving(演进)模式:平台可以在同一进程中处理多个目标,并修改运行中的进程以添加更多目标和 AI 智能体。例如,一个动作可以意识到实现额外目标已变得很重要。
Embabel AI 智能体系统还将支持联合,既支持与其他 Embabel 系统(允许规划纳入远程动作和目标),也支持第三方 AI 智能体框架。
通过点击 "Use this template" 按钮,从我们的 Java 或 Kotlin GitHub 模板创建你自己的 AI 智能体仓库。
如果你已经安装了 OPENAI_API_KEY 和 Maven,不到一分钟就能运行一个 AI 智能体。
📚 有关示例和教程,请参阅 Embabel Agent Examples Repository
🚗 有关复杂现实的示例应用程序,请参阅 Tripper travel planner agent

AI 生成的旅行行程,包含详细建议

输出中包含的地图链接
太长不看版:因为 AI 智能体框架的发展还处于早期阶段,还有很大的改进空间;因为在 JVM 上运行的 AI 智能体框架将带来巨大的业务价值。
我们可以不依赖更高层次的抽象,直接调用 LLM 并在代码中直接控制流程来编写代码。然而,更高级别的 AI 智能体框架提供了令人信服的优势。例如:
拆分 LLM 交互,使其更简单、更专注。这最大化了重用,最小化了成本和错误。它通常允许我们使用更便宜的模型来进行单点交互。
促进单元测试和集成测试,这在 AI 智能体系统中与任何其他软件系统一样重要。
增加可组合性,子 Flow 和单个动作可以被重用。
使应用程序更易于管理和健壮,使工作流管理器能够控制它们的执行,并在维护先前状态的同时重试操作。
通过能够在多个地方应用护栏来增强安全性。
虽然 AI 智能体框架最初主要出现在 Python 中,但现在还处于早期阶段,有很多新颖且更优方法的空间。关键邻近性不在于 LLM——它只是一个简单的 HTTP 调用——而在于现有代码和基础设施资产,这些在 JVM 上比在 Python 上更有价值。
Spring AI 很棒。我们构建在它之上,并采用 Spring 组件模型。然而,我们相信大多数应用程序应该使用更高级别的 API。一个类比:Spring AI 处于 Servlet API 的级别,而 Embabel 更像是 Spring MVC。在 Embabel 中表达和测试复杂需求比直接使用 Spring AI 容易得多。
这个项目需要与 Spring 不同的治理模式,在 Spring 模式下大多数项目存在于稳定环境中,依赖性和稳定性比快速创新更重要。其次,这些概念并非 JVM 特有的。我们希望 Embabel 成为跨平台的领先 AI 智能体框架。虽然 Spring 品牌在 Java 中很有价值,但在 TypeScript 或 Python 中并非如此。
在 Java 或 Kotlin 中,AI 智能体实现代码直观且易于测试。
@Agent(description = "根据一个人的星座查找新闻")
public class StarNewsFinder {
private final HoroscopeService horoscopeService;
private final int storyCount;
// 服务由 Spring 注入
public StarNewsFinder(
HoroscopeService horoscopeService,
@Value("${star-news-finder.story.count:5}") int storyCount) {
this.horoscopeService = horoscopeService;
this.storyCount = storyCount;
}
@Action
public StarPerson extractStarPerson(UserInput userInput, Ai ai) {
return ai
.withLlm(OpenAiModels.GPT_41)
.createObjectIfPossible(
"""
根据以下用户输入创建一个人,提取他们的姓名和星座:
%s""".formatted(userInput.getContent()),
StarPerson.class
);
}
@Action
public Horoscope retrieveHoroscope(StarPerson starPerson) {
return new Horoscope(horoscopeService.dailyHoroscope(starPerson.sign()));
}
@Agent(description = "Find news based on a person's star sign")
class StarNewsFinder(
// Services such as Horoscope are injected by Spring
private val horoscopeService: HoroscopeService,
// Potentially externalized by Spring
@param:Value("\${star-news-finder.story.count:5}")
private val storyCount: Int = 5,
) {
@Action
fun extractPerson(
userInput: UserInput,
ai: Ai
): StarPerson =
// All prompts are typesafe
ai.withDefaultLlm()
.createObject("Create a person from this user input, extracting their name and star sign: $userInput")
// This action doesn't use an LLM
// Embabel makes it easy to mix LLM use with regular code
@Action
fun retrieveHoroscope(starPerson: StarPerson) =
Horoscope(horoscopeService.dailyHoroscope(starPerson.sign))
// This action uses tools
// "toolGroups" specifies tools that are required for this action to run
@Action(toolGroups = [ToolGroup.WEB])
fun findNewsStories(
person: StarPerson,
horoscope: Horoscope,
ai: Ai,
): RelevantNewsStories =
ai.withDefaultLlm().createObject(
"""
${person.name} is an astrology believer with the sign ${person.sign}.
Their horoscope for today is:
<horoscope>${horoscope.summary}</horoscope>
Given this, use web tools and generate search queries
to find $storyCount relevant news stories summarize them in a few sentences.
Include the URL for each story.
Do not look for another horoscope reading or return results directly about astrology;
find stories relevant to the reading above.
For example:
- If the horoscope says that they may
want to work on relationships, you could find news stories about
novel gifts
- If the horoscope says that they may want to work on their career,
find news stories about training courses.
""".trimIndent()
)
// The @AchievesGoal annotation indicates that completing this action
// achieves the given goal, so the agent run will be complete
@AchievesGoal(
description = "Write an amusing writeup for the target person based on their horoscope and current news stories",
)
@Action
fun writeup(
person: StarPerson,
relevantNewsStories: RelevantNewsStories,
horoscope: Horoscope,
ai: Ai,
): Writeup =
ai
.withLlm(
LlmOptions
.withModel(model)
.withTemperature(0.9)
)
.createObject(
"""
Take the following news stories and write up something
amusing for the target person.
Begin by summarizing their horoscope in a concise, amusing way, then
talk about the news. End with a surprising signoff.
${person.name} is an astrology believer with the sign ${person.sign}.
Their horoscope for today is:
<horoscope>${horoscope.summary}</horoscope>
Relevant news s