A Java-based AI agent that implements the ReAct (Reason + Act) pattern using the Anthropic Claude API. This project demonstrates how Claude can reason about tasks, decide which tools to use, and execute them in a loop until reaching a final answer.
Hemant Naik
This project showcases a sophisticated agentic AI system where Claude acts as an intelligent orchestrator. The agent:
- Reasons about tasks presented by the user
- Decides which tools are most appropriate to solve the problem
- Acts by executing those tools with parameters Claude determines
- Observes the results and continues reasoning if needed
- Provides a final answer when sufficient information is gathered
- ReAct Loop Implementation - Handles multi-step reasoning with tool usage
- Tool Abstraction - Clean separation of tool definitions, execution, and API logic
- Claude Integration - Uses Anthropic Claude Sonnet 4.6 for reasoning
- Multiple Tools - Calculator, Weather info, and String utilities (easily extensible)
- Production-Ready - Proper error handling, safety limits, and clear architecture
The agent will run three demo queries:
-
Mathematical reasoning:
"What is 1337 multiplied by 42?"β Uses calculator tool to compute
-
Multiple tool usage:
"What's the weather like in Tokyo and London? Which is warmer?"β Uses weather tool twice, then reasons about results
-
Complex reasoning:
"Reverse the string 'Hello, World!' and tell me its length."β Uses string tools and combines results
User: What is 1337 multiplied by 42?
[Iteration 1] Calling Claude API... Stop reason: tool_use [Tool] Calling 'calculator' with input: {"operation":"multiply","a":1337,"b":42} [Tool Result] Result: 1337.0 multiply 42.0 = 56154.0
[Iteration 2] Calling Claude API... Stop reason: end_turn
User: What's the weather like in Tokyo and London? Which is warmer?
[Iteration 1] Calling Claude API... Stop reason: tool_use [Tool] Calling 'get_weather' with input: {"city":"Tokyo"} [Tool Result] Partly cloudy, 18Β°C, humidity 60% [Tool] Calling 'get_weather' with input: {"city":"London"} [Tool Result] Cloudy, 12Β°C, humidity 78%
[Iteration 2] Calling Claude API... Stop reason: end_turn
Final Answer: Here's a quick comparison of the current weather in both cities:
| City | Condition | Temperature | Humidity |
|---|---|---|---|
| π―π΅ Tokyo | Partly cloudy | 18Β°C | 60% |
| π¬π§ London | Cloudy | 12Β°C | 78% |
Tokyo is warmer, coming in at 18Β°C compared to London's 12Β°C β that's a difference of 6Β°C! London is also cloudier and more humid than Tokyo right now.
User: Reverse the string 'Hello, World!' and tell me its length. [Iteration 1] Calling Claude API... Stop reason: tool_use [Tool] Calling 'string_util' with input: {"operation":"reverse","input":"Hello, World!"} [Tool Result] !dlroW ,olleH [Tool] Calling 'string_util' with input: {"operation":"length","input":"Hello, World!"} [Tool Result] Length: 13
[Iteration 2] Calling Claude API... Stop reason: end_turn
Final Answer: Here are the results for 'Hello, World!':
- π Reversed:
!dlroW ,olleH - π Length:
13characters
The project is organized into three focused Java classes:
src/main/java/
βββ AIAgent.java # Main orchestrator - handles API communication and ReAct loop
βββ ToolManager.java # Tool definitions - manages tool schemas and configurations
βββ ToolExecutor.java # Tool execution - routes and executes tool requests
- Purpose: Core agent orchestrator
- Key Methods:
run(String userMessage)- Main ReAct loop that coordinates with Claudemain(String[] args)- Entry point with demo queries
- Responsibilities:
- HTTP communication with Claude API
- Conversation history management
- Tool result processing and iteration logic
- Purpose: Tool definition and schema management
- Key Methods:
buildTools()- Creates all available tool definitionsbuildCalculatorTool()- Defines calculator tool schemabuildWeatherTool()- Defines weather tool schemabuildStringUtilTool()- Defines string utility tool schema
- Responsibilities:
- Tool schema creation with JSON Schema format
- Tool descriptions and parameter documentation
- Tool availability management
- Purpose: Tool execution and request routing
- Key Methods:
executeTool(String toolName, JsonNode toolInput)- Routes tool requestsrunCalculator(JsonNode input)- Executes arithmetic operationsrunWeather(JsonNode input)- Returns weather informationrunStringUtil(JsonNode input)- Performs string manipulations
- Responsibilities:
- Tool implementation
- Parameter extraction and validation
- Result formatting
The agent comes with three demo tools:
| Tool | Purpose | Parameters |
|---|---|---|
| calculator | Basic arithmetic operations | operation (add/subtract/multiply/divide), a, b |
| get_weather | Weather information lookup | city (city name) |
| string_util | String manipulations | operation (uppercase/lowercase/reverse/length), input |
- Java 17+ - Uses Java's modern HTTP client and records
- Maven 3.6+ - For dependency management and building
- Anthropic API Key - Get one from console.anthropic.com
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.0</version>
</dependency>
<dependency>
<groupId>io.github.cdimascio</groupId>
<artifactId>java-dotenv</artifactId>
<version>5.3.1</version>
</dependency>- Jackson parsing constraints β all JSON handling uses
JacksonUtils.newMapper(). This mapper is pre-configured withStreamReadConstraintslimiting numeric length to 1,000 characters, preventing DoS via the async parser path. - Disable native SSL engine β Netty's OpenSSL provider is turned off by
setting
io.netty.handler.ssl.noOpenSsl=true(seeAIAgentconstructor). This works around CVE-2025-24970 which can crash servers when receiving malformed packets. - HTTP/2 frame limits β when using Netty-based HTTP/2 clients/servers (e.g. via AWS SDK), apply rate limits on RST_STREAM or other control frames to mitigate rapid-reset / MadeYouReset DDoS attacks.
cd "Agents Implementation"Create a .env file in the project root with your API key:
ANTHROPIC_API_KEY=your-api-key-heremvn clean compilemvn exec:java -Dexec.mainClass="AIAgent"1. User submits task
β
2. Send to Claude with available tools
β
3. Claude decides if tools are needed
ββ If YES: Tool use block β Execute tool
ββ Send results back to Claude
ββ Loop back to step 2
β
ββ If NO: End turn β Return final answer
β
4. Return Claude's response to user
AIAgent agent = new AIAgent(apiKey);
String result = agent.run("What is 100 + 200?");
System.out.println(result);To add a new tool:
-
Add tool definition in
ToolManager.java:private ObjectNode buildMyToolName() { ObjectNode tool = mapper.createObjectNode(); tool.put("name", "my_tool"); tool.put("description", "What my tool does"); // Define input_schema... return tool; }
-
Add tool implementation in
ToolExecutor.java:switch (toolName) { case "my_tool" -> runMyTool(toolInput); // ... } private String runMyTool(JsonNode input) { // Implementation }
Key constants in AIAgent.java:
| Constant | Value | Purpose |
|---|---|---|
API_URL |
https://api.anthropic.com/v1/messages |
Claude API endpoint |
MODEL |
claude-sonnet-4-6 |
Model version |
VERSION |
2023-06-01 |
API version |
MAX_TOKENS |
1024 |
Response length limit |
- ToolManager handles "what tools exist"
- ToolExecutor handles "how to execute tools"
- AIAgent handles "when/why to use tools"
- Claude reasons before acting (no hallucination of results)
- Tool results feed back into reasoning loop
- Supports multi-step problem solving
- Clear audit trail of assistant's reasoning
| Issue | Solution |
|---|---|
ANTHROPIC_API_KEY not found |
Create .env file with your API key |
Compilation errors |
Ensure Java 17+ and Maven 3.6+ are installed |
API errors (401) |
Verify your API key is valid and active |
Timeout errors |
Check your internet connection or increase iteration limits |
- Web search tool integration
- File parsing and analysis
- Database query capabilities
- Email/Slack integration
- Persistent memory/context management
- Tool chaining optimization
- Streaming responses
- Multi-agent coordination
This project is provided as-is for educational and experimental purposes.