Spring Boot + Embabel 入门:用 Java 写一个会规划步骤的 AI 博客助手

本文通过一个完整的"AI 博客生成助手"示例,介绍如何在 Spring Boot 中使用 Embabel 框架构建目标驱动的 Agentic Flow,涵盖 Maven 配置、领域模型设计、@Agent/@Action 编写和 REST Controller 集成。
Mttao
Mttao
@mttao
13 分钟
Spring Boot + Embabel 入门:用 Java 写一个会规划步骤的 AI 博客助手

如果你已经会写 Spring Boot 应用,并且正在尝试把大语言模型接入业务系统,那么你很快会遇到一个现实问题:直接调用一次 LLM 很简单,但把多个 LLM 调用、数据库查询、规则判断、工具调用和业务对象组织成一个可靠流程,就没有那么简单了

Spring AI 更像是”让 Spring 应用能方便地调用模型、向量库和工具”的基础设施,而 Embabel 站在更高一层。Embabel 是一个运行在 JVM 上的 agentic flow 框架,它的目标是把 LLM 提示词交互、普通 Java/Kotlin 代码和强类型领域模型 混合起来,用 Agent、Action、Goal、Plan 等概念来组织流程。

Embabel 官方文档将 Agent 描述为一个自包含组件,它把领域逻辑、AI 能力和工具使用组合在一起,用来代表用户完成某个特定目标。

本文会用一个非常贴近内容生产场景的例子来入门:我们要基于 Spring Boot + Embabel 写一个”AI 博客助手”。用户输入一个主题,系统先理解写作需求,再生成大纲,再生成初稿,最后审稿并输出最终 Markdown 文章。示例力求通俗易懂,但代码会尽量完整,方便你直接改造成自己的项目。

1. Embabel 到底解决什么问题

在没有 Agent 框架时,很多人会这样写 AI 流程:Controller 收到请求,然后 Service 里按顺序调用 parseTopic()generateOutline()writeDraft()reviewDraft()。这种写法当然可以工作,但它有一个明显缺点:流程顺序完全写死在代码里。一旦你想增加 SEO 优化、事实检查、敏感词审查、数据库查询或外部工具调用,Service 很容易变成又长又难维护的”流程脚本”。

Embabel 的思路不同。你不是先写一个固定流程,而是先定义 Agent 能做哪些动作,也就是 @Action;再告诉系统什么结果算达成目标,也就是 @AchievesGoal 或 Goal。Embabel 会根据当前已有对象、每个 Action 的入参和返回值,动态规划该执行哪些步骤。官方文档把这种工作方式称为围绕 Actions、Goals、Conditions、Domain Model 和 Plan 建模,并且每个 Action 完成后会重新评估状态和计划。

概念通俗理解在代码里的常见形态
Agent一个具备一组能力的”智能业务组件”标注 @Agent 的 Spring Bean
ActionAgent 能执行的一个步骤标注 @Action 的 Java 方法
GoalAgent 最终要得到的结果@AchievesGoal 或目标类型
Domain Model流程中流转的强类型业务对象Java record / class
Plan为了达到目标而生成的步骤序列由 Embabel 平台动态规划

这就是 Embabel 和普通 LLM 调用最大的区别:它不是把 AI 当成一个文本生成接口,而是把 AI 放进一个由强类型对象和业务代码共同约束的执行系统里。这对于 Java 开发者非常友好,因为你仍然可以使用 Spring 的依赖注入、配置管理、测试体系、事务、数据库访问和普通业务服务。

2. 本文要做什么

我们要实现一个简单但完整的”博客生成助手”。用户通过 HTTP 接口提交主题,后端返回一篇经过审稿的 Markdown 博客。

整个流程可以想象成下面这样:

flowchart LR
    A[用户输入主题] --> B[BlogIdea\n理解主题和目标读者]
    B --> C[BlogOutline\n生成文章大纲]
    C --> D[BlogDraft\n生成初稿]
    D --> E[ReviewedBlogPost\n审稿并输出最终文章]

