05-02-03 — Tool calling / function calling em profundidade

⏱ 15 minFontes validadas em: 2026-04-29

TL;DR

Tool calling é o mecanismo que permite ao LLM "agir": ele gera um JSON estruturado com o nome da função e os argumentos; o runtime executa a função e retorna o resultado ao LLM. É o componente técnico central de qualquer agente. OpenAI e Anthropic têm APIs ligeiramente diferentes mas o conceito é idêntico.

Como funciona: o fluxo completo

sequenceDiagram participant App as Aplicação participant API as LLM API participant Fn as Sua Função App->>API: messages + tools schema (JSON) API-->>App: tool_call {name: "get_stock_price", args: {symbol: "VALE3"}} App->>Fn: executa get_stock_price("VALE3") Fn-->>App: {"price": 58.40, "currency": "BRL"} App->>API: messages + tool_result API-->>App: "O preço da VALE3 é R$ 58,40"

O LLM nunca executa código. Ele apenas decide qual ferramenta chamar e com quais argumentos, no formato JSON. A aplicação é responsável por executar e retornar o resultado.

OpenAI — tools API

import openai
import json

client = openai.OpenAI()

# Define as ferramentas disponíveis (schema JSON)
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_project_status",
            "description": "Retorna o status atual de um projeto por ID",
            "parameters": {
                "type": "object",
                "properties": {
                    "project_id": {
                        "type": "string",
                        "description": "ID do projeto no sistema"
                    },
                    "include_risks": {
                        "type": "boolean",
                        "description": "Incluir análise de riscos na resposta"
                    }
                },
                "required": ["project_id"]
            }
        }
    }
]

messages = [{"role": "user", "content": "Qual o status do projeto PRJ-2024-001?"}]

# Primeira chamada: LLM decide usar a ferramenta
response = client.chat.completions.create(
    model="gpt-4o",
    messages=messages,
    tools=tools,
    tool_choice="auto"  # ou "required" para forçar uso de ferramenta
)

tool_call = response.choices[0].message.tool_calls[0]
print(f"Tool: {tool_call.function.name}")
print(f"Args: {tool_call.function.arguments}")
# Output: Tool: get_project_status
# Output: Args: {"project_id": "PRJ-2024-001", "include_risks": false}

# Executa a função real
def get_project_status(project_id: str, include_risks: bool = False) -> dict:
    # Simulação — na vida real, consulta seu sistema
    return {"status": "Em andamento", "completion": "67%", "deadline": "2024-06-30"}

args = json.loads(tool_call.function.arguments)
result = get_project_status(**args)

# Segunda chamada: retorna resultado ao LLM
messages.append(response.choices[0].message)
messages.append({
    "role": "tool",
    "tool_call_id": tool_call.id,
    "content": json.dumps(result)
})

final = client.chat.completions.create(model="gpt-4o", messages=messages)
print(final.choices[0].message.content)

Anthropic — tool_use API

import anthropic
import json

client = anthropic.Anthropic()

tools = [
    {
        "name": "get_project_status",
        "description": "Retorna status de um projeto por ID",
        "input_schema": {
            "type": "object",
            "properties": {
                "project_id": {"type": "string"},
                "include_risks": {"type": "boolean"}
            },
            "required": ["project_id"]
        }
    }
]

response = client.messages.create(
    model="claude-opus-4-5",
    max_tokens=1024,
    tools=tools,
    messages=[{"role": "user", "content": "Status do projeto PRJ-2024-001?"}]
)

# Extrai tool use
for block in response.content:
    if block.type == "tool_use":
        print(f"Tool: {block.name}, Input: {block.input}")

C# — Semantic Kernel com tools

using Microsoft.SemanticKernel;
using System.ComponentModel;

// Plugin: define ferramentas com atributos
public class ProjectPlugin
{
    [KernelFunction("get_project_status")]
    [Description("Retorna status atual de um projeto por ID")]
    public async Task<string> GetProjectStatusAsync(
        [Description("ID do projeto")] string projectId,
        [Description("Incluir riscos")] bool includeRisks = false)
    {
        // Consulta seu sistema real aqui
        return $"{{\"status\":\"Em andamento\",\"completion\":\"67%\"}}";
    }
}

// Setup do kernel
var builder = Kernel.CreateBuilder();
builder.AddAzureOpenAIChatCompletion("gpt-4o", endpoint, apiKey);
builder.Plugins.AddFromType<ProjectPlugin>();

var kernel = builder.Build();

// Invoca com function calling automático
var settings = new OpenAIPromptExecutionSettings 
{ 
    FunctionChoiceBehavior = FunctionChoiceBehavior.Auto() 
};

var result = await kernel.InvokePromptAsync(
    "Qual o status do projeto PRJ-2024-001?",
    new KernelArguments(settings)
);
Console.WriteLine(result);

Parallel tool calls

Modelos modernos (GPT-4o, Claude 3+) suportam chamar múltiplas ferramentas em paralelo numa única resposta:

# LLM pode retornar múltiplos tool_calls numa única resposta
# Ex: "Busque preço da VALE3 E do ITUB4 simultaneamente"
response = client.chat.completions.create(
    model="gpt-4o",
    messages=messages,
    tools=tools,
    # parallel_tool_calls=True  # Default: True no GPT-4o
)

# Processa todos em paralelo
import asyncio

async def process_tool_calls(tool_calls):
    tasks = [execute_tool(tc) for tc in tool_calls]
    return await asyncio.gather(*tasks)
Parallel tool calls: Reduzem latência em até 60% quando múltiplas informações independentes são necessárias. Use quando as ferramentas não têm dependência entre si — busca de múltiplos preços, consultas a múltiplas APIs ao mesmo tempo.

Forced tool choice

Quando você precisa garantir que o LLM use uma ferramenta específica:

# OpenAI: força uso de uma ferramenta específica
response = client.chat.completions.create(
    model="gpt-4o",
    messages=messages,
    tools=tools,
    tool_choice={"type": "function", "function": {"name": "get_project_status"}}
)

# Anthropic: equivalente
response = client.messages.create(
    model="claude-opus-4-5",
    tools=tools,
    tool_choice={"type": "tool", "name": "get_project_status"},
    messages=messages
)
Azure OpenAI: Mesma API da OpenAI, inclui parallel tool calls e forced tool choice. No Semantic Kernel, FunctionChoiceBehavior.Required() força uso de ferramenta. Disponível em todos os modelos GPT-4o no Azure AI Foundry.
Segurança: Valide e sanitize os argumentos retornados pelo LLM antes de executar. Um LLM pode ser manipulado por prompt injection para gerar argumentos maliciosos (ex: SQL injection via args de ferramenta). Trate a saída do LLM como input não confiável.

Como isso se conecta

  • 05-02-01 — ReAct usa tool calling como mecanismo de "Action".
  • 05-03-01 — Em sistemas multi-agent, chamar outro agente é tecnicamente um tool call.
  • 05-04-04 — O desafio usa tool calling para buscar preços em sites diferentes.

Fontes

  1. OpenAI — Function Calling guide — documentação oficial com exemplos e best practices.
  2. Anthropic — Tool use (function calling) — documentação do tool_use da API Claude.
  3. Microsoft — Semantic Kernel Plugins — como registrar e usar ferramentas no SK.
  4. OpenAI — Parallel function calling — documentação de chamadas paralelas.