Se você tem código Spring AI que usa toolNames(), SpringBeanToolCallbackResolver ou depende do loop interno de tool execution dentro do ChatModel, ele vai quebrar quando o Spring AI 2.0 GA sair. O RC1 lançado em 06/06/2026 consolida todas as mudanças. Aqui está o guia completo com before/after para cada breaking change do Tool Calling Overhaul.

Nesse artigo você vai encontrar: o mapa completo dos breaking changes do Tool Calling no RC1, código before/after funcional para cada mudança, e a sequência correta para migrar sem quebrar seu agente em produção.

Por que o Tool Calling mudou tanto no 2.0

No Spring AI 1.x, cada ChatModel (OpenAI, Anthropic, Ollama, etc.) tinha um loop interno de execução de tools. Quando o LLM retornava uma tool call, o próprio ChatModel executava a ferramenta, pegava o resultado e mandava de volta ao modelo de forma automática e invisível.

O problema: comportamento inconsistente entre providers, sem ponto de extensão limpo para logging, rate limiting ou autorização. O Spring AI 2.0 corrigiu isso: o loop de execução saiu dos ChatModels e foi para o ToolCallingAdvisor. Mais controle, mais testabilidade — mas código que dependia do comportamento automático precisa ser atualizado.

Breaking Change 1: toolNames() foi removido

A API toolNames() e toolBeanDefinitionNames() foram removidas do ChatClient e de todas as implementações de ChatOptions. O SpringBeanToolCallbackResolver também foi removido.

// ANTES (Spring AI 1.x) - NÃO COMPILA no 2.0
ChatResponse response = chatClient.prompt()
    .user("Temperatura em São Paulo?")
    .options(OpenAiChatOptions.builder()
        .toolNames("climaService")  // removido
        .build())
    .call()
    .chatResponse();

// DEPOIS (Spring AI 2.0) - ToolCallback explícito
@Component
public class ClimaToolCallback implements ToolCallback {
    @Override
    public String call(ToolRequest request) {
        return "{"temperatura": 28, "cidade": "São Paulo"}";
    }
    @Override
    public ToolDefinition getToolDefinition() {
        return ToolDefinition.builder()
            .name("climaService")
            .description("Retorna temperatura atual de uma cidade")
            .inputTypeSchema(/* JSON schema */)
            .build();
    }
}

// Uso:
ChatResponse response = chatClient.prompt()
    .user("Temperatura em São Paulo?")
    .tools(climaToolCallback)  // instância explícita
    .call()
    .chatResponse();

Breaking Change 2: internalToolExecutionEnabled removido

// ANTES - NÃO COMPILA no 2.0
ChatOptions options = OpenAiChatOptions.builder()
    .internalToolExecutionEnabled(false)  // removido
    .build();

// DEPOIS - controle via ToolCallingAdvisor
@Bean
public ChatClient chatClient(ChatModel chatModel,
                              ToolCallingAdvisor toolCallingAdvisor) {
    return ChatClient.builder(chatModel)
        .defaultAdvisors(toolCallingAdvisor)
        .build();
}

Breaking Change 3: ToolCallingAdvisor é obrigatório

Sem o ToolCallingAdvisor, as tools não são executadas e não há erro — só silêncio. O agente retorna resposta vazia ou JSON bruto de tool call.

// ANTES (1.x) - execução automática no ChatModel
this.chatClient = chatClientBuilder.build();

// DEPOIS (2.0) - ToolCallingAdvisor obrigatório
this.chatClient = chatClientBuilder
    .defaultAdvisors(toolCallingAdvisor)  // obrigatório
    .build();

// Configuração do bean:
@Bean
public ToolCallingAdvisor toolCallingAdvisor(ToolCallingManager toolCallingManager,
                                              ObservationRegistry observationRegistry) {
    return ToolCallingAdvisor.builder()
        .toolCallingManager(toolCallingManager)
        .observationRegistry(observationRegistry)
        .build();
}

Breaking Change 4: ChatClientCustomizer depreciado

// ANTES (1.x) - deprecated no 2.0
@Bean
public ChatClientCustomizer toolsCustomizer(ToolCallingAdvisor advisor) {
    return builder -> builder.defaultAdvisors(advisor);
}

// DEPOIS (2.0) - novo nome
@Bean
public ChatClientBuilderCustomizer toolsCustomizer(ToolCallingAdvisor advisor) {
    return builder -> builder.defaultAdvisors(advisor);
}

Novo no RC1: ToolSearchToolCallingAdvisor

Quando você tem muitas tools, mandar todas as definições para o LLM a cada request aumenta custo e degrada qualidade. O novo ToolSearchToolCallingAdvisor indexa tools e carrega apenas as relevantes para cada query:

@Bean
public ToolSearchToolCallingAdvisor toolSearchAdvisor(
        VectorStore toolVectorStore,
        List<ToolCallback> allTools,
        ToolCallingManager toolCallingManager) {

    ToolIndex toolIndex = VectorStoreToolIndex.builder()
        .vectorStore(toolVectorStore)
        .tools(allTools)
        .build();

    return ToolSearchToolCallingAdvisor.builder()
        .toolIndex(toolIndex)
        .toolCallingManager(toolCallingManager)
        .maxToolsPerRequest(5)
        .build();
}

Sequência segura de migração

1. Identificar código afetado

grep -r "toolNames\|SpringBeanToolCallbackResolver\|internalToolExecutionEnabled\|ChatClientCustomizer" src/

2. Converter para ToolCallback explícito
Para cada tool resolvida por nome, criar implementação de ToolCallback e registrar via .tools().

3. Adicionar ToolCallingAdvisor ao ChatClient
Todo ChatClient que executa tools precisa do advisor. Sem ele: silêncio.

4. Renomear ChatClientCustomizer
Trocar ChatClientCustomizer por ChatClientBuilderCustomizer.

5. Rodar testes de integração reais
Testes unitários com mocks não detectam o problema do loop. Use WireMock mockando o provider para verificar que a tool foi chamada e o resultado devolvido ao modelo.

FAQ: Perguntas Frequentes

@Tool ainda funciona no 2.0?
A anotação continua suportada. O que mudou é o mecanismo de resolução. O método precisa ser empacotado em MethodToolCallback e passado explicitamente. O Spring AI fornece helpers para isso.

Quando sai a GA do Spring AI 2.0?
RC1 é um milestone de estabilização de API. Após RC1, apenas bug fixes. Dado o ritmo de releases, espere a GA em julho de 2026.

Vale migrar para RC1 em produção?
RC1 é estável para homologação. Para produção, aguardar a GA. Mas criar a branch de migração agora e estar pronto para o bump quando a GA sair é a estratégia correta.

ToolSearchToolCallingAdvisor requer vector store?
Existem três implementações de ToolIndex: VectorStoreToolIndex (semântico), LuceneToolIndex (textual, sem embedding) e RegexToolIndex (matching por nome). Para menos de 10 tools, o ToolCallingAdvisor padrão é mais simples.

A migração para Spring AI 2.0 não é opcional quando a GA sair. Com a sequência certa, é uma mudança de horas. Comenta aqui o breaking change que mais te preocupa no seu projeto.

Segue o Meu Universo Nerd para não perder o próximo conteúdo sobre Spring AI e Java.