Building a Minimal Spring AI Tool Chain for Multi-Tool Calls

This tutorial demonstrates how to integrate Spring AI with Ollama, define @Tool‑annotated weather and translation utilities, register them for automatic chaining, and let a large language model answer queries like “fetch Beijing weather and reply in English” using a concise end‑to‑end example.

The Dominant Programmer
The Dominant Programmer
The Dominant Programmer
Building a Minimal Spring AI Tool Chain for Multi-Tool Calls

Scenario

Spring AI can call external tools from a large language model (LLM) and automatically compose their execution order, enabling agents to complete multi‑step tasks such as "query Beijing weather and answer in English".

Core Concepts

Tool Calling : The LLM generates a function‑call request (function name and parameters); Spring AI intercepts the request, invokes the corresponding Java method, and returns the result to the model.

@Tool annotation : Placed on a method, Spring AI parses the method signature and JavaDoc to produce a JSON Schema that the model can understand.

Multiple Tool Registration : Use defaultTools(...) to register several tools at once; the model decides the order and combination of calls.

Chain Calling : Within a single response the model can invoke multiple tools sequentially, feeding the output of one tool as the input to the next, forming a chain.

Implementation

pom.xml

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.3.3</version> <!-- downgrade to stable version -->
</parent>
<groupId>com.example</groupId>
<artifactId>spring-ai-ollama-tool-chain</artifactId>
<version>1.0</version>
<properties>
    <java.version>17</java.version>
    <spring-ai.version>1.1.2</spring-ai.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Spring AI Ollama core -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-ollama</artifactId>
        <version>${spring-ai.version}</version>
    </dependency>
</dependencies>

application.yml

server:
  port: 886
spring:
  ai:
    ollama:
      base-url: http://localhost:11434
      chat:
        model: qwen2.5:7b-instruct
        options:
          temperature: 0.7
          num-ctx: 4096 # context window size
logging:
  level:
    org.springframework.ai.chat.client: DEBUG # view tool‑call details

Weather Tool

package com.badao.ai.tools;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Component;

@Component
public class WeatherTool {
    @Tool(name = "get_weather", description = "查询指定城市的实时天气")
    public String getWeather(@ToolParam(description = "城市名称") String city) {
        System.out.println("调用了天气工具");
        // Simulated weather data
        return String.format("%s当前天气:晴,温度22℃,湿度45%%。", city);
    }
}

Translate Tool

package com.badao.ai.tools;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Component;

@Component
public class TranslateTool {
    @Tool(name = "translate_to_english", description = "将中文文本翻译成英文")
    public String translate(@ToolParam(description = "待翻译的中文文本") String text) {
        System.out.println("调用了翻译工具");
        // Simulated translation; real implementation could call a translation API
        return "Translated: " + text + " (This is the English version.)";
    }
}

Tool Registration Configuration

package com.badao.ai.config;
import com.badao.ai.tools.WeatherTool;
import com.badao.ai.tools.TranslateTool;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ToolConfig {
    @Bean
    public ChatClient chatClient(ChatModel chatModel, WeatherTool weatherTool, TranslateTool translateTool) {
        return ChatClient.builder(chatModel)
            .defaultTools(weatherTool, translateTool) // register weather and translation tools
            .build();
    }
}

Agent Service Layer

package com.badao.ai.service;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.stereotype.Service;

@Service
public class AgentService {
    private final ChatClient chatClient;
    public AgentService(ChatClient chatClient) {
        this.chatClient = chatClient;
    }
    public String ask(String question) {
        return chatClient.prompt()
            .user(question + "(请先用天气工具,再用翻译工具)")
            .call()
            .content();
    }
}

Controller

package com.badao.ai.controller;
import com.badao.ai.service.AgentService;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api")
public class AgentController {
    private final AgentService agentService;
    public AgentController(AgentService agentService) {
        this.agentService = agentService;
    }
    @PostMapping("/agent")
    public String ask(@RequestBody String question) {
        return agentService.ask(question);
    }
}

Testing

Test a single tool call and a chained tool call using the provided REST endpoint. The screenshots below show the console output for each scenario.

Single tool test
Single tool test
Tool chain test
Tool chain test
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaSpring Bootspring-aiTool Callingollama
The Dominant Programmer
Written by

The Dominant Programmer

Resources and tutorials for programmers' advanced learning journey. Advanced tracks in Java, Python, and C#. Blog: https://blog.csdn.net/badao_liumang_qizhi

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.