Getting Started¶
This comprehensive guide will help you master Agentle4j step by step.
Prerequisites¶
- Java 21+ installed
- Maven or Gradle build tool
- An API key from OpenRouter, OpenAI, or another supported provider
Your First Request¶
Let's create a simple chatbot that responds to a message:
import com.paragon.responses.Responder;
import com.paragon.responses.spec.CreateResponsePayload;
import com.paragon.responses.Response;
public class HelloAgentle {
public static void main(String[] args) {
// 1. Create a Responder (the core HTTP client)
Responder responder = Responder.builder()
.openRouter()
.apiKey(System.getenv("OPENROUTER_API_KEY"))
.build();
// 2. Build the request payload
var payload = CreateResponsePayload.builder()
.model("openai/gpt-4o-mini")
.addDeveloperMessage("You are a helpful assistant.")
.addUserMessage("What is the capital of France?")
.build();
// 3. Get the response (blocking with .join())
Response response = responder.respond(payload).join();
// 4. Print the output
System.out.println(response.outputText());
// Output: The capital of France is Paris.
}
}
Understanding the Code¶
| Component | Description |
|---|---|
Responder |
The HTTP client that communicates with the AI API |
CreateResponsePayload |
A builder to construct your request |
.addDeveloperMessage() |
Sets the system prompt (AI's behavior) |
.addUserMessage() |
The user's input message |
.respond() |
Returns CompletableFuture<Response> |
.join() |
Blocks until the response is ready |
Async vs Blocking¶
Agentle4j is async by default. Choose your style:
Blocking (Simple)¶
// Use .join() to block and wait for the result
Response response = responder.respond(payload).join();
System.out.println(response.outputText());
Async with Callbacks¶
// Non-blocking with callbacks
responder.respond(payload)
.thenAccept(response -> {
System.out.println("Got response: " + response.outputText());
})
.exceptionally(error -> {
System.err.println("Error: " + error.getMessage());
return null;
});
// Continue doing other work while waiting...
System.out.println("Request sent, doing other work...");
Async with CompletableFuture¶
// Chain multiple operations
CompletableFuture<String> result = responder.respond(payload)
.thenApply(Response::outputText)
.thenApply(text -> text.toUpperCase());
// Use the result later
String upperCaseResponse = result.join();
Streaming Responses¶
Stream responses in real-time for a better user experience:
var payload = CreateResponsePayload.builder()
.model("openai/gpt-4o")
.addUserMessage("Write a short poem about Java programming")
.streaming() // Enable streaming mode
.build();
responder.respond(payload)
.onTextDelta(delta -> {
// Called for each chunk of text as it arrives
System.out.print(delta);
System.out.flush(); // Important: flush for immediate display
})
.onComplete(response -> {
System.out.println("\n\nā
Generation complete!");
System.out.println("Total tokens: " + response.usage().totalTokens());
})
.onError(error -> {
System.err.println("Error: " + error.getMessage());
})
.start(); // Don't forget to call start()!
Streaming Callbacks Reference¶
| Callback | When Called | Use Case |
|---|---|---|
.onTextDelta(String) |
Each text chunk | Display real-time typing |
.onComplete(Response) |
Stream finished | Show final stats, save |
.onError(Throwable) |
Error occurred | Handle failures |
Structured Outputs¶
Get type-safe JSON responses using Java records. No manual parsing needed!
Basic Example¶
// 1. Define your output schema as a Java record
public record Person(
String name,
int age,
String occupation,
List<String> skills
) {}
// 2. Request structured output
var payload = CreateResponsePayload.builder()
.model("openai/gpt-4o")
.addUserMessage("Create a fictional senior software engineer")
.withStructuredOutput(Person.class) // Magic happens here!
.build();
// 3. Get the parsed response
ParsedResponse<Person> response = responder.respond(payload).join();
Person person = response.parsed();
// 4. Use the strongly-typed object
System.out.println("Name: " + person.name());
System.out.println("Age: " + person.age());
System.out.println("Occupation: " + person.occupation());
System.out.println("Skills: " + String.join(", ", person.skills()));
Real-World Example: Data Extraction¶
// Extract structured data from unstructured text
public record ContactInfo(
String name,
String email,
String phone,
String company
) {}
String rawText = """
Hi, I'm John Smith from Acme Corporation.
You can reach me at john.smith@acme.com
or call me at (555) 123-4567.
Looking forward to hearing from you!
""";
var payload = CreateResponsePayload.builder()
.model("openai/gpt-4o")
.addUserMessage("Extract contact information from this text:\n\n" + rawText)
.withStructuredOutput(ContactInfo.class)
.build();
ContactInfo contact = responder.respond(payload).join().parsed();
System.out.println("Name: " + contact.name()); // John Smith
System.out.println("Email: " + contact.email()); // john.smith@acme.com
System.out.println("Phone: " + contact.phone()); // (555) 123-4567
System.out.println("Company: " + contact.company()); // Acme Corporation
Complex Nested Structures¶
// Nested records work perfectly
public record Address(String street, String city, String country) {}
public record Employee(
String name,
String department,
Address address,
List<String> projects
) {}
var payload = CreateResponsePayload.builder()
.model("openai/gpt-4o")
.addUserMessage("Create a fictional employee at a tech company in San Francisco")
.withStructuredOutput(Employee.class)
.build();
Employee emp = responder.respond(payload).join().parsed();
System.out.println(emp.name() + " works in " + emp.department());
System.out.println("Located at: " + emp.address().city() + ", " + emp.address().country());
Multi-Turn Conversations¶
Build conversational experiences by maintaining message history:
import java.util.ArrayList;
import java.util.List;
// Keep track of the conversation
List<ResponseInputItem> conversation = new ArrayList<>();
// Helper to add messages
void addUserMessage(String text) {
conversation.add(new UserMessage(text));
}
void addAssistantMessage(String text) {
conversation.add(new AssistantMessage(text));
}
// First turn
addUserMessage("My name is Alice and I'm a Java developer.");
Response response1 = responder.respond(
CreateResponsePayload.builder()
.model("openai/gpt-4o-mini")
.inputItems(conversation)
.build()
).join();
addAssistantMessage(response1.outputText());
System.out.println("Assistant: " + response1.outputText());
// Second turn - the AI remembers!
addUserMessage("What's my name and what do I do?");
Response response2 = responder.respond(
CreateResponsePayload.builder()
.model("openai/gpt-4o-mini")
.inputItems(conversation)
.build()
).join();
System.out.println("Assistant: " + response2.outputText());
// Output: Your name is Alice and you're a Java developer!
Using Different Providers¶
Agentle4j supports multiple AI providers through a unified API:
Access 300+ models through a single API:
Responder responder = Responder.builder()
.openRouter()
.apiKey(System.getenv("OPENROUTER_API_KEY"))
.build();
// Use any model available on OpenRouter
var payload = CreateResponsePayload.builder()
.model("anthropic/claude-3.5-sonnet") // Claude
// .model("google/gemini-pro") // Gemini
// .model("meta-llama/llama-3-70b") // Llama
.addUserMessage("Hello!")
.build();
Connect directly to OpenAI:
Ultra-fast inference with Groq:
Complete Example: AI Assistant¶
Here's a complete, runnable example of an AI assistant:
import com.paragon.responses.Responder;
import com.paragon.responses.spec.CreateResponsePayload;
import java.util.Scanner;
public class ChatBot {
public static void main(String[] args) {
// Initialize the responder
Responder responder = Responder.builder()
.openRouter()
.apiKey(System.getenv("OPENROUTER_API_KEY"))
.build();
Scanner scanner = new Scanner(System.in);
System.out.println("š¤ AI Assistant Ready! (type 'quit' to exit)\n");
while (true) {
System.out.print("You: ");
String input = scanner.nextLine();
if (input.equalsIgnoreCase("quit")) {
System.out.println("Goodbye!");
break;
}
System.out.print("Assistant: ");
// Stream the response
var payload = CreateResponsePayload.builder()
.model("openai/gpt-4o-mini")
.addDeveloperMessage("You are a helpful, friendly assistant. Keep responses concise.")
.addUserMessage(input)
.streaming()
.build();
responder.respond(payload)
.onTextDelta(delta -> {
System.out.print(delta);
System.out.flush();
})
.onComplete(r -> System.out.println("\n"))
.onError(e -> System.err.println("\nError: " + e.getMessage()))
.start();
// Small delay to ensure streaming completes before next prompt
try { Thread.sleep(100); } catch (InterruptedException e) {}
}
scanner.close();
}
}
Next Steps¶
Now that you understand the basics, dive deeper:
| Guide | What You'll Learn |
|---|---|
| Responder Guide | Advanced Responder configuration |
| Agents Guide | Build AI agents with tools and memory |
| Streaming Guide | Real-time streaming patterns |
| Function Tools Guide | Let the AI call your Java functions |
| Observability Guide | Monitor and trace AI calls |
Troubleshooting¶
Common Issues¶
"API key not found"
"Connection timeout"
// Increase timeout in the builder
Responder responder = Responder.builder()
.openRouter()
.apiKey(apiKey)
.timeout(Duration.ofSeconds(60))
.build();
"Rate limit exceeded"
Getting Help¶
- š Full API Reference
- š Report Issues
- š¬ Discussions