# Tool calling e saída JSON com modelos open-weight

> Function calling com modelos open-weight no formato OpenAI: tools, tool_choice, o ciclo de chamada e resposta, e response_format para saída JSON válida.

- URL: https://llmwithcrypto.com/pt/docs/tool-calling/
- Última atualização: 2026-10-23
- Editor: LLMwithCrypto (https://llmwithcrypto.com)

O modelo pode pedir ao seu código para executar uma função e depois usar o resultado na resposta; ou pode responder com um objeto JSON que seu programa lê diretamente. Ambos usam o formato de requisição da OpenAI e ambos dependem do modelo que você escolher.

**Resposta rápida — Como o tool calling funciona no LLMwithCrypto?**

Envie suas funções em `tools`, no formato OpenAI. Quando o modelo quiser uma, **LLMwithCrypto** retorna `finish_reason: "tool_calls"` com o nome da função e os argumentos em JSON; seu código a executa e envia o resultado de volta como uma mensagem `tool`. Para respostas estruturadas, `response_format: {"type": "json_object"}` pede JSON válido. Ambos funcionam nos modelos que os suportam, conforme documentado em 23 de outubro de 2026.

## Quais modelos suportam tools e JSON?

O streaming funciona em todos os modelos; tool calling e saída em JSON seguem o que cada modelo suporta por si.

Teste seu próprio schema no modelo que você pretende usar antes de depender dele. Um modelo que não suporta tools responde em texto simples em vez de chamar a função; um modelo que não suporta o modo JSON retorna um erro `400` para `response_format`.

## O que é o ciclo?

1. **Descreva as funções** — Cada tool tem um name, uma description que o modelo lê para decidir quando usá-la, e parameters como JSON Schema.
2. **Envie a conversa com tools** — O modelo ou responde em texto, ou para com finish_reason: "tool_calls" e uma ou mais chamadas em message.tool_calls.
3. **Execute cada chamada** — Faça o parse de function.arguments (uma string JSON), execute sua função e nunca confie nos argumentos às cegas: valide-os como qualquer entrada do usuário.
4. **Envie os resultados de volta** — Anexe a mensagem do assistant e, depois, uma mensagem tool por chamada com seu tool_call_id e o resultado como texto. Chame a API de novo; repita até o modelo responder em texto.

*Python: um ciclo de tools completo com gpt-oss-120b*

```python
import json
import os

from openai import OpenAI

client = OpenAI(
    base_url="https://llmwithcrypto.com/api/v1",
    api_key=os.environ["LLMWITHCRYPTO_API_KEY"],
)

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_order_status",
            "description": "Return the delivery status of an order.",
            "parameters": {
                "type": "object",
                "properties": {"order_id": {"type": "string"}},
                "required": ["order_id"],
            },
        },
    }
]


def get_order_status(order_id):
    return {"order_id": order_id, "status": "shipped", "eta": "2026-10-25"}


messages = [{"role": "user", "content": "Where is my order A-1042?"}]
while True:
    resp = client.chat.completions.create(model="gpt-oss-120b", messages=messages, tools=tools, max_tokens=300)
    msg = resp.choices[0].message
    if not msg.tool_calls:
        print(msg.content)
        break
    messages.append(msg)
    for call in msg.tool_calls:
        args = json.loads(call.function.arguments)
        result = get_order_status(**args)
        messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(result)})

```

## Como é uma chamada de tool na resposta?

A mensagem do assistant não tem texto, tem um array `tool_calls`, e a escolha termina com `finish_reason: "tool_calls"`. Os argumentos vêm como uma string JSON, não como um objeto. Os ids e contagens abaixo são ilustrativos.

*Resposta pedindo uma chamada de função (ilustrativa)*

```json
{
  "id": "chatcmpl-3c9d27e1",
  "object": "chat.completion",
  "created": 1792742400,
  "model": "gpt-oss-120b",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": null,
        "tool_calls": [
          {
            "id": "call_7f31",
            "type": "function",
            "function": {
              "name": "get_order_status",
              "arguments": "{\"order_id\": \"A-1042\"}"
            }
          }
        ]
      },
      "finish_reason": "tool_calls"
    }
  ],
  "usage": {
    "prompt_tokens": 118,
    "completion_tokens": 22,
    "total_tokens": 140
  }
}

```

## Como controlo quando as tools são usadas?

- **`"tool_choice": "auto"`** (o padrão quando `tools` está definido): o modelo decide.
- **`"tool_choice": "none"`**: o modelo responde em texto mesmo com tools listadas.
- **`"tool_choice": "required"`**: o modelo precisa chamar pelo menos uma tool.
- **`{"type": "function", "function": {"name": "get_order_status"}}`**: o modelo precisa chamar aquela tool específica.

Toda definição de tool é enviada como entrada em cada chamada, então descrições longas e muitas tools aumentam os tokens de entrada. Mantenha as descrições curtas e envie apenas as tools que cada etapa precisa.

## Como recebo JSON válido de volta?

Defina `response_format` como `{"type": "json_object"}` e descreva as chaves esperadas na mensagem de sistema: o modo JSON garante que a resposta faz parse, não que ela tem as chaves que você quer. Mantenha `temperature` baixo para uma saída estável e verifique o objeto após o parse no seu código antes de usá-lo.

*Node.js: uma resposta JSON com response_format*

```javascript
import OpenAI from 'openai';

const client = new OpenAI({
  baseURL: 'https://llmwithcrypto.com/api/v1',
  apiKey: process.env.LLMWITHCRYPTO_API_KEY,
});

const resp = await client.chat.completions.create({
  model: 'gpt-oss-120b',
  messages: [
    { role: 'system', content: 'Reply with a JSON object {"sentiment": "positive" | "negative" | "neutral", "reason": string}.' },
    { role: 'user', content: 'The delivery was late but support fixed it in an hour.' },
  ],
  response_format: { type: 'json_object' },
  temperature: 0.2,
  max_tokens: 150,
});
const result = JSON.parse(resp.choices[0].message.content);
console.log(result.sentiment, '-', result.reason);

```

## Tools e JSON: perguntas frequentes

### Chamadas de tool custam a mais?

Não há taxa própria. As definições de tool, a chamada e os resultados que você envia de volta são todos tokens, cobrados como quaisquer outros. Você paga por token a partir do seu saldo: tokens de entrada e de saída são contados pelo tokenizer do próprio modelo e cobrados ao preço daquele modelo por 1M de tokens. Uma chamada que termina em erro não custa nada.

### O modelo pode chamar várias tools ao mesmo tempo?

Alguns modelos retornam mais de uma chamada em `tool_calls`. Execute todas e envie uma mensagem `tool` por chamada antes da próxima requisição.

### A API executa minhas funções?

Não. O modelo apenas diz qual função chamar e com quais argumentos; seu código a executa. Nada é executado do nosso lado, e nada da troca é armazenado: Não armazenamos seus prompts nem as respostas do modelo: assim que uma resposta é enviada, o texto dela se vai. Cada chamada deixa uma linha de log com o horário, a conta, o modelo e as contagens de tokens, apagada após 30 dias.

---

LLMwithCrypto: O LLMwithCrypto é uma API de LLM compatível com OpenAI para modelos open-weight — DeepSeek V4 Pro, DeepSeek V4.1 Flash, DeepSeek R1, Qwen3.5 397B A17B, Qwen3 235B A22B Instruct, gpt-oss-120b, gpt-oss-20b, GLM-4.7, Llama 3.3 70B Instruct, Gemma 4 31B, Mistral Large 3, Mistral Small 4 — paga por token a partir de um saldo cripto pré-pago, a 5% abaixo do preço mediano dos hosts públicos. Sem KYC: sem documento de identidade, sem selfie, sem documentos. Prompts e respostas não são armazenados.
