CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-springframework-ai--spring-ai-client-chat

Spring AI Chat Client provides a fluent API for building AI-powered applications with LLMs, supporting advisors, streaming, structured outputs, and conversation memory

Overview
Eval results
Files

tool-calling.mddocs/guides/

Tool Calling

Enable AI to call Java functions during processing.

Basic Tool Calling

import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.chat.client.advisor.ToolCallAdvisor;

// Define request/response types
record WeatherRequest(String location) {}
record WeatherResponse(String location, double temp, String conditions) {}

// Implement tool function
public WeatherResponse getWeather(WeatherRequest request) {
    // Fetch weather data
    return new WeatherResponse(request.location(), 22.5, "Sunny");
}

// Create tool callback
ToolCallback weatherTool = ToolCallback.builder()
    .function("getCurrentWeather", this::getWeather)
    .description("Get the current weather for a location")
    .inputType(WeatherRequest.class)
    .build();

// Configure client with tool advisor
ChatClient client = ChatClient.builder(chatModel)
    .defaultAdvisors(ToolCallAdvisor.builder().build())
    .defaultTools(weatherTool)
    .build();

// Use tool
String response = client
    .prompt("What's the weather in Paris?")
    .call()
    .content();
// Response: "The weather in Paris is currently sunny with a temperature of 22.5°C."

How It Works

  1. User sends query
  2. AI determines it needs tool data
  3. AI requests tool call
  4. ToolCallAdvisor executes function
  5. ToolCallAdvisor sends result back to AI
  6. AI generates final response

Multiple Tools

// Weather tool
ToolCallback weatherTool = ToolCallback.builder()
    .function("getWeather", this::getWeather)
    .description("Get weather")
    .inputType(WeatherRequest.class)
    .build();

// Calculator tool
ToolCallback calcTool = ToolCallback.builder()
    .function("calculate", this::calculate)
    .description("Perform calculations")
    .inputType(CalculationRequest.class)
    .build();

ChatClient client = ChatClient.builder(chatModel)
    .defaultAdvisors(ToolCallAdvisor.builder().build())
    .defaultTools(weatherTool, calcTool)
    .build();

// AI can call multiple tools
String answer = client
    .prompt("What's 2+2 and what's the weather in London?")
    .call()
    .content();

Per-Request Tools

ChatClient client = ChatClient.builder(chatModel)
    .defaultAdvisors(ToolCallAdvisor.builder().build())
    .build();

// Tools specific to this request
String response = client
    .prompt("Calculate expenses")
    .tools(expenseTool, budgetTool)
    .call()
    .content();

Tool Context

Share data between tools:

Map<String, Object> context = Map.of(
    "userId", "user-123",
    "apiKey", "secret-key",
    "database", databaseConnection
);

chatClient
    .prompt("Process my data")
    .toolContext(context)
    .toolCallbacks(dataTool)
    .call()
    .content();

Tool accessing context:

public class DataTool {
    @Tool(description = "Process user data")
    public String processData(
        @ToolParam("data") String data,
        @ToolContext Map<String, Object> context
    ) {
        String userId = (String) context.get("userId");
        Database db = (Database) context.get("database");
        return db.process(userId, data);
    }
}

Annotated Tools

@Component
class WeatherTools {
    @Tool(description = "Get the current weather for a location")
    public String getCurrentWeather(@ToolParam("location") String location) {
        // Fetch weather
        return "Sunny, 22°C";
    }
    
    @Tool(description = "Get weather forecast")
    public List<String> getForecast(
        @ToolParam("location") String location,
        @ToolParam("days") int days
    ) {
        return List.of("Day 1: Sunny", "Day 2: Cloudy");
    }
}

// Use annotated tools
String response = chatClient
    .prompt("What's the weather in Paris?")
    .tools(weatherTools)
    .call()
    .content();

RAG Pattern

Combine tool calling with retrieval:

record SearchRequest(String query) {}
record SearchResult(List<String> documents) {}

public SearchResult searchDocuments(SearchRequest request) {
    // Search vector database
    return vectorStore.similaritySearch(request.query());
}

ToolCallback searchTool = ToolCallback.builder()
    .function("searchDocuments", this::searchDocuments)
    .description("Search knowledge base")
    .inputType(SearchRequest.class)
    .build();

ChatClient client = ChatClient.builder(chatModel)
    .defaultAdvisors(ToolCallAdvisor.builder().build())
    .defaultTools(searchTool)
    .build();

String answer = client
    .prompt("What are the benefits of Spring Boot?")
    .call()
    .content();
// AI will call searchDocuments tool, then answer using retrieved docs

Error Handling

try {
    String response = client
        .prompt("Call the weather tool")
        .call()
        .content();
} catch (ToolExecutionException e) {
    System.err.println("Tool failed: " + e.getMessage());
    System.err.println("Tool name: " + e.getToolName());
}

Best Practices

Clear Descriptions

// GOOD: Clear, specific description
.description("Get the current weather for a location. Returns temperature in Celsius and conditions.")

// BAD: Vague description
.description("Get weather")

Type Safety

// GOOD: Use typed records
record WeatherRequest(String location) {}

// AVOID: Untyped maps
Map<String, Object> request

Error Recovery

public WeatherResponse getWeather(WeatherRequest request) {
    try {
        return weatherApi.fetch(request.location());
    } catch (Exception e) {
        // Return error info for AI to handle
        return new WeatherResponse(
            request.location(),
            0.0,
            "Weather data unavailable"
        );
    }
}

Next Steps

  • Utility Advisors Reference - ToolCallAdvisor details
  • Real-World Scenarios - Production patterns
  • Edge Cases - Advanced tool calling

Install with Tessl CLI

npx tessl i tessl/maven-org-springframework-ai--spring-ai-client-chat

docs

index.md

tile.json