站点图标 高效码农

Embabel Agent Framework如何革新JVM智能代理开发?Spring开发者必看指南

Embabel Agent Framework:JVM 上的智能代理框架

在当今的软件开发领域,人工智能和代理技术正发挥着越来越重要的作用。Embabel Agent Framework 作为一个在 JVM 上运行的代理框架,为开发者提供了一种强大而灵活的方式来创建智能代理应用。本文将详细介绍 Embabel Agent Framework 的特点、使用方法以及未来发展方向。

一、Embabel Agent Framework 简介

Embabel(发音为 Em – BAY – bel)是一个用于在 JVM 上编写代理流程的框架,它能够无缝地将大语言模型(LLM)驱动的交互与代码和领域模型相结合,支持智能路径规划以实现目标。该框架由 Spring 的创造者开发,采用 Kotlin 编写,同时也为 Java 提供了自然的使用模型。

Embabel Agent Framework

(一)关键概念

Embabel Agent Framework 基于以下几个关键概念来构建代理流程:

  1. 动作(Actions):代理执行的步骤。例如,在一个新闻查找代理中,提取用户输入中的人物信息就是一个动作。
  2. 目标(Goals):代理试图实现的目的。比如,为特定星座的人找到相关新闻故事就是一个目标。
  3. 条件(Conditions):在执行动作或确定目标是否达成之前需要评估的条件。条件会在每个动作执行后重新评估。例如,只有在成功提取到人物信息后,才能继续执行获取星座运势的动作。
  4. 领域模型(Domain model):支撑流程并为动作、目标和条件提供信息的对象。例如,在新闻查找代理中,人物信息、星座运势、新闻故事等都是领域模型的一部分。
  5. 计划(Plan):为实现目标而执行的一系列动作。计划由系统动态制定,而不是由程序员硬编码。系统会在每个动作完成后重新规划,以适应新信息和观察前一个动作的效果,这类似于 OODA 循环

(二)与其他代理框架的区别

Embabel Agent Framework 相对于其他代理框架具有以下优势:

  1. 复杂的规划能力:它不仅仅是有限状态机或顺序执行,还引入了真正的规划步骤,使用非 LLM 的 AI 算法。这使得系统能够通过组合已知步骤以新颖的顺序执行任务,并且能够做出关于并行化和其他运行时行为的决策。
  2. 卓越的可扩展性和复用性:由于采用动态规划,添加更多的领域对象、动作、目标和条件可以扩展系统的功能,而无需编辑有限状态机(FSM)定义或现有代码。
  3. 强类型和面向对象的优势:动作、目标和条件都基于领域模型,领域模型可以包含行为。所有内容都是强类型的,提示和手动编写的代码能够干净地交互,避免了使用魔法映射的问题,并且支持完全的重构。

(三)其他优势

除了上述区别外,Embabel Agent Framework 还具有以下优点:

  1. 平台抽象:编程模型和平台内部实现之间的清晰分离,允许在本地运行,同时在生产环境中可能提供更高的服务质量(QoS),而无需更改应用程序代码。
  2. 适合与 LLM 混合使用:易于构建混合使用大语言模型的应用程序,确保以最具成本效益且功能强大的解决方案。这使得系统能够利用不同模型的优势来完成不同的任务,特别是便于使用本地模型进行特定任务,这对于成本和隐私很重要。
  3. 基于 Spring 和 JVM:可以轻松访问现有的企业功能和能力。例如,Spring 可以注入和管理代理,包括使用 Spring AOP 来装饰函数;还可以使用强大的持久化和事务管理解决方案。
  4. 易于测试:从设计之初就考虑了可测试性,单元测试和代理端到端测试都很容易。

二、Embabel Agent Framework 的使用方式

(一)编写代理流程的方式

Embabel Agent Framework 支持两种编写代理流程的方式:

  1. 基于注解的模型:类似于 Spring MVC,使用 Spring 原型注解 @Agent 对类型进行注解,并使用 @Goal@Condition@Action 方法。以下是一个使用注解的示例:
@Agent(description = "Find news based on a person's star sign")
class StarNewsFinder(
    private val horoscopeService: HoroscopeService,
    private val storyCount: Int = 5,
) {

    @Action
    fun extractPerson(userInput: UserInput): StarPerson =
        PromptRunner().createObject("Create a person from this user input, extracting their name and star sign: $userInput")

    @Action
    fun retrieveHoroscope(starPerson: StarPerson) =
        Horoscope(horoscopeService.dailyHoroscope(starPerson.sign))

    @Action(toolGroups = [ToolGroup.WEB])
    fun findNewsStories(person: StarPerson, horoscope: Horoscope): RelevantNewsStories =
        PromptRunner().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()
        )

    @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,
    ): Writeup =
        PromptRunner().withTemperature(1.2).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 stories are:
            ${relevantNewsStories.items.joinToString("\n") { "- ${it.url}: ${it.summary}" }}

            Format it as Markdown with links.
        """.trimIndent()
        )
}
  1. Kotlin DSL:使用 agent {action { 块进行编写。这种方式更具 Kotlin 语言的特性,代码更加简洁和灵活。

(二)规划步骤

规划步骤是可插拔的,默认的规划方法是 目标导向动作规划(Goal Oriented Action Planning,GOAP)。GOAP 是一种在游戏中常用的 AI 规划算法,它允许根据世界的当前状态和代理的目标进行动态决策和动作选择。未来的规划选项还包括由推理模型(如 OpenAI o1 或 DeepSeek R1)创建的计划。

(三)执行模式

Embabel Agent Framework 通过 AgentPlatform 实现来执行代理。代理平台支持以下几种执行模式:

  1. 聚焦模式(Focused):用户代码请求特定功能,通过调用方法来运行特定的代理,并传入输入。这种模式适用于代码驱动的流程,例如响应传入事件而触发的流程。
  2. 封闭模式(Closed):对用户意图(或其他传入事件)进行分类,以选择合适的代理。平台会在所有已知的代理中尝试找到合适的代理,但只会运行特定代理中定义的动作。
  3. 开放模式(Open):评估用户的意图,平台使用所有资源来尝试实现该意图。平台会在所有已知的目标中寻找合适的目标,并从起始状态构建一个自定义代理来实现该目标,包括相关的动作和条件。如果平台不确定任何目标的适用性,则不会继续执行。GoalChoiceApprover 接口为开发者提供了进一步限制目标选择的方法。

开放模式是最强大但也是最不确定的模式。在开放模式下,平台能够找到开发者未曾预想的新颖路径,甚至可以组合多个提供者的功能。但即使在开放模式下,平台也只会执行已经指定的单个步骤,尽管这些步骤可能是 LLM 转换,其结果仍然具有一定的不确定性。

未来可能还会支持 “演进模式(Evolving)”,即平台可以在同一进程中处理多个目标,并修改正在运行的进程以添加更多的目标和代理。例如,一个动作可能会意识到实现额外的目标变得很重要。

三、快速开始使用 Embabel Agent Framework

(一)创建代理项目

要快速开始使用 Embabel Agent Framework,可以通过以下两种方式创建自己的代理项目:

  1. 使用 GitHub 模板:从 JavaKotlin GitHub 模板创建自己的代理仓库,只需点击 “Use this template” 按钮即可。
  2. 使用快速启动工具:在本地创建 Embabel 代理项目,可以使用以下命令:
uvx --from git+https://github.com/embabel/project-creator.git project-creator

选择 Java 或 Kotlin,并指定项目名称和包名,如果已经有 OPENAI_API_KEY 并且安装了 Maven,那么在不到一分钟的时间内就可以让代理运行起来。

(二)为什么需要 Embabel Agent Framework

在软件开发中,为什么需要使用 Embabel Agent Framework 呢?主要有以下几个原因:

  1. 需要代理框架的原因:虽然我们可以直接编写代码来调用大语言模型并控制流程,但使用高级代理框架具有明显的优势。例如,它可以将大语言模型的交互分解为更简单、更聚焦的步骤,从而最大化复用性,最小化成本和错误;便于进行单元测试和集成测试;提高组件的可组合性,使子流程和单个动作可以被复用;使应用程序更易于管理和健壮,允许工作流管理器控制其执行并在保持先前状态的情况下重试操作;通过在多个地方应用护栏来增强安全性。
  2. JVM 上的代理框架需求:虽然目前在 Python 或 TypeScript 中代理框架的发展更为成熟,但在 JVM 上开发代理框架仍然有很大的潜力。关键原因在于现有的代码和基础设施资产更有可能在 JVM 上,而不是在 Python 中。
  3. 与 Spring AI 的区别:Spring AI 是一个很好的框架,Embabel Agent Framework 基于 Spring AI 构建,并采用了 Spring 组件模型。但 Embabel Agent Framework 认为大多数应用程序应该使用更高级的 API。可以将 Spring AI 类比为 Servlet API,而 Embabel Agent Framework 更像是 Spring MVC。在 Embabel Agent Framework 中,复杂的需求更容易表达和测试。
  4. 不贡献给 Spring 的原因:这个项目需要与 Spring 不同的治理方式,因为 Spring 中的大多数项目存在于稳定的环境中,可靠性和稳定性比快速创新更重要。此外,这些概念并不局限于 JVM,Embabel Agent Framework 希望成为跨平台的领先代理框架。虽然 Spring 品牌在 Java 中很有价值,但在 TypeScript 或 Python 中并非如此。

四、代码示例

(一)代理实现代码

以下是一个使用 Kotlin 实现的代理示例,用于根据人的星座查找新闻:

@Agent(description = "Find news based on a person's star sign")
class StarNewsFinder(
    private val horoscopeService: HoroscopeService,
    private val storyCount: Int = 5,
) {

    @Action
    fun extractPerson(userInput: UserInput): StarPerson =
        PromptRunner().createObject("Create a person from this user input, extracting their name and star sign: $userInput")

    @Action
    fun retrieveHoroscope(starPerson: StarPerson) =
        Horoscope(horoscopeService.dailyHoroscope(starPerson.sign))

    @Action(toolGroups = [ToolGroup.WEB])
    fun findNewsStories(person: StarPerson, horoscope: Horoscope): RelevantNewsStories =
        PromptRunner().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()
        )

    @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,
    ): Writeup =
        PromptRunner().withTemperature(1.2).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 stories are:
            ${relevantNewsStories.items.joinToString("\n") { "- ${it.url}: ${it.summary}" }}

            Format it as Markdown with links.
        """.trimIndent()
        )
}

(二)领域类

以下是确保类型安全的领域类:

data class RelevantNewsStories(
    val items: List<NewsStory>
)

data class NewsStory(
    val url: String,
    val summary: String,
)

data class Subject(
    val name: String,
    val sign: String,
)

data class Horoscope(
    val summary: String,
)

data class FunnyWriteup(
    override val text: String,
) : HasContent

五、开发和使用过程中的注意事项

(一)狗粮政策

Embabel Agent Framework 项目遵循 “狗粮政策”,即认为软件开发的各个方面都可以且应该通过使用 AI 代理来大大加速。但最终的决策者仍然是人类,人类应该对代理的贡献进行指导和迭代。具体原则如下:

  1. 使用 AI 代理来帮助项目的各个方面,如编码、文档编写、生成营销文案等。任何执行任务的人类都应该思考为什么不能将其自动化,并努力实现最大程度的自动化。
  2. 开发者保留最终控制权。开发者负责引导代理朝着解决方案前进,并在必要时进行迭代。提交或合并代理贡献的开发者负责确保其符合项目的编码标准,代码必须是人类可读的。
  3. 只使用基于 Embabel 平台构建的开源代理,并贡献任何改进。虽然商业编码代理可能更先进,但项目认为自己的平台是自动化的最佳通用解决方案,通过自我使用可以最快地改进它。通过开源在开源项目中使用的代理,可以最大程度地造福社区。
  4. 优先使用有助于加速项目进度的代理。就像飞行安全建议中先给自己戴上氧气面罩再帮助他人一样,项目将优先使用有助于加速自身进度的代理。这不仅可以产生有用的示例,还可以提高整体项目速度。

(二)环境配置

在使用 Embabel Agent Framework 时,需要进行以下环境配置:

  1. 获取代码:可以通过 git clone https://github.com/embabel/embabel-agent 克隆仓库,也可以创建一个新的 Spring Boot 项目并添加必要的依赖。
  2. 环境变量:需要设置以下环境变量:
    • OPENAI_API_KEY:用于 OpenAI API。
    • 可选的 ANTHROPIC_API_KEY:用于 Anthropic API,对于编码代理是必需的。强烈建议同时提供 OpenAI 和 Anthropic 密钥,因为一些示例需要两者。并且应该尝试为给定任务找到最佳的大语言模型,而不是自动选择熟悉的提供商。
  3. 服务:需要安装 Docker Desktop 并安装 Docker MCP 扩展,以使用 Docker MCP 工具(如网络搜索工具)。确保从目录中激活以下工具:
    • Brave Search
    • Fetch
    • Puppeteer
    • Wikipedia
      也可以使用 Spring AI 约定设置自己的 MCP 工具。可以参考 application - docker - desktop.yml 文件获取示例。
      如果在本地运行 Ollama,设置 ollama 配置文件,Embabel 将自动连接到 Ollama 端点并使所有模型可用。

(三)运行和测试

  1. 运行应用程序:可以使用以下命令创建自己的代理项目:
uvx --from git+https://github.com/embabel/project-creator.git project-creator

也可以使用 scripts 目录中的脚本运行应用程序。在交互式模式下启动 shell 可以使用以下命令:

cd scripts
./shell.sh

