Voltar ao blog

API e SDKGuia

Function calling em Python com uma API compatível com OpenAI

Envie ferramentas, leia tool_calls e retorne o resultado com role tool: um ciclo de function calling em duas etapas em Python com MiniMax-M2.7.

Por CheapTokens TeamPublicado em Atualizado em 6 min de leitura

Diagrama de um ciclo de chamada de ferramenta em duas etapas: enviar ferramentas, ler tool_calls, retornar o resultado como uma mensagem de ferramenta
Nesta página
  1. Como funciona o function calling
  2. Configure o cliente
  3. Declare uma função e envie a primeira requisição
  4. O que você deve ver
  5. Várias chamadas e ciclos mais longos
  6. Por que o MiniMax-M2.7 é adequado para ciclos de ferramentas
  7. Se não funcionar
  8. Próximos passos

O function calling (tool calling) permite que um modelo peça ao seu código para executar uma função. Você envia uma lista tools junto com a requisição, o modelo responde com tool_calls em vez de texto, você executa a função por conta própria e envia o resultado de volta em uma mensagem com role: tool. O modelo então escreve a resposta final. Este guia mostra o ciclo completo em Python contra o endpoint compatível com OpenAI https://api.cheaptokens.dev/v1/chat/completions com MiniMax-M2.7 (id MiniMaxAI/MiniMax-M2.7, contexto de 180K, até 8.192 tokens de saída por resposta).

O tool calling está listado como suportado para todos os modelos do catálogo (CheapTokens docs, verificado em 22 de outubro de 2026). Você precisa de uma chave de API; se ainda não fez uma requisição, comece com sua primeira requisição de API.

Como funciona o function calling#

O modelo nunca executa nada. Ele apenas produz uma requisição estruturada: "chame get_weather com {\"city\": \"Paris\"}". Seu programa faz o trabalho real e reporta de volta. Isso forma um ciclo de duas requisições:

  1. Requisição 1. Você envia a mensagem do usuário mais a lista tools. O modelo responde em texto ou retorna uma ou mais tool_calls.
  2. Seu código. Você analisa cada chamada, executa a função correspondente e coleta o resultado.
  3. Requisição 2. Você envia a conversa inteira novamente: as mensagens originais, a mensagem do assistente com tool_calls e uma mensagem role: tool por chamada. O modelo usa os resultados para escrever a resposta final.

Cada requisição reenvia todo o histórico, então ciclos de ferramentas usam mais tokens de entrada do que uma única pergunta. Se isso é novo para você, leia o que é um token.

Configure o cliente#

Instale o SDK da OpenAI (pip install openai) e coloque sua chave em uma variável de ambiente em vez do código-fonte:

bash
export CHEAPTOKENS_API_KEY="your-key-here"

A URL base é https://api.cheaptokens.dev/v1. Pegue o id do modelo na documentação da CheapTokens: provedores diferentes nomeiam o mesmo modelo de formas diferentes. Este guia usa MiniMaxAI/MiniMax-M2.7.

Declare uma função e envie a primeira requisição#

Uma função é descrita no array tools. Cada entrada tem type: function e um objeto function com um name, um description e parameters escrito como JSON Schema. A descrição é o que o modelo lê para decidir quando chamar a função, então escreva-a como uma frase curta e concreta.

Abaixo está um script completo. A função de clima é um stub com dados falsos, então o exemplo não precisa de serviços extras:

python
import json
import os

from openai import OpenAI

client = OpenAI(
    base_url='https://api.cheaptokens.dev/v1',
    api_key=os.environ['CHEAPTOKENS_API_KEY'],
)
MODEL = 'MiniMaxAI/MiniMax-M2.7'


def get_weather(city: str) -> dict:
    # Stub with fake data: replace with a real lookup
    fake = {'Paris': 14, 'Tokyo': 19}
    return {'city': city, 'temp_c': fake.get(city, 10)}


FUNCTIONS = {'get_weather': get_weather}

tools = [
    {
        'type': 'function',
        'function': {
            'name': 'get_weather',
            'description': 'Get the current temperature in Celsius for a city.',
            'parameters': {
                'type': 'object',
                'properties': {
                    'city': {'type': 'string', 'description': 'City name, for example Paris'},
                },
                'required': ['city'],
            },
        },
    }
]

messages = [{'role': 'user', 'content': 'What is the weather in Paris right now?'}]

# Step 1: the model decides whether to call a function
first = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
message = first.choices[0].message

