Tokia

Tool Calling / Function Calling

Tool calling permite que o modelo “chame funções” que você define. O modelo não executa código — ele retorna o nome da função e os argumentos em JSON, e você executa a função no seu código. Isso habilita agentes, pesquisa em banco de dados, chamadas a APIs externas, e qualquer integração programática.

Como funciona

O fluxo tem 4 passos:

  • 1. Você envia a mensagem do usuário + a lista de tools disponíveis
  • 2. O modelo decide se precisa chamar uma tool e retorna tool_calls com nome e argumentos
  • 3. Você executa a função localmente e envia o resultado de volta como mensagem role: "tool"
  • 4. O modelo usa o resultado para compor a resposta final ao usuário

Definindo tools

Cada tool tem um name, description e parameters (JSON Schema). A description é fundamental — é o que o modelo lê para decidir quando usar a tool.

python
tools = [
    {
        "type": "function",
        "function": {
            "name": "consultar_clima",
            "description": "Consulta a previsão do tempo para uma cidade brasileira",
            "parameters": {
                "type": "object",
                "properties": {
                    "cidade": {
                        "type": "string",
                        "description": "Nome da cidade, ex: 'Brasília'"
                    },
                    "dias": {
                        "type": "integer",
                        "description": "Quantos dias de previsão (1-7)",
                        "default": 1
                    }
                },
                "required": ["cidade"]
            }
        }
    }
]

Exemplo completo (Python)

python
from openai import OpenAI
import json

client = OpenAI(
    api_key="sk-...",
    base_url="https://api.usetokia.com/v1",
)

# 1. Definir tools
tools = [
    {
        "type": "function",
        "function": {
            "name": "consultar_clima",
            "description": "Consulta a temperatura atual de uma cidade",
            "parameters": {
                "type": "object",
                "properties": {
                    "cidade": {"type": "string", "description": "Nome da cidade"}
                },
                "required": ["cidade"]
            }
        }
    }
]

# Implementação local da função
def consultar_clima(cidade: str) -> dict:
    # Na prática, chamaria uma API de clima
    return {"cidade": cidade, "temperatura": 28, "condicao": "ensolarado"}

# 2. Enviar mensagem + tools
messages = [{"role": "user", "content": "Qual a temperatura em Brasília?"}]

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=messages,
    tools=tools,
)

# 3. Verificar se o modelo quer chamar uma tool
message = response.choices[0].message

if message.tool_calls:
    # Adicionar a mensagem do assistente ao histórico
    messages.append(message)

    for tool_call in message.tool_calls:
        # Executar a função localmente
        args = json.loads(tool_call.function.arguments)
        result = consultar_clima(**args)

        # 4. Enviar resultado de volta
        messages.append({
            "role": "tool",
            "tool_call_id": tool_call.id,
            "content": json.dumps(result),
        })

    # 5. Obter resposta final
    final = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=messages,
        tools=tools,
    )
    print(final.choices[0].message.content)
    # → "A temperatura em Brasília está em 28°C, com tempo ensolarado."
else:
    print(message.content)

Exemplo completo (TypeScript)

typescript
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.TOKIA_KEY,
  baseURL: "https://api.usetokia.com/v1",
});

const tools: OpenAI.ChatCompletionTool[] = [
  {
    type: "function",
    function: {
      name: "consultar_clima",
      description: "Consulta a temperatura atual de uma cidade",
      parameters: {
        type: "object",
        properties: {
          cidade: { type: "string", description: "Nome da cidade" },
        },
        required: ["cidade"],
      },
    },
  },
];

function consultarClima(cidade: string) {
  return { cidade, temperatura: 28, condicao: "ensolarado" };
}

const messages: OpenAI.ChatCompletionMessageParam[] = [
  { role: "user", content: "Qual a temperatura em Brasília?" },
];

const response = await client.chat.completions.create({
  model: "gpt-4o-mini",
  messages,
  tools,
});

const message = response.choices[0].message;

if (message.tool_calls) {
  messages.push(message);

  for (const toolCall of message.tool_calls) {
    const args = JSON.parse(toolCall.function.arguments);
    const result = consultarClima(args.cidade);

    messages.push({
      role: "tool",
      tool_call_id: toolCall.id,
      content: JSON.stringify(result),
    });
  }

  const final = await client.chat.completions.create({
    model: "gpt-4o-mini",
    messages,
    tools,
  });
  console.log(final.choices[0].message.content);
} else {
  console.log(message.content);
}

Múltiplas tools e chamadas paralelas

Você pode definir várias tools. O modelo pode chamar mais de uma na mesma resposta (chamada paralela). Itere sobre tool_calls e envie todos os resultados antes de pedir a resposta final:

python
tools = [
    {
        "type": "function",
        "function": {
            "name": "consultar_clima",
            "description": "Consulta temperatura de uma cidade",
            "parameters": {
                "type": "object",
                "properties": {"cidade": {"type": "string"}},
                "required": ["cidade"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "consultar_cotacao",
            "description": "Consulta cotação do dólar em BRL",
            "parameters": {"type": "object", "properties": {}}
        }
    }
]

# O modelo pode retornar tool_calls com ambas as funções
# Trate cada uma e envie os resultados

Forçando ou impedindo tool calls

Use tool_choice para controlar quando o modelo usa tools:

ValorComportamento
"auto"O modelo decide se usa tool ou não (padrão)
"none"O modelo nunca usa tool, responde só com texto
"required"O modelo é obrigado a chamar pelo menos uma tool
{"type":"function","function":{"name":"X"}}O modelo é obrigado a chamar a tool X especificamente

Tool calling com streaming

Tool calls também funcionam com stream: true. Os argumentos chegam em chunks parciais que você precisa concatenar:

python
stream = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Qual o clima em SP?"}],
    tools=tools,
    stream=True,
)

tool_calls_acc = {}
for chunk in stream:
    delta = chunk.choices[0].delta
    if delta.tool_calls:
        for tc in delta.tool_calls:
            idx = tc.index
            if idx not in tool_calls_acc:
                tool_calls_acc[idx] = {"id": tc.id, "name": tc.function.name, "args": ""}
            if tc.function.arguments:
                tool_calls_acc[idx]["args"] += tc.function.arguments

# Agora tool_calls_acc tem as chamadas completas
for tc in tool_calls_acc.values():
    args = json.loads(tc["args"])
    print(f"Tool: {tc['name']}, Args: {args}")

Modelos com suporte a tool calling

A maioria dos modelos de chat suporta tool calling, mas nem todos. Modelos populares com suporte:

  • OpenAI: gpt-4o, gpt-4o-mini, gpt-4-turbo, o1, o3-mini
  • Anthropic: claude-sonnet-4-20250514, claude-opus-4-20250514, claude-3.5-sonnet, claude-3-haiku
  • Google: gemini-2.0-flash, gemini-2.5-pro
  • Meta: llama-3.1-70b, llama-3.3-70b
  • Mistral: mistral-large, mistral-small
  • DeepSeek: deepseek-chat (V3)

Boas práticas

  • Descriptions claras: O modelo decide qual tool usar baseado na description. Seja específico.
  • JSON Schema restrito: Use required, enum e tipos precisos para evitar argumentos inválidos.
  • Valide argumentos: Mesmo com schema, valide os argumentos antes de executar.
  • Limite o loop: Em agentes, defina um máximo de iterações para evitar loops infinitos.
  • Trate erros: Se a execução da tool falhar, envie o erro como resultado — o modelo pode tentar outra abordagem.

Próximos passos