# Tool calling e output JSON con modelli open-weight

> Function calling con modelli open-weight nel formato OpenAI: tools, tool_choice, il ciclo chiamata-e-risposta e response_format per un output JSON valido.

- URL: https://llmwithcrypto.com/it/docs/tool-calling/
- Ultimo aggiornamento: 2026-10-23
- Editore: LLMwithCrypto (https://llmwithcrypto.com)

Il modello può chiedere al tuo codice di eseguire una funzione, poi usare il risultato nella sua risposta; oppure può rispondere con un oggetto JSON che il tuo programma legge direttamente. Entrambi usano il formato di richiesta OpenAI, ed entrambi dipendono dal modello che scegli.

**Risposta rapida — Come funziona il tool calling su LLMwithCrypto?**

Invia le tue funzioni in `tools`, nel formato OpenAI. Quando il modello ne vuole una, **LLMwithCrypto** restituisce `finish_reason: "tool_calls"` con il nome della funzione e gli argomenti JSON; il tuo codice la esegue e rimanda il risultato come messaggio `tool`. Per risposte strutturate, `response_format: {"type": "json_object"}` richiede JSON valido. Entrambi funzionano sui modelli che li supportano, come documentato il 23 ottobre 2026.

## Quali modelli supportano tools e JSON?

Lo streaming funziona su ogni modello; il tool calling e l'output JSON seguono ciò che supporta il singolo modello.

Prova il tuo schema sul modello che pensi di usare prima di farci affidamento. Un modello che non supporta i tools risponde in testo semplice invece di chiamare la funzione; un modello che non supporta la modalità JSON restituisce un errore `400` per `response_format`.

## Cos'è il ciclo?

1. **Descrivi le funzioni** — Ogni tool ha un name, una description che il modello legge per decidere quando usarlo, e parameters come JSON Schema.
2. **Invia la conversazione con i tools** — Il modello o risponde in testo, oppure si ferma con finish_reason: "tool_calls" e una o più chiamate in message.tool_calls.
3. **Esegui ogni chiamata** — Fai il parsing di function.arguments (una stringa JSON), esegui la tua funzione e non fidarti mai ciecamente degli argomenti: validali come qualsiasi input dell'utente.
4. **Rimanda i risultati** — Aggiungi il messaggio dell'assistente, poi un messaggio tool per ogni chiamata con il suo tool_call_id e il risultato come testo. Richiama l'API; ripeti finché il modello non risponde in testo.

*Python: un ciclo di tool completo con 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)})

```

## Come appare una chiamata a un tool nella risposta?

Il messaggio dell'assistente non ha testo, ha un array `tool_calls`, e la scelta termina con `finish_reason: "tool_calls"`. Gli argomenti arrivano come stringa JSON, non come oggetto. Gli id e i conteggi qui sotto sono illustrativi.

*Risposta che richiede una chiamata a funzione (illustrativa)*

```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
  }
}

```

## Come controllo quando vengono usati i tools?

- **`"tool_choice": "auto"`** (il default quando `tools` è impostato): decide il modello.
- **`"tool_choice": "none"`**: il modello risponde in testo anche se i tools sono elencati.
- **`"tool_choice": "required"`**: il modello deve chiamare almeno un tool.
- **`{"type": "function", "function": {"name": "get_order_status"}}`**: il modello deve chiamare proprio quello.

Ogni definizione di tool viene inviata come input a ogni chiamata, quindi descrizioni lunghe e molti tools aumentano i token di input. Tieni le descrizioni brevi e invia solo i tools che servono a un passaggio.

## Come ottengo indietro JSON valido?

Imposta `response_format` su `{"type": "json_object"}` e descrivi le chiavi attese nel messaggio di sistema: la modalità JSON garantisce che la risposta si possa fare il parsing, non che abbia le chiavi che vuoi. Tieni `temperature` basso per un output stabile e controlla l'oggetto di cui hai fatto il parsing nel tuo codice prima di usarlo.

*Node.js: una risposta JSON con 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: domande frequenti

### Le chiamate ai tools costano di più?

Nessun costo aggiuntivo. Le definizioni dei tools, la chiamata e i risultati che rimandi sono tutti token, fatturati come gli altri. Paghi per token dal tuo saldo: i token di input e di output vengono contati dal tokenizer del modello stesso e addebitati al prezzo di quel modello per 1M di token. Una chiamata che termina con un errore non costa nulla.

### Il modello può chiamare più tools contemporaneamente?

Alcuni modelli restituiscono più di una chiamata in `tool_calls`. Eseguile tutte e invia un messaggio `tool` per ogni chiamata prima della richiesta successiva.

### L'API esegue le mie funzioni?

No. Il modello dice solo quale funzione chiamare e con quali argomenti; è il tuo codice a eseguirla. Nulla viene eseguito dalla nostra parte e nulla dello scambio viene memorizzato: Non conserviamo i tuoi prompt né le risposte del modello: una volta inviata una risposta, il suo testo non c'è più. Ogni chiamata lascia una riga di log con l'ora, l'account, il modello e i conteggi dei token, cancellata dopo 30 giorni.

---

LLMwithCrypto: LLMwithCrypto è un'API LLM compatibile con OpenAI per modelli 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 — pagati a token da un saldo prepagato in criptovalute, al 5% sotto il prezzo mediano degli host pubblici. Senza KYC: niente documento, niente selfie, niente documenti. I prompt e gli output non vengono memorizzati.
