Il fine-tuning è l’ultima leva, non la prima. La documentazione lo colloca dove il prompt engineering diventa insostenibile — messaggi di sistema che crescono a forza di esempi, token e latenza che salgono — oppure dove servono uno stile costante, un formato di output rigido, un uso più affidabile dei tool, o un modello piccolo che faccia il lavoro di uno grande. Non sostituisce il recupero: la combinazione documentata è addestrare il modello a usare bene i dati recuperati filtrando quelli irrilevanti. E soprattutto non è un evento isolato: dal momento in cui si specializza un modello nasce un secondo ciclo di vita da gestire, con dataset, versioni, deployment e scadenze proprie.

I metodi, e quando ciascuno ha senso

Microsoft Foundry documenta tre tecniche. Il supervised fine-tuning (SFT) addestra su un dataset etichettato in cui ogni esempio ha la risposta corretta: funziona meglio quando i modi giusti di risolvere il problema sono pochi e definiti, e si vuole insegnare un compito specifico migliorando accuratezza e concisione. Il reinforcement fine-tuning (RFT) ottimizza il comportamento in ambienti complessi o dinamici tramite feedback iterativo: un grader premia il modello in modo incrementale, ed è la scelta indicata quando i modi validi di risolvere il problema sono molti e ciò che va migliorato è la qualità del ragionamento. La direct preference optimization (DPO) allinea il modello a preferenze umane fornendo nel training set la risposta preferita e quella non preferita; a differenza di RLHF non richiede di addestrare un reward model, quindi è più leggera e veloce. Le tecniche si impilano: prima SFT per il compito, poi DPO per allineare lo stile delle risposte. A parte, la distillazione usa gli output di un modello grande per specializzare un modello piccolo, per esempio raccogliendo traffico di produzione da un modello di punta e addestrando con quello un modello più economico, riducendo costo e latenza.

Sul piano operativo il dataset è JSONL in formato chat; il campo weight a 0 o 1 permette di escludere singoli messaggi assistant dal calcolo della loss nelle conversazioni multi-turno. Il servizio accetta anche una decina di esempi, ma la pratica documentata parla di centinaia o migliaia di esempi di alta qualità. Gli iperparametri principali sono n_epochs, batch_size, learning_rate_multiplier e seed — quest’ultimo serve alla riproducibilità, che per un MLOps engineer è il punto: stesso seed, stessi parametri, stesso risultato.

response = client.fine_tuning.jobs.create(
    training_file=training_file_id,
    validation_file=validation_file_id,
    model="gpt-4.1-2025-04-14",
    suffix="support-it",
    seed=105,
    method={
        "type": "supervised",
        "supervised": {"hyperparameters": {"n_epochs": 2}},
    },
)

Dati sintetici senza amplificare gli errori

Il servizio di data generation di Microsoft Foundry produce dataset versionati e, nella stessa esperienza, li marca come destinati alla valutazione oppure al fine-tuning. Ci sono due sorgenti, ed è importante saperle contrapporre. La generazione sintetica (anteprima) parte da tre tipi di sorgente combinabili: la definizione di un agente distribuito, un prompt inline che descrive il dominio o ne governa la difficoltà, e un file di riferimento caricato — una policy, una specifica, un export di knowledge base — che àncora le domande generate a contenuto reale. Serve quando non esiste ancora traffico di produzione, quando il traffico è troppo scarso per estrarne campioni distinti, o quando si vogliono coprire casi limite e costruire una baseline di regressione stabile.

La generazione dalle tracce parte invece dalle tracce che l’agente già emette e applica l’intelligent sampling: scarta le tracce senza segnale (messaggi di un carattere e simili), seleziona con MinHash un campione diverso e rappresentativo invece di concentrarsi sui prompt quasi identici più frequenti, e gestisce i contenuti sensibili. Le due strade sono complementari, non alternative: il sintetico copre il prelancio e i casi limite, le tracce riflettono il comportamento reale.

Le regole per non amplificare gli errori sono documentate come best practice. Si fissa la versione dell’agente da cui si prelevano le tracce, altrimenti il job mescola versioni e comportamenti obsoleti. Si controlla sempre quante righe sono state davvero generate, perché il massimo richiesto è un tetto e non una garanzia: il campionamento rimuove duplicati e tracce di bassa qualità. Si parte da un lotto piccolo, si rivedono le righe a mano e solo dopo si sale. Si rigenera il dataset quando cambiano le istruzioni, perché un set nato da un prompt diverso invecchia. E resta la regola generale: dati non rappresentativi o di scarsa qualità producono overfitting, underfitting o bias nel modello specializzato.

Monitorare e ottimizzare il modello specializzato

Durante l’addestramento le metriche da leggere sono train_loss e train_mean_token_accuracy per batch, full_valid_loss e full_valid_mean_token_accuracy a fine epoca, tutte disponibili anche nel file results.csv a job concluso. Il quadro sano è loss che scende e accuratezza che sale; se la curva di training e quella di validazione divergono, si sta facendo overfitting. A ogni epoca viene prodotto un checkpoint distribuibile e restano disponibili le versioni più recenti, quindi un modello leggermente sovra-addestrato non impone di ripartire da zero: si distribuisce il checkpoint precedente.

Dopo il rilascio, il modello specializzato si tratta come qualunque altro: valutazioni ricorrenti sullo stesso dataset di riferimento, tracing e metriche di Azure Monitor su token, latenza e throughput, e allarmi sulle soglie. Una trappola specifica del fine-tuning: il messaggio di sistema usato in produzione deve essere lo stesso usato in addestramento, altrimenti il modello può comportarsi in modo inatteso. E una trappola economica: un deployment fatturato a ore costa anche quando non riceve traffico, mentre un deployment lasciato inattivo viene eliminato automaticamente dopo quindici giorni — il modello resta e si può ridistribuire.

Dal dev alla produzione, con le stesse regole degli altri

La promozione non merita un percorso speciale. Il job di fine-tuning si dichiara in un file YAML e si sottomette da riga di comando con l’estensione di fine-tuning dell’Azure Developer CLI (azd ai finetuning jobs submit, poi list, show, pause, resume, cancel e infine deploy), il che lo rende ripetibile dentro un workflow GitHub Actions autenticato con OpenID Connect.

permissions:
  id-token: write
  contents: read
jobs:
  train:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
      - run: azd ai finetuning jobs submit -f ./fine-tune-job.yaml

Per la valutazione esiste un tipo di deployment dedicato: Developer, SKU DeveloperTier, pensato solo per valutare modelli specializzati, senza garanzie di residenza dei dati né SLA e con una durata fissa di 24 ore, dopo le quali viene eliminato automaticamente. In produzione si usa un tipo standard o provisioned, con la logica di migrazione documentata in sei fasi — Discover, Assess, Adapt, Validate, Roll out, Retire — e il dataset di test preparato prima di iniziare. Il rollback è la vecchia regola del deployment affiancato: si tiene in piedi la versione precedente finché la nuova non ha dimostrato di reggere. Per ripulire, si elimina prima il deployment e poi il modello, mai il contrario.

Due fatti di ciclo di vita chiudono il quadro. Un modello specializzato si può riaddestrare partendo da sé stesso, passando il modello già personalizzato come base di un nuovo job. E i modelli fine-tuned hanno un ritiro in due fasi: il ritiro per l’addestramento, dopo il quale non si può più specializzare quel modello ma i modelli già addestrati restano distribuibili, e il ritiro per il deployment, dopo il quale sia l’inferenza sia la distribuzione restituiscono errore. Sono due date diverse, e vanno entrambe nel calendario.

Da ricordare per l esame

  • SFT quando i modi corretti di risolvere il problema sono pochi; RFT quando sono molti e conta la qualità del ragionamento, con un grader che premia in modo incrementale; DPO per allineare a preferenze, fornendo risposta preferita e non preferita. SFT e DPO si impilano in quest’ordine.
  • Il dataset è JSONL in formato chat; weight a 0 esclude un messaggio assistant dal training. Riproducibilità via seed, iperparametri n_epochs, batch_size, learning_rate_multiplier.
  • Dati sintetici e dati da tracce sono complementari: il sintetico copre prelancio ed edge case, le tracce con intelligent sampling riflettono il comportamento reale. Il numero massimo di campioni è un tetto, non una garanzia.
  • Il messaggio di sistema in produzione deve coincidere con quello usato in addestramento; divergenza fra loss di training e di validazione significa overfitting.
  • Il deployment DeveloperTier serve solo a valutare un modello fine-tuned, dura 24 ore e non ha SLA né garanzie di residenza; i modelli specializzati hanno due ritiri distinti, uno per l’addestramento e uno per il deployment.