embabel/embabel-agent

▲ 4 stars today★ 4,480⑂ 438

Agent framework for the JVM. Pronounced Em-BAY-bel /ɛmˈbeɪbəl/

About embabel/embabel-agent

embabel/embabel-agent is an open-source project on GitHub, mainly written in Kotlin. Agent framework for the JVM. Pronounced Em-BAY-bel /ɛmˈbeɪbəl/ It currently holds 4,480 stars and 438 forks with 0 open issues, and was last pushed on an unknown date (repository created unknown).

Project Overview

AI Homed tracks it on the Today's Trending board, currently at rank #82 with 4 new stars today.

GitHub Repository Details

Repository embabel/embabel-agent · default branch - · size 0 KB · watchers 0 · source: GitHub REST API and repository README

README

Embabel Agent Framework

Docs Maven Central Build YourKit JProfiler Quality Gate Status Discord

[//]: # ([![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=embabel_embabel-agent&metric=alert_status&token=d275d89d09961c114b8317a4796f84faf509691c)](https://sonarcloud.io/summary/new_code?id=embabel_embabel-agent))

[//]: # ([![Bugs](https://sonarcloud.io/api/project_badges/measure?project=embabel_embabel-agent&metric=bugs)](https://sonarcloud.io/summary/new_code?id=embabel_embabel-agent)) Kotlin Java Spring Spring Boot Apache Tomcat Apache Maven JUnit ChatGPT Jinja JSON GitHub Actions SonarQube Docker IntelliJ IDEA License Commits

    

Embabel (Em-BAY-bel) is a framework for authoring agentic flows on the JVM that seamlessly mix LLM-prompted interactions with code and domain models. Supports intelligent path finding towards goals. Written in Kotlin but offers a natural usage model from Java. From the creator of Spring.

 

Talk to the Docs

Have questions? Talk to the docs via the Embabel-powered hub — an Embabel agent that answers your questions about the framework in natural language.

Key Concepts

Models agentic flows in terms of:

Conditions are reassessed after each action is executed. The system replans after the completion of each action, allowing it to adapt to new information as well as observe the effects of the previous action. This is effectively an OODA loop.

Application developers don't usually have to deal with these concepts directly,
as most conditions result from data flow defined in code, allowing the system to infer
pre and post conditions.

These concepts underpin these differentiators versus other agent frameworks:

with nesting by introducing a true planning step, using a non-LLM AI algorithm. This enables the system to perform tasks it wasn’t programmed to do by combining known steps in a novel order, as well as make decisions about parallelization and other runtime behavior. conditions can extend the capability of the system, _without editing FSM definitions_ or existing code. model, which can include behavior. Everything is strongly typed and prompts and manually authored code interact cleanly. No more magic maps. Enjoy full refactoring support.

Other benefits:

while potentially offering higher QoS in production without changing application code. capable solution. This enables the system to leverage the strengths of different models for different tasks. In particular, it facilitates the use of local models for point tasks. This can be important for cost and privacy. For example: Flows can be authored in one of two ways: @Goal, @Condition and @Action methods. Either way, flows are backed by a domain model of objects that can have rich behavior.

We are working toward allowing natural language actions and goals to be deployed.

The planning step is pluggable.

The default planning approach is Goal Oriented Action Planning. GOAP is a popular AI planning algorithm used in gaming. It allows for dynamic decision-making and action selection based on the current state of the world and the goals of the agent.

Goals, actions and plans are independent of GOAP. Embabel also supports Utility AI out of the box, which can run the same actions but chooses actions based on (potentially dynamic) utility scores rather than strict preconditions and postconditions. This is valuable for exploration and open-ended tasks, when we do not need to achieve a specific goal but want to maximize overall utility.

The framework executes via an AgentPlatform implementation.

An agent platform supports the following modes of execution:

passing in input. This is ideal for code-driven flows such as a flow invoked in response to an incoming event. find a suitable agent among all the agents it knows about. Agent choice is dynamic, but only actions defined within the particular agent will run. platform tries to find a suitable goal among all the goals it knows about and builds a custom agent to achieve it from the start state, including relevant actions and conditions. The platform will not proceed if it is unconvinced as to the applicability of any goal. The GoalChoiceApprover interface provides developers a way to limit goal choice further.

Open mode is the most powerful, but least deterministic.

In open mode, the platform is capable of finding novel paths that were not envisioned by developers, and even
combining functionality from multiple providers.

Even in open mode, the platform will only perform individual steps that have been specified. (Of course, steps may themselves be LLM transforms, in which case the prompts are controlled by user code but the results are still non-deterministic.)

Possible future modes:

add further goals and agents. For example, an action can realize that it has become important to achieve additional goals.

Embabel agent systems will also support federation, both with other Embabel systems (allowing planning to incorporate remote actions and goals) and third party agent frameworks.

Quick Start

Get an agent running in under 5 minutes.

Create your own agent repo from our Java or Kotlin GitHub template by clicking the "Use this template" button.

You'll have an agent running in under a minute if you already have an OPENAI_API_KEY and have Maven installed.

📚 For examples and tutorials, see the Embabel Agent Examples Repository

🚗 For a sophisticated, realistic example application, see the Tripper travel planner agent

https://github.com/embabel/embabel-agent/blob/HEAD/Travel Planner Output

AI-generated travel itinerary with detailed recommendations

https://github.com/embabel/embabel-agent/blob/HEAD/Interactive map

Map link included in output

Why Is Embabel Needed?

TL;DR Because the evolution of agent frameworks is early and there's a lot of room for improvement; because an agent framework on the JVM will deliver great business value.

LLMs and controlling flow directly in code. However, a higher level agent framework offers compelling benefits. For example: errors. It often allows us to use cheaper models for point interactions. software systems. operations while maintaining previous state appeared predominantly Python, it's early and there's plenty of room for novel and superior approaches. The key adjacency is not the LLM--which is a simple HTTP call away--but existing code and infrastructure assets that are more valuable on the JVM than in Python. believe that most applications should work with higher level APIs. An analogy: Spring AI exists at the level of the Servlet API, while Embabel is more like Spring MVC. Complex requirements are much easier to express and test in Embabel than with direct use of Spring AI. from Spring, where most projects exist in stable environments and dependability and stability outweighs rapid innovation. Second, the concepts are not JVM-specific. We hope that Embabel will become the leading agent framework across platforms. While the Spring brand is valuable in Java, it is not in TypeScript or Python.

Show Me The Code

In Java or Kotlin, agent implementation code is intuitive and easy to test.

Java

@Agent(description = "Find news based on a person's star sign")
public class StarNewsFinder {

private final HoroscopeService horoscopeService; private final int storyCount;

// Services are injected by 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( """ Create a person from this user input, extracting their name and star sign: %s""".formatted(userInput.getContent()), StarPerson.class ); }

@Action public Horoscope retrieveHoroscope(StarPerson starPerson) { return new Horoscope(horoscopeService.dailyHoroscope(starPerson.sign())); }

// toolGroups specifies tools that are required for this action to run @Action(toolGroups = {CoreToolGroups.WEB}) public RelevantNewsStories findNewsStories( StarPerson person, Horoscope horoscope, Ai ai) { var prompt = """ %s is an astrology believer with the sign %s. Their horoscope for today is: %s Given this, use web tools and generate search queries to find %d 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.""".formatted( person.name(), person.sign(), horoscope.summary(), storyCount); return ai .withDefaultLlm() .createObject(prompt, RelevantNewsStories.class); }

// The @AchievesGoal annotation indicates that completing this action // achieves the given goal, so the agent can be complete @AchievesGoal( description = "Write an amusing writeup for the target person based on their horoscope and current news stories", export = @Export( remote = true, name = "starNewsWriteupJava", startingInputTypes = {StarPerson.class, UserInput.class}) ) @Action public Writeup writeup( StarPerson person, RelevantNewsStories relevantNewsStories, Horoscope horoscope, Ai ai) { var llm = LlmOptions .withModel(OpenAiModels.GPT_41_MINI) // High temperature for creativity .withTemperature(0.9);

var newsItems = relevantNewsStories.getItems().stream() .map(item -> "- " + item.getUrl() + ": " + item.getSummary()) .collect(Collectors.joining("\n"));

var prompt = """ 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. %s is an astrology believer with the sign %s. Their horoscope for today is: %s Relevant news stories are: %s Format it as Markdown with links.""".formatted( person.name(), person.sign(), horoscope.summary(), newsItems); return ai .withLlm(llm) .createObject(prompt, Writeup.class); } }

Kotlin
@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.summary} 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.summary} Relevant news stories are: ${relevantNewsStories.items.joinToString("\n") { "- ${it.url}: ${it.summary}" }}

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

}

