modulo 07 / lezione 35

Agenti, tool use, integrazione

Integrare LLM in un'app: pattern di architettura

Conoscere i pattern ricorrenti per integrare un LLM senza incollarlo in modo fragile a tutto il sistema.

60 minPrompt Engineering

Integrare LLM in un’app: pattern di architettura

Integrare un LLM in un’app non significa chiamare un’API dal controller e incollare la risposta nella UI. Significa introdurre una dipendenza probabilistica dentro un sistema che ha bisogno di confini, contratti, fallback, osservabilità e test.

Il prompt è una parte dell’architettura. Non deve vivere disperso in stringhe anonime, componenti UI o job schedulati senza versione.

Perché questa lezione conta

La fragilità delle feature LLM nasce spesso dall’architettura, non dal modello. Prompt duplicati in più file, schema non validati, log assenti, fallback improvvisati, chiamate sincrone lunghe, tool troppo potenti, dati sensibili nei trace.

Questa lezione mostra pattern semplici per tenere separati prompt, logica applicativa, provider, valutazione e osservabilità.

Obiettivo operativo

Alla fine della lezione devi saper disegnare l’architettura minima di una feature LLM-driven, decidendo dove vivono prompt, template, schema, provider adapter, eval, cache e log.

Pattern: LLM gateway

Un gateway centralizza le chiamate ai modelli:

app feature -> llm gateway -> provider adapter -> modello

Il gateway gestisce:

  1. scelta modello;
  2. parametri;
  3. limiti input/output;
  4. retry e fallback;
  5. logging;
  6. redazione dati;
  7. metriche costo/latenza;
  8. versione prompt.

Senza gateway, ogni feature inventa la propria integrazione e i comportamenti divergono.

Pattern: prompt template service

I prompt dovrebbero essere template versionati, non stringhe sparse.

prompts/
  summarize-ticket/
    v1.md
    v2.md
    schema.json
    eval-cases.jsonl

Il codice passa variabili al template:

{{ticket_title}}
{{ticket_body}}
{{customer_plan}}
{{language}}

Il template dichiara quali variabili richiede. Il runtime valida che siano presenti e redatte quando necessario.

Pattern: output contract

Ogni feature dovrebbe sapere se accetta testo libero o output strutturato.

Per UI editoriali può bastare testo. Per automazioni serve contratto:

{
  "category": "bug|question|billing|security",
  "priority": "low|normal|high|urgent",
  "confidence": 0.0,
  "needs_human_review": true,
  "rationale_short": "string"
}

Il codice valida lo schema prima di usare l’output. Se non è valido, non prova a “capire lo stesso” con parsing fragile: chiede riparazione, usa fallback o manda a revisione.

Pattern: evaluator

Un evaluator è un componente separato che misura prompt e output. Non deve stare mescolato alla feature.

prompt version -> eval dataset -> run -> report -> decisione

Serve per confrontare modelli, cambiare template, ridurre costi o controllare regressioni prima del rollout.

Pattern: queue per richieste lente

Non tutte le feature LLM devono essere sincrone. Se il task richiede molti file, tool multipli o output lungo, una coda è spesso più adatta:

  1. l’utente invia richiesta;
  2. il sistema crea job;
  3. worker esegue chiamate LLM;
  4. stato e progress vengono aggiornati;
  5. l’utente riceve risultato o notifica.

Questo evita timeout UI e permette retry controllati.

Pattern: cache

La cache può ridurre costi, ma va usata con cautela:

  1. chiave basata su prompt, variabili, modello e parametri;
  2. separazione per tenant o utente;
  3. TTL coerente con freschezza dei dati;
  4. esclusione per dati sensibili;
  5. invalidazione quando cambia versione prompt.

La cache non deve nascondere regressioni. Nei test e nelle eval va controllata o disattivata.

Confini di responsabilità

Una separazione sana:

UI. Raccoglie input, mostra stato, gestisce errore utente.

Application service. Decide il caso d’uso e prepara dati.

Prompt layer. Compone template e variabili.

LLM gateway. Esegue richiesta, applica policy, logga metriche.

Provider adapter. Traduce verso API specifica.

Evaluator. Misura qualità su dataset.

Observability. Traccia prompt version, costo, latenza, esito, fallback.

Questa separazione rende possibile cambiare provider o modello senza riscrivere la feature.

Laboratorio guidato

Scegli una feature LLM-driven:

  1. classificazione ticket;
  2. generazione descrizione prodotto;
  3. review automatica PR;
  4. assistente documentazione;
  5. estrazione dati da PDF.

Disegna il flusso con questi blocchi:

input -> redazione -> template -> modello -> validazione -> fallback -> output -> log/eval

Poi marca cosa è sincrono, cosa è asincrono, cosa è versionato e cosa richiede revisione umana.

Output atteso

Devi produrre un diagramma minimo con:

  1. componenti;
  2. confini;
  3. dati in ingresso;
  4. prompt e schema;
  5. tool o provider;
  6. punti di fallback;
  7. eventi di osservabilità;
  8. dataset di eval collegato.

Il diagramma deve essere abbastanza concreto da guidare un’implementazione.

Errori comuni

Prompt hardcoded nella UI. Rende difficile versionare, testare e riusare.

Output non validato. Se l’LLM guida logica applicativa, il contratto deve essere controllato.

Provider sparso nel codice. Cambiare modello diventa un refactor globale.

Nessun fallback. La feature funziona solo quando tutto va bene.

Nessuna osservabilità. Non puoi sapere perché costi, latenza o qualità cambiano.

Checklist di verifica

  • i prompt sono template versionati;
  • esiste un confine tra app e provider;
  • gli output strutturati sono validati;
  • richieste lente hanno una strategia asincrona;
  • costo, latenza, modello e prompt version sono tracciati.

Collegamenti

  • Modulo: Agenti, tool use, integrazione — questa lezione è la numero 35 del corso.
  • Prepara il modulo 8: prompt in produzione, osservabilità, rollout e governance.