Tema
Idioma
·5 min de leitura

Chamada de funções com uma API de LLM: um loop completo e funcional

Como funciona a chamada de funções (uso de ferramentas) em uma API compatível com OpenAI: um loop completo em Python que executamos no GPT-6 Luna, DeepSeek V4.1 Flash e Claude Haiku 5.5, forçando uma chamada com tool_choice e usando o formato Messages da Anthropic.

Chamada de funções com uma API de LLM: um loop completo e funcional

Chamada de funções (também chamada de chamada de ferramentas ou uso de ferramentas) é como você dá a um modelo acesso ao seu código. Você descreve funções como "consultar um pedido" ou "calcular o frete". O modelo decide qual chamar e com quais argumentos; seu código a executa e envia o resultado de volta. Todo agente, de um bot de suporte de loja ao Claude Code, é baseado nesse loop.

Na GetVibe API, a chamada de funções funciona pelo endpoint padrão /v1/chat/completions no formato da OpenAI e por /v1/messages no formato da Anthropic. Abaixo está um loop completo que executamos em três modelos de três fabricantes diferentes.

Como o loop funciona

  1. Você envia mensagens junto com uma lista de tools. Cada ferramenta tem um nome, uma descrição e um JSON Schema para seus parâmetros.
  2. Em vez de texto, o modelo retorna tool_calls: qual função chamar e com quais argumentos. finish_reason é tool_calls.
  3. Seu código executa as funções e acrescenta uma mensagem com o papel tool para cada chamada, contendo o mesmo tool_call_id.
  4. Você envia o histórico novamente. O modelo pode pedir mais chamadas ou responder ao usuário em texto.

O modelo nunca executa nada por conta própria. Ele apenas solicita uma chamada. O que é realmente executado e com quais permissões é decidido pelo seu código.

Um exemplo completo: um assistente de suporte de loja

Duas funções: status do pedido e uma cotação de frete. O usuário pergunta sobre os dois ao mesmo tempo, e o modelo chama ambas em uma única rodada.

import json
import os
from openai import OpenAI

client = OpenAI(base_url="https://getvibeapi.com/v1", api_key=os.environ["GETVIBE_API_KEY"])
MODEL = "gpt-6-luna"

def get_order_status(order_id: str) -> dict:
    # sua consulta ao banco de dados ou CRM entra aqui
    return {"order_id": order_id, "status": "out for delivery", "eta": "2026-10-24"}

def get_shipping_quote(zip_code: str) -> dict:
    return {"zip_code": zip_code, "price_usd": 7.5, "days": 2}

TOOLS = [
    {"type": "function", "function": {
        "name": "get_order_status",
        "description": "Look up an order by its ID",
        "parameters": {"type": "object",
                       "properties": {"order_id": {"type": "string", "description": "Order ID, e.g. A-1042"}},
                       "required": ["order_id"]}}},
    {"type": "function", "function": {
        "name": "get_shipping_quote",
        "description": "Courier shipping price and delivery time to a US ZIP code",
        "parameters": {"type": "object",
                       "properties": {"zip_code": {"type": "string"}},
                       "required": ["zip_code"]}}},
]
FUNCTIONS = {"get_order_status": get_order_status, "get_shipping_quote": get_shipping_quote}

messages = [
    {"role": "system", "content": "Você é um assistente de suporte de loja. Seja breve."},
    {"role": "user", "content": "Onde está meu pedido A-1042? E quanto custa o frete para 94110?"},
]

for _ in range(5):  # limite o número de rodadas
    resp = client.chat.completions.create(model=MODEL, messages=messages, tools=TOOLS)
    msg = resp.choices[0].message
    if not msg.tool_calls:
        print(msg.content)
        break
    messages.append(msg.model_dump(exclude_none=True))
    for call in msg.tool_calls:
        args = json.loads(call.function.arguments)
        result = FUNCTIONS[call.function.name](**args)
        messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(result)})

Executamos este código sem alterações em gpt-6-luna, deepseek-v4.1-flash e claude-haiku-5.5, alterando apenas MODEL. Na primeira rodada, os três chamaram ambas as funções, get_order_status com A-1042 e get_shipping_quote com 94110. Na segunda rodada, os três responderam em texto com o status da entrega, a previsão, o preço de 7.50 e o prazo de entrega de dois dias.

O que importa neste código

  • Acrescente a mensagem de chamada de ferramenta do modelo completa ao histórico. Sem isso, sua mensagem tool responde a uma chamada que o modelo não consegue ver, e muitos modelos simplesmente chamam a mesma função novamente, fazendo o loop ficar travado.
  • Uma mensagem tool por chamada, com o tool_call_id correspondente. O modelo pode solicitar várias chamadas de uma vez, como aconteceu aqui.
  • Os argumentos chegam como uma string. arguments é um JSON dentro de uma string. Faça o parse e valide-o, porque o modelo pode fornecer um valor incorreto.
  • Limite as rodadas. Sem um limite, um bug em uma função pode transformar o loop em um processo infinito e gerar uma cobrança infinita de tokens.

tool_choice: quando uma chamada é obrigatória

Por padrão, o modelo decide se deve chamar uma ferramenta ou responder em texto ("auto"). tool_choice altera esse comportamento:

  • "none" — nunca chama ferramentas;
  • "required" — chama pelo menos uma ferramenta;
  • {"type": "function", "function": {"name": "..."}} — chama esta função específica.

A última forma é útil para extração de dados. O schema de parâmetros da função se torna o formato da resposta:

curl https://getvibeapi.com/v1/chat/completions \
  -H "Authorization: Bearer $GETVIBE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-v4.1-flash",
    "messages": [{"role": "user", "content": "Jane Doe, [email protected], quer uma demonstração na quinta-feira"}],
    "tools": [{
      "type": "function",
      "function": {
        "name": "save_lead",
        "description": "Save a sales lead to the CRM",
        "parameters": {
          "type": "object",
          "properties": {"name": {"type": "string"}, "email": {"type": "string"}, "request": {"type": "string"}},
          "required": ["name", "email", "request"]
        }
      }
    }],
    "tool_choice": {"type": "function", "function": {"name": "save_lead"}}
  }'

A resposta foi uma chamada save_lead com name "Jane Doe", email "[email protected]" e request "Quer uma demonstração na quinta-feira".

Uma ressalva: alguns modelos Claude, incluindo Claude Sonnet 5.5 e Claude Opus 5.5, não aceitam uma escolha de ferramenta forçada. A GetVibe transforma essa solicitação em auto com as mesmas ferramentas, para que você receba uma resposta em vez de um erro, mas então o modelo decide por conta própria se deve chamar a ferramenta. Para obter JSON estrito desses modelos, use saídas estruturadas.

O formato da Anthropic: /v1/messages

Com o SDK da Anthropic, as ferramentas têm uma aparência um pouco diferente: o schema de parâmetros vai em input_schema, e a chamada retorna como um bloco de conteúdo tool_use.

curl https://getvibeapi.com/v1/messages \
  -H "x-api-key: $GETVIBE_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-haiku-5.5",
    "max_tokens": 512,
    "tools": [{
      "name": "get_order_status",
      "description": "Look up an order by its ID",
      "input_schema": {"type": "object", "properties": {"order_id": {"type": "string"}}, "required": ["order_id"]}
    }],
    "messages": [{"role": "user", "content": "Onde está o pedido A-1042?"}]
  }'

A resposta tinha stop_reason tool_use e um bloco tool_use chamando get_order_status com order_id A-1042. Você envia o resultado de volta como um bloco tool_result na próxima mensagem do usuário, com o mesmo tool_use_id.

Qual modelo usar para ferramentas

  • Bots de alto volume e ferramentas simples — DeepSeek V4.1 Flash ($0.0112 entrada · $0.0445 saída por 1M de tokens) ou Claude Haiku 5.5 ($0.0267 entrada · $0.1334 saída por 1M de tokens).
  • Agentes com muitas ferramentas e planos longos — GPT-6 Luna ($0.0055 entrada · $0.0274 saída por 1M de tokens) ou Claude Sonnet 5.5.

Os loops de agentes reenviam o mesmo prefixo longo a cada rodada, então o cache de prompts é muito importante aqui. Mais detalhes sobre os campos da solicitação estão na documentação de chamada de ferramentas.

API de chamada de funçõeschamada de ferramentas em LLMexemplo de chamada de funções da OpenAItool_choiceuso de ferramentas da Anthropicferramentas para agentes de LLM

Experimente GetVibe API gratuitamente

GPT, Claude, Gemini e muito mais por meio de uma única API compatível com OpenAI. Pague em USD com cartão ou criptomoedas.

Artigos relacionados

Chamada de funções com uma API de LLM: um loop completo e funcional | GetVibe API