Domain Objects

Domain objects in Embabel are not just strongly-typed data structures - they are real objects with behavior that can be selectively exposed to LLMs and used in agent actions.

Objects with Behavior

Unlike simple structs or DTOs, Embabel domain objects can encapsulate business logic and expose it to LLMs through the @Tool annotation. For example:

@Entity
public class Customer {
    private String name;
    private LoyaltyLevel loyaltyLevel;
    private List<Order> orders;

    @Tool(description = "Calculate the customer's loyalty discount percentage") // ①
    public BigDecimal getLoyaltyDiscount() {
        return loyaltyLevel.calculateDiscount(orders.size());
    }

    @Tool(description = "Check if customer is eligible for premium service")
    public boolean isPremiumEligible() {
        return orders.stream()
            .mapToDouble(Order::getTotal)
            .sum() > 1000.0;
    }

    public void updateLoyaltyLevel() { // ②
        // Internal business logic
    }
}
  1. The @Tool annotation exposes this method to LLMs when the object is added via PrompRunner.withToolObject().
  2. Unannotated methods such as updateLoyaltyLevel are never exposed to LLMs, regardless of their visibility level. This ensures that tool exposure is safe, explicit and controlled.

Selective Tool Exposure

The @Tool annotation allows you to selectively expose domain object methods to LLMs. For example:

  • Business Logic: Expose methods that provide safely invocable business value to the LLM
  • Calculated Properties: Methods that compute derived values. This can help LLMs with calculations they might otherwise get wrong.
  • Business Rules: Methods that implement domain-specific rules

Use of Domain Objects in Actions

Domain objects can be used naturally in action methods, combining LLM interactions with traditional object-oriented programming. The availability of the domain object instances also drives Embabel planning.

@Action
public Recommendation generateRecommendation(Customer customer, OperationContext context) {
    var prompt = String.format(
        "Generate a personalized recommendation for %s based on their profile",
        customer.getName()
    );

    return context.ai()
        .withToolObject(customer) // ①
        .withDefaultLlm()
        .createObject(prompt, Recommendation.class);
}
  1. The Customer domain object is provided as a tool object, allowing the LLM to call its @Tool methods. The LLM has access to customer.getLoyaltyDiscount() and customer.isPremiumEligible().

Domain Understanding is Critical

As outlined in Context Engineering Needs Domain Understanding, Rod Johnson’s blog introducing DICE (Domain-Integrated Context Engineering), domain understanding is fundamental to effective context engineering. Domain objects serve as the bridge between:

  • Business Domain: Real-world entities and their relationships
  • Agent Behavior: How LLMs understand and interact with the domain
  • Code Actions: Traditional programming logic that operates on domain objects

Benefits

  • Rich Context: LLMs receive both data structure and behavioral context
  • Encapsulation: Business logic stays within domain objects where it belongs
  • Reusability: Domain objects can be used across multiple agents
  • Testability: Domain logic can be unit tested independently
  • Evolution: Adding new tools to domain objects extends agent capabilities

This approach ensures that agents work with meaningful business entities rather than generic data structures, leading to more natural and effective AI interactions.

Was this page helpful?

Share