if not message.tool_calls:
    print(message.content)
    raise SystemExit

# Step 2: run every requested call and send the results back
messages.append(message)
for call in message.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),
    })

final = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
print(final.choices[0].message.content)

Três detalhes decidem se o ciclo funciona:

  • call.function.arguments é uma string JSON, não um dicionário. Analise-a com json.loads.
  • Cada mensagem role: tool deve carregar o tool_call_id da chamada que ela responde, que é call.id.
  • O content de uma mensagem de ferramenta é uma string. Use json.dumps para resultados estruturados.

O que você deve ver#

Se você imprimir os campos após a primeira requisição, eles se parecem com isto (o id da chamada muda a cada execução):

text
finish_reason: tool_calls
call.id: call_abc123
call.function.name: get_weather
call.function.arguments: {"city": "Paris"}

O script então imprime a resposta final, uma frase simples como "It is currently 14 °C in Paris." A redação muda a cada execução; o número vem da sua função.

Várias chamadas e ciclos mais longos#

Um modelo pode retornar mais de uma chamada em uma única resposta, por exemplo quando você pergunta sobre o clima em duas cidades. É por isso que o exemplo itera sobre message.tool_calls e responde cada chamada pelo seu próprio id. O guia de function calling da OpenAI descreve o mesmo comportamento: com o tool_choice padrão de auto, o modelo pode chamar zero, uma ou várias funções (OpenAI docs, verificado em 22 de outubro de 2026; a página não tem data de última atualização e descreve o formato mais novo da Responses API, enquanto este guia usa o formato Chat Completions do endpoint /v1/chat/completions).

Agentes repetem os dois passos até o modelo parar de pedir ferramentas. Envolva as requisições em um loop e sempre defina um limite de passos:

python
for _ in range(5):  # safety limit against endless loops
    response = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
    message = response.choices[0].message
    if not message.tool_calls:
        print(message.content)
        break
    messages.append(message)
    for call in message.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)})

Se você quer que a resposta apareça token por token, combine isso com streaming em Python.

Por que o MiniMax-M2.7 é adequado para ciclos de ferramentas#

Um ciclo de ferramentas envia muitas requisições com um histórico crescente. Para esse padrão, a CheapTokens oferece o MiniMax-M2.7: contexto de 180K, até 8.192 tokens de saída por resposta, um preço a qualquer hora do dia sem horários de pico e um saldo para todos os modelos. Entrada e saída contadas juntas, é mais barato que o preço de referência do OpenRouter (comparação de preços da CheapTokens, verificada em 31 de outubro de 2026).

Preços atuais por 1M de tokens: entrada $0.05, saída $0.15. Como exemplo de carga de trabalho (não uma medição), a ida e volta de duas requisições acima com cerca de 2.700 tokens de entrada e 350 de saída no total custa $0.00019. A lista completa de preços está na página de preços.

Para experimentar outro modelo, mude apenas o id; a lista de ids está na página de modelos.

Se não funcionar#

  • message.tool_calls é None. O modelo respondeu em texto. Torne a função description mais específica e certifique-se de que a pergunta realmente precisa da função.
  • json.JSONDecodeError em arguments. O modelo produziu JSON inválido. Envolva json.loads em try/except e envie o texto do erro de volta como resultado da ferramenta, para que o modelo possa tentar novamente com argumentos corrigidos.
  • A segunda requisição falha ou o modelo ignora o resultado. Verifique se cada chamada tem exatamente uma mensagem role: tool com um tool_call_id correspondente e se a mensagem do assistente com tool_calls está no histórico antes delas.
  • KeyError em FUNCTIONS[...]. O modelo nomeou uma função que você não registrou. Retorne uma string de erro curta como resultado da ferramenta em vez de travar.
  • A resposta está cortada. Verifique finish_reason: o valor length significa que o limite de tokens de saída foi atingido. Veja por que uma resposta de IA para no meio da frase.
  • 401 ou erros de autenticação. Verifique se a chave está em CHEAPTOKENS_API_KEY e se a URL base termina com /v1.

Próximos passos#

Substitua o stub por uma função real: uma consulta ao banco de dados, uma chamada de busca ou uma calculadora. Adicione mais entradas a tools e a FUNCTIONS, e mantenha todo resultado de função curto, porque ele volta para o histórico em cada requisição seguinte. Para obter uma chave e fazer a primeira chamada, abra a documentação da CheapTokens.