Getting Started with Spring Boot + Embabel: Build an AI Blog Assistant in Java

A complete walkthrough of building a goal-driven AI blog writing assistant using Spring Boot and Embabel. Covers Maven setup, domain model design, @Agent/@Action authoring, and REST Controller integration.
Mttao
Mttao
@mttao
14 min read
Getting Started with Spring Boot + Embabel: Build an AI Blog Assistant in Java

If you already know how to write Spring Boot applications and are exploring ways to integrate large language models into your business systems, you will quickly run into a practical problem: a single LLM call is simple, but orchestrating multiple LLM calls, database queries, rule checks, tool invocations, and business objects into a reliable workflow is anything but.

Spring AI acts as infrastructure for making model calls, vector stores, and tool invocations accessible from Spring applications. Embabel operates at a higher level. It is an agentic flow framework running on the JVM whose goal is to blend LLM prompt interactions, ordinary Java/Kotlin code, and strongly typed domain models using concepts like Agent, Action, Goal, and Plan to organize workflows.

Embabel’s official documentation describes an Agent as a self-contained component that combines domain logic, AI capabilities, and tool use to accomplish a specific goal on behalf of a user.

This guide uses a scenario close to real content production: we will build an AI Blog Assistant on top of Spring Boot + Embabel. The user submits a topic; the system understands the writing intent, generates an outline, writes a draft, reviews it, and returns a final Markdown article. The example is designed to be approachable while keeping the code complete enough to serve as a starting point for your own projects.

1. What Problem Does Embabel Solve?

Without an agent framework, a common approach to AI workflows looks like this: a Controller receives a request, and a Service calls parseTopic(), generateOutline(), writeDraft(), and reviewDraft() in sequence. This works, but it has a clear drawback: the workflow order is hardcoded. As soon as you need to add SEO optimization, fact checking, content moderation, database lookups, or external tool calls, that Service easily becomes a long, hard-to-maintain “process script.”

Embabel takes a different approach. Instead of writing a fixed pipeline upfront, you declare what actions an Agent can perform using @Action, and then tell the system what result constitutes success using @AchievesGoal or a Goal type. Embabel dynamically plans which steps to execute based on the objects currently available and the input/output types of each Action. The official documentation describes this as modeling around Actions, Goals, Conditions, a Domain Model, and a Plan, with the plan re-evaluated after each Action completes.

ConceptPlain-language meaningTypical code form
AgentA “smart business component” with a set of capabilitiesA Spring Bean annotated with @Agent
ActionA single step an Agent can performA Java method annotated with @Action
GoalThe final result the Agent needs to produce@AchievesGoal or a target type
Domain ModelStrongly typed business objects flowing through the pipelineJava records or classes
PlanThe sequence of steps generated to reach the goalDynamically planned by the Embabel platform

This is the fundamental difference between Embabel and a plain LLM call: instead of treating AI as a text-generation endpoint, Embabel places AI inside an execution system jointly constrained by strongly typed objects and business code. This is very Java-developer-friendly because you still use Spring’s dependency injection, configuration management, testing infrastructure, transactions, database access, and ordinary business services.

2. What We Are Building

We will implement a simple but complete blog generation assistant. The user submits a topic through an HTTP endpoint, and the backend returns a reviewed Markdown blog post.

The overall flow looks like this:

flowchart LR
    A[User submits topic] --> B[BlogIdea\nUnderstand topic and audience]
    B --> C[BlogOutline\nGenerate article outline]
    C --> D[BlogDraft\nWrite first draft]
    D --> E[ReviewedBlogPost\nReview and produce final article]

None of these four nodes are plain Map or raw JSON strings — they are Java records. Embabel strongly encourages this strongly typed approach because it turns LLM output into objects that business code can understand, test, and refactor.

StepInput objectOutput objectLLM callDescription
Understand topicUserInputBlogIdeaYesExtract topic, audience, and tone from natural language
Generate outlineBlogIdeaBlogOutlineYesProduce a structured section outline
Write draftBlogOutlineBlogDraftYesWrite a Markdown first draft based on the outline
Review and finalizeBlogDraftReviewedBlogPostYesImprove the draft and return the final result

Note that the Embabel API continues to evolve across versions. The code in this guide follows conventions seen in the official documentation and 2026 community examples: @Agent, @Action, @AchievesGoal, OperationContext, and AgentInvocation.builder(agentPlatform). If your version differs slightly, always defer to the official documentation for that version.

3. Environment Setup and Version Selection

The Embabel official documentation states that the easiest way to get started is to add the Embabel Spring Boot starter to your project, with release versions published to Maven Central. The com.embabel.agent:embabel-agent-starter artifact has several Central versions available, with 0.4.0 released on 2026-05-19 and 0.3.5 being a recent 0.3.x release.

For a stable experience, this guide recommends starting with Spring Boot 3.5.x, Java 21+, and Embabel 0.4.0. If your project is still on Java 17, check the compatibility requirements for your target Embabel version. The official examples repository lists Java 21+, at least one LLM API key, and Maven 3.9+ as prerequisites.

SoftwareRecommended versionNotes
JDK21+Java 21 is a widely accepted LTS version for enterprise projects
Spring Boot3.5.xA solid choice for getting started; check docs for Boot 4 compatibility
Maven3.9+Required by the official examples repository
Embabel0.4.0One of the latest release versions on Maven Central
Model providerOpenAI-compatibleThe example uses the OPENAI_API_KEY environment variable

4. Create the Spring Boot Project

Create a standard Maven project at Spring Initializr using these settings:

FieldExample value
Groupcom.example
Artifactembabel-blog-demo
Packagecom.example.embabelblog
Java21
DependenciesOnly Spring Web for now

After generating the project, manually edit pom.xml to add the Embabel dependencies.

5. Maven Configuration

Below is the complete pom.xml. We use embabel-agent-starter because we are building a web application driven by an HTTP Controller, plus embabel-agent-starter-openai to connect to OpenAI or an OpenAI-compatible model. The official documentation explains that the base starter registers the Agent Platform Bean in the Spring container; embabel-agent-starter-openai is also needed if you are not using a template project and want to work with OpenAI-compatible models.

<?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>

If you are using a snapshot version rather than a Maven Central release, you will also need to configure Embabel’s release and snapshot repositories. For getting started, stick with release versions to avoid dependency resolution issues and unexpected API changes.

6. Configure application.yml

Create src/main/resources/application.yml to configure the application name, port, and default LLM. For OpenAI-compatible setups you need at minimum an OPENAI_API_KEY; you can also specify the API key and base URL directly in the configuration file.

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 sets the default model. OPENAI_API_KEY is read from an environment variable — never hardcode real keys in your repository. Before starting the application, set the variable:

export OPENAI_API_KEY="your-api-key"

If you are using an OpenAI-compatible endpoint such as an enterprise gateway or another cloud provider, also set:

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

7. Main Class: Enable Agent Scanning

Create src/main/java/com/example/embabelblog/EmbabelBlogApplication.java. The @EnableAgents annotation activates Embabel Agent scanning, which is how classes annotated with @Agent are registered with the platform.

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);
    }
}

Think of @EnableAgents as “tell Spring Boot to also discover Embabel Agents at startup.” Once discovered, Embabel knows which Agents, Actions, and Goals the application contains.

8. Define the Domain Model

Create a model package. Domain models are a crucial part of any Embabel application. Rather than rushing to write prompts or returning large JSON strings from the LLM, first ask yourself: what business objects does this workflow produce? What are the inputs and outputs at each step?

8.1 BlogIdea

BlogIdea represents the writing intent extracted from the user’s input.

package com.example.embabelblog.model;

public record BlogIdea(
        String topic,
        String targetAudience,
        String tone,
        String keyMessage
) {
}
FieldMeaningExample
topicArticle topicGlobal exception handling in Spring Boot
targetAudienceIntended readersJunior to mid-level Java developers
toneWriting stylePractical and approachable
keyMessageCore takeawayUnified error handling improves API consistency

8.2 BlogOutline

BlogOutline represents the article outline. We use a nested record to keep the code concise.

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
    ) {
    }
}

The sections list is a structured chapter breakdown. Compared to asking the model to return raw Markdown, an outline object is easier to validate and makes it simple to later add actions like “adjust the outline” or “inject SEO keywords.”

8.3 BlogDraft

BlogDraft holds the first draft written from the outline.

package com.example.embabelblog.model;

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

A draft is not the final goal — it is an intermediate artifact in the pipeline.

8.4 ReviewedBlogPost

ReviewedBlogPost is the reviewed final article and will be the return type of our HTTP endpoint.

package com.example.embabelblog.model;

import java.util.List;

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

improvements lists the changes made during the review stage. warnings flags anything that may still need a human check — for example, “this version number should be verified against the official documentation.”

8.5 GenerateBlogRequest

A simple request object for the Controller to accept a JSON body.

package com.example.embabelblog.model;

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

9. Write the BlogWritingAgent

Now we get to the heart of Embabel. Create an agent package and add BlogWritingAgent.java.

An Embabel Agent is a Spring Bean containing one or more @Action methods. Each Action method’s parameters declare which objects it needs, and the return type declares what it produces. Embabel infers the workflow path from these type relationships.

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 = "Generates a beginner-friendly technical blog post from a user-supplied topic")
public class BlogWritingAgent {

    @Action(description = "Extract the blog writing intent from user input")
    public BlogIdea understandIdea(UserInput input, OperationContext context) {
        String prompt = """
                You are a senior technical editor. Extract the blog writing intent from the
                user's input and return a structured object.

                Requirements:
                1. topic: the article subject.
                2. targetAudience: the intended readers; default to "junior to mid-level Java developers"
                   if the user does not specify.
                3. tone: the writing style; default to "practical and approachable" if not specified.
                4. keyMessage: the single most important idea the article should convey.

                User input:
                %s
                """.formatted(input.getContent());

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

    @Action(description = "Generate a blog outline from the writing intent")
    public BlogOutline createOutline(BlogIdea idea, OperationContext context) {
        String prompt = """
                You are a Java technical blogger. Generate a clear outline based on the writing
                intent below.

                Topic: %s
                Audience: %s
                Tone: %s
                Key message: %s

                Outline requirements:
                1. The title must be specific, not generic.
                2. summary: 2–3 sentences describing the article content.
                3. sections: 5–7 chapters recommended.
                4. Each section must include a heading, purpose, and keyPoints.
                5. keyPoints should be short phrases easy to expand later.
                """.formatted(
                idea.topic(),
                idea.targetAudience(),
                idea.tone(),
                idea.keyMessage()
        );

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

    @Action(description = "Write a Markdown first draft from the blog outline")
    public BlogDraft writeDraft(BlogOutline outline, OperationContext context) {
        String prompt = """
                You are a technical writer specializing in Spring Boot and Java. Write a Markdown
                first draft based on the outline below.

                Title: %s
                Summary: %s
                Sections: %s

                Writing requirements:
                1. Write in English.
                2. Target beginners — explanations should be clear and accessible.
                3. Each section must contain full paragraphs, not just bullet points.
                4. Include short but understandable Java code examples where relevant.
                5. Estimate estimatedReadingMinutes based on the length of the body text.
                """.formatted(
                outline.title(),
                outline.summary(),
                outline.sections()
        );

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

    @Action(description = "Review the first draft, correct phrasing and technical details, and produce the final article")
    @AchievesGoal(description = "Produce a reviewed technical blog post")
    public ReviewedBlogPost reviewDraft(BlogDraft draft, OperationContext context) {
        String prompt = """
                You are a rigorous but supportive technical reviewer. Review and improve the
                blog draft below.

                Original title: %s
                Draft:
                %s

                Review requirements:
                1. Correct obvious technical inaccuracies.
                2. Make the language more accessible for beginners.
                3. Preserve Markdown formatting.
                4. improvements: list the main changes you made.
                5. warnings: list anything that should still be verified by a human;
                   return an empty list if there are none.
                """.formatted(draft.title(), draft.markdown());

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

Several things are worth examining carefully.

First, BlogWritingAgent is annotated with @Agent. This marks it as an Embabel-recognized Agent rather than a plain Service. It is still a Spring-managed component, so you can freely inject your own Repositories, Services, configuration classes, or auditing components through the constructor.

Second, all four methods are annotated with @Action. understandIdea() takes UserInput and returns BlogIdea; createOutline() takes BlogIdea and returns BlogOutline; writeDraft() takes BlogOutline and returns BlogDraft; reviewDraft() takes BlogDraft and returns ReviewedBlogPost. These type relationships are exactly what Embabel uses to plan the execution path.

Third, reviewDraft() also carries @AchievesGoal. This tells Embabel: once the system successfully produces a ReviewedBlogPost, the blog generation task is complete.

10. Write the REST Controller

The official documentation shows how to inject AgentPlatform, build an invocation with AgentInvocation.builder(agentPlatform), and execute it with invoke(input). We embed this pattern in a Spring MVC Controller.

Create 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 = """
                Please write a technical blog post for me.
                Topic: %s
                Target audience: %s
                Writing style: %s
                """.formatted(
                request.topic(),
                defaultIfBlank(request.targetAudience(), "junior to mid-level Java developers"),
                defaultIfBlank(request.tone(), "practical and approachable")
        );

        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;
    }
}

The Controller only states: I have a UserInput and I want a ReviewedBlogPost. Which Actions to execute in between is determined by the Embabel platform based on the capabilities declared in the Agent. That is the key point — you do not write:

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

If the package names or constructors for AgentInvocation or UserInput differ in your version of Embabel, refer to the official documentation examples for that version. Embabel is evolving quickly and such API changes are not uncommon.

11. Run and Test

Set your API key before starting:

export OPENAI_API_KEY="your-api-key"

Then run the application:

mvn spring-boot:run

Call the endpoint with curl:

curl -X POST http://localhost:8080/api/blogs/generate \
  -H "Content-Type: application/json" \
  -d '{
    "topic": "Elegant global exception handling in Spring Boot",
    "targetAudience": "Java developers new to Spring Boot",
    "tone": "clear and practical, with real-world tips"
  }'

You will receive a response similar to the following (actual content varies by model output):

{
  "title": "Global Exception Handling in Spring Boot: Consistent API Error Responses",
  "markdown": "# Global Exception Handling in Spring Boot\n\nIn real projects...",
  "improvements": [
    "Added context explaining why unified exception handling matters",
    "Renamed example code variables to better match Spring Boot conventions",
    "Included explanations for pitfalls beginners commonly encounter"
  ],
  "warnings": [
    "Example code should be validated against the specific Spring Boot version in use"
  ]
}

If you inspect the application logs, you can typically see Embabel planning and executing Actions: first formulated plan, then executing action for each step, and finally goal achieved. These logs are invaluable for understanding why the Agent chose a particular execution path.

12. Why This Is Better Than Calling the LLM Directly

You might ask: every step in this example calls the LLM anyway, so why not just write four sequential method calls? Functionally, that works in the short term. But Embabel’s value shows up as the system evolves.

Future requirementHardcoded pipelineEmbabel style
Add SEO optimizationEdit the Service flowAdd an Action that takes BlogDraft and returns SeoBlogDraft
Add content moderationInsert a conditional branchAdd a moderation Action and make the goal depend on the moderated object
Pull reference material from a databaseQuery manually in the ServiceInject a Repository or Service directly into an Action
Mix multiple modelsManage different model clients manuallySelect LLMs by config and role; the framework supports LLM mixing
Trace the execution pathWrite your own loggingThe platform can emit planning and execution details

Embabel may feel like “an extra layer of abstraction” at first. But when a workflow grows from two steps to a dozen and starts mixing LLMs, databases, rules, tools, and external systems, that abstraction is what keeps the system maintainable.

13. Injecting Regular Spring Services into Actions

Embabel does not require every Action to call an LLM. In production systems, the recommended pattern is to use LLMs where they excel — understanding natural language, generating drafts, summarizing content — and leave deterministic logic to ordinary Java code. An Action can just as well be a database query, a scoring step, a validation check, or a call to a business service.

For example, define a reference lookup service:

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(
                "Internal Java coding standards",
                "Spring Boot official reference documentation",
                "Historical incident post-mortems"
        );
    }
}

Then inject it into the Agent:

@Agent(description = "Generates a beginner-friendly technical blog post from a user-supplied topic")
public class BlogWritingAgent {

    private final BlogReferenceService referenceService;

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

    @Action(description = "Find internal reference materials related to the topic")
    public BlogReferences findReferences(BlogIdea idea) {
        return new BlogReferences(referenceService.findReferences(idea.topic()));
    }
}

The Agent can now use both LLMs and ordinary business code. For production systems this matters enormously: do not let the LLM take over all logic; let the LLM handle uncertain language tasks and let Java handle deterministic business rules.

14. Frequently Asked Questions

14.1 How does Embabel relate to Spring AI?

Spring AI provides foundational abstractions in the Spring ecosystem for model calls, vector stores, and tool invocations. Embabel is a higher-level Agent framework that can orchestrate goal-driven workflows on top of capabilities like Spring AI. In short: Spring AI helps you interact with models, tools, and vector stores; Embabel helps you build Agents that execute Actions to reach Goals.

14.2 Do I have to use the Shell starter?

No. The official documentation lists three common starters:

StarterUse caseUsed in this guide
embabel-agent-starter-shellLearning, debugging, interactive CLINo
embabel-agent-starter-mcpserverExposing an Agent as an MCP ServerNo
embabel-agent-starterWeb API, microservice, custom startup modeYes

14.3 Why use Java records for domain models?

Java records are ideal for immutable data transfer objects. Embabel emphasizes strongly typed domain models, and records make the input/output structure explicit, easier to test, and straightforward to refactor. Returning objects like BlogOutline, BlogDraft, and ReviewedBlogPost is far more suitable for a business pipeline than returning unstructured text from the model.

14.4 What if the model output does not match the expected structure?

Production systems need validation and fallback handling. You can use Bean Validation on record fields, or add a dedicated validation Action after the problematic step. If validation fails, another Action can attempt to repair the format, or you can return a descriptive error. Embabel’s value is not in preventing LLMs from ever producing bad output — it is in placing that uncertain output inside a more observable and controllable pipeline.

14.5 Can I use a model other than OpenAI?

Yes. The official documentation covers Anthropic, DeepSeek, Gemini, Mistral AI, LM Studio, Ollama, and other provider starters or configuration options. For local model execution try Ollama or LM Studio; for an enterprise-internal OpenAI-compatible gateway, configure the corresponding base URL.

15. Where to Go from Here

Once you have the example running, consider these enhancements:

EnhancementNew domain objectsNew Actions
SEO optimizationSeoSuggestion, SeoBlogPostoptimizeSeo()
Fact checkingFactList, FactCheckReportextractFacts(), checkFacts()
Persist to databaseSavedBlogPostsaveBlogPost()
Generate cover image promptImagePromptcreateCoverImagePrompt()
Multi-language translationTranslatedBlogPosttranslatePost()

This extension pattern highlights Embabel’s advantage: instead of continuously modifying a large pipeline, you add new types and Actions, giving the platform more composable capabilities.

16. Summary

This guide introduced the basics of Spring Boot + Embabel through an “AI Blog Assistant” example. A typical Embabel application includes a Maven starter, model configuration, @EnableAgents, domain models, @Agent, @Action, @AchievesGoal, and an invocation issued via AgentPlatform.

More importantly, Embabel brings not “fancier prompt writing” but an AI engineering mindset better suited to Java enterprise applications: use strongly typed objects to carry context, decompose capabilities into Actions, express intent as Goals, let the platform plan the execution path, and manage LLM calls and ordinary business code within the same Spring ecosystem.

If you are new to Embabel, start with a simple Agent like the one in this guide to understand how objects flow between Actions. Then gradually introduce databases, business services, tool calls, multi-model configuration, and tests. This keeps the learning curve manageable and makes it far easier to bring Embabel into a real project.

References

/ Comments