CodeGym /Corsi /ChatGPT Apps /Introduzione agli agenti: ruoli, ciclo di esecuzione (run...

Introduzione agli agenti: ruoli, ciclo di esecuzione (run), determinismo, idempotenza

ChatGPT Apps
Livello 12 , Lezione 0
Disponibile

1. Che cos’è un agente e perché vi serve

Gli agenti non sono una parte obbligatoria di ChatGPT App: si possono creare applicazioni eccellenti senza usare agenti LLM. Tuttavia, ho tre buone ragioni per parlarvene.

Gli agenti sono un ottimo modo per aggiungere intelligenza al backend della vostra applicazione. Selezione intelligente di regali, analisi dei desideri testuali dell’utente. Scenari complessi di ricerca, analisi, elaborazione e riassunto — tutto questo è molto facile da fare con gli agenti LLM.

ChatGPT ha rilasciato la propria Agents SDK in TS e Python. È davvero valida. L’orchestrazione degli agenti è fornita out‑of‑the‑box. Su un compito complesso non lavorerà un solo agente, ma un intero team. È una direzione molto promettente.

E c’è anche un obiettivo didattico. ChatGPT chiama mcp-tools esattamente come gli agenti LLM chiamano i propri tools. Una volta capito come funzionano gli agenti LLM, vi sarà chiaro, per esempio, come costruire una macchina a stati sul lato modello nell’applicazione. Inoltre, studiare l’Agents SDK dà un’idea di come funzionerà in futuro il ChatGPT SDK.

Dunque, cominciamo.

Che cos’è un agente LLM

Se ChatGPT App è il «front‑end» bello e comodo del vostro servizio dentro ChatGPT, e il server MCP è il «motore» con strumenti e logica di business, allora l’agente è una sorta di dispatcher intelligente che sa:

  • leggere l’obiettivo;
  • decidere autonomamente quali strumenti chiamare e in quale ordine;
  • se necessario, chiedere dati aggiuntivi;
  • ripetere i passi in caso di errori;
  • arrivare a un risultato finale comprensibile.

In una formulazione vicina alla documentazione ufficiale dell’Agents SDK, un agente è un programma. Avendo accesso a un’LLM e a un insieme di strumenti, è in grado di pianificare i passi in autonomia per raggiungere l’obiettivo e eseguirli tramite tool‑calls.

Se facciamo un parallelo con ciò che avete già:

  • Nella normale ChatGPT App il modello di ChatGPT orchestra direttamente le chiamate dei vostri strumenti MCP.
  • Un agente LLM sul backend ha anch’esso la descrizione del compito, un set di strumenti e decide da solo quali tools chiamare, quanti passi fare, quando fermarsi e quale risultato restituire.

Nel contesto del nostro GiftGenius questo può apparire così:

  • Applicazione senza agente: il modello chiama direttamente searchGifts, poi filterByBudget, poi getDetails — ogni volta ripensando da capo;
  • Applicazione con agente: ChatGPT chiama un mcp‑tool, e il backend assegna all’agente il compito: «Trova i top‑5 regali per un certo profilo». L’agente fa più passi: raccoglie informazioni aggiuntive, chiama diversi strumenti di ricerca, filtra, ordina, costruisce le schede finali e restituisce già una risposta strutturata pronta.

ChatGPT e un agente LLM sul backend sono come il direttore di un’azienda e un dipendente. ChatGPT ha molta più libertà: parla con l’utente e decide quali compiti strategici avviare (chiamare gli mcp tools). L’agente LLM lavora solo sul backend, non interagisce con l’utente, ma anch’esso «pensa» e può chiamare i propri tool. Una sorta di «ChatGPT in versione ridotta».

2. Di cosa è composto un agente: LLM, istruzioni, strumenti e stato

È comodo pensare all’agente come a più livelli.

Per prima cosa, sotto il cofano abbiamo sempre un’LLM. Può essere GPT‑5.1 o un altro modello usato dall’Agents SDK. Genera testo, pianifica i passi, seleziona gli strumenti — in breve, si occupa del «ragionamento», ma nel vostro contesto di orchestrazione.

Poi, sopra il modello ci sono le istruzioni. È il prompt di sistema dell’agente, che definisce il suo ruolo, i confini, lo stile di comunicazione, le modalità d’uso degli strumenti. Avete già fatto qualcosa di simile per ChatGPT App, ma ora si applica a un agente separato.

In terzo luogo, c’è un set di strumenti dell’agente. Possono essere:

  • funzioni in TypeScript (il classico function calling);
  • strumenti HTTP/REST;
  • wrappers sopra i vostri MCP‑tools, in modo che l’agente possa chiamare lo stesso backend della ChatGPT App;
  • strumenti «hosted» integrati di OpenAI (per esempio, web‑search, se li abilitate).

Infine, ci sono le regole per lo stato e i passi: come viene gestito lo stato di sessione (session state), come si salvano i risultati intermedi, come si limitano i cicli. Ne parleremo più in profondità nella prossima lezione su memoria e stato, ma è già utile tenere a mente che un agente non è una «richiesta usa e getta», bensì potenzialmente un processo lungo con salvataggio dell’avanzamento.

Se lo guardate con gli occhi di uno sviluppatore TypeScript, mentalmente si ottiene un oggetto di questo tipo (pseudocodice, vicino all’Agents SDK TS):

const giftAgent = new Agent({
  model: "gpt-5.1",
  systemPrompt: giftAgentPrompt,
  tools: { searchGifts, filterGifts, checkoutDraft },
  // qui — impostazioni della memoria, limiti dei passaggi ecc.
});

Per ora non entriamo nelle API esatte, conta l’immagine generale: modello, istruzioni, strumenti e impostazioni di comportamento in un unico posto.

3. Ruoli dei messaggi: system / user / assistant / tool nel mondo dell’agente

Conoscete già i ruoli classici system, user, assistant e tool da Chat Completions. Nell’Agents SDK si conservano, ma assumono un significato più applicativo.

Il ruolo system definisce la personalità e la missione dell’agente. Per esempio, per l’agente GiftGenius potrebbe essere: «Sei un agente di selezione regali. Il tuo compito è selezionare in un numero minimo di passi 3–7 opzioni di regali pertinenti in base al profilo del destinatario e al budget, quindi preparare un JSON strutturato per il widget». Qui indicate anche i limiti: cosa non deve fare (per esempio, non eseguire acquisti reali senza un passo separato) e come deve lavorare con gli strumenti.

Il ruolo user nel contesto dell’agente non è necessariamente «una persona in carne e ossa». Più spesso è «l’incarico» per l’agente: l’obiettivo, formulato dalla vostra App, da un servizio o da un altro agente. Per esempio, ChatGPT App può chiamare l’agente con un messaggio user: «Seleziona 5 idee regalo per un collega sviluppatore, budget 50 $, occasione — compleanno».

Il ruolo assistant è ciò che «dice» il modello all’interno dell’agente. Qui possono esserci sia ragionamenti e piani intermedi, sia la risposta finale. Il vostro compito è configurare il prompt di sistema in modo che questi messaggi siano utili e, se necessario, vengano loggati.

Il ruolo tool (o i suoi analoghi nello specifico SDK) descrive i risultati delle chiamate agli strumenti: «tramite MCP sono stati trovati 50 prodotti», «l’API ha restituito un errore di timeout», «il DB ha restituito il profilo utente». Questi messaggi insieme ai messaggi assistant costituiscono la storia del run‑cycle dell’agente.

È comodo riassumere tutto in una piccola tabella:

Ruolo Chi parla Esempio nel contesto di GiftGenius
system
Voi (come sviluppatori dell’agente) «Sei un agente per la selezione di regali…»
user
Chiamata esterna (App, altro agente) «Seleziona 5 regali fino a 50 $…»
assistant
Il modello all’interno dell’agente «Piano: 1) chiedere i dettagli…»
tool
Risultato dello strumento chiamato «searchGifts ha restituito 20 opzioni…»

Questa struttura è importante, perché è proprio su di essa che si costruisce il run‑cycle — il protagonista della lezione di oggi.

4. Come l’LLM richiama funzioni sul vostro backend

Quando ci si abitua alla modalità «domanda–risposta», può sembrare che l’LLM lavori con uno schema semplice: arriva un testo → il modello risponde con un testo. In realtà, sotto il cofano è un po’ più complesso ed è proprio per questo che funziona il function calling.

Il modello non riceve una sola domanda, riceve una lista di messaggi — la storia del dialogo. Lì ci sono già tutte le battute precedenti: istruzioni di sistema («chi sei e cosa è consentito/non consentito»), i vostri messaggi, le risposte precedenti del modello, i risultati degli strumenti. A ogni passo il modello guarda tutta questa timeline, come un log di chat, e decide: «Qual è il prossimo messaggio da aggiungere in coda?».

Questa è l’idea chiave: l’LLM fa sempre un solo passo — aggiunge il messaggio successivo in fondo alla storia. Non «cambia il passato» e non modifica i messaggi vecchi, ma continua semplicemente l’elenco. Voi scrivete una domanda, il modello risponde. Aggiungete una seconda domanda, il modello risponde di nuovo, ma tenendo conto di tutta la storia del dialogo (tutti i messaggi).

Il function calling è costruito sullo stesso principio. Invece di «lanciare direttamente una funzione», il modello fa quanto segue:

  • vede l’elenco degli strumenti/tools disponibili e le loro descrizioni insieme alla storia del dialogo;
  • decide: «Ora ha più senso non rispondere solo con del testo, ma prima chiamare un certo strumento»;
  • e come messaggio successivo aggiunge alla storia non una normale risposta testuale, ma un messaggio speciale nel formato «voglio chiamare questo tool con questi argomenti».

Poi non è più il modello, ma il vostro backend a leggere questo nuovo messaggio alla fine della storia, capire che è una richiesta di chiamata di funzione e chiamare lo strumento necessario. Quindi aggiunge alla storia un altro messaggio — con il risultato del tool, e invia di nuovo al modello l’elenco completo dei messaggi. Il modello guarda nuovamente tutta la timeline e aggiunge il passo successivo: o un’altra chiamata, oppure la risposta finale leggibile.

Ovvero:

  • per il normale Q&A: «messaggio successivo» = risposta testuale;
  • per il function calling: «messaggio successivo» = istruzione di chiamare una funzione oppure risposta dopo l’uso della funzione.

Non c’è alcun «comando magico separato» per chiamare una funzione — è solo un tipo particolare di messaggio successivo che il modello aggiunge in coda alla catena.

Il modello non invoca le funzioni del vostro backend tramite API pubbliche. Semplicemente «scrive in chat» che vuole chiamare una funzione con dei parametri. Ed è il vostro backend a chiamare la funzione locale e ad aggiungerne la risposta in chat. E tutto ricomincia da capo.

5. Il ciclo di esecuzione (run) dell’agente: come «pensa» passo dopo passo

Di fatto un agente LLM è un oggetto/algoritmo sul vostro server che esegue il ciclo di esecuzione dell’agente — un ciclo esteso «domanda → pensare → eventualmente fare un’azione → pensare di nuovo → … → risposta finale». Nella documentazione OpenAI viene talvolta chiamato agent loop o pattern ReAct (Reason + Act + Observe).

A livello concettuale una run dell’agente appare così:

  1. L’agente riceve l’input: istruzioni di sistema, incarico (messaggio user), eventualmente lo stato corrente.
  2. Il modello genera un passo: o una risposta testuale, o piani e decisione di chiamare uno o più strumenti.
  3. Se il modello sceglie un tool‑call, l’agente chiama lo strumento corrispondente nel codice (può essere una funzione locale, un MCP‑tool, una richiesta HTTP, accesso al DB, ecc.).
  4. I risultati degli strumenti vengono aggiunti alla storia come messaggi tool.
  5. Il ciclo torna al modello con il nuovo contesto. Il modello decide cosa fare dopo: continuare la pianificazione, chiamare un altro strumento o completare il compito con una risposta finale.
  6. Quando il modello termina esplicitamente o in base alle condizioni di arresto, l’agente restituisce il risultato finale al chiamante.

Con una piccola diagramma si può mostrare così:

flowchart TD
    A[Avvio del run: obiettivo + system] --> B[Chiamata al modello]
    B --> C{Il modello vuole
rispondere con testo
o chiamare un tool?} C --> D["Risposta testuale
(assistant)"] D --> E{Il compito è concluso?} E -->|Sì| F[Risultato finale] E -->|No| B C --> G["Tool‑call
(descrizione della chiamata)"] G --> H[Chiamata funzione / MCP / HTTP] H --> I["Risultato del tool
(tool message)"] I --> B

Se traduciamo questo in uno pseudocodice TypeScript semplificato (lontano dalle API reali, ma logicamente corretto), si ottiene qualcosa del genere:

async function runAgent(goal: string) {
  let context = buildInitialContext(goal);

  while (!isFinished(context)) {
    const decision = await callLLM(context); // passo dell’agente

    if (decision.type === "tool_call") {		// chiamare una funzione?
      const toolResult = await callTool(decision.tool, decision.args);	// chiamiamo la funzione locale
      context = appendToolResult(context, toolResult);		// aggiungiamo il risultato in coda all’elenco
    } else {
      context = appendAssistantMessage(context, decision.message); 
    }

    enforceLimits(context); // limiti di passi/tempo/cicli
  }

  return extractFinalResult(context);
}

L’Agents SDK si occupa della maggior parte di questa routine: memorizzazione della storia, marshalling dei tool‑calls, logica dei retry, ecc. A voi resta configurare e implementare gli strumenti stessi.

Run vs step

È importante distinguere due concetti:

  • run — un’esecuzione dell’agente per un certo obiettivo: «seleziona i regali per questo caso»;
  • step — un passo del run‑cycle: una specifica chiamata del modello che può portare a una risposta testuale o a un tool‑call.

Nel monitoring vedrete proprio molti passi all’interno di una singola run, e i limiti di sicurezza e costo sono spesso impostati o «per run» o «per passo».

Ora che è chiaro come l’agente vive all’interno di una run e procede nel run‑cycle, vediamo dove abbia senso introdurlo e dove siano sufficienti semplici tools.

5. Dove in GiftGenius serve un agente e dove è superfluo

Prima di mettervi a scrivere un agente per tutto, è utile porsi onestamente la domanda: «Ma qui serve davvero?».

Un buon scenario per un agente è un compito multi‑passo con diramazioni, ripetizioni e logica che è scomodo gestire solo con i prompt.

In GiftGenius un compito del genere può essere un «wizard di selezione intelligente dei regali», che:

  • sa chiedere i dettagli importanti (sesso del destinatario, hobby, livello di confidenza);
  • può rivolgersi a più fonti di prodotti (diversi vendor tramite MCP‑tools);
  • filtra e classifica i risultati;
  • in caso di errori delle fonti ripete il tentativo o segue una via alternativa;
  • restituisce non solo un elenco di testi, ma un elenco strutturato di candidati con spiegazioni e link agli SKU dal product feed.

Qui l’agente sarà davvero utile come «orchestratore», soprattutto se poi vorrete aggiungere uno scenario voice/Realtime o una commerce complessa (ACP).

Invece, per una semplice chiamata a getGiftDetails(giftId) l’agente non serve: un normale MCP‑tool, invocato direttamente da ChatGPT, copre completamente il caso. Lo stesso vale per scenari «a un solo passo» banali come «scrivi la descrizione di questo regalo a partire dal testo della scheda prodotto».

L’approccio di buon senso è questo: se potete descrivere lo scenario come «un unico tool ben fatto», probabilmente l’agente non serve. Se invece iniziate a esplicitare un workflow multi‑passo con controlli e retry, con buona probabilità l’agente vi soddisferà.

6. Determinismo: come rendere prevedibile il comportamento dell’agente

Il determinismo nel mondo degli agenti LLM è una cosa insidiosa. In teoria, con lo stesso input e le stesse impostazioni vorreste ottenere lo stesso piano d’azione e la stessa sequenza di tool‑calls. In pratica il modello resta stocastico, ma avete alcuni leve per gestire la prevedibilità.

Primo, la classica: temperatura e altri parametri di generazione. Più bassa è la temperatura, meno creatività e più «obbedienza» del modello. Per un agente di selezione regali probabilmente vorrete un livello di libertà non nullo ma nemmeno troppo alto, altrimenti il modello ogni mattina inventerà un modo nuovo per chiamare lo stesso strumento.

Secondo, istruzioni di sistema chiare. Se descrivete vagamente un comportamento del tipo «puoi chiamare strumenti diversi e fare ciò che vuoi», non stupitevi se l’agente salterà tra le API o proverà a rispondere «di fantasia». Molto meglio descrivere esplicitamente quando chiamare uno strumento, quali parametri sono ammessi, come interpretare gli errori e in quali casi bisogna chiudere il compito.

Per esempio, il prompt di sistema per l’agente GiftGenius può includere il frammento:

Se non hai un profilo completo del destinatario (età, sesso, occasione, budget approssimativo),
prima poni domande di chiarimento tramite il canale rivolto all’utente e attendi le risposte.
Solo dopo chiama lo strumento search_gifts con il profilo compilato.
Non inventare prodotti dal nulla, basati sempre sui risultati degli strumenti.

Istruzioni di questo tipo riducono la variabilità delle decisioni e rendono il comportamento più deterministico.

Terzo, design degli strumenti. Se avete tre strumenti che «più o meno» cercano regali, il modello inevitabilmente a volte sceglierà uno, a volte un altro. Meglio progettare gli strumenti con ambiti di responsabilità chiari, non sovrapposti, e descriverlo nelle relative descrizioni.

Infine, potete usare i guardrails — regole e schemi che verificano le azioni dell’agente e i risultati del modello. Nell’Agents SDK c’è supporto integrato per controlli e vincoli, anche sulla struttura dei dati in uscita. Se il modello cerca di generare qualcosa che non rispetta lo schema, potete correggerlo dolcemente o addirittura ripetere il passo.

Mini‑esempio: fissare il formato del risultato

Supponiamo che serva far sì che l’agente restituisca sempre un JSON con il campo gifts, e all’interno oggetti con id, title e score. Potete:

  • descrivere questo schema a livello di agente;
  • indicare che l’output finale deve rispettarlo;
  • in caso di violazioni — ripetere il passo o restituire un errore sicuro.

Pseudocodice:

const giftResultSchema = z.object({
  gifts: z.array(z.object({
    id: z.string(),
    title: z.string(),
    score: z.number().min(0).max(1),
  }))
});

// Nella configurazione dell’agente
const agent = new Agent({
  /* ... */
  outputSchema: giftResultSchema,
});

Quando il modello proverà a restituire qualcosa di strano, il runner segnalerà un errore di validazione, e voi potrete o richiedere di nuovo al modello o loggare l’incidente.

7. Idempotenza: perché l’agente può chiamare la vostra API due volte

Se il determinismo riguarda «lo stesso piano con gli stessi input», l’idempotenza riguarda la sicurezza dei retry. Nel contesto degli agenti è fondamentale per due motivi.

Primo, compare un ulteriore livello di retry: non solo i client HTTP e i load balancer, ma anche l’agente stesso può decidere di ripetere la chiamata a uno strumento se ha ricevuto un errore o un risultato incompleto. Secondo, in scenari reali di produzione si aggiungono webhooks, code, canali di streaming — e potreste elaborare accidentalmente più volte lo stesso passo logico.

Avete già discusso l’idempotenza a livello di MCP‑tools: non effettuare doppie transazioni, non creare due volte lo stesso ordine, usare idempotency keys nelle richieste. Ora è la stessa cosa, ma moltiplicata per la natura multi‑passo dell’agente.

Immaginiamo che in GiftGenius compaia lo strumento create_checkout_session, che crea un draft di checkout in ACP/Stripe a partire dall’elenco dei regali selezionati. Se l’agente decide di ripetere questa chiamata a causa di un errore di rete, non volete assolutamente due ordini separati e due addebiti.

Quindi serve:

  • ideare una idempotency key esterna per ogni azione logica (per esempio, runId + stepIndex o un checkoutDraftId generato esplicitamente);
  • passarla al vostro endpoint backend/ACP;
  • sul lato backend verificare se avete già elaborato quella chiave e restituire il risultato salvato invece di eseguire di nuovo.

Pseudoesempio in TypeScript:

async function createCheckoutDraft(runId: string, payload: DraftPayload) {
  const key = `gift-checkout-${runId}`;

  const existing = await findDraftByKey(key);
  if (existing) return existing;

  const draft = await stripe.checkout.sessions.create({
    /* ... */,
    idempotencyKey: key, // oppure uno strato vostro sopra
  });

  await saveDraftWithKey(key, draft);
  return draft;
}

Ora, anche se per qualche motivo l’agente chiamasse questo strumento due volte con lo stesso runId, il vostro codice resterebbe idempotente: stesso passo logico → stesso risultato effettivo.

«Prima la verifica, poi l’azione»

Il secondo pattern di idempotenza diffuso — prima verificare lo stato, poi agire. Per esempio, prima di creare un ordine, controllare che non esista già un ordine con lo stesso clientReferenceId o con lo stesso insieme di parametri. È particolarmente utile in workflow lunghi, dove l’agente può «dimenticare» di aver già fatto qualcosa nel passo precedente.

Modalità sicura (safe‑mode) / fake‑mode

In fase di sviluppo è utile avere una «modalità sicura» per gli strumenti pericolosi: invece di eseguire l’azione reale, registrano soltanto cosa sarebbe stato fatto e restituiscono un pseudo‑risultato. Per gli agenti è un modo comodo per eseguire il run‑cycle in ambiente di produzione senza rischiare denaro o dati.

8. Mini‑pratica: descrivere l’agente GiftGenius in linguaggio naturale

Abbiamo già parlato del run‑cycle, del determinismo e dell’idempotenza degli strumenti. Stacchiamoci un attimo dal codice e verifichiamo come tutto questo si compone in uno scenario reale.

Ora è utile fare un piccolo esercizio su carta (o mentalmente), senza codice.

Immaginate di descrivere un agente semplice:

  • system
    : sei un assistente per la selezione di regali; chiedi sempre i dettagli importanti, non inventi prodotti di fantasia, ma usi solo i risultati degli strumenti.
  • user
    : voglio un regalo per un collega fino a 50 $.

Descrivete a parole quali passi dovrebbe fare un tale agente.

Uno scenario tipico può essere questo.

  1. Per prima cosa l’agente verifica se le informazioni sono sufficienti. In caso contrario, pone domande di chiarimento: di cosa si occupa all’incirca il collega (designer, sviluppatore, manager), se ci sono tabù (alcol, regali scherzosi), se ci sono vincoli di consegna. Le risposte finiscono o nel session state o nei parametri della chiamata allo strumento.
  2. Poi l’agente chiama lo strumento search_gifts con il profilo compilato: «collega sviluppatore, budget 50, categoria — gadget e ufficio». Lo strumento restituisce un elenco di candidati con prezzi, categorie e ID dei prodotti.
  3. Successivamente l’agente può chiamare uno strumento aggiuntivo filter_gifts_by_constraints, se risulta che parte dei prodotti non può essere consegnata nella regione richiesta, oppure filtrare manualmente nel proprio prompt. Dopodiché ordina le opzioni per pertinenza e costo, eventualmente aggiungendo i propri commenti («adatto se al collega piace il caffè», «buona scelta per il lavoro da remoto»).
  4. Infine, l’agente prepara la risposta finale strutturata per ChatGPT App: un elenco di 5–7 regali con brevi descrizioni, suggerimenti d’uso e link al Checkout (o al passo successivo — creazione del draft di checkout).

Dove servono i tool‑calls? Ovviamente nella ricerca e nel filtraggio dei prodotti, nel controllo della disponibilità e nella creazione del draft di checkout. Quali passi devono essere idempotenti? Prima di tutto tutte le operazioni legate a ordini e denaro — creazione del draft di checkout, eventualmente la registrazione della storia nel DB.

9. Errori tipici ai primi passi con gli agenti

Errore n. 1: l’agente come «secondo ChatGPT senza limiti».
A volte si vorrebbe semplicemente dare al modello un altro prompt e chiamarlo «agente». Il risultato è qualcosa che genera molto testo, chiama gli strumenti in modo caotico e difficilmente controllabile. Per evitarlo, è importante descrivere chiaramente il ruolo dell’agente in system, limitare l’elenco degli strumenti e pensarci proprio come a un orchestratore con una missione specifica, non come a «un secondo universo di generazione testuale».

Errore n. 2: mancanza di idempotenza negli strumenti.
Gli sviluppatori spesso portano i vecchi HTTP‑handler sotto l’agente «così come sono», senza considerare che ora il runner può ripetere automaticamente le chiamate. Nel caso di pagamenti e ordini questo può avere conseguenze molto spiacevoli. L’approccio corretto è progettare fin da subito gli strumenti in modo che una chiamata ripetuta con la stessa chiave logica non porti a un’azione ripetuta.

Errore n. 3: impostazioni del modello troppo creative.
Una temperatura alta è ottima per inventare brindisi e poesie, ma per un agente che deve orchestrare in modo affidabile processi multi‑passo è la via verso un comportamento imprevedibile: il modello sceglierà ogni volta strumenti diversi, genererà piani differenti e a volte dimenticherà persino di avere i tools. Trattate gli agenti come entità «di servizio» e manteneteli in un regime più rigido.

Errore n. 4: lo strumento «per tutti i casi».
A volte si vuole creare un tool universale come execute_any_sql o do_anything_with_orders, e poi darlo in mano all’agente. In combinazione con la creatività dell’LLM è quasi una minaccia alla sicurezza garantita. Molto meglio avere più strumenti specializzati con contratti e permessi chiari, che uno «onnipotente» con pieni diritti su tutto.

Errore n. 5: assenza di criteri espliciti di termine della run.
Se non spiegate all’agente quando fermarsi, potrebbe entrare in cicli infiniti o quasi: ricontrollare ancora i risultati, chiedere ancora una volta all’utente, provare ancora a chiamare uno strumento con lo stesso errore. Spesso questo emerge solo sotto carico, quando una dipendenza è instabile. Il modo corretto è impostare limiti al numero di passi, al tempo della run e al numero di retry sullo stesso errore, e inoltre descrivere in system che l’agente deve «arrendersi onestamente» quando ha esaurito opzioni ragionevoli.

Errore n. 6: memorizzare tutto e subito nello stato dell’agente.
Dato che l’Agents SDK semplifica il lavoro con il session state, c’è la tentazione di metterci dentro di tutto: documenti grandi, log non elaborati, dati sensibili. Questo gonfia il contesto, aumenta i costi e crea rischi di sicurezza. Lo stato dell’agente deve contenere solo ciò che è davvero necessario per proseguire; tutto il resto — nel DB, nei log e in altri livelli, con attenzione alla privacy.

Errore n. 7: tentare di usare un agente dove basta un semplice MCP‑tool.
A volte gli sviluppatori partono da un agente, anche se il compito è solo chiamare una funzione e restituire il risultato. Questo aggiunge complessità dove non serve: compaiono run‑cycle, stato, log aggiuntivi e potenziali punti di failure. Se lo scenario rientra in un singolo tool‑call senza workflow complesso, è meglio lasciarlo così e collegare un agente solo quando emerge una reale multi‑passo.

1
Compito
ChatGPT Apps, livello 12, lezione 0
Bloccato
Feed dei messaggi dell'agente (ruoli + tool-call vs tool-result)
Feed dei messaggi dell'agente (ruoli + tool-call vs tool-result)
1
Compito
ChatGPT Apps, livello 12, lezione 0
Bloccato
Mini-runtime dell'agente (ciclo di esecuzione: model → tool-call → tool → final)
Mini-runtime dell'agente (ciclo di esecuzione: model → tool-call → tool → final)
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION