Class EasyAI
EasyAI is a simple abstraction layer over LangChain4J. It hides all the low-level details (ChatLanguageModel, ChatMemory, AiServices, ToolSpecification, EmbeddingStore...) behind a clean builder-pattern API that any Java developer can use in minutes.
Quick Start
Step 1: Add your API key to easyai.properties on the classpath:
easyai.provider=openai easyai.api-key=sk-YOUR-KEY easyai.model-name=gpt-4o-mini
Step 2: Start chatting!
Three Ways to Use EasyAI
1. Simple Chat (chat())
Send messages to AI and get responses. Optionally remembers conversation history.
Conversation chat = EasyAI.chat()
.withMemory(20) // remember last 20 messages
.withSystemMessage("You are a helpful tutor") // set AI personality
.build();
String answer = chat.send("What is Java?");
String follow = chat.send("Give me an example"); // AI remembers the context
2. AI Assistant with Tools (assistant(Class))
Define an interface, give it your existing service classes as "tools", and the AI will call your Java methods when needed.
// 1. Define assistant interface
@EasyAIAssistant(systemMessage = "You are an e-commerce support bot")
public interface SupportBot {
String ask(String question);
}
// 2. Your existing service (no AI annotations needed!)
public class OrderService {
public String findOrder(String orderId) {
return database.findById(orderId).toString();
}
}
// 3. Wire it together
SupportBot bot = EasyAI.assistant(SupportBot.class)
.withTools(orderService, userService)
.build();
// 4. The AI will automatically call orderService.findOrder("12345")
String answer = bot.ask("Where is my order #12345?");
3. Document-Powered Assistant (RAG)
Let the AI answer questions based on your PDF, DOCX, or TXT files.
@EasyRAG(source = "classpath:company-policy.pdf")
@EasyAIAssistant(systemMessage = "Answer based on the company policy")
public interface PolicyBot {
String ask(String question);
}
PolicyBot bot = EasyAI.assistant(PolicyBot.class).build();
String answer = bot.ask("What is the vacation policy?");
// AI reads the PDF and answers based on its content
Overriding Configuration Per-Call
You can override any config property when building:
Conversation chat = EasyAI.chat()
.withProvider("ollama") // use local Ollama
.withModel("llama3") // specific model
.withBaseUrl("http://localhost:11434/v1/") // custom endpoint
.withTemperature(0.3) // less creative
.withMaxTokens(500) // shorter answers
.build();
CDI / Jakarta EE Integration
In a Jakarta EE application, assistants are automatically injectable:
@Inject SupportBot bot; // no manual build() needed
- See Also:
-
Method Summary
Modifier and TypeMethodDescriptionstatic AgentBuilderagent()Starts building anEasyAgentthat autonomously plans and executes multi-step tasks by orchestrating calls to your registered Java services.static <T> AssistantBuilder<T> Starts building an AI Assistant proxy for the given interface.static ConversationBuilderchat()Starts building a newConversationfor simple chat.static voidconfigure(EasyAIConfig config) Sets a global configuration that will be used as default for all new conversations and assistants (unless overridden per-builder).static StringExtracts a clean, human-readable error message from an AI exception.static EasyAIConfigReturns the global configuration, or loads fromeasyai.propertiesif not set.
-
Method Details
-
chat
Starts building a newConversationfor simple chat.Conversation chat = EasyAI.chat() .withMemory(20) .withSystemMessage("You are a helpful assistant") .build(); String answer = chat.send("Hello!");- Returns:
- a new
ConversationBuilder
-
assistant
Starts building an AI Assistant proxy for the given interface.The interface should have one or more methods that accept a String and return a String. Annotate it with
@EasyAIAssistantfor a system message.@EasyAIAssistant(systemMessage = "You are a code reviewer") public interface CodeReviewer { String review(String code); } CodeReviewer reviewer = EasyAI.assistant(CodeReviewer.class).build(); String feedback = reviewer.review("public void foo() { ... }");- Type Parameters:
T- the assistant interface type- Parameters:
assistantInterface- the interface class to create a proxy for- Returns:
- a new
AssistantBuilder
-
agent
Starts building anEasyAgentthat autonomously plans and executes multi-step tasks by orchestrating calls to your registered Java services.Unlike
assistant(Class), which answers a single question, an agent receives a complex task and breaks it into steps — calling your service methods in the right order, using the result of each step to decide what to do next, and adapting if a step fails.EasyAgent agent = EasyAI.agent() .withServices(inventoryService, paymentService, orderService) .withMaxSteps(10) .withPlanningPrompt(true) .withStepListener(step -> log.info("[AGENT] Step {}: {}({}) -> {}", step.stepNumber(), step.toolName(), step.arguments(), step.result())) .build(); String result = agent.execute( "Order 2 laptops for user U123, apply loyalty credit, " + "use fallback warehouse WH-EU if out of stock." );- Returns:
- a new
AgentBuilder
-
configure
Sets a global configuration that will be used as default for all new conversations and assistants (unless overridden per-builder).EasyAI.configure(EasyAIConfig.builder() .provider("openai") .apiKey("sk-...") .modelName("gpt-4o") .build());- Parameters:
config- the global configuration
-
getGlobalConfig
Returns the global configuration, or loads fromeasyai.propertiesif not set.- Returns:
- the current global
EasyAIConfig
-
extractErrorMessage
Extracts a clean, human-readable error message from an AI exception.LangChain4J exceptions (especially from OpenAI-compatible providers like Groq, Azure OpenAI, and OpenAI itself) often carry raw JSON in their message, for example:
{"error":{"message":"Failed to call a function...","type":"invalid_request_error",...}}This method parses the JSON and extracts only the
error.messagefield. If the message is not JSON, it is returned as-is. If the exception isnull, an empty string is returned.Typical usage in a JSF backing bean or REST endpoint:
try { return bot.ask(userQuestion); } catch (Exception e) { log.error("AI call failed", e); return "Sorry, something went wrong: " + EasyAI.extractErrorMessage(e); }Common LangChain4J exception types to catch separately if needed:
dev.langchain4j.exception.AuthenticationException— wrong API keydev.langchain4j.exception.RateLimitException— rate limit exceededdev.langchain4j.exception.InvalidRequestException— bad request, tool call failuredev.langchain4j.exception.InternalServerException— provider server error
- Parameters:
t- the exception thrown by an AI assistant or conversation call- Returns:
- a clean, readable error message
-