The following domain classes ensure type safety:

Java

@JsonClassDescription("Person with astrology details")
@JsonDeserialize(as = StarPerson.class)
public record StarPerson(
        String name,
        @JsonPropertyDescription("Star sign") String sign
) implements Person {

@JsonCreator public StarPerson( @JsonProperty("name") String name, @JsonProperty("sign") String sign ) { this.name = name; this.sign = sign; }

@Override public String getName() { return name; } }

public record Horoscope(String summary) { }

@JsonClassDescription("Writeup relating to a person's horoscope and relevant news") public record Writeup(String text) implements HasContent {

@JsonCreator public Writeup(@JsonProperty("text") String text) { this.text = text; }

@Override public String getContent() { return text; } }

Kotlin
data class RelevantNewsStories(
    val items: List
)

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

It's easy to unit test your agents to ensure that they correctly execute logic and pass the correct prompts and hyperparameters to LLMs. For example:

```java public class StarNewsFinderTest {

@Test void writeupPromptMustContainKeyData() { HoroscopeService horoscopeService = mock(HoroscopeService.class); StarNewsFinder starNewsFinder = new StarNewsFinder(horoscopeService, 5); var context = new FakeOperationContext(); context.expectResponse(new com.embabel.example.horoscope.Writeup("Gonna be a good day"));

NewsStory cockatoos = new NewsStory( "https://fake.com.au", "Cockatoo behavior", "Cockatoos are eating cabbages" );

NewsStory emus = new NewsStory( "https://morefake.com.au", "Emu movements", "Emus are massing" );

StarPerson starPerson = new StarPerson("Lynda", "Scorpio"); RelevantNewsStories relevantNewsStories = new RelevantNewsStories(Arrays.asList(cockatoos, emus)); Horoscope horoscope = new Horoscope("This is a good day for you");

starNewsFinder.writeup(starPerson, relev

GitHub Stars & Activity

4,480Stars
438Forks
0Open issues
KotlinLanguage

GitHub Popularity

GitHub stars4,480
Forks438
Open issues0
Primary languageKotlin
License-
Stars gained today4
Created-
Last pushed-

Trending History

Daily boardrank #82 · ▲ 4 stars

Related AI Projects

1

openclaw / openclaw

TypeScript★ 390,939⑂ 82,214▲ 136 stars
→
2

obra / superpowers

Shell★ 293,410⑂ 26,254▲ 588 stars
→
3

mattpocock / skills

Shell★ 272,865⑂ 22,953▲ 908 stars
→
4

affaan-m / ECC

JavaScript★ 270,120⑂ 40,363▲ 650 stars
→
5

firecrawl / firecrawl

TypeScript★ 187,086⑂ 9,993▲ 579 stars
→
6

msitarzewski / agency-agents

Shell★ 155,492⑂ 25,093▲ 212 stars
→
7

DietrichGebert / ponytail

JavaScript★ 148,999⑂ 8,012▲ 865 stars
→
8

anthropics / claude-code

TypeScript★ 148,706⑂ 25,110▲ 123 stars
→

More AI Rankings