这四个节点都不是随便传递的 Map 或 JSON 字符串,而是 Java record。Embabel 很鼓励这种强类型方式,因为它能让 LLM 的输出变成业务代码能理解、能测试、能重构的对象。

步骤输入对象输出对象是否调用 LLM说明
理解主题UserInputBlogIdea从自然语言里提取主题、读者和写作风格
生成大纲BlogIdeaBlogOutline生成结构化章节大纲
生成初稿BlogOutlineBlogDraft根据大纲写 Markdown 初稿
审稿定稿BlogDraftReviewedBlogPost改进内容并返回最终结果

需要说明的是,Embabel 的 API 在不同版本中仍在持续演进。本文代码采用官方文档和 2026 年社区示例中较一致的写法:@Agent@Action@AchievesGoalOperationContext 以及 AgentInvocation.builder(agentPlatform)。如果你使用的版本有细微差异,请优先以所选版本的官方文档为准。

3. 环境准备与版本选择

Embabel 官方文档说明,最简单的开始方式是把 Embabel 的 Spring Boot starter 加入项目,并且 release 版本会发布到 Maven Central。Maven 仓库页面显示,com.embabel.agent:embabel-agent-starter 已有多个 Central 版本,其中 0.4.0 发布于 2026-05-19,0.3.5 是 0.3.x 的较新版本。

为了让示例更稳妥,本文建议新手先使用 Spring Boot 3.5.x、Java 21+ 和 Embabel 0.4.0。如果你所在公司项目还停留在 Java 17,也可以先查阅当前 Embabel 版本的兼容性要求;官方示例仓库的快速开始明确列出了 Java 21+、至少一个 LLM API Key 和 Maven 3.9+ 作为前置条件。

软件推荐版本说明
JDK21+Java 21 是当前企业项目较容易接受的 LTS 选择
Spring Boot3.5.x更适合作为入门示例;Boot 4 相关兼容性请看所选版本文档
Maven3.9+官方示例仓库建议 Maven 3.9+
Embabel0.4.0Maven Central 当前较新 release 版本之一
模型供应商OpenAI-compatible示例使用 OPENAI_API_KEY 环境变量

4. 创建 Spring Boot 项目

你可以在 Spring Initializr 创建一个普通 Maven 项目。项目元信息可以这样填写:

配置项示例值
Groupcom.example
Artifactembabel-blog-demo
Packagecom.example.embabelblog
Java21
Dependencies暂时只选 Spring Web 即可

项目创建好以后,我们手动修改 pom.xml,加入 Embabel 依赖。

5. Maven 配置

下面是完整的 pom.xml 示例。这里使用 embabel-agent-starter,因为我们要做一个由 HTTP Controller 驱动的 Web 应用;同时加入 embabel-agent-starter-openai,用于接入 OpenAI 或 OpenAI-compatible 模型。官方文档说明,基础 starter 会把 Agent Platform Bean 放进 Spring 容器,应用可以通过依赖注入使用;如果不是用模板项目,并且要使用 OpenAI-compatible 模型,还需要加入 embabel-agent-starter-openai

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.5.0</version>
        <relativePath/>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>embabel-blog-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>embabel-blog-demo</name>
    <description>Spring Boot + Embabel getting started demo</description>

    <properties>
        <java.version>21</java.version>
        <embabel-agent.version>0.4.0</embabel-agent.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.embabel.agent</groupId>
            <artifactId>embabel-agent-starter</artifactId>
            <version>${embabel-agent.version}</version>
        </dependency>

        <dependency>
            <groupId>com.embabel.agent</groupId>
            <artifactId>embabel-agent-starter-openai</artifactId>
            <version>${embabel-agent.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

如果你使用的是 snapshot 版本,而不是 Maven Central 上的 release 版本,还需要额外配置 Embabel 的 release 和 snapshot 仓库。入门阶段建议优先用 release 版本,减少依赖解析和 API 变化带来的困扰。

6. 配置 application.yml

接下来在 src/main/resources/application.yml 中配置应用名称、端口和默认 LLM。OpenAI-compatible 场景至少需要 OPENAI_API_KEY,也可以通过配置文件指定 API Key 和 base URL。

spring:
  application:
    name: embabel-blog-demo

server:
  port: 8080

embabel:
  models:
    default-llm: gpt-4.1-mini
  agent:
    platform:
      models:
        openai:
          api-key: ${OPENAI_API_KEY}
          base-url: ${OPENAI_BASE_URL:}

default-llm 指定默认模型。OPENAI_API_KEY 从环境变量读取,不建议把真实 Key 写死在代码仓库里。启动应用前,你可以这样设置环境变量:

export OPENAI_API_KEY="你的 API Key"

如果你使用的是兼容 OpenAI 协议的模型服务,例如企业内部网关或其他云厂商,可以同时设置:

export OPENAI_BASE_URL="https://your-compatible-endpoint.example.com/v1"

7. 启动类:开启 Agent 扫描

新建 src/main/java/com/example/embabelblog/EmbabelBlogApplication.java@EnableAgents 用来启用 Embabel Agent 扫描。社区示例和教程中都采用这种方式把 @Agent 标注的类注册到平台中。

package com.example.embabelblog;

import com.embabel.agent.config.annotation.EnableAgents;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableAgents
public class EmbabelBlogApplication {

    public static void main(String[] args) {
        SpringApplication.run(EmbabelBlogApplication.class, args);
    }
}

你可以把 @EnableAgents 理解成”让 Spring Boot 启动时顺便发现 Embabel Agent”。发现以后,Embabel 才知道应用里有哪些 Agent、Action 和 Goal。

8. 定义领域模型

接下来创建 model 包。领域模型是 Embabel 示例中非常重要的一部分。不要急着写提示词,也不要一上来就让模型返回一大段 JSON 字符串。更推荐先问自己:这个流程中会产生哪些业务对象?每一步的输入输出分别是什么?

8.1 BlogIdea

BlogIdea 表示系统从用户输入中理解出来的写作意图。

package com.example.embabelblog.model;

public record BlogIdea(
        String topic,
        String targetAudience,
        String tone,
        String keyMessage
) {
}
字段含义示例
topic文章主题Spring Boot 全局异常处理
targetAudience目标读者初中级 Java 开发者
tone语气风格通俗、实践导向
keyMessage核心观点统一异常处理能提升 API 一致性

8.2 BlogOutline

BlogOutline 表示文章大纲。为了让代码简洁,我们在一个 record 中定义嵌套 record。

package com.example.embabelblog.model;

import java.util.List;

public record BlogOutline(
        String title,
        String summary,
        List<Section> sections
) {
    public record Section(
            String heading,
            String purpose,
            List<String> keyPoints
    ) {
    }
}

这里的 sections 是结构化章节列表。相比直接让模型返回 Markdown,大纲对象更容易检查,也更容易在后续增加”调整大纲""插入 SEO 关键词”等动作。

8.3 BlogDraft

BlogDraft 表示根据大纲写出的初稿。

package com.example.embabelblog.model;

public record BlogDraft(
        String title,
        String markdown,
        int estimatedReadingMinutes
) {
}

初稿未必完美,所以我们不把它当作最终目标。它只是流程中间产物。

8.4 ReviewedBlogPost

ReviewedBlogPost 表示审稿后的最终文章。这个类型会作为我们 HTTP 接口的返回结果。

package com.example.embabelblog.model;

import java.util.List;

public record ReviewedBlogPost(
        String title,
        String markdown,
        List<String> improvements,
        List<String> warnings
) {
}

improvements 用于说明审稿阶段做了哪些改进,warnings 用于提醒可能还需要人工确认的地方。例如,模型可能会提醒”某个版本号需要根据官方文档再次核对”。

8.5 GenerateBlogRequest

为了让 Controller 接收 JSON 请求,再定义一个简单请求对象。

package com.example.embabelblog.model;

public record GenerateBlogRequest(
        String topic,
        String targetAudience,
        String tone
) {
}

9. 编写 BlogWritingAgent

现在进入 Embabel 的核心部分。新建 agent 包,并创建 BlogWritingAgent.java

一个 Embabel Agent 就是一个 Spring Bean,它包含多个 @Action 方法。每个 Action 方法的参数代表它需要哪些对象,返回值代表它执行后产生什么对象。Embabel 正是根据这些输入输出类型来推断流程路径的。

package com.example.embabelblog.agent;

import com.embabel.agent.api.annotation.AchievesGoal;
import com.embabel.agent.api.annotation.Action;
import com.embabel.agent.api.annotation.Agent;
import com.embabel.agent.api.common.OperationContext;
import com.embabel.agent.domain.io.UserInput;
import com.example.embabelblog.model.BlogDraft;
import com.example.embabelblog.model.BlogIdea;
import com.example.embabelblog.model.BlogOutline;
import com.example.embabelblog.model.ReviewedBlogPost;

@Agent(description = "根据用户主题生成适合初学者阅读的技术博客")
public class BlogWritingAgent {

    @Action(description = "从用户输入中提取博客写作意图")
    public BlogIdea understandIdea(UserInput input, OperationContext context) {
        String prompt = """
                你是一名资深技术编辑。请从用户输入中提取博客写作意图,返回结构化对象。

                要求:
                1. topic 表示文章主题。
                2. targetAudience 表示目标读者,如果用户没有说明,默认为"初中级 Java 开发者"。
                3. tone 表示写作风格,如果用户没有说明,默认为"通俗易懂、实践导向"。
                4. keyMessage 表示文章最想传达的核心观点。

                用户输入:
                %s
                """.formatted(input.getContent());

        return context.ai()
                .withDefaultLlm()
                .createObject(prompt, BlogIdea.class);
    }

    @Action(description = "根据写作意图生成博客大纲")
    public BlogOutline createOutline(BlogIdea idea, OperationContext context) {
        String prompt = """
                你是一名 Java 技术博客作者。请根据下面的写作意图生成一份清晰的大纲。

                主题:%s
                目标读者:%s
                语气:%s
                核心观点:%s

                大纲要求:
                1. 标题要具体,不要空泛。
                2. summary 用 2 到 3 句话说明文章内容。
                3. sections 建议 5 到 7 个章节。
                4. 每个章节都要有 heading、purpose 和 keyPoints。
                5. keyPoints 使用简短中文短语,方便后续扩写。
                """.formatted(
                idea.topic(),
                idea.targetAudience(),
                idea.tone(),
                idea.keyMessage()
        );

        return context.ai()
                .withDefaultLlm()
                .createObject(prompt, BlogOutline.class);
    }

    @Action(description = "根据博客大纲生成 Markdown 初稿")
    public BlogDraft writeDraft(BlogOutline outline, OperationContext context) {
        String prompt = """
                你是一名擅长 Spring Boot 和 Java 的技术作者。请根据下面的大纲写一篇 Markdown 初稿。

                标题:%s
                摘要:%s
                章节:%s

                写作要求:
                1. 使用中文。
                2. 面向初学者,解释要通俗。
                3. 每个章节都要有完整段落,不要只写列表。
                4. 如果涉及代码,请给出简短但可理解的 Java 示例。
                5. estimatedReadingMinutes 根据正文长度估算。
                """.formatted(
                outline.title(),
                outline.summary(),
                outline.sections()
        );

        return context.ai()
                .withDefaultLlm()
                .createObject(prompt, BlogDraft.class);
    }

    @Action(description = "审阅初稿,修正表达和技术细节,输出最终博客")
    @AchievesGoal(description = "生成一篇经过审阅的中文技术博客")
    public ReviewedBlogPost reviewDraft(BlogDraft draft, OperationContext context) {
        String prompt = """
                你是一名严格但友好的技术审稿人。请审阅并改进下面的博客初稿。

                原标题:%s
                原文:
                %s

                审稿要求:
                1. 修正明显的技术表述问题。
                2. 让语言更适合初学者阅读。
                3. 保留 Markdown 格式。
                4. improvements 列出你做出的主要改进。
                5. warnings 列出仍建议人工确认的内容;如果没有,请返回空列表。
                """.formatted(draft.title(), draft.markdown());

        return context.ai()
                .withDefaultLlm()
                .createObject(prompt, ReviewedBlogPost.class);
    }
}

这段代码有几个关键点值得慢慢看。

首先,BlogWritingAgent 标注了 @Agent。这说明它不是普通 Service,而是一个 Embabel 可以识别的 Agent。它仍然是 Spring 管理的组件,所以你完全可以通过构造器注入自己的 Repository、Service、配置类或审计组件。

其次,四个方法都标注了 @ActionunderstandIdea() 的输入是 UserInput,输出是 BlogIdeacreateOutline() 的输入是 BlogIdea,输出是 BlogOutlinewriteDraft() 的输入是 BlogOutline,输出是 BlogDraftreviewDraft() 的输入是 BlogDraft,输出是 ReviewedBlogPost。这种类型关系就是 Embabel 规划流程的重要依据。

最后,reviewDraft() 多了一个 @AchievesGoal。它告诉 Embabel:当系统成功得到 ReviewedBlogPost 时,这次博客生成任务就算完成。

10. 编写 REST Controller

官方文档展示了如何注入 AgentPlatform,然后通过 AgentInvocation.builder(agentPlatform) 构建调用,并用 invoke(input) 执行。我们可以把这个思路放进 Spring MVC Controller 中。

新建 controller/BlogController.java

package com.example.embabelblog.controller;

import com.embabel.agent.api.common.AgentInvocation;
import com.embabel.agent.api.common.AgentPlatform;
import com.embabel.agent.api.common.ProcessOptions;
import com.embabel.agent.domain.io.UserInput;
import com.example.embabelblog.model.GenerateBlogRequest;
import com.example.embabelblog.model.ReviewedBlogPost;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/blogs")
public class BlogController {

    private final AgentPlatform agentPlatform;

    public BlogController(AgentPlatform agentPlatform) {
        this.agentPlatform = agentPlatform;
    }

    @PostMapping("/generate")
    public ReviewedBlogPost generate(@RequestBody GenerateBlogRequest request) {
        String userMessage = """
                请帮我写一篇技术博客。
                主题:%s
                目标读者:%s
                写作风格:%s
                """.formatted(
                request.topic(),
                defaultIfBlank(request.targetAudience(), "初中级 Java 开发者"),
                defaultIfBlank(request.tone(), "通俗易懂、实践导向")
        );

        UserInput input = new UserInput(userMessage);

        AgentInvocation<ReviewedBlogPost> invocation = AgentInvocation
                .builder(agentPlatform)
                .options(ProcessOptions.builder()
                        .verbosity(v -> v.showPrompts(false))
                        .build())
                .build(ReviewedBlogPost.class);

        return invocation.invoke(input);
    }

    private static String defaultIfBlank(String value, String defaultValue) {
        return value == null || value.isBlank() ? defaultValue : value;
    }
}

Controller 只说明:我现在有一个 UserInput,我想要一个 ReviewedBlogPost。至于从输入到最终结果要经过哪些 Action,则交给 Embabel 的平台根据 Agent 中声明的能力去规划。这正是重点所在——你不再需要手写:

BlogIdea idea = agent.understandIdea(input);
BlogOutline outline = agent.createOutline(idea);
BlogDraft draft = agent.writeDraft(outline);
ReviewedBlogPost result = agent.reviewDraft(draft);

如果你的 Embabel 版本中 AgentInvocationUserInput 的包名、构造方式略有不同,请参考当前版本官方文档中的示例。Embabel 仍在快速发展,这类 API 命名变化并不罕见。

11. 运行和测试

启动前先设置 API Key:

export OPENAI_API_KEY="你的 API Key"

然后运行:

mvn spring-boot:run

使用 curl 调用接口:

curl -X POST http://localhost:8080/api/blogs/generate \
  -H "Content-Type: application/json" \
  -d '{
    "topic": "Spring Boot 中如何优雅地处理全局异常",
    "targetAudience": "刚入门 Spring Boot 的 Java 开发者",
    "tone": "通俗易懂,带一点实战经验"
  }'

你将得到类似下面的响应(真实内容会因为模型输出而变化):

{
  "title": "Spring Boot 全局异常处理入门:让你的 API 错误返回更统一",
  "markdown": "# Spring Boot 全局异常处理入门\n\n在实际项目中...",
  "improvements": [
    "补充了为什么需要统一异常处理的背景说明",
    "调整了示例代码的命名,使其更贴近 Spring Boot 项目",
    "增加了初学者容易踩坑的解释"
  ],
  "warnings": [
    "示例代码需要根据项目实际 Spring Boot 版本调整依赖"
  ]
}

如果你打开应用日志,通常可以看到 Embabel 规划和执行 Action 的过程:先 formulated plan,然后依次 executing action,最后 goal achieved。这类日志对理解 Agent 为什么这么执行非常有帮助。

12. 为什么这个例子比直接调用 LLM 更好

你可能会问:这个例子里每一步都在调用 LLM,那我直接写四个方法顺序调用不也可以吗?从功能结果看,短期确实可以。但 Embabel 的价值在于后续演进。

后续需求手写固定流程Embabel 风格
增加 SEO 优化修改 Service 流程代码增加一个输入 BlogDraft、输出 SeoBlogDraft 的 Action
增加敏感词审查在流程中插入条件判断增加审查 Action,让目标依赖审查后的对象
接入数据库素材在 Service 中手动查询在 Action 中注入 Repository 或 Service
多模型混用手动管理不同模型客户端按配置和角色选择不同 LLM,框架支持 LLM mixing
排查执行过程自己打日志平台可输出规划和执行过程

