Back to LangChain4j Overview
    Level 4
    30 min read

    Tools & Function Calling

    Give your AI the power to take real-world actions

    Spring AI Craft Team
    Updated Dec 2024

    What Are Tools?

    LLMs are incredibly powerful at understanding and generating text, but they have fundamental limitations. They can't access real-time information, can't perform calculations reliably, can't interact with databases, and can't take actions in the real world. Their knowledge is frozen at their training cutoff date, and they can only work with the text you provide in the prompt.

    Tools (also called Function Calling) solve these limitations by allowing the LLM to request that your application execute specific functions on its behalf. The LLM doesn't actually run the code — it recognizes when a tool would be helpful, generates a structured request to call that tool, and your application executes it and returns the result. This creates a powerful loop where the AI can reason about what it needs, request actions, and incorporate the results into its responses.

    Think of tools as giving arms and legs to a brain. The LLM is the intelligent reasoning center, but tools let it reach out and interact with the world — checking current weather, querying databases, sending emails, booking appointments, or any other action your application can perform.

    Without Tools

    • ❌ "What's the weather?" → Cannot access real-time data
    • ❌ "Check my order status" → No database access
    • ❌ "Calculate 17.5% of $1,247.83" → Often makes math errors
    • ❌ "Book a meeting for tomorrow" → Cannot take actions

    With Tools

    • ✅ Calls WeatherAPI → "Currently 72°F and sunny"
    • ✅ Queries OrderDB → "Order #1234 shipped yesterday"
    • ✅ Uses Calculator → "$218.37 exactly"
    • ✅ Calls CalendarAPI → "Meeting booked for 2pm"

    Creating Your First Tool

    In LangChain4j, creating tools is remarkably simple. You write a regular Java method, annotate it with @Tool, and LangChain4j handles the rest — describing the tool to the LLM, parsing the LLM's tool calls, executing your method, and returning results. The framework uses reflection and your annotations to generate the tool descriptions that the LLM needs.

    Simple Calculator Tool

    Let's start with a simple example — a calculator tool that gives the LLM reliable math capabilities:

    CalculatorTool.java
    importdev.langchain4j.agent.tool.Tool;importdev.langchain4j.agent.tool.P;publicclassCalculatorTool{@Tool("Adds two numbers together")publicdoubleadd(@P("First number")double a,@P("Second number")double b){return a + b;}@Tool("Multiplies two numbers")publicdoublemultiply(@P("First number")double a,@P("Second number")double b){return a * b;}@Tool("Calculates percentage of a number")publicdoublepercentage(@P("The percentage to calculate")double percent,@P("The number to calculate percentage of")double number
    ){return(percent /100)* number;}}

    Annotations Explained

    • @Tool("description") — Describes what the tool does. The LLM uses this to decide when to call it.
    • @P("description") — Describes each parameter. Helps the LLM provide correct values.

    Registering Tools with AI Services

    Once you've created your tool class, register it with your AI Service:

    AssistantWithTools.java
    interfaceMathAssistant{Stringchat(String userMessage);}publicclassAssistantWithTools{publicstaticvoidmain(String[] args){ChatLanguageModel model =OpenAiChatModel.builder().apiKey(System.getenv("OPENAI_API_KEY")).modelName("gpt-4o-mini").build();MathAssistant assistant =AiServices.builder(MathAssistant.class).chatLanguageModel(model).tools(newCalculatorTool())// Register tools.build();// The LLM will automatically use the calculator when neededString response = assistant.chat("What is 17.5% of $1,247.83?");System.out.println(response);// "17.5% of $1,247.83 is $218.37"}}

    Real-World Tool Examples

    Calculators are nice for learning, but the real power of tools comes from connecting your AI to external services and databases. Let's look at some practical examples that you might use in production applications. These tools transform your chatbot from a text generator into an intelligent assistant that can actually get things done.

    Weather API Tool

    WeatherTool.java
    @ComponentpublicclassWeatherTool{privatefinalWeatherApiClient weatherClient;@Tool("Gets current weather for a city. Use when user asks about weather conditions.")publicWeatherInfogetCurrentWeather(@P("City name, e.g. 'London' or 'New York'")String city){return weatherClient.fetchCurrentWeather(city);}@Tool("Gets weather forecast for the next 5 days")publicList<DailyForecast>getForecast(@P("City name")String city,@P("Number of days (1-5)")int days
    ){return weatherClient.fetchForecast(city,Math.min(days,5));}}recordWeatherInfo(String city,double temperature,String condition,int humidity){}recordDailyForecast(String date,double high,double low,String condition){}

    Database Query Tool

    OrderTool.java
    @ComponentpublicclassOrderTool{privatefinalOrderRepository orderRepository;@Tool("Looks up order status by order ID. Use when customer asks about their order.")publicOrderStatusgetOrderStatus(@P("The order ID, e.g. ORD-12345")String orderId){return orderRepository.findById(orderId).map(order ->newOrderStatus(
    order.getId(),
    order.getStatus(),
    order.getShippedDate(),
    order.getEstimatedDelivery())).orElseThrow(()->newOrderNotFoundException(orderId));}@Tool("Lists all orders for a customer email address")publicList<OrderSummary>getCustomerOrders(@P("Customer email")String email){return orderRepository.findByCustomerEmail(email).stream().map(o ->newOrderSummary(o.getId(), o.getTotal(), o.getStatus())).toList();}}

    Email and Calendar Tools

    ProductivityTools.java
    @ComponentpublicclassProductivityTools{privatefinalEmailService emailService;privatefinalCalendarService calendarService;@Tool("Sends an email. Use only when user explicitly asks to send an email.")publicStringsendEmail(@P("Recipient email address")Stringto,@P("Email subject line")String subject,@P("Email body content")String body
    ){
    emailService.send(to, subject, body);return"Email sent successfully to "+to;}@Tool("Schedules a meeting on the calendar")publicStringscheduleMeeting(@P("Meeting title")String title,@P("Date in YYYY-MM-DD format")String date,@P("Time in HH:MM format (24h)")String time,@P("Duration in minutes")int durationMinutes
    ){LocalDateTime dateTime =LocalDateTime.parse(date +"T"+ time);
    calendarService.createEvent(title, dateTime, durationMinutes);return"Meeting '"+ title +"' scheduled for "+ date +" at "+ time;}}

    Security Warning: Dangerous Tools

    Tools that send emails, delete data, or make purchases are dangerous. The LLM might misinterpret user intent and take unwanted actions. Always implement confirmation steps for destructive operations, and consider requiring explicit user approval before executing sensitive tools.

    Understanding the Execution Flow

    When you register tools with an AI Service, LangChain4j automatically handles a multi-step process behind the scenes. Understanding this flow helps you debug issues and design better tools. Here's what happens when a user asks a question that requires tool use:

    1

    Describe Tools

    LangChain4j sends tool descriptions to LLM

    2

    LLM Decides

    LLM decides which tool to call with what arguments

    3

    Execute

    Your Java method runs and returns result

    4

    Respond

    LLM incorporates result into final answer

    Multiple Tool Calls

    The LLM can call multiple tools in sequence. For example, if a user asks "What's the weather in Paris and should I bring an umbrella?", the LLM might:

    MultiToolExample.java
    // User: "What's the weather in Paris and what should I pack?"// Step 1: LLM calls getCurrentWeather("Paris")// Result: { temperature: 18, condition: "Rainy", humidity: 85 }// Step 2: LLM calls getForecast("Paris", 3)// Result: [{ date: "2024-01-15", condition: "Rainy" }, ...]// Step 3: LLM generates response using both tool results:// "It's currently 18°C and rainy in Paris with 85% humidity.//  The forecast shows rain continuing for the next 3 days.//  I recommend packing an umbrella, rain jacket, and waterproof shoes."

    Tool Design Best Practices

    Well-designed tools make the difference between a helpful AI assistant and a frustrating one. The LLM relies on your tool descriptions to understand when and how to use each tool, so clarity and precision in your annotations is critical. Here are key principles for effective tool design:

    Write Clear, Specific Descriptions

    Bad: @Tool("Gets weather")

    Good: @Tool("Gets current weather conditions for a city. Returns temperature, humidity, and conditions. Use when user asks about current weather.")

    Use Descriptive Parameter Names

    Parameter descriptions help the LLM extract the right values from user input. Include expected formats, valid ranges, and examples where helpful.

    Handle Errors Gracefully

    Don't throw raw exceptions. Return meaningful error messages that the LLM can relay to the user: "Order ORD-12345 was not found. Please check the order ID and try again."

    Keep Tools Focused

    Each tool should do one thing well. Rather than a single "manageOrder" tool that creates, updates, and cancels, create separate tools for each operation.

    🎉 Level 4 Complete!

    You've unlocked the power of tools! Your AI can now interact with APIs, databases, and external services to take real-world actions. In the next level, we'll explore Embeddings and RAG — teaching your AI to search and reason over your own documents and data.

    💬 Comments & Discussion