该脚本还会警告任何缺失的环境变量。也可以在 IDE 中或通过命令行直接使用 Maven 运行 shell:

export SPRING_PROFILES_ACTIVE=shell,starwars
mvn -P agent-examples-kotlin -Dmaven.test.skip=true spring-boot:run

注意要通过 -P 设置 agent-examples-kotlin Maven 配置文件,否则 Embabel 将找不到示例代理。如果在 IDE 中运行,也需要设置此配置文件。在 IntelliJ 中,可以通过菜单选项 View -> Tool Windows – > Maven 后勾选相应的框来激活它。
2. 测试:可以通过 Maven 运行测试:

mvn test

这将运行单元测试和集成测试,但不需要互联网连接或任何外部服务。

(四)Spring 配置文件

Spring 配置文件用于为不同的环境和行为配置应用程序:

  1. 交互配置文件shell 配置文件用于在交互式 shell 中运行代理,不会启动 Web 进程。
  2. 模型配置文件
    • ollama 配置文件用于查找 Ollama 模型,需要在本地安装 Ollama 并拉取相关模型。
    • docker-desktop 配置文件用于在 Docker 桌面环境中运行时查找 Docker 管理的本地模型,建议使用此配置文件以获得最佳体验,并使用 Docker 提供的网络工具。
    • docker 配置文件用于在 Docker 容器中运行时查找 Docker 管理的本地模型。
  3. 日志配置文件
    • severance 配置文件用于特定的日志记录,参考 Severance
    • starwars 配置文件用于星球大战风格的日志记录,是默认配置文件,因为它在银河系中广为人知。
    • colossus 配置文件用于《巨像:福宾计划》风格的日志记录。
    • montypython 配置文件用于蒙提·派森风格的日志记录,让人意想不到。
    • hh 配置文件用于《银河系漫游指南》风格的日志记录,答案是 42。

如果没有选择这些配置文件,Embabel 将使用普通的日志记录,这可能会让人觉得不够有趣。

(五)在项目中使用 Embabel Agent Framework

1. Maven

pom.xml 中添加 Embabel Agent BOM:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.embabel.agent</groupId>
            <artifactId>embabel-agent-dependencies</artifactId>
            <version>1.0.0-SNAPSHOT</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>    

pom.xml 中添加感兴趣的模块(如 embabel-agent-api)的编译依赖:

<dependencies>
    <dependency>
        <groupId>com.embabel.agent</groupId>
        <artifactId>embabel-agent-api</artifactId>
    </dependency>
</dependencies>

2. Gradle(Kotlin DSL)

build.gradle.kts 中添加所需的仓库:

repositories {
    mavenCentral()
    maven {
        name = "embabel-snapshots"
        url = uri("https://repo.embabel.com/artifactory/libs-snapshot")
        mavenContent {
            snapshotsOnly()
        }
    }
    maven {
        name = "Spring Milestones"
        url = uri("https://repo.spring.io/milestone")
    }
}

build.gradle.kts 中添加 Embabel Agent BOM 和感兴趣的模块:

dependencies {
    implementation(platform("com.embabel.agent:embabel-agent-dependencies:1.0.0-SNAPSHOT"))
    implementation("com.embabel.agent:embabel-agent-api:1.0.0-SNAPSHOT")
}

3. Gradle(Groovy DSL)

build.gradle 中添加所需的仓库:

repositories {
    mavenCentral()
    maven {
        name = 'embabel-snapshots'
        url = 'https://repo.embabel.com/artifactory/libs-snapshot'
        mavenContent {
            snapshotsOnly()
        }
    }
    maven {
        name = 'Spring Milestones'
        url = 'https://repo.spring.io/milestone'
    }
}

build.gradle 中添加 Embabel Agent BOM 和感兴趣的模块:

dependencies {
    implementation platform('com.embabel.agent:embabel-agent-dependencies:1.0.0-SNAPSHOT')
    implementation 'com.embabel.agent:embabel-agent-api:1.0.0-SNAPSHOT'
}

需要注意的是,Spring Milestones 仓库是必需的,因为 Embabel BOM 对实验性的 Spring 组件有传递依赖,特别是 mcp - bom。这个 BOM 在 Maven Central 上不可用,只发布到 Spring 里程碑仓库。与 Maven 不同,Gradle 不会继承父 POM 或 BOM 中声明的仓库配置,因此需要在仓库块中显式声明 Spring 里程碑仓库,以确保所有传递依赖的正确解析。

(六)使用 Embabel 作为 MCP 服务器

