How to Use Spring AI @Tool Annotation for Function Calling
Purpose
I wanted to build an AI application that could actually do things - check the weather, set reminders, query databases - not just chat with users. But I found the traditional approach to function calling complex: parse the AI response, figure out which function to call, execute it, format the result, send it back to the AI. That’s a lot of boilerplate.
Spring AI’s @Tool annotation solved this for me. I just annotate my Java methods with @Tool, register them with ChatClient, and the AI figures out when to call them automatically.
Environment
- Java 21
- Spring Boot 3.3
- Spring AI 1.0.0
- OpenAI GPT-4 (but works with Anthropic, Google, etc.)
How It Works
The @Tool annotation tells Spring AI: “This method can be called by the AI.” When you register these tools with ChatClient, Spring AI handles the entire function-calling protocol:
- Sends your tool definitions to the AI model
- Parses the AI’s function call requests
- Executes your Java methods with the right parameters
- Sends results back to the AI
- Continues the conversation
You just write regular Java methods. Spring AI does the rest.
Creating Tools
Here’s a service with two tools:
import org.springframework.ai.tool.annotation.Tool;import org.springframework.ai.tool.annotation.ToolParam;import org.springframework.stereotype.Service;
@Servicepublic class WeatherService {
@Tool(description = "Get current weather information for a city") public String getWeather(@ToolParam(description = "City name") String city) { // In production, call a real weather API if (city.equalsIgnoreCase("New York")) { return "72°F, Sunny"; } else if (city.equalsIgnoreCase("London")) { return "58°F, Cloudy"; } return "Weather data not available for: " + city; }
@Tool(description = "Set a reminder for a specific time") public void setReminder( @ToolParam(description = "Reminder description") String description, @ToolParam(description = "Time in ISO-8601 format") String time ) { // Save to database in real app System.out.println("Reminder set: '" + description + "' at " + time); }}The @Tool annotation marks methods as callable by the AI. The description is crucial - it tells the AI what the method does so it knows when to use it. The @ToolParam annotations describe each parameter so the AI passes the right values.
Registering with ChatClient
Now register the tools with ChatClient:
import org.springframework.ai.chat.client.ChatClient;import org.springframework.ai.chat.model.ChatModel;import org.springframework.web.bind.annotation.*;
@RestController@RequestMapping("/ai")public class ChatController {
private final ChatClient chatClient;
public ChatController(ChatModel chatModel, WeatherService weatherService) { this.chatClient = ChatClient.create(chatModel); }
@PostMapping("/chat") public String chat(@RequestBody String message) { return chatClient.prompt() .user(message) .tools(weatherService) // Register the service containing @Tool methods .call() .content(); }}The .tools(weatherService) call scans the service for @Tool-annotated methods and makes them available to the AI.
What Happens During Conversation
When a user sends a message, the AI decides whether to call a tool:
User: "What's the weather like in New York?"
AI (thinking): I need to call getWeather with "New York"
Spring AI: Calls getWeather("New York") → Returns "72°F, Sunny"
AI (responding): The weather in New York is 72°F and sunny.You don’t write any code to parse the request or invoke the method. Spring AI handles all of that.
Multiple Tools in One Service
You can have as many tools as you need in a service:
@Servicepublic class AssistantService {
@Tool(description = "Search the product database") public List <Product> searchProducts( @ToolParam(description = "Search query") String query ) { return productRepository.findByNameContaining(query); }
@Tool(description = "Get order status by order ID") public OrderStatus getOrderStatus( @ToolParam(description = "Order ID") String orderId ) { return orderService.findById(orderId); }
@Tool(description = "Create a new support ticket") public String createTicket( @ToolParam(description = "Issue description") String issue, @ToolParam(description = "Customer email") String email ) { return supportService.createTicket(issue, email); }}The AI will choose the right tool based on what the user asks.
Common Mistakes I Made
Vague tool descriptions
At first I wrote descriptions like:
@Tool(description = "Process data") // Too vague!public String process(String input) { ... }The AI rarely used this tool because it couldn’t tell when it should apply. Better:
@Tool(description = "Summarize customer feedback into key points")public String summarizeFeedback(@ToolParam(description = "Customer feedback text") String feedback) { ...}Not handling null parameters
Sometimes the AI doesn’t have all the information. I learned to validate:
@Tool(description = "Get user profile")public String getUserProfile(@ToolParam(description = "Username") String username) { if (username == null || username.isBlank()) { return "Error: Username is required"; } return userService.getProfile(username);}Expecting tools to always be called
The AI decides when to use tools. If a user asks “Tell me a joke”, the AI won’t call any tools - it just responds directly. Tools only get invoked when they’re relevant to the user’s request.
Summary
In this post, I showed how Spring AI’s @Tool annotation eliminates the complexity of function calling. You annotate your Java methods, register them with ChatClient, and Spring AI handles the entire protocol - parsing requests, executing methods, and returning results to the AI. The key point is that you write regular Java code and let Spring AI bridge the gap between your AI model and your application logic.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
- 👨💻 Spring AI Official Documentation
- 👨💻 I built my first AI app entirely in Java (Reddit discussion)
- 👨💻 OpenAI Function Calling Guide
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments