Building AI-Powered Java Applications with A2A Agents
Introduction
In the world of Generative AI, the "Chatbot" phase is over. The "Agent" phase has begun. While Python has dominated AI research, Java is claiming its throne in the Enterprise AI space.
Why? because when you move from "toys" to "production systems," you need type safety, concurrency (Virtual Threads), and robust integration patterns.
Today, we explore Agent-to-Agent (A2A) interaction: creating specialized AI agents that talk to each other to solve complex problems without human intervention.
What is an A2A System?
A single LLM (Large Language Model) is a generalist. It's okay at everything but great at nothing. An A2A System is a team of specialists.
- Manager Agent: Breaks down a user goal into sub-tasks.
- Research Agent: Has internet access (Search Tool).
- Coding Agent: Has a sandbox environment.
- Reviewer Agent: Critiques the code.
The Manager passes tasks to the Researcher, who passes data to the Coder, who gets critiqued by the Reviewer.
The Stack: Spring AI
We will use Spring AI, the official framework bringing AI capabilities to the Spring ecosystem. It abstracts away the complexity of connecting to OpenAI, Bedrock, or Ollama.
Step 1: Dependencies
Ensure you are using Spring Boot 3.4+ and Java 25.
1<dependency> 2 <groupId>org.springframework.ai</groupId> 3 <artifactId>spring-ai-openai-spring-boot-starter</artifactId> 4</dependency>
Step 2: Defining the Tools (The Skills)
Agents need tools (Functions) to perform actions. Let's define a tool that allows an agent to "Delegate" work to another agent.
In Spring AI, any Java Function can be a tool.
1@Configuration 2public class AgentTools { 3 4 @Bean 5 @Description("Ask the Math Specialist to solve complex calculations") 6 public Function<MathRequest, MathResponse> callMathAgent() { 7 return request -> { 8 // In a real system, this would call another LLM or a specialized service 9 System.out.println("DELEGATING TO MATH AGENT: " + request.expression()); 10 return new MathResponse(evaluateExpression(request.expression())); 11 }; 12 } 13} 14 15public record MathRequest(String expression) {} 16public record MathResponse(double result) {}
Step 3: The Manager Agent (The Orchestrator)
The Manager Agent is the entry point. It decides which specialist to call.
1@Service 2public class OrchestratorService { 3 4 private final ChatClient chatClient; 5 6 public OrchestratorService(ChatClient.Builder builder) { 7 this.chatClient = builder 8 .defaultSystem("You are a Project Manager. You do not do work yourself. " + 9 "You delegate tasks to your available tools: 'Math Specialist'.") 10 .defaultFunctions("callMathAgent") // Register the tool 11 .build(); 12 } 13 14 public String handleUserRequest(String prompt) { 15 // The LLM will decide IF it needs to call the tool based on the prompt 16 return chatClient.prompt() 17 .user(prompt) 18 .call() 19 .content(); 20 } 21}
Step 4: Seeing it in Action
Scenario: User asks, "If I invest $10,000 at 5% interest for 10 years, and then take half of it to buy 50 widgets, how much per widget did I pay?"
- Manager Agent receives the prompt. "This requires math. I should not hallucinate the answer."
- Manager generates a Tool Call: callMathAgent("10000 * (1.05)^10").
- Spring AI executes the Java function callMathAgent.
- Math Agent (Function) calculates $16,288.95 and returns it.
- Manager thinks: "Now I need to divide half of $16,288.95 by 50."
- Manager generates Tool Call: callMathAgent("(16288.95 / 2) / 50").
- Math Agent returns 162.88.
- Manager responds to User: "You paid roughly $162.88 per widget."
Why Java for A2A?
In Python, running 50 concurrent agents can choke the GIL (Global Interpreter Lock). In Java 25, with Virtual Threads (Project Loom), you can spawn thousands of autonomous agents in parallel with minimal memory footprint.
1// Java 25: Massive Parallelism for Agents 2try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { 3 var researchTask = scope.fork(() -> researchAgent.investigate(topic)); 4 var marketTask = scope.fork(() -> marketAgent.analyzePatterns(topic)); 5 6 scope.join(); // Wait for all agents to finish 7 8 var finalReport = synthesizerAgent.combine(researchTask.get(), marketTask.get()); 9}
Conclusion
Building A2A systems in Java is not just possible; it's often architecturally superior for enterprise workloads. By leveraging Spring AI for the LLM abstraction and Java 25 for the concurrency, you can build Multi-Agent Systems that are robust, type-safe, and ready for production.