可以将 Embabel 代理平台用作 MCP 服务器,从像 Claude Desktop 这样的 UI 中使用。由于 Claude 目前只通过标准输入输出(stdio)工作,而 Embabel 正确地忽略了 stdio 而使用服务器发送事件(SSE),因此需要使用一个 中间层。需要注意的是,这个功能目前还不成熟。

(七)消费 MCP 服务器

Embabel Agent Framework 提供了对消费模型上下文协议(MCP)服务器的内置支持,允许通过标准化接口扩展应用程序的强大 AI 功能。

1. MCP 简介

模型上下文协议(MCP)是一个开放协议,它标准化了应用程序如何为大语言模型提供上下文和额外功能。由 Anthropic 引入,MCP 已经成为连接 AI 代理和工具的事实上的标准,作为一种客户端 – 服务器协议,客户端(如 Embabel Agent)向服务器发送请求,服务器处理这些请求以向 AI 模型提供必要的上下文。MCP 通过标准化将 “M×N 问题” 转化为 “M + N 问题”,类似于 USB 对硬件外设所做的事情。

2. 在 Embabel Agent 中配置 MCP

要在 Embabel Agent 应用程序中配置 MCP 服务器,需要在 application.yml 中添加以下内容:

spring:
  ai:
    mcp:
      client:
        enabled: true
        name: embabel
        version: 1.0.0
        request-timeout: 30s
        type: SYNC
        stdio:
          connections:
            docker-mcp:
              command: docker
              args:
                - run
                - -i
                - --rm
                - alpine/socat
                - STDIO
                - TCP:host.docker.internal:8811

这个配置设置了一个 MCP 客户端,它通过 Docker 的 socat 实用程序使用标准输入输出传输连接到基于 Docker 的 MCP 服务器,以连接到 TCP 端点。

3. Docker 桌面 MCP 集成

Docker 通过其 Docker MCP 目录和工具包采用了 MCP,提供了以下功能:
– 集中式发现:一个可信的中心,用于发现集成到 Docker Hub 中的 MCP 工具。
– 容器化部署:无需复杂设置即可将 MCP 服务器作为容器运行。
– 安全的凭证管理:集中式、加密的凭证处理。
– 内置安全:沙箱隔离和权限管理。
Docker MCP 生态系统包括来自 Stripe、Elastic、Neo4j 等合作伙伴的 100 多个经过验证的工具,所有这些工具都可以通过 Docker 的基础设施访问。

(八)A2A 集成

Embabel 集成了 A2A 协议,允许连接到其他支持 A2A 的代理和服务。

  1. 启用 a2a Spring 配置文件以启动 A2A 服务器。
  2. 需要设置以下环境变量:GOOGLE_STUDIO_API_KEY,用于 Google Studio API,用于 Gemini。
  3. 使用 a2a Docker 配置文件启动 Google A2A 网络界面:
docker compose --profile a2a up
  1. 访问运行在容器内的网络界面 http://localhost:12000/
  2. 连接到代理 host.docker.internal:8080/a2a。需要注意的是,localhost:8080/a2a 在 Docker 容器中运行时服务器无法访问。

六、未来发展方向

Embabel Agent Framework 目前处于早期阶段,但有很大的发展计划:

  1. 成为 Java 应用程序的自然选择:特别是对于基于 Spring 构建的应用程序,使它们能够轻松实现生成式 AI 功能。
  2. 证明模型的强大能力:通过添加目标和动作来展示无需修改即可扩展的能力;展示成为自然语言平台即服务(PaaS)的潜力;展示在 GOAP 模型内进行代理联合的潜力;展示预算感知的代理,如 “研究以下主题,在学习时最多花费 20 美分”;集成数据存储并展示在组织内部展示现有功能的能力。
  3. 扩展到其他平台:概念框架并不局限于 JVM,一旦在 JVM 上建立起来,计划创建 TypeScript 和 Python 项目。

七、总结

Embabel Agent Framework 是一个功能强大、灵活且易于使用的代理框架,它为开发者提供了在 JVM 上创建智能代理应用的新途径。通过无缝集成大语言模型和代码,以及支持智能规划和多种执行模式,Embabel Agent Framework 能够帮助开发者构建更高效、更智能的应用程序。同时,它还提供了丰富的工具和功能,如易于测试、支持 MCP 服务器和 A2A 集成等,为开发者提供了便利。随着其未来的发展,我们有理由相信 Embabel Agent Framework 将在软件开发领域发挥越来越重要的作用。

如果你对 Embabel Agent Framework 感兴趣,可以按照本文提供的快速开始步骤进行尝试,体验其带来的便利和强大功能。在使用过程中,遵循项目的狗粮政策和相关的开发规范,充分发挥其优势,为你的项目带来更多的价值。

退出移动版