Sproutice
All articles

AI Agents in Spring Boot with Java — Sprout 1.5.0

AI AgentsJavaSpring bootDependency InjectionOpenAIAnthropicSproutRelease

Add AI agents to your Spring Boot app in pure Java, with no glue code

If you build backends in Java, adding AI agents has usually meant a detour: stand up a separate Python service, wire it over HTTP, and keep two runtimes in sync. Sprout is a Java AI framework that runs inside Spring Boot instead — and Sprout 1.5.0 makes the seam between the two disappear. The best part: your controllers, your @Services and your application.yml stay exactly as they are.

TL;DR

  • Sprout runs inside your Spring Boot process — inject an agent into a @RestController, back its @Tools with the Spring @Services you already have.
  • 1.5.0 lets Sprout and Spring beans use each other's DI annotations both ways, so same-named @Autowired / @Value / @Qualifier never clash again.
  • Drop in sprout-openai or sprout-anthropic and the @Model executor is auto-discovered — no sprout.scan.base-packages.
  • sprout-monitoring activates on its own, exposed as a Spring bean.
  • Same JVM, same configuration, same tests. No Python service.

Running AI agents inside Spring Boot

Add the sprout-spring-boot-starter dependency and the two containers start talking: every Sprout bean — agents, models, tools, services — is registered in the Spring ApplicationContext, and Sprout components can depend on your Spring beans in return. So an agent is just another bean you @Autowired:

@RestController
class ChatController {

    private final AgentExecutor supportAgent;   // a Sprout @Agent, exposed as a Spring bean

    ChatController(@Qualifier("supportAgentExecutor") AgentExecutor supportAgent) {
        this.supportAgent = supportAgent;
    }

    @PostMapping("/chat")
    String chat(@RequestBody String prompt) {
        return supportAgent.execute("conversation-1", prompt).response();
    }
}

That bridge has existed for a while. 1.5.0 is about the last rough edges.

Mixing annotations: Sprout and Spring, both ways

Sprout and Spring each ship an @Autowired, a @Value and a @Qualifier. Before 1.5.0, using the "wrong" one inside a class managed by the other container meant it was silently ignored — the classic "why is this field null?" papercut. In 1.5.0 the two sets are treated as equivalents, in both directions.

A Sprout component works when wired with Spring's — or JSR-330's — annotations:

@Service                                                          // Sprout's stereotype
public class PricingService {

    @org.springframework.beans.factory.annotation.Autowired       // Spring's @Autowired
    private RateRepository rates;

    @org.springframework.beans.factory.annotation.Value("${pricing.currency}")  // Spring's @Value
    private String currency;

    @io.github.ivannavas.sprout.annotation.Value("${pricing.margin:0.15}")      // Sprout's @Value
    private double margin;
}

And a Spring bean works when wired with Sprout's @Autowired / @Value / @Qualifier / @PostConstruct (field injection and @PostConstruct; for constructor injection on a Spring bean, use Spring's own @Autowired):

@Component                                                        // Spring's stereotype
public class ReportBuilder {

    @io.github.ivannavas.sprout.annotation.Autowired              // Sprout's @Autowired
    private SummaryAgentExecutor agent;                           // a Sprout @Agent bean

    @io.github.ivannavas.sprout.annotation.Value("${report.title}")
    private String title;

    @io.github.ivannavas.sprout.annotation.PostConstruct
    void init() { /* runs after the fields above are wired */ }
}

Here's the important part: this is a compatibility net, not a style. It exists so mixed or migrating code never breaks silently — not as an invitation to scatter both flavours everywhere. The recommendation stays simple: use Sprout's annotations in Sprout components, and each DI container's own annotations in its own beans. And none of it leaks Spring into Sprout's core — sprout-core recognises only its own annotations; the starter contributes the Spring and JSR-330 equivalents.

Zero config: drop in OpenAI or Anthropic

Adding a model provider used to need one extra line — telling Sprout which package the executor lived in, via sprout.scan.base-packages. In 1.5.0 each module contributes its own package to the scan, so the OpenAI and Anthropic @Model executors are discovered the moment the jar is on the classpath.

<dependency>
    <groupId>io.github.ivannavas</groupId>
    <artifactId>sprout-spring-boot-starter</artifactId>
    <version>1.5.0</version>
</dependency>
<dependency>
    <groupId>io.github.ivannavas</groupId>
    <artifactId>sprout-openai</artifactId>   <!-- or sprout-anthropic -->
    <version>1.5.0</version>
</dependency>

No scan configuration. Inject the executor into any Spring bean by name:

ChatController(@Qualifier("openai") ModelExecutor openai) { ... }   // a Sprout @Model, injected by Spring

Monitoring, on by default

sprout-monitoring follows the same rule: add the module and usage, token and cost tracking activates on its own, exposed as the Spring usageStore bean. Declare your own @UsageStore and it takes over — nothing to scan, nothing to configure.

One source of truth for configuration

Spring's Environmentapplication.yml / application.properties, system properties, environment variables — feeds Sprout's configuration. A Sprout @Value("${pricing.currency}") reads the same property a Spring @Value would, from the same place. Nothing to duplicate.

FAQ

Can I use AI agents in Spring Boot with Java (no Python)?

Yes. Sprout is a Java AI framework that runs inside your Spring Boot process. Agents, LLM model executors and tools are ordinary Spring-injectable beans, so there's no separate Python service and no network hop.

Does Sprout replace Spring's dependency injection?

No. Sprout keeps its own container for its components and exposes them to Spring, and it can consume Spring beans. You keep using Spring exactly as you do today; the starter bridges the two.

Which annotations should I use — Sprout's or Spring's?

Use Sprout's in Sprout components and Spring's in Spring beans. 1.5.0 makes them interchangeable so mixed or migrating code doesn't break, but consistency is the recommended style.

How do I call OpenAI or Anthropic from Spring Boot?

Add sprout-openai or sprout-anthropic alongside the starter. The @Model executor (openai / anthropic) is auto-discovered and injectable by name — configure the API key as a property.

Is Sprout open source?

Yes — Sprout is open source on GitHub and published to Maven Central.

Get it

Sprout 1.5.0 is on Maven Central. Add sprout-spring-boot-starter (plus sprout-openai and/or sprout-anthropic) at 1.5.0, keeping every Sprout artifact on the same version, set your provider API key, and write your first @Agent — no sprout.scan.base-packages, no second process. Full reference: the starter README and the 1.5.0 release notes. If it saves you a Python service, a ⭐ on GitHub helps others find it.

Let's talk