05-02-03 — Tool calling / function calling em profundidade
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
Fontes
- OpenAI — Function Calling guide — documentação oficial com exemplos e best practices.
- Anthropic — Tool use (function calling) — documentação do tool_use da API Claude.
- Microsoft — Semantic Kernel Plugins — como registrar e usar ferramentas no SK.
- OpenAI — Parallel function calling — documentação de chamadas paralelas.