也就是说,Embabel 对初学者的第一印象可能是”多了一层抽象”,但当流程从两个步骤变成十几个步骤,并且混合 LLM、数据库、规则、工具和外部系统时,这层抽象就会让系统更容易维护。

13. 在 Action 中注入普通 Spring Service

Embabel 并不要求每个 Action 都调用 LLM。实际上,企业项目中更推荐把 LLM 用在它擅长的地方,例如理解自然语言、生成草稿、总结内容;而把确定性逻辑留给普通 Java 代码。Action 可以是 LLM 步骤,也可以是数据库查询、评分、校验或调用业务服务这样的确定性步骤。

比如你可以定义一个素材服务:

package com.example.embabelblog.service;

import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class BlogReferenceService {

    public List<String> findReferences(String topic) {
        return List.of(
                "公司内部 Java 开发规范",
                "Spring Boot 官方参考文档",
                "历史故障复盘文档"
        );
    }
}

然后在 Agent 中注入它:

@Agent(description = "根据用户主题生成适合初学者阅读的技术博客")
public class BlogWritingAgent {

    private final BlogReferenceService referenceService;

    public BlogWritingAgent(BlogReferenceService referenceService) {
        this.referenceService = referenceService;
    }

    @Action(description = "查找和主题相关的内部参考资料")
    public BlogReferences findReferences(BlogIdea idea) {
        return new BlogReferences(referenceService.findReferences(idea.topic()));
    }
}

这样一来,Agent 既可以使用 LLM,也可以使用普通业务代码。对于生产系统来说,这非常重要:不要让 LLM 接管所有逻辑;让 LLM 处理不确定的语言任务,让 Java 处理确定的业务规则

14. 常见问题

14.1 Embabel 和 Spring AI 是什么关系

Spring AI 是 Spring 生态里的 AI 基础抽象,重点是模型调用、向量库、工具调用等能力。Embabel 是更高层的 Agent 框架,它可以基于 Spring AI 等底层能力来编排目标驱动的工作流。简单来说:Spring AI 帮你和模型、工具、向量库交互;Embabel 帮你构建会根据目标运行 Action 的 Agent。

14.2 我一定要用 Shell starter 吗

不一定。官方文档列出了三类常见 starter:

Starter适用场景本文是否使用
embabel-agent-starter-shell学习、调试、命令行交互
embabel-agent-starter-mcpserver作为 MCP 服务暴露 Agent
embabel-agent-starterWeb API、微服务、自定义启动模式

14.3 为什么要用 Java record

Java record 很适合表达不可变的数据传输对象。Embabel 强调强类型领域模型,record 可以让输入输出结构更清楚,也便于测试和重构。相比让模型返回一段散乱文本,返回 BlogOutlineBlogDraftReviewedBlogPost 这样的对象更适合进入业务流程。

14.4 如果模型输出不符合结构怎么办

生产环境中需要增加校验和兜底。你可以在 record 字段上配合 Bean Validation,也可以在 Action 返回后增加一个校验 Action。如果校验失败,可以让另一个 Action 修复格式,或者直接返回可解释的错误。Embabel 的价值不是让 LLM 永不出错,而是把不确定输出放进一个更可观察、更可控制的流程里。

14.5 可以不用 OpenAI 吗

可以。官方文档列出了 Anthropic、DeepSeek、Gemini、Mistral AI、LM Studio、Ollama 等 provider starter 或配置方式。如果你希望本地运行模型,可以尝试 Ollama 或 LM Studio;如果你在企业内网中使用 OpenAI-compatible 网关,可以配置对应的 base URL。

15. 入门后的改造方向

当你跑通本文示例以后,可以尝试做几个增强版本:

改造方向需要新增的对象需要新增的 Action
SEO 优化SeoSuggestionSeoBlogPostoptimizeSeo()
事实检查FactListFactCheckReportextractFacts()checkFacts()
存入数据库SavedBlogPostsaveBlogPost()
生成配图提示词ImagePromptcreateCoverImagePrompt()
多语言翻译TranslatedBlogPosttranslatePost()

这种扩展方式体现了 Embabel 的优势:你不是不断修改一个巨大流程,而是在增加新的类型和 Action,让平台拥有更多可组合的能力。

16. 总结

本文用一个”AI 博客助手”示例介绍了 Spring Boot + Embabel 的基本用法。一个 Embabel 应用通常包括 Maven starter、模型配置、@EnableAgents、领域模型、@Agent@Action@AchievesGoal 以及通过 AgentPlatform 发起调用。

更重要的是,Embabel 带来的不是”更花哨的提示词写法”,而是一种更适合 Java 企业应用的 AI 工程化思路:用强类型对象承载上下文,用 Action 拆分能力,用 Goal 表达目标,用平台规划执行路径,并把 LLM 调用和普通业务代码放在同一个 Spring 体系中管理

如果你刚开始学习 Embabel,建议先写一个像本文这样的简单 Agent,理解对象如何在 Action 之间流动;然后再逐步加入数据库、业务服务、工具调用、多模型配置和测试。这样学习曲线会更平滑,也更容易把 Embabel 用到真实项目里。

References

/ 评论