CodeGym /Corsi /ChatGPT Apps /Strumenti dell'agente (Tools): schemi, instradamento, err...

Strumenti dell'agente (Tools): schemi, instradamento, errori

ChatGPT Apps
Livello 12 , Lezione 1
Disponibile

1. Lo strumento dell’agente: che cos’è davvero

Nei moduli precedenti avete già visto gli strumenti dal lato dell’Apps SDK — come «funzioni di backend» a cui ChatGPT accede tramite la vostra App. Ora cambiamo prospettiva: guardiamo agli strumenti con gli occhi di un agente nell’Agents SDK e vediamo come sceglie cosa invocare e cosa fare con gli errori.

Nel backend tradizionale siete abituati a pensare in termini di «endpoint», «metodo del controller», «funzione di servizio». Nel mondo degli agenti l’unità di azione di base diventa lo strumento (tool). I tools dell’agente e gli mcp-tools sono cose diverse, sebbene si sovrappongano.

Parlando con rigore: uno strumento nel contesto del ChatGPT Agents SDK è la descrizione di una funzione che il modello può chiedere di eseguire. Il modello non esegue il codice; genera una richiesta strutturata (di solito JSON) e il runtime (il vostro codice, il server MCP o l’Agents SDK) esegue l’operazione e restituisce il risultato.

Nell’ecosistema del ChatGPT Agents SDK uno strumento è descritto da una configurazione: ha un name, una description e dei parameters (JSON Schema degli argomenti). L’agente vede questo set di strumenti, li mantiene nel proprio contesto e durante il reasoning decide quale tool invocare e con quali argomenti.

L’agente (o ChatGPT come host) riceve questo elenco, lo «memorizza» nel suo contesto e nel processo di ragionamento (reasoning) decide: a quale richiesta dell’utente associare quale strumento e con quali argomenti. Per questo nelle specifiche viene ripetuto il mantra «tools are a contract» — gli strumenti sono un contratto tra il modello e il vostro codice, non semplicemente «una funzione in Python/TS».

Si può fare un’analogia con le API classiche. La route /api/gifts/search è puro sintassi: URL, metodo, formato del body. Un tool search_gifts è la semantica: «ricerca regali in base al profilo e al budget». La descrizione dello strumento è un prompt, ma strutturato e pensato per una LLM, non per una persona.

2. Tipi di strumenti: di cosa può occuparsi un LLM‑agent

Per non annegare nel caos di «funzioni che fanno tutto», è utile guardare agli strumenti come a qualche categoria tipica. Non è una tipizzazione formale dell’SDK, ma un modo di pensare architetturale che aiuta molto.

Nel nostro backend gli agenti LLM di solito hanno tre fonti di strumenti.

  • Strumenti business locali. Sono ciò che vive nel vostro backend: lavoro con il DB, logica di dominio (filtri, raccomandazioni, scoring). Per esempio, per GiftGenius possiamo avere strumenti che estraggono prodotti da una tabella PostgreSQL oppure calcolano uno scoring personalizzato «quanto piacerà questo regalo a questa persona».
  • Strumenti MCP. Qui il server MCP funge da fornitore di strumenti (tools): registra funzioni, risorse e prompt e li espone al client (ChatGPT, agente LLM). Gli strumenti tramite MCP possono chiamare API esterne, lavorare con file o fornire template di prompt.
  • Strumenti di integrazione. Tutto ciò che vi collega al resto del mondo: ACP/commerce (creazione ordine e checkout), invio email, webhook, scrittura nel CRM. Questi strumenti (tools) sono spesso più pericolosi, perché modificano lo stato di sistemi esterni, e vanno trattati con particolare attenzione per sicurezza e idempotenza.

Esiste anche un’altra classificazione utile — per natura dell’azione. Nella ricerca sugli strumenti LLM si distinguono di solito: strumenti di recupero dati (ricerca, RAG, get_*), strumenti d’azione con effetti collaterali (create_order, send_email), puramente computazionali (calculate_loan) e di sistema/controllo (handoff_to_human, finish_task).

Per fissare le idee, è comodo guardare una piccola tabella.

Categoria Esempio in GiftGenius Effetto collaterale Rischio
Data Retrieval
search_gifts, get_details
No Basso
Action / Mutating
create_order, buy_gift
Alto
Computation
estimate_delivery_cost
No Medio
System / Control
finish_recommendation
No Logico

Dal punto di vista architetturale la cosa più importante: gli strumenti read‑only devono essere numerosi ed economici, mentre quelli che modificano lo stato — rari, estremamente accurati, con log, idempotenza e spesso con conferma dell’utente.

D’ora in poi parleremo soprattutto di strumenti di recupero dati e strumenti di tipo Action, perché su questi si costruisce la logica di GiftGenius.

3. JSON Schema come contratto tra il modello e il tuo codice

Approfondiamo come viene descritto uno strumento. Nel ChatGPT Agents SDK (come anche nell’Apps SDK) il formato standard per descrivere i parametri di uno strumento è JSON Schema: descrivete un tipo object, le sue properties, i tipi dei campi, i campi obbligatori, i vincoli e così via.

È importante capire: JSON Schema qui non è solo (e non tanto) per la validazione. È parte del prompt per il modello. Nelle guide ufficiali OpenAI sulla progettazione degli strumenti (tools) si afferma esplicitamente che la qualità del lavoro dell’agente dipende molto da quanto in modo dettagliato e univoco sono descritti i campi, i loro nomi e i commenti.

Vediamo un esempio per GiftGenius, già comparso nel piano del corso.

{
  "name": "search_gifts",
  "description": "Trova regali in base al tipo di destinatario, agli interessi e al budget.",
  "parameters": {
    "type": "object",
    "properties": {
      "recipient_type": {
        "type": "string",
        "description": "Chi è il destinatario del regalo (ad esempio, 'uomo', 'donna', 'bambino')."
      },
      "interests": {
        "type": "array",
        "items": { "type": "string" },
        "description": "Interessi chiave (sport, libri, tecnologia, ecc.)."
      },
      "budget": {
        "type": "number",
        "description": "Budget massimo nella valuta dell’utente."
      }
    },
    "required": ["recipient_type", "budget"]
  }
}

Qui ci sono alcuni punti importanti.

  • Primo, name e description. Per il modello è il segnale principale su quando usare questo strumento. La documentazione sull’instradamento semantico sottolinea che la descrizione dello strumento è di fatto un’API per il modello: se lo chiamate func1 e scrivete «fa qualcosa di utile», il modello onestamente non capirà quando invocarlo. Se invece scrivete search_gifts e aggiungete una descrizione chiara, la scelta diventa più ovvia.
  • Secondo, i parameters. I nomi dei campi e le loro descrizioni sono fondamentali. Per una LLM recipient_type è molto più chiaro di type. Una buona descrizione come «Chi è il destinatario…» suggerisce al modello che qui va inserito il tipo di destinatario, non, per esempio, il tipo di confezione.
  • Terzo, required. Non è solo validazione lato vostro, ma anche un suggerimento al modello: proverà a compilare i campi obbligatori e tralascerà quelli opzionali se non chiari dal contesto. Questo riduce il numero di invocazioni del tool «vuote» o non corrette.

Le guide ufficiali dell’Apps SDK raccomandano: fate strumenti ristretti, con una sola responsabilità, con nomi e descrizioni chiare, ed evitate strumenti «fai tutto per i regali» che cercano di unire compiti diversi.

4. Progettiamo gli strumenti di GiftGenius: dallo schema al codice

Prendiamo GiftGenius e aggiungiamo due strumenti chiave dell’agente LLM, che serviranno quasi in tutti gli scenari:

  • suggest_gifts(profile, budget) — restituisce una lista di candidati;
  • get_gift_details(gift_id) — mostra i dettagli di un regalo specifico.

I nostri suggest_gifts e get_gift_details sono il classico esempio di strumenti business locali della precedente classificazione, per lo più della categoria Data Retrieval.

Schema per suggest_gifts

Partiamo da un JSON Schema «pulito», poi mostriamo come potrebbe apparire nel codice TypeScript del backend/runtime dell’agente.

{
  "name": "suggest_gifts",
  "description": "Seleziona una lista di regali in base al profilo del destinatario e al budget.",
  "parameters": {
    "type": "object",
    "properties": {
      "age": {
        "type": "integer",
        "minimum": 0,
        "maximum": 120,
        "description": "Età del destinatario in anni."
      },
      "relationship": {
        "type": "string",
        "enum": ["friend", "coworker", "partner", "family"],
        "description": "Relazione con il destinatario: amico, collega, partner, famiglia."
      },
      "interests": {
        "type": "array",
        "items": { "type": "string" },
        "description": "Interessi del destinatario (sport, libri, tecnologia, ecc.)."
      },
      "budget": {
        "type": "number",
        "minimum": 1,
        "description": "Budget massimo nella valuta dell’utente."
      }
    },
    "required": ["budget"]
  }
}

Qui usiamo un enum per relationship, così il modello non inventa stringhe arbitrarie tipo "collega cattivo" e non le fa scorrere nel codice. Un design di schema accurato aiuta sia il modello (vede le opzioni ammesse), sia lo sviluppatore (meno sorprese a runtime).

Ora immaginiamo di avere un server MCP su Node.js con un ipotetico McpServer. La registrazione dello strumento può apparire così:

// esempio semplificato di registrazione di uno strumento nel server MCP
server.registerTool(
  {
    name: "suggest_gifts",
    description: "Seleziona regali in base al profilo e al budget.",
    inputSchema: suggestGiftsSchema
  },
  async (input, ctx) => {
    const gifts = await findGiftsInDb(input, ctx.userLocale);
    return { items: gifts }; // JSON che poi vedrà l'agente
  }
);

Il codice è molto semplificato, ma la logica è chiara: in un punto — la descrizione del contratto (nome, descrizione, schema), in un altro — l’implementazione.

Schema per get_gift_details

Il secondo strumento, utile quasi in ogni vetrina:

{
  "name": "get_gift_details",
  "description": "Ottiene tutte le informazioni sul regalo tramite il suo identificatore.",
  "parameters": {
    "type": "object",
    "properties": {
      "gift_id": {
        "type": "string",
        "description": "UUID del regalo nel database GiftGenius."
      }
    },
    "required": ["gift_id"]
  }
}

E una registrazione analoga:

server.registerTool(
  {
    name: "get_gift_details",
    description: "Restituisce informazioni dettagliate sul regalo.",
    inputSchema: getGiftDetailsSchema
  },
  async ({ gift_id }) => {
    const gift = await db.gifts.findById(gift_id);
    if (!gift) return { notFound: true };
    return { gift };
  }
);

Notate: qui mostriamo subito che lo strumento può restituire notFound: true. Questi sono già i germi delle errori semantici (errori di business), di cui parleremo sotto. L’agente potrà vedere «regalo non trovato» e decidere: per esempio, provare un altro id o proporre all’utente di scegliere un altro prodotto.

5. Come l’agente sceglie quale strumento chiamare

Ora la parte più interessante: instradamento. In un’app web tradizionale il routing è rigido: URL → controller specifico. Nel mondo delle ChatGPT Apps e degli agenti, la scelta dello strumento è semantica e probabilistica.

Il ciclo ad alto livello può essere rappresentato così:

flowchart TD
  U[User message] --> M["Modello (agente)"]
  M -->|analisi della richiesta| C{Serve uno strumento?}
  C -->|no| T[Risposta testuale]
  C -->|sì| S[Scelta dello strumento]
  S --> K[Costruzione degli argomenti JSON]
  K --> R[Esecuzione dello strumento]
  R --> M2[Il modello vede il risultato]
  M2 --> T2[Risposta finale o passo successivo]

In ogni passaggio l’agente vede alcune cose:

  • Primo, le istruzioni di system (ruolo dell’agente, vincoli);
  • Secondo, la cronologia del dialogo;
  • E infine, l’elenco degli strumenti (tools) con i rispettivi name, description, inputSchema.

Quando arriva un nuovo messaggio dell’utente, il modello confronta il senso della richiesta con le descrizioni degli strumenti (matching semantico). Se la richiesta è «scegli un regalo per un amico fino a 50 dollari», la descrizione di suggest_gifts risulta molto più pertinente di get_gift_details, e l’agente con alta probabilità sceglierà proprio quello.

Le guide ufficiali sottolineano due aspetti che influiscono molto sulla qualità dell’instradamento.

  • Primo, evitare strumenti che si sovrappongono nel significato: se avete search_gifts e find_gifts descritti quasi allo stesso modo, il modello si confonderà.
  • Secondo, attenersi al principio della singola responsabilità per uno strumento: un tool — un compito chiaro, non «seleziona i regali e crea un ordine e invia una email».

All’interno dei vari agenti LLM esistono meccanismi per controllare la modalità di scelta degli strumenti: per esempio, «auto» (il modello decide da sé se serve uno strumento), «required» (obbligatorio chiamare un tool), «none» (tools disabilitati). Questo aiuta in workflow complessi (scenari multi‑step), quando, per esempio, in un certo passaggio volete forzare la chiamata di suggest_gifts e non permettere al modello di «chiacchierare».

Esempio di instradamento semantico in GiftGenius

Supponiamo che il nostro agente abbia almeno due strumenti: suggest_gifts e get_gift_details.

  1. L’utente scrive: «Scegli un regalo per un collega fino a 30 dollari, gli piacciono i giochi da tavolo».
  2. L’agente vede che la richiesta contiene l’obiettivo «selezionare un regalo», informazioni su budget e interessi. La descrizione di suggest_gifts è perfetta — invochiamo questo strumento.
  3. Lo strumento restituisce un elenco di cinque regali con i rispettivi id, nomi e una breve descrizione.
  4. L’utente prosegue: «Dimmi di più sulla terza opzione». L’agente associa «terza opzione» all’id dal risultato precedente e ora, per senso, è adatto lo strumento get_gift_details — viene invocato quello.

È importante notare: da nessuna parte nel codice avete scritto esplicitamente «se nella richiesta c’è la parola “scegli”, chiama suggest_gifts». Se ne occupa il modello in base alle vostre descrizioni e alla cronologia del dialogo. Vostra responsabilità, come sviluppatori, è rendere la scelta ovvia sia per il modello sia per l’essere umano.

6. Errori degli strumenti: non 500, ma segnali per il modello

Ricordate, in get_gift_details abbiamo già mostrato notFound: true? È proprio un esempio di errore di business, che l’agente deve vedere ed elaborare in modo sensato, invece di ricevere un nudo 500.

Ora la parte più dolente. In una REST‑API normale qualcosa è crollato nelle profondità del backend — si restituisce 500 Internal Server Error, si registra lo stack trace nel log — e poi l’utente se la cava. Nel caso di un agente questo approccio funziona male.

Guide pratiche e materiali sull’Agents SDK raccomandano di trattare gli errori degli strumenti come eventi osservabili, non semplici crash. Spesso è chiamato pattern «Error as Observation».

In poche parole, non dovete «andare in crash» senza spiegazioni; dovete restituire al modello una risposta strutturata che spieghi cos’è andato storto, in modo che possa adattare il proprio comportamento: riformulare la richiesta, chiedere all’utente, provare un altro strumento e così via.

Di solito si distinguono tre tipi di errori.

  • Errori di validazione degli argomenti. Il modello può generare parametri non corretti: omettere un campo obbligatorio, mettere una stringa al posto di un numero, uscire dai limiti validi. Qui il vostro schema e la validazione vanno usati non solo per lanciare eccezioni, ma per risposte sensate: per esempio, restituire quale campo è errato e perché.
  • Errori di business. Situazioni previste come «prodotto non trovato», «regione non disponibile», «budget troppo basso per questo tipo di regali». Dal punto di vista dell’API sono errori, ma vanno restituiti all’interno di una risposta normale — con un codice e un messaggio comprensibili, non come un crash.
  • Errori di sistema. Timeout di servizi esterni, problemi di rete, malfunzionamenti del database. Qui di solito all’agente basta un messaggio cauto e generico, tipo «servizio temporaneamente non disponibile, riprova più tardi». Niente stack trace, nomi di tabelle o dettagli superflui, che non servono al modello e possono essere pericolosi per la sicurezza.

I materiali ufficiali dell’Agents SDK propongono persino un meccanismo speciale failure_error_function, che consente di formare con cura il testo dell’errore visto dal modello, invece di limitarsi a rilanciare un’eccezione lungo lo stack.

Struttura di un errore «amichevole»

In uno strumento dell’agente (nel vostro backend) potete stabilire che qualsiasi errore venga restituito, ad esempio, come oggetto:

type ToolError = {
  code: string;      // 'VALIDATION_ERROR', 'OUT_OF_STOCK', ...
  message: string;   // per il modello
  retryable: boolean;
};

E il risultato dello strumento — come unione:

type SuggestGiftsResult =
  | {
      ok: true;
      items: GiftSummary[];
    }
  | {
      ok: false;
      error: ToolError;
    };

Il modello (o il runtime dell’agente) vedrà questo JSON e potrà decidere: se retryable: true, si può riprovare con piccole modifiche; se l’errore è di business e non retryable, è meglio tornare all’utente e spiegare cosa non va.

7. Esempi: validazione, errore di business ed errore di sistema

Torniamo al nostro backend/agli strumenti dell’agente e vediamo come implementare le stesse idee nel codice.

Errore di validazione

Immaginiamo che venga chiamato lo strumento suggest_gifts, ma per qualche motivo il modello passi un budget negativo.

async function handleSuggestGifts(input: SuggestGiftsInput)
  : Promise<SuggestGiftsResult> {

  if (input.budget <= 0) {
    return {
      ok: false,
      error: {
        code: "VALIDATION_ERROR",
        message: "budget deve essere un numero positivo.",
        retryable: false
      }
    };
  }

  const items = await findGiftsInDb(input);
  return { ok: true, items };
}

Qui consapevolmente non lanciamo un’eccezione, ma restituiamo un errore strutturato. L’agente può riconsiderare la richiesta: magari capisce di aver confuso la valuta, chiede all’utente o semplicemente ammette di non poter selezionare un regalo con quel budget.

Errore di business

Ora un esempio con get_gift_details. Il regalo con l’id specificato potrebbe non esistere.

async function handleGetGiftDetails(input: { gift_id: string }) {
  const gift = await db.gifts.findById(input.gift_id);

  if (!gift) {
    return {
      ok: false,
      error: {
        code: "GIFT_NOT_FOUND",
        message: "Nessun regalo trovato con questo identificatore.",
        retryable: false
      }
    };
  }

  return { ok: true, gift };
}

Nella risposta del modello ci si può aspettare qualcosa del tipo: «Sembra che il regalo selezionato non sia più disponibile. Posso proporti alcune alternative della stessa categoria?». Per questo all’agente non servono errori SQL e stack trace — solo un code e un message comprensibili.

Errore di sistema

Infine, un esempio di errore di sistema. Supponiamo che il vostro strumento chiami una API esterna di consegna che a volte «cade».

async function handleEstimateDelivery(input: EstimateDeliveryInput) {
  try {
    const eta = await callDeliveryApi(input);
    return { ok: true, eta_days: eta };
  } catch (e) {
    return {
      ok: false,
      error: {
        code: "DELIVERY_SERVICE_UNAVAILABLE",
        message: "Il servizio di consegna è temporaneamente non disponibile.",
        retryable: true
      }
    };
  }
}

L’agente può decidere: «Sembra che il servizio di consegna non sia disponibile in questo momento. Ti mostrerò comunque i regali, ma il tempo di consegna potrebbe variare. Vuoi continuare?».

8. Sicurezza e idempotenza degli strumenti (rapido sguardo lato tools)

Una conversazione completa su sicurezza e permessi sarà in un modulo a parte, ma gli strumenti dell’agente sono troppo collegati a questi temi per non accennarvi.

Primo, occorre separare strumenti di lettura e strumenti di scrittura. Nelle descrizioni, negli schemi e nei permessi indicate chiaramente quali tools leggono soltanto i dati e sono assolutamente sicuri, e quali possono addebitare denaro, modificare ordini, ecc. Documentazione e forum sugli scenari con agenti parlano esplicitamente di separare strumenti ReadOnly e Mutating.

Secondo, per gli strumenti mutating bisogna pensare all’idempotenza. L’agente o il client MCP può ripetere la chiamata (ad esempio per un errore di rete), e non volete che create_order crei due ordini invece di uno. I pattern tipici sono:

  • idempotency‑key passato come argomento dello strumento;
  • verifica dell’esistenza dell’operazione prima di eseguirla;
  • suddivisione in step «crea una bozza d’ordine» e «conferma l’ordine».

Tutto ciò è strettamente legato al modo in cui progettate il contratto dello strumento: se nello JSON Schema non c’è un campo per l’idempotency‑key, aggiungere l’idempotenza dopo sarà molto più doloroso.

9. Uno sguardo rapido all’Agents SDK: com’è nel runtime dell’agente

Questa sezione è una breve panoramica per chi lavorerà con un Agents SDK orientato a TypeScript. Benché la parte principale del corso tratti di MCP, è utile capire come strumenti simili vengano visti dall’Agents SDK e come appaia un tool tipico a runtime.

Nella documentazione ufficiale si descrive di solito un’entità come «strumento funzionale»: qualsiasi funzione, descritta tramite un oggetto di configurazione (o un helper come tool(...)) e fornita di tipi, può essere automaticamente trasformata in uno strumento per il quale l’SDK genererà JSON Schema e descrizione.

A livello concettuale è esattamente ciò che abbiamo già discusso: il nome della funzione, i suoi parametri e il commento/description svolgono il ruolo di nome, schema e descrizione dello strumento. La differenza è che gran parte del lavoro «meccanico» la fa l’SDK e/o una libreria di supporto per gli schemi (ad esempio, Zod o JSON Schema).

Esempio ipotetico (pseudo‑TypeScript, semplificato):

type Gift = {
  id: string;
  title: string;
  // ...
};

const suggestGifts = tool({
  name: "suggest_gifts",
  description: "Seleziona una lista di regali per tipo di destinatario e budget.",
  parameters: {
    type: "object",
    properties: {
      recipient_type: {
        type: "string",
        description: "Chi è il destinatario del regalo (ad esempio, 'uomo', 'donna', 'bambino')."
      },
      budget: {
        type: "number",
        description: "Budget massimo nella valuta dell'utente."
      }
    },
    required: ["recipient_type", "budget"]
  }
}, async (args: { recipient_type: string; budget: number }): Promise<Gift[]> => {
  // All'interno — la tua logica di dominio
  return findGifts(args.recipient_type, args.budget);
});

L’SDK (o il vostro helper tool) costruirà il JSON Schema in base all’oggetto parameters e lo passerà all’agente; il runtime si occuperà della validazione e del marshalling degli argomenti da e verso la funzione. Concettualmente è esattamente ciò che fate manualmente in un server MCP in TypeScript, solo che ora lo strumento è «collegato» direttamente al runtime dell’agente.

Qui non è importante memorizzare la sintassi specifica dell’helper tool, ma cogliere il concetto: tipizzazione di qualità + description/commenti chiari = strumento di qualità.

Mettendo tutto insieme: un buon strumento dell’agente è una funzione ristretta, chiaramente descritta, con JSON Schema ben progettato, una descrizione comprensibile per il modello e una gestione accurata degli errori. L’instradamento semantico funzionerà solo se gli strumenti non si sovrappongono per significato. E le operazioni mutating devono essere sicure e idempotenti, altrimenti in produzione l’agente diventerà presto fonte di sorprese.

10. Errori tipici nella progettazione degli strumenti dell’agente

Errore n. 1: Strumenti troppo ampi «do_everything».
A volte è forte la tentazione di mettere tutto in un unico strumento manage_gifts, che cerca i regali, mostra i dettagli, crea l’ordine e invia l’email. Per il modello diventa difficile: la descrizione si fa vaga, l’instradamento semantico degrada e l’agente inizia a chiamare questo strumento «per ogni evenienza» anche dove basterebbe una semplice ricerca. Meglio suddividere in strumenti separati con una responsabilità ben chiara.

Errore n. 2: Strumenti che si sovrappongono per significato.
Se avete search_gifts e find_gifts, entrambi «cercano regali per interessi», il modello sceglierà casualmente. Il risultato è un comportamento instabile: richieste identiche talvolta vanno a un tool, talvolta all’altro. Cercate che ogni nome e descrizione occupino una «nicchia» unica nello spazio semantico.

Errore n. 3: Descrizioni scarse o mancanti e campi di schema inadeguati.
Il nome func1, la descrizione «Does something» e il parametro data: string — è il modo classico per rendere l’agente «stupido». Il modello non è telepatico e non può leggere il vostro sorgente. Si basa su description, properties e le loro description nello schema. Se non spiegate cosa sia recipient_type, il modello dovrà indovinare e sbaglierà.

Errore n. 4: Focalizzarsi solo sull’happy path, ignorando gli errori.
Molte implementazioni di strumenti assumono: «Avremo sempre argomenti corretti e servizi disponibili». Nel mondo reale il modello può generare parametri errati, i servizi esterni cadono e il database talvolta risponde «timeout». Se non progettate formati d’errore e non restituite un messaggio sensato all’agente, non potrà correggere il comportamento e finirà per crashare in silenzio o allucinare.

Errore n. 5: Restituire un 500 grezzo e lo stack trace alla LLM.
Nelle REST‑API siamo abituati a loggare l’intero stack trace per fare debug. Nel contesto di un agente, passare lo stack trace al modello è al tempo stesso inutile (il modello non sa cos’è una SQLException nella vostra libreria specifica) e potenzialmente pericoloso (dettagli d’implementazione superflui e forse informazioni confidenziali). Molto meglio intercettare l’eccezione, registrare i dettagli nel log e inviare al modello un code e un message curati.

Errore n. 6: Mancanza di idempotenza negli strumenti mutating.
Uno strumento create_order senza idempotency‑key è un invito a ordini duplicati, soprattutto in condizioni di errori di rete e retry automatici. Se il vostro agente opera in scenari commerciali, gli strumenti legati al denaro devono essere progettati in modo che invocazioni ripetute non portino a addebiti extra o duplicati.

Errore n. 7: Mettere segreti e dettagli tecnici nello schema o nella descrizione.
A volte per abitudine lo sviluppatore scrive nella description: «Internamente chiama il servizio X su https://internal-api.example.com». Al modello questa informazione non serve, all’utente ancor meno. Schemi e descrizioni sono parte del prompt, vivono nel contesto del modello, e lì non si dovrebbero inserire URL di servizi interni, nomi di tabelle private e men che meno segreti.

Errore n. 8: Passare agli strumenti di tutto e di più, invece di un set di campi ponderato.
È facile cedere all’idea «passiamo dentro l’intero prompt dell’utente come stringa e poi si vede». Così perdete i vantaggi della strutturazione tramite JSON Schema: il modello non capisce più quali parti della richiesta siano rilevanti per la logica, e perdete validazione e prevedibilità. Meglio estrarre dalla richiesta i campi espliciti (budget, interests, user_location) e descriverli come parte del contratto dello strumento.

Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION