Torna al blog

Ottimizzazione dei costiGuida

Da linguaggio naturale a comando shell con un'API LLM: JSON e costo

Uno script Python che chiede a un modello economico un comando shell come JSON, rifiuta o segnala le richieste incerte, non esegue mai nulla e calcola il prezzo di 1.000 richieste.

Di CheapTokens TeamPubblicato il 7 min di lettura

Una richiesta in linguaggio naturale trasformata in un comando shell in un oggetto JSON con i tipi command, refuse e unsure
In questa pagina
  1. Un compito ristretto: perché la risposta è breve
  2. Il formato della risposta: comando, rifiuto o incertezza
  3. Lo script
  4. Quanto costano 1.000 richieste
  5. Verificalo sulle tue richieste

Chiedi al modello un singolo oggetto JSON con tre campi (type, command, explanation), limita la risposta a un paio di centinaia di token e stampa il comando invece di eseguirlo. In termini di token, una richiesta così è quasi tutta prompt con una risposta breve e prevedibile: con le ipotesi qui sotto, 1.000 di queste costano $0.012 su DeepSeek-V4-Flash.

Immagina di aggiungere una casella "descrivi cosa vuoi" a una CLI interna. Qualcuno scrive trova i file più grandi di 100 MB nella mia cartella home, e tu vuoi indietro una riga che possa leggere, controllare e incollare. Seguono due domande: come impedisci al modello di tirare a indovinare o di fare qualcosa di pericoloso, e quanto costa quando cento persone lo usano tutto il giorno?

Un compito ristretto: perché la risposta è breve#

Il 9 novembre 2026 un canale Telegram ha riproposto la model card di dale-0.8b, un modello aperto che fa esattamente questo unico lavoro. Secondo la model card su Hugging Face (verificata il 10 novembre 2026), dale-0.8b è un full fine-tune di Qwen3.5-0.8B sotto Apache-2.0 che trasforma una richiesta in spagnolo o inglese in un singolo comando bash Linux. L'autore, Manuel García, riporta il 79,4% (374 casi su 471) sul proprio test set, contro il 62,8% di Qwen3.5-9B base e di Gemma 4 E4B-it senza fine-tuning. Sono numeri auto-dichiarati su un test set di una sola persona, quindi trattali come un dato, non come una classifica.

Ciò che ci è utile è la forma del compito, non il modello. La card descrive un system prompt fisso, una riga di contesto (OS, distro, package manager, strumenti) più la richiesta, il thinking disattivato e una risposta limitata a 200 token. Quel limite è una delle due leve sul costo: quando la risposta è un breve oggetto JSON, il lato output è breve e prevedibile, perché il limite lo contiene. L'altra leva è il prompt. Quale quota del conto spetti a ciascun lato lo mostra la tabella qui sotto; varia da modello a modello.

Non ti serve un modello da 0.8B per questo. Lo stesso formato funziona su qualsiasi modello API, ed è ciò che costruisce il resto di questo articolo.

Il percorso di una richiesta: prompt in ingresso, JSON in uscita, decide una persona
Il flusso della richiesta nello script: nulla viene eseguito finché non lo fai tu stesso.

Il formato della risposta: comando, rifiuto o incertezza#

Il trucco è che il modello ha sempre un modo legittimo per dire "no". La risposta è un solo oggetto:

json
{"type": "command | refuse | unsure", "command": "...", "explanation": "..."}
  • command: un comando bash, più una spiegazione di una frase su cosa fa.
  • refuse: la richiesta è distruttiva o non ha nulla a che fare con la shell. Nessun comando.
  • unsure: la richiesta è troppo vaga ("pulisci il mio disco"). La spiegazione contiene una domanda di chiarimento.

Senza unsure, una richiesta vaga obbliga a tirare a indovinare, e un rm indovinato è quello che ti ricordi. Il formato della card ha gli stessi tre tipi; riusiamo l'idea, non il modello.

Abbina le coppie

Abbina ogni tipo di risposta a ciò che lo script deve fare

  • commandMostra il comando e la spiegazione; la persona lo copia e lo esegue da sola
  • refuseStampa la spiegazione e non offrire nulla da eseguire
  • unsureStampa la domanda e lascia che l'utente la riformuli

Lo script#

Un file, il pacchetto openai, chiave in una variabile d'ambiente. La base URL e l'id completo del modello vengono dai documenti di CheapTokens; gli id brevi non sono accettati, quindi usa deepseek-ai/DeepSeek-V4-Flash-0731.

python
import json
import os
import sys

from openai import OpenAI

client = OpenAI(
    base_url='https://api.cheaptokens.dev/v1',
    api_key=os.environ['CHEAPTOKENS_API_KEY'],
)
MODEL = 'deepseek-ai/DeepSeek-V4-Flash-0731'

SYSTEM = '''You turn a request into ONE Linux bash command.
Reply with a single JSON object and nothing else:
{"type": "command" | "refuse" | "unsure", "command": "<one command, or empty>", "explanation": "<one short sentence>"}
Use "refuse" when the request is destructive or not about the shell.
Use "unsure" when it is too vague, and put a clarifying question in "explanation".'''

CONTEXT = 'os: Ubuntu 24.04; package manager: apt; tools: git, curl, jq'


def parse(text):
    start = text.find('{')
    if start == -1:
        return None
    try:
        obj, _ = json.JSONDecoder().raw_decode(text[start:])
    except json.JSONDecodeError:
        return None
    if not isinstance(obj, dict) or obj.get('type') not in ('command', 'refuse', 'unsure'):
        return None
    return obj


def ask(request):
    resp = client.chat.completions.create(
        model=MODEL,
        max_tokens=200,
        temperature=0,
        messages=[
            {'role': 'system', 'content': SYSTEM},
            {'role': 'user', 'content': f'Context: {CONTEXT}\nRequest: {request}'},
        ],
    )
    return parse(resp.choices[0].message.content), resp.usage


if __name__ == '__main__':
    result, usage = ask(' '.join(sys.argv[1:]))
    if result is None:
        print('Could not read the reply as JSON. Try again.')
    elif result['type'] == 'command':
        print(result['explanation'])
        print('\n    ' + result['command'] + '\n')
        print('Read it, then copy it yourself. This script never runs it.')
    else:
        print(f"[{result['type']}] {result['explanation']}")
    print(f'tokens: {usage.prompt_tokens} in, {usage.completion_tokens} out')

Eseguilo come python shellhelp.py find files bigger than 100 MB in my home folder. Tre scelte contano qui:

  • Nessun subprocess da nessuna parte. Il comando è testo sullo schermo. Eseguirlo è una tua decisione, dopo averlo letto.
  • max_tokens=200, come il limite della card. Un oggetto JSON ci sta comodamente; una risposta prolissa viene tagliata a 200 token invece di continuare a tue spese. Il limite si applica all'intera risposta, quindi se un modello scrive il suo ragionamento, questo può consumare il limite. Se una risposta termina con finish_reason uguale a length, alza un po' il limite. Ne parliamo in ridurre i token di output con max_tokens.
  • Il formato è richiesto nel prompt, poi analizzato in modo difensivo. raw_decode salta un code fence vagante o una frase prima del {. Se vuoi spingerti oltre, vedi JSON valido da un'API compatibile con OpenAI e la soluzione per json.JSONDecodeError su una risposta.

Prima di eseguire qualsiasi cosa, verifica che l'ordine dei passaggi sia chiaro:

Metti in ordine

Metti in ordine corretto i passaggi dello script

  1. Costruisci il prompt: testo di sistema fisso, una riga di contesto, la richiesta
  2. Chiama l'API con un max_tokens piccolo
  3. Analizza il JSON e verifica che type sia uno dei tre
  4. Mostra il comando e attendi che la persona lo esegua

Quanto costano 1.000 richieste#

L'ultima riga dello script stampa usage. Quello è il numero reale, e dovresti leggere il tuo. Finché non ce l'hai, lavora con un'ipotesi: il prompt arriva a circa 400 token di input (il prompt nudo nello script è all'incirca 150 token a un conteggio approssimativo; il resto è spazio per le tre o quattro coppie di esempio richiesta-e-risposta che probabilmente aggiungeresti), e la risposta JSON a circa 60 token di output.

Per 1.000 richieste sono 400 × 1.000 = 400.000 token di input e 60 × 1.000 = 60.000 token di output. La tabella prezza esattamente questo per ogni modello del catalogo, con la colonna OpenRouter accanto; le cifre provengono da prezzi live, quindi restano aggiornate.

Modello Per richiesta 1000 richieste OpenRouter, 1000 richieste
GLM-5.3-Flash $0.00001 $0.0104 $0.0184
DeepSeek-V4-Flash $0.000012 $0.012 $0.0364
MiniMax-M2.7 $0.000029 $0.029 $0.348

400 token di input e 60 token di output per richiesta. I prezzi per 1M di token sono attuali e cambiano insieme alle nostre tariffe; la colonna OpenRouter mostra i prezzi di riferimento per lo stesso carico di lavoro.

In totale, contando insieme input e output, DeepSeek-V4-Flash risulta più economico di OpenRouter per questo carico di lavoro. In termini di token la richiesta è quasi tutta input e la risposta è breve, ma entrambi i lati vengono fatturati, quindi riduci sia il prompt sia la risposta. I prezzi per modello sono sulla pagina dei prezzi, e il modello stesso è descritto su la pagina DeepSeek: contesto da 380K, fino a 32.768 token di output, un unico prezzo a qualsiasi ora.

Un modo rapido per percepire le proporzioni:

Verifica rapida

Quale parte della richiesta limita max_tokens=200?

Mostra risposta

Risposta: La risposta

max_tokens limita solo la risposta; il prompt viene fatturato così com'è, quindi riducilo separatamente.

Vuoi 100.000 richieste al mese? Moltiplica per 100: 40.000.000 di input e 6.000.000 di token di output. Inserisci quei due numeri in ::cost allo stesso modo e leggi la riga.

Verificalo sulle tue richieste#

Il 79,4% della card non dice nulla sul tuo prompt, sul tuo OS o sulle parole dei tuoi utenti. Scrivi 20 richieste reali con i comandi che accetteresti e confronta, esattamente come in testare un prompt su un piccolo set di eval. Includine alcune che lo script dovrebbe rifiutare o segnalare come incerte, come "cancella tutto" o "rendi più veloce il mio computer".

Quando qualcosa va storto, il sintomo di solito indica la soluzione:

  • Could not read the reply as JSON: stampa una volta il testo grezzo. Un prefisso come "Sure!" viene gestito; una risposta tagliata dal limite no, quindi controlla finish_reason.
  • 401 o 404: chiave, base URL o id del modello sbagliati. L'elenco è in API 401 o 404: chiave, base URL, id del modello.
  • Comandi adatti a un sistema diverso: la causa è la riga di contesto. Mantienila accurata (OS, package manager, strumenti); costa qualche decina di token e risparmia un apt sbagliato su una macchina Fedora.

Stesso compito, modello diverso? Sostituisci MODEL con l'id GLM o MiniMax dai documenti, mantieni il prompt e confronta i conteggi di token che lo script stampa con la tabella qui sopra.