Torna al catalogo
Season 6 18 Episodi 1h 5m 2026

OpenAI Agents SDK

v0.13 — Edizione 2026. Una guida completa per creare sistemi multi-agent pronti per la produzione con l'OpenAI Agents SDK per Python (v0.13 - 2026). Impara i core primitives, i pattern di orchestrazione, i tools, gli handoff, i guardrail, lo state management, MCP e l'integrazione vocale realtime.

Framework AI/ML Sistemi Multi-Agente
OpenAI Agents SDK
In Riproduzione
Click play to start
0:00
0:00
1
Oltre Swarm: I Core Primitives
Scopri i concetti fondamentali dell'OpenAI Agents SDK. Questo episodio spiega perché l'SDK esiste, come migliora Swarm e i principi di design fondamentali che privilegiano astrazioni minime.
3m 36s
2
Definire l'Agent e il Run Loop
Impara a configurare l'oggetto base Agent. Esploriamo le instructions, le impostazioni del modello e come forzare output di dati strutturati in modo fluido.
3m 18s
3
Equipaggiare gli Agent con i Python Function Tools
Dai ai tuoi agent la capacità di agire convertendo funzioni Python standard in tool eseguibili. Comprendi l'automatic schema generation e la type inference.
3m 24s
4
Scalare le Tool Surfaces con Hosted Tool Search
Impara a gestire enormi librerie di tool senza esaurire il tuo budget di token. Trattiamo il deferred loading, i namespace e l'hosted tool execution.
3m 22s
5
Delegazione Decentralizzata: Il Pattern Handoff
Padroneggia l'arte dell'orchestrazione multi-agent usando il pattern Handoff. Scopri come creare triage agent che delegano fluidamente il controllo totale a sub-agent specializzati.
3m 22s
6
Orchestrazione Centralizzata: Agents as Tools
Mantieni il controllo della conversazione in un unico posto usando il pattern Agents as Tools. Discutiamo di come un manager agent possa sintetizzare le risposte di più sub-agent specializzati.
3m 37s
7
Plasmare il Contesto con Handoff Inputs e Filters
Ottimizza l'uso dei token multi-agent modificando le cronologie delle conversazioni tra gli handoff. Impara a iniettare metadati e ad applicare transcript filters.
4m 09s
8
Controllare lo State: to_input_list e Server IDs
Un'analisi approfondita della gestione manuale delle conversazioni. Comprendi i metodi di più basso livello per preservare il contesto tra i turni e utilizzare i response IDs lato server.
4m 00s
9
Automatizzare la Memoria con le Built-in Sessions
Semplifica i tuoi chat loop con il sistema di memoria integrato nell'SDK. Esploriamo SQLiteSession, OpenAIConversationsSession e la persistenza automatizzata.
3m 53s
10
Proteggere i Workflow: Input e Output Guardrails
Metti in sicurezza le tue pipeline IA intercettando gli input malevoli prima che raggiungano modelli costosi. Trattiamo i guardrail a livello di agent e l'esecuzione parallela rispetto a quella bloccante.
3m 38s
11
Validare le Azioni: Tool-Level Guardrails
Previeni fughe di dati critici a livello di funzione. Impara a wrappare tool specifici con precisi input e output guardrails.
4m 01s
12
Mettere in Pausa l'Esecuzione: Human-in-the-Loop e RunState
Implementa salvaguardie per le azioni irreversibili imponendo approvazioni human-in-the-loop. Esploriamo la pipeline di serializzazione RunState per mettere in pausa e riprendere i workload.
3m 21s
13
Iniettare Dipendenze Locali con RunContextWrapper
Padroneggia la dependency injection nei flussi del tuo agent. Impara a passare in modo sicuro local states e connessioni al database ai tool senza farli trapelare all'LLM.
3m 59s
14
L'USB-C per l'IA: Introduzione a MCP
Un'introduzione al Model Context Protocol (MCP). Scopri come questo standard agisce da connettore universale per collegare facilmente gli AI agent alle piattaforme SaaS.
3m 17s
15
Connettere Local MCP Servers tramite Stdio e HTTP
Approfondisci MCP eseguendo server locali standard. Impara a mettere in sandbox l'accesso al filesystem e i tool interni in modo sicuro con MCPServerStdio.
3m 16s
16
Visualizzare i Workflow con il Built-in Tracing
Elimina il debug tramite print statement usando l'observability integrata nell'SDK. Scopri come span e trace automatici collegano interi workflow complessi.
3m 29s
17
Voce a Bassa Latenza con i Realtime Agents
Rompi il paradigma standard di request-response. Scopri come i Realtime Agents mantengono connessioni WebSocket live per gestire le interruzioni e il ragionamento multimodale.
3m 50s
18
Costruire UI Reattive con gli Streaming Events
Vai oltre lo streaming dei token di testo. Utilizza i semantic streaming events per costruire interfacce frontend ultra-responsive che reagiscono alle azioni dell'agent in tempo reale.
3m 43s

Episodi

1

Oltre Swarm: I Core Primitives

3m 36s

Scopri i concetti fondamentali dell'OpenAI Agents SDK. Questo episodio spiega perché l'SDK esiste, come migliora Swarm e i principi di design fondamentali che privilegiano astrazioni minime.

Download
Ciao, sono Alex di DEV STORIES DOT EU. OpenAI Agents SDK, episodio 1 di 18. La maggior parte dei framework per agent AI ti costringe a imparare una dozzina di nuove astrazioni, sintassi custom e gerarchie di oggetti pesanti. Passi più tempo a combattere con il framework che a scrivere la vera logica della tua applicazione. Oggi vediamo Beyond Swarm: le primitive fondamentali. Quando gli sviluppatori sentono parlare di un nuovo framework per agent, spesso si aspettano un ecosistema enorme con una curva di apprendimento ripida. L'OpenAI Agents SDK è esattamente l'opposto. È un'evoluzione della libreria sperimentale Swarm. Swarm ha dimostrato che puoi costruire interazioni complesse con concetti molto semplici. L'Agents SDK prende questa filosofia e la rende più solida per l'uso in produzione. È volutamente leggero e interamente Python-first. L'architettura si basa su due principi di design fondamentali: esporre pochissime primitive core e mantenere l'esecuzione altamente personalizzabile. Non hai bisogno di un grafo di nodi complesso o di un linguaggio dichiarativo proprietario per costruire un agent qui. L'SDK ti fornisce un piccolo set di building block. Il pezzo fondamentale è l'oggetto Agent. Definisci un Agent passandogli un nome e un set di istruzioni. Se vuoi creare un semplice tutor di storia, istanzi un Agent, lo chiami HistoryTutor e gli passi una string di testo che gli ordina di insegnare gli eventi storici in modo chiaro e accurato. Questa è l'intera configurazione del tuo agent. Non c'è nessuno state nascosto e nessuna inizializzazione complessa. Ma un agent di per sé è solo una struttura dati statica. Non fa nulla finché non viene eseguito. Ed è qui che la cosa si fa interessante. L'esecuzione è gestita interamente da un componente separato chiamato Runner. Il Runner gestisce l'intero loop di interazione tra il tuo codice locale e l'API remota di OpenAI. In un'applicazione tipica, dovresti scrivere un while-loop custom per controllare se il modello vuole fare una tool call, parsare la response, eseguire il tool e rimandare indietro il risultato. Il Runner astrae tutto questo. Per avviare il processo, passi il tuo agent HistoryTutor e il prompt dell'utente al metodo run. Da lì in poi, il Runner prende il controllo. Invia il prompt al modello. Se il modello decide di dover cercare una data storica specifica, richiederà una tool call. Il Runner si mette in pausa, esegue la funzione Python locale che hai fornito per quel tool, cattura il valore di ritorno e lo rimanda subito al modello. Ripete questo loop automaticamente. Restituisce il controllo alla tua applicazione solo quando il modello determina che il task è completo e genera una response testuale finale. Questa netta separazione tra la definizione statica dell'Agent e l'esecuzione attiva del Runner è ciò che rende l'SDK così personalizzabile. Dato che i tool sono semplici funzioni Python con dei normali type hint, e l'agent è un semplice oggetto, mantieni il controllo totale sul flow della tua applicazione. Puoi iniettare facilmente logging custom, metriche o error handling attorno al Runner senza dover fare l'override di classi profonde del framework. Stai semplicemente scrivendo in Python. Il vero valore di questo SDK non è in ciò che aggiunge, ma in ciò che toglie: si fa da parte e ti permette di orchestrare i modelli linguistici usando codice semplice e leggibile. Se vuoi supportare lo show, puoi cercare DevStoriesEU su Patreon. Per questo episodio è tutto. Ci sentiamo alla prossima!
2

Definire l'Agent e il Run Loop

3m 18s

Impara a configurare l'oggetto base Agent. Esploriamo le instructions, le impostazioni del modello e come forzare output di dati strutturati in modo fluido.

Download
Ciao, sono Alex di DEV STORIES DOT EU. OpenAI Agents SDK, episodio 2 di 18. E se potessi forzare il tuo language model a rispondere sempre con una data structure perfettamente parsed senza scrivere una sola riga di regex complesse? Oggi parliamo di Defining the Agent e del Run Loop, che è esattamente il modo in cui ottieni questo controllo rigoroso. Un punto di confusione comune quando inizi a usare questo SDK è pensare che un Agent sia un processo attivo in esecuzione. Non lo è. In questa architettura, l'oggetto Agent è strettamente un configuration container. Incapsula uno specifico language model in un context predefinito. Non va in esecuzione da solo e non mantiene alcuno state. Stai semplicemente costruendo un blueprint. Per definire questo blueprint, istanzi un Agent. Inizi con il parametro instructions. Questo è il tuo system prompt principale, dove definisci la persona, i limiti e le regole specifiche che il modello deve seguire. Successivamente, fornisci i model settings. Questo stabilisce quale modello sottostante utilizzare e configura i dettagli standard di inference. A questo punto, il tuo Agent è completamente definito ma del tutto inattivo in memoria. È qui che la cosa si fa interessante. Puoi vincolare fisicamente la struttura della risposta dell'Agent usando il parametro output type. Immagina di creare un tool per estrarre eventi del calendario da thread di email disordinati. Invece di scrivere instructions supplicando il modello di formattare correttamente le date, definisci una data structure concreta nel tuo codice. Definisci una classe Calendar Event con campi rigorosi per un titolo, un'ora di inizio e una posizione. Passi questa classe nel parametro output type del tuo Agent. Quando è configurata in questo modo, l'API forza lo schema. L'Agent non può restituire una risposta testuale conversazionale. Restituirà sempre e solo un oggetto Calendar Event validato che il codice della tua applicazione può processare immediatamente. Ora hai un blueprint dell'Agent rigoroso e ben configurato. Per fargli fare del lavoro vero, hai bisogno del Run Loop. Poiché l'Agent è solo una definizione statica, l'esecuzione è gestita interamente da un componente Runner separato. Il Runner è il motore. Passi la definizione del tuo Agent e lo user input al Runner, e lui prende il controllo dell'esecuzione. Quando avvii il Runner, questo entra in un execution loop. Raggruppa le instructions del tuo Agent, il rigoroso output schema e lo user prompt, quindi li invia al modello. Il Run Loop è responsabile della gestione di tutta l'orchestrazione di back-and-forth. Se il modello decide di dover chiamare un tool esterno per recuperare i dati mancanti, il Runner intercetta quella richiesta, esegue il codice del tool locale e restituisce il risultato al modello. Gestisce automaticamente tutti questi passaggi intermedi. Il loop termina solo quando il modello risolve il prompt e produce l'output finale che corrisponde esattamente al tuo calendar output type. Mantenere la configurazione statica dell'Agent completamente separata dal Run Loop attivo è ciò che ti permette di riutilizzare in modo sicuro quello stesso identico Agent di estrazione del calendario su migliaia di esecuzioni simultanee senza alcun data bleeding. Grazie per l'ascolto, happy coding a tutti!
3

Equipaggiare gli Agent con i Python Function Tools

3m 24s

Dai ai tuoi agent la capacità di agire convertendo funzioni Python standard in tool eseguibili. Comprendi l'automatic schema generation e la type inference.

Download
Ciao, sono Alex di DEV STORIES DOT EU. OpenAI Agents SDK, episodio 3 di 18. Scrivere a mano i JSON schema per i tool dei language model è noioso e fragile. Basta una parentesi mancante o un type errato, e il modello non riesce a capire come interagire con il tuo sistema. Invece di scrivere a mano queste definizioni, ti basta scrivere del normale codice Python e lasciare che il framework faccia la traduzione. Questo è esattamente ciò di cui parliamo oggi: dotare gli agent di Python Function Tools. Un malinteso comune è pensare che esporre la logica locale a un agent richieda di mantenere due fonti di verità. Spesso si pensa di aver bisogno del codice Python vero e proprio, più un file di configurazione JSON separato e complesso che descriva quel codice al language model. Con l'Agents SDK, eviti completamente di scrivere JSON a mano. Ti basta scrivere una funzione Python standard e posizionare il decorator function tool direttamente sopra di essa. Quando applichi quel decorator, l'SDK si mette al lavoro dietro le quinte usando il modulo inspect integrato di Python e Pydantic. Analizza la signature della tua funzione. Legge i nomi dei parametri, estrae i type hint e recupera la docstring della funzione. Da questi elementi, genera automaticamente un JSON schema rigoroso e lo collega all'agent. Vediamo uno scenario concreto. Vuoi dare al tuo agent una funzione chiamata fetch weather. Questa funzione ha bisogno di dati geografici precisi per funzionare. Invece di lasciare che il modello indovini quale formato di string usare, definisci una struttura specifica. Crei un custom type, magari un Typed Dictionary chiamato Location, che contiene campi string distinti per città e paese. Usi quindi questo type Location come type hint rigoroso per il parametro di input della tua funzione fetch weather. Ecco il punto chiave. Devi aggiungere una docstring chiara a questa funzione. Potresti scrivere una semplice frase per indicare che questo tool recupera le condizioni meteo attuali per una città e un paese specifici. Il framework estrae questo testo e lo usa come descrizione principale del tool nel prompt. La tua docstring non è più solo una nota utile per i tuoi colleghi sviluppatori. È il vero e proprio manuale di istruzioni che l'agent valuta per decidere se attivare il tool. Se un utente chiede se ha bisogno di una giacca a Tokyo, l'agent esamina i tool disponibili. Legge la tua docstring, capisce che la funzione fetch weather fornisce la risposta e struttura una richiesta. Dato che hai usato il type hint per l'input con il tuo dizionario Location, Pydantic garantisce che l'output dell'agent corrisponda esattamente ai campi richiesti prima ancora che la tua logica Python venga eseguita. Se il modello prova a passare una singola string di testo invece del dizionario, il framework intercetta l'errore e forza l'agent a riprovare con la struttura corretta. L'SDK esegue la funzione localmente, cattura il valore di ritorno e lo reinserisce direttamente nel reasoning loop dell'agent. I tuoi type hint e le tue docstring Python standard non sono più documentazione passiva; formano il contratto API attivo e vincolante su cui il tuo agent si basa per interagire con il mondo reale. Grazie per aver passato qualche minuto con me. Alla prossima, stammi bene.
4

Scalare le Tool Surfaces con Hosted Tool Search

3m 22s

Impara a gestire enormi librerie di tool senza esaurire il tuo budget di token. Trattiamo il deferred loading, i namespace e l'hosted tool execution.

Download
Ciao, sono Alex di DEV STORIES DOT EU. OpenAI Agents SDK, episodio 4 di 18. Passare un centinaio di tool a un modello linguistico distrugge le performance e brucia il tuo budget di token prima ancora che venga eseguita una singola azione. Non puoi infilare ogni schema API aziendale nella context window iniziale e aspettarti un buon ragionamento. La soluzione a questo problema è scalare la tool surface con l'Hosted Tool Search. Prima di parlare di scaling, dobbiamo definire gli hosted tool. Gli hosted tool vengono eseguiti nativamente sull'infrastruttura OpenAI anziché girare sulla tua macchina locale. Esempi integrati includono il Web Search Tool e il File Search Tool. Non devi scrivere la logica di esecuzione, gestire il web crawler o creare il meccanismo di file chunking per questi tool. Li attacchi al tuo agent, e il backend di OpenAI gestisce il lavoro vero e proprio. Ma il concetto di hosted tool si estende a come il modello scopre i tuoi custom tool quando ne hai troppi. Prendi ad esempio un agent CRM. Potresti avere cinquanta tool diversi per controllare lo stato degli ordini, recuperare lo storico di fatturazione, aggiornare gli indirizzi di spedizione e recuperare i log di supporto. Se passi tutti e cinquanta gli schemi in anticipo, sovraccarichi il modello e sprechi token di input. Molti sviluppatori pensano di dover risolvere questo problema creando uno step di retrieval lato client. Danno per scontato di dover intercettare il prompt dell'utente, cercare in un vector database locale gli schemi dei tool pertinenti e iniettarli dinamicamente nel prompt prima di chiamare il modello linguistico. Non hai bisogno di farlo. L'Hosted Tool Search avviene nativamente sui server OpenAI usando la Responses API. Il modello stesso è in grado di cercare nella tool surface disponibile senza che il tuo codice client faccia da intermediario. Puoi ottenere questo risultato usando due parametri: tool namespace e defer loading. Quando registri i tuoi tool CRM, raggruppi le funzioni correlate assegnandole a un namespace condiviso. Ad esempio, potresti inserire tutti i tool del profilo cliente in un namespace chiamato customer account. Poi, imposti il parametro defer loading a true per quei tool. Questa è la parte che conta. Quando il defer loading è attivo, l'agent non invia i singoli schemi dei tool al modello linguistico all'inizio della conversazione. Invece, invia un singolo schema leggero che rappresenta il namespace customer account stesso. Il modello viene informato dell'esistenza di questo namespace e sa come interrogarlo se necessario. Quando l'utente chiede di cercare uno specifico customer ID, il modello si rende conto di aver bisogno di maggiori informazioni. Esegue una ricerca nativa sul namespace customer account. I server OpenAI trovano il tool di fatturazione o di supporto pertinente, caricano solo quello specifico schema del tool nel context del modello, e poi il modello esegue il tool call. Questo disaccoppia completamente la dimensione della tua tool library dal tuo costo in token iniziale. Potresti attaccare centinaia di tool a un singolo agent, e il prompt iniziale rimane minuscolo. Il modello paga il prezzo in token solo per gli schemi dei tool specifici che decide attivamente di caricare a runtime. Facendo il defer loading, scambi un enorme peso sul context statico con un meccanismo di retrieval dinamico e preciso. Per questo episodio è tutto. Alla prossima!
5

Delegazione Decentralizzata: Il Pattern Handoff

3m 22s

Padroneggia l'arte dell'orchestrazione multi-agent usando il pattern Handoff. Scopri come creare triage agent che delegano fluidamente il controllo totale a sub-agent specializzati.

Download
Ciao, sono Alex da DEV STORIES DOT EU. OpenAI Agents SDK, episodio 5 di 18. A volte il modo migliore in cui un manager può gestire un task complesso è farsi completamente da parte. Se il tuo routing agent principale cerca di mediare ogni interazione tra un utente e i tuoi sistemi di backend, i tuoi prompt diventano enormi e l'esecuzione diventa inaffidabile. Questo è esattamente ciò che la delega decentralizzata, e nello specifico l'Handoff Pattern, è progettata per risolvere. Un handoff è un meccanismo in cui un agente trasferisce il pieno controllo della conversazione a un altro agente. Un errore comune è confondere un handoff con il normale tool calling. Sono fondamentalmente diversi. Quando un agente chiama una funzione normale, va in pausa, aspetta che i dati vengano restituiti e poi formula una risposta per l'utente. Quando un agente innesca un handoff, cede l'intero turno della conversazione. Il controllo passa completamente al nuovo agente. L'agente originale si fa completamente da parte. Questo è importante perché mantiene la tua architettura decentralizzata. Se un triage agent centrale deve elaborare l'output di ogni azione dello specialista, il suo system prompt deve essere enorme. Ha bisogno di istruzioni su come formulare le policy di rimborso, il troubleshooting tecnico e l'eliminazione dell'account. Peggio ancora, il triage agent cercherà inevitabilmente di raccontare il lavoro dello specialista all'utente. Questo spreca token, aggiunge latenza e introduce un alto rischio di allucinazioni. Gli handoff evitano questo problema lasciando che lo specialista parli direttamente con l'utente. Pensa a un sistema di customer support. Fai il deploy di un triage agent generico per salutare gli utenti e categorizzare le richieste. Un cliente scrive per chiedere di elaborare un rimborso. Hai anche un refund agent dedicato, equipaggiato con tool di fatturazione specifici e istruzioni rigorose sulla policy di reso aziendale. Per connetterli usando l'SDK, scrivi una funzione standard chiamata transfer to refund. Ma invece di restituire una string o dati JSON, questa funzione restituisce il tuo oggetto refund agent. Passi quindi questa funzione di transfer al tuo triage agent, elencandola proprio come qualsiasi altro tool. Quando il cliente chiede un rimborso, il triage agent decide di chiamare la funzione di transfer. Ecco il punto chiave. Il runner loop dell'SDK sottostante esegue la funzione e vede che è stato restituito un oggetto Agent invece di dati standard. Il runner sostituisce all'istante l'agente attivo nella sua memoria. Prende la history della conversazione esistente e la passa direttamente al refund agent appena attivato. Il refund agent prende il controllo del turno attivo, elabora la richiesta dell'utente, triggera i propri billing tool e risponde direttamente all'utente. Puoi anche passare dei dati durante questa transizione. Se il triage agent ha già chiesto all'utente il suo numero d'ordine, può passare quel numero d'ordine come argomento nella funzione di transfer. La funzione può quindi iniettare quel numero d'ordine nelle context variables del nuovo agente prima di restituirlo. Il refund agent si sveglia sapendo già esattamente quale transazione cercare. Usando gli handoff, mantieni ogni agente piccolo, focalizzato e prevedibile, lasciando che la conversazione fluisca naturalmente da un esperto all'altro. Questo è tutto per questo episodio. Grazie per l'ascolto, e continua a sviluppare!
6

Orchestrazione Centralizzata: Agents as Tools

3m 37s

Mantieni il controllo della conversazione in un unico posto usando il pattern Agents as Tools. Discutiamo di come un manager agent possa sintetizzare le risposte di più sub-agent specializzati.

Download
Ciao, sono Alex di DEV STORIES DOT EU. OpenAI Agents SDK, episodio 6 di 18. Se il tuo assistente AI deve consultare tre reparti diversi prima di rispondere a un utente, raramente vuoi che l'utente parli direttamente con questi reparti. Vuoi che una singola voce coerente gestisca la conversazione, recuperando le informazioni silenziosamente dietro le quinte. Questo è esattamente ciò che la Centralized Orchestration usando gli Agent come Tool ti permette di fare. Potresti confondere tutto questo con gli handoff, in cui un agent passa permanentemente l'utente a un altro agent. Con gli handoff, il nuovo agent prende completamente il controllo della conversazione. Con la centralized orchestration, il controllo non viene mai passato. L'agent principale, che di solito fa da manager, mantiene il controllo assoluto sulla conversazione. Il manager è l'unica voce che l'utente sente. Ottieni questo prendendo un agent completamente configurato e trasformandolo in una callable function. Ogni oggetto agent nell'SDK ha un metodo chiamato as_tool. Quando chiami questo metodo, incapsula l'intero agent, incluse le sue istruzioni specifiche e i suoi tool, in un formato tool standard. Successivamente, passi questo agent incapsulato al tuo manager agent, esattamente come faresti con una normale funzione Python. Vediamo uno scenario pratico. Stai creando un portale di customer support. Crei un booking specialist agent. Il suo unico compito è fare query sui sistemi interni, incrociare le date e restituire la disponibilità. Questo agent è altamente tecnico. Le sue istruzioni sono ottimizzate per la database accuracy, non per una conversazione cortese. Non vuoi che l'utente interagisca con questo specialista. Quindi, chiami il metodo as_tool sul booking specialist. Successivamente, crei il tuo manager agent. Dai al manager istruzioni precise per mantenere un tono cortese e aziendale e gestire la relazione con l'utente. Infine, aggiungi il booking specialist incapsulato alla lista di tool del manager. Quando un utente chiede al manager di verificare la disponibilità per il prossimo martedì, il manager elabora la richiesta. Riconosce di non avere i dati effettivi, ma sa di avere un tool in grado di trovarli. Il manager invoca il tool di prenotazione. Ecco il punto chiave. Quando viene invocato quel tool, il booking specialist agent si attiva, esegue i propri step interni in modo isolato e produce una risposta. Tuttavia, non invia quella risposta all'utente. Restituisce un risultato raw e fattuale direttamente al manager. Il manager riceve questi dati, li sintetizza, li incapsula in un cortese saluto aziendale e infine risponde all'utente. Questo pattern hub-and-spoke risolve un problema importante delle applicazioni complesse: il context bloat. Il manager agent non ha bisogno di conoscere il database schema o le regole per il controllo delle date. Mantiene pulito il suo system prompt, concentrandosi esclusivamente sul routing delle richieste e sulla formattazione delle risposte. Allo stesso tempo, lo specialist agent non deve preoccuparsi della conversation history o della brand voice. Si limita a svolgere il suo compito specifico e a restituire un risultato. Quando devi decidere tra un handoff e un tool, chiediti a chi spetta la risposta finale. Se lo specialized agent deve avviare un lungo dialogo con l'utente, vuoi un handoff. Ma se lo specialized agent è semplicemente un sofisticato elaboratore di dati che fornisce una risposta da far utilizzare all'assistente principale, wrappalo come tool e lascia che sia il manager a gestire la relazione. Grazie per aver passato qualche minuto con me. Alla prossima, stammi bene.
7

Plasmare il Contesto con Handoff Inputs e Filters

4m 09s

Ottimizza l'uso dei token multi-agent modificando le cronologie delle conversazioni tra gli handoff. Impara a iniettare metadati e ad applicare transcript filters.

Download
Ciao, sono Alex di DEV STORIES DOT EU. OpenAI Agents SDK, episodio 7 di 18. Quando trasferisci un cliente a uno specialista umano, non lo obblighi a leggere un'enorme trascrizione grezza di ogni controllo automatico di sistema appena eseguito. Gli fornisci un motivo chiaro per il trasferimento e un riassunto pulito del problema. Eppure, quando gli sviluppatori connettono gli agenti IA, spesso riversano l'intero chat log grezzo nella context window dell'agente successivo. Oggi risolviamo questo problema modellando il context con gli Handoff Input e i Filter. Quando un agente passa il controllo a un altro, ha bisogno di un modo per comunicare il motivo dell'handoff. Lo fai usando il parametro input type nella tua routine di handoff. Definisci uno schema, tipicamente un modello Pydantic, che specifica esattamente quali informazioni richiede l'agente ricevente. Quando l'agente corrente decide di eseguire l'handoff, il modello linguistico sottostante genera un payload che corrisponde a questo schema. Chiariamo subito un equivoco comune. È facile confondere questo input type con lo state persistente dell'applicazione, come l'ID di un profilo utente o una connessione al database di backend che rimane viva per tutta la sessione. Non è così. L'input type serve strettamente per metadati transitori generati dal modello, creati esattamente al momento dell'handoff. Ad esempio, se un agente di triage passa un utente a uno specialista della fatturazione, l'input type potrebbe richiedere un campo chiamato escalation reason. L'agente di triage genera una breve string che spiega lo specifico errore di fatturazione, e l'agente di fatturazione riceve quei dati strutturati non appena si attiva. Questo gestisce il messaggio esplicito di handoff. Ora dobbiamo gestire la conversation history. Di default, l'intera message history viaggia con l'handoff. Ogni prompt dell'utente, ogni reply dell'assistente e ogni tool call in background vengono passati oltre. Questo brucia rapidamente i token e riempie la context window di rumore irrilevante. Puoi controllare questo aspetto usando un input filter. Un input filter è una funzione Python standard che intercetta la conversation history un attimo prima che l'agente ricevente la legga. Prende la lista completa dei messaggi precedenti come argomento, li elabora e restituisce una nuova lista di messaggi modificata. Immagina uno scenario in cui il tuo agente iniziale ha passato dieci turni a chiamare vari search tool e API del database cercando di risolvere un problema, prima di arrendersi e indirizzare l'utente a un agente FAQ generico. L'agente FAQ ha bisogno solo delle vere domande dell'utente. Non ha assolutamente bisogno degli output JSON grezzi di dieci tool call fallite. Per risolvere questo problema, scrivi una funzione di input filter. Al suo interno, iteri attraverso la lista dei messaggi in arrivo. Controlli il role di ogni messaggio. Se il messaggio è un'esecuzione di un tool o un tool result grezzo, lo scarti. Se è un messaggio diretto dell'utente o una reply finale dell'assistente, lo aggiungi in append alla tua nuova lista. Quindi restituisci questa lista pulita e colleghi la tua funzione di filter alla definizione dell'handoff. L'agente FAQ ora riceve una history snellita che contiene solo il botta e risposta human-readable. Ecco il punto chiave. Gli handoff input aggiungono intelligenza strutturata alla transizione, mentre gli input filter tagliano il rumore senza pietà. Insieme, modellano esattamente ciò che l'agente ricevente sa. Risparmi token, riduci la latenza e impedisci al nuovo agente di avere allucinazioni basate sul ragionamento scartato dell'agente precedente. Controllare il context al confine dell'handoff è il modo in assoluto più efficace per mantenere un sistema multi-agente veloce e preciso. Se vuoi aiutare a far andare avanti lo show, puoi cercare DevStoriesEU su Patreon: il tuo supporto significa molto. Questo è tutto per questo episodio. Grazie per l'ascolto, e continua a sviluppare!
8

Controllare lo State: to_input_list e Server IDs

4m 00s

Un'analisi approfondita della gestione manuale delle conversazioni. Comprendi i metodi di più basso livello per preservare il contesto tra i turni e utilizzare i response IDs lato server.

Download
Ciao, sono Alex di DEV STORIES DOT EU. OpenAI Agents SDK, episodio 8 di 18. Un agente IA con amnesia è inutile. Ma salvare la sua memoria in modo errato può duplicare silenziosamente la cronologia della conversazione e raddoppiare i costi delle API. Questo succede quando mischi accidentalmente metodi diversi per tracciare la cronologia della chat. Oggi parliamo del controllo dello state: to_input_list e Server ID. Di default, una run base di un agente è completamente stateless. Invii una stringa e ricevi una stringa. Se fai una domanda di follow-up, l'agente non ha alcun contesto su ciò di cui hai appena discusso. Devi fornire tu la cronologia. Anche se l'SDK offre wrapper di sessione ad alto livello, a volte ti serve il metodo di più basso livello e più trasparente per mantenere la cronologia della chat su più turni, senza alcuno state nascosto magicamente. Ci sono due modi espliciti per gestirlo. Il primo metodo mantiene la source of truth sulla tua macchina usando un metodo chiamato to_input_list. Quando un agente finisce una run, restituisce un oggetto result. Questo oggetto contiene la risposta finale, ma contiene anche i passaggi nascosti che l'agente ha fatto per arrivarci. Se l'agente ha chiamato un tool del database, ha letto l'output e poi ha formulato una risposta, tutti questi passaggi intermedi fanno parte dello state della conversazione. Chiamare to_input_list sull'oggetto result impacchetta l'intera sequenza. Restituisce un array flat che contiene il prompt originale dell'utente, le risposte dell'agente, le tool call specifiche e i tool output. Formatta tutto esattamente come l'API si aspetta di riceverlo. Se stai costruendo un loop di chat da riga di comando, la logica è questa. Definisci una variabile per contenere l'array della conversazione. All'inizio, contiene solo il primo prompt dell'utente. Passi questo array all'agente. Quando l'agente finisce, prendi il result e chiami to_input_list, che ti dà la cronologia completa e aggiornata di quel turno. Quando l'utente digita la sua seconda domanda, fai l'append manuale del suo nuovo messaggio alla fine di quella lista, e passi di nuovo il tutto all'agente. Hai il controllo totale del payload. Ora, la seconda parte. Trasferire avanti e indietro sulla rete un array enorme di messaggi precedenti e tool output in JSON a ogni singolo turno, consuma banda. Se vuoi evitarlo, puoi usare i Server ID. Ogni risposta che ricevi dall'API include un identificatore univoco. Invece di passare un array di messaggi passati nella tua prossima run dell'agente, passi un parametro chiamato previous_response_id. Ecco il punto chiave. Quando fornisci un previous_response_id, il tuo client invia solo il nuovo messaggio dell'utente. Non invii l'array della cronologia. Il server di OpenAI cerca quell'ID, recupera il thread di contesto esistente lato suo, ci attacca il tuo nuovo messaggio e genera la risposta successiva. Questo ci porta a una trappola critica. Potresti essere tentato di mischiare questi approcci. Potresti fare l'append dell'input dell'utente alla lista lato client, passare quella lista completa all'agente e, per sicurezza, passare anche il previous_response_id. Non farlo. Devi scegliere esattamente una strategia per conversazione. Se fornisci sia l'array completo della cronologia che un previous_response_id, il server li concatenerà. Il tuo agente leggerà l'intera conversazione due volte, si confonderà per le tool call duplicate, e tu pagherai due volte per quei token. La scelta tra questi due metodi si riduce a visibilità contro efficienza. Usa le liste lato client quando devi fare audit, filtrare o modificare la cronologia della conversazione tra un turno e l'altro. Usa i Server ID quando ti fidi del thread grezzo e vuoi minimizzare il tuo payload di rete. Questo è tutto per questo episodio. Grazie per l'ascolto, e continua a sviluppare!
9

Automatizzare la Memoria con le Built-in Sessions

3m 53s

Semplifica i tuoi chat loop con il sistema di memoria integrato nell'SDK. Esploriamo SQLiteSession, OpenAIConversationsSession e la persistenza automatizzata.

Download
Ciao, sono Alex di DEV STORIES DOT EU. OpenAI Agents SDK, episodio 9 di 18. Stai creando un chat bot persistente. Scrivi del codice per recuperare i messaggi precedenti da un database, passarli al tuo agent, estrarre la nuova risposta e riscrivere la lista aggiornata nel database. È il solito noioso boilerplate che hai scritto decine di volte. Oggi vediamo come automatizzare la memoria con le Built-in Sessions, che sostituiscono tutta quella logica di read e write sul database con un singolo oggetto. Chiariamo subito un malinteso comune. Quando gli sviluppatori iniziano a usare le session in questo SDK, spesso pensano di dover ancora recuperare e passare manualmente la message history all'agent runner insieme alla session. Non è così. Passare un oggetto session al runner sostituisce completamente la gestione manuale della history. Gli consegni le chiavi. Il runner recupera automaticamente i messaggi passati un attimo prima che inizi il turno di conversazione, e fa l'append automatico dei nuovi messaggi non appena il turno finisce. Prendi ad esempio un bot Slack persistente che deve ricordare le preferenze dell'utente nel corso dei giorni. Vuoi salvare questo state su disco senza dover tirare su un database esterno pesante. L'SDK fornisce un tool built-in per questo scopo, chiamato SQLite Session. Dato che interagire con un file system richiede operazioni di input output, questo tool è completamente asincrono. Per usarlo, per prima cosa istanzi una SQLite Session, passando un file path per il tuo database locale. Poi, ti ci connetti usando un async context manager. Pensala come l'apertura di una connessione sicura che garantisce che il file del database venga correttamente messo in lock e unlock. All'interno di quel blocco di connessione, chiami il tuo agent runner. Invece di passare un array di messaggi passati al runner, passi semplicemente l'oggetto session e un session ID. Il session ID è semplicemente una string univoca. Per il tuo bot Slack, questo ID potrebbe essere lo user ID o il channel ID. Il runner prende quell'ID, cerca nel file SQLite, carica la history esistente, processa il prompt dell'utente e poi persiste in modo sicuro il nuovo state nel file. Tutto questo avviene dietro le quinte. Ecco il punto chiave. Una history di conversazione illimitata finirà per rompere i limiti della tua context window. Non vuoi certo che una chiacchierata di tre mesi fa faccia gonfiare il tuo utilizzo di token o causi il crash della tua chiamata API oggi. Per controllare questo aspetto, l'SDK fornisce i Session Settings. Quando chiami il runner, puoi includere un oggetto Session Settings insieme alla session stessa. Questo oggetto settings accetta un parametro per il numero massimo di messaggi passati. Se lo imposti a dieci, il runner tronca automaticamente la history caricata. Mantiene solo i dieci messaggi più recenti nel context attivo inviato al modello, ma il tuo intero log storico rimane al sicuro e intatto nel database SQLite. SQLite Session è l'ideale per la persistenza locale o per applicazioni single server. Se il tuo bot Slack cresce e hai bisogno di scalare su più server, l'SDK lo gestisce senza problemi. Mantieni il codice del tuo runner esattamente uguale, ma sostituisci la SQLite Session locale con un'opzione distribuita come una Redis Session o una Dapr Session. Il concetto chiave è che le session forzano una rigorosa separation of concerns. Configurando un oggetto session e passandolo al runner, elimini il fragile boilerplate del database e garantisci che la memoria del tuo agent sia sempre perfettamente sincronizzata con il suo execution state. Per oggi è tutto. Grazie per l'ascolto: vai a creare qualcosa di fantastico!
10

Proteggere i Workflow: Input e Output Guardrails

3m 38s

Metti in sicurezza le tue pipeline IA intercettando gli input malevoli prima che raggiungano modelli costosi. Trattiamo i guardrail a livello di agent e l'esecuzione parallela rispetto a quella bloccante.

Download
Ciao, sono Alex di DEV STORIES DOT EU. OpenAI Agents SDK, episodio 10 di 18. Il tuo modello di ragionamento più potente è anche il più costoso. Se un utente cerca di ingannarlo per fargli fare i compiti di matematica o violare le policy di sicurezza, non vuoi certo scoprirlo dopo che ha impiegato due minuti e mille token per pensarci. Proteggere i tuoi workflow con i guardrail di input e output è il modo per evitarlo. I guardrail a livello di agent funzionano da buttafuori per i tuoi modelli principali. Sono funzioni separate, spesso basate su modelli più piccoli, veloci ed economici, che validano i dati in entrata o in uscita dal tuo agent. Intercettando le request, mantengono i tuoi modelli più costosi concentrati sul lavoro reale e garantiscono che la tua applicazione resti sicura e in topic. Li applichi in due punti: in input e in output. I guardrail di input valutano il prompt dell'utente prima che il tuo agent principale si metta al lavoro. Immagina uno scenario in cui hai un modello pesante e lento che gestisce analisi finanziarie complesse. Puoi configurare un guardrail di input usando un modello veloce e leggero per esaminare ogni messaggio in arrivo. Quando un utente fa una domanda, questo modello veloce la intercetta. Verifica se l'utente sta cercando di far fare un compito scolastico all'agent, o se magari sta tentando un attacco di prompt injection. Se l'input viene flaggato, il guardrail lo rifiuta immediatamente e restituisce un messaggio di rifiuto standard. Il tuo modello di ragionamento pesante non si sveglia nemmeno. Risparmi tempo e risparmi soldi. I guardrail di output gestiscono l'altra estremità della transazione. Forniscono un controllo finale prima che l'utente veda la risposta. L'agent principale ha completato il suo task, ma devi assicurarti che non ci siano leak di dati sensibili, o che il tono sia in linea con le linee guida aziendali. Il guardrail di output esamina il testo generato. Se rileva un'allucinazione o una violazione delle policy, blocca il messaggio prima che raggiunga l'utente. Ecco il punto chiave. L'impatto di questi guardrail sulla tua applicazione dipende interamente dalla loro execution mode. Puoi eseguirli in blocking mode o in parallel mode. Il blocking mode è una sequenza rigorosa. Un guardrail di input deve finire la sua valutazione e restituire un esito positivo prima che l'agent principale possa partire. Un guardrail di output deve finire di controllare la risposta finale prima che l'utente riceva una sola parola. Questo è l'approccio più sicuro e ti garantisce di non sprecare soldi per delle bad request, ma aggiunge latenza all'interazione. Il parallel mode scambia il controllo rigoroso dei costi con la velocità. Un malinteso comune è che l'esecuzione in parallelo metta in qualche modo in pausa l'agent principale mentre il guardrail gira al suo fianco. Non è così. In parallel mode, il guardrail di input e l'agent principale partono esattamente nello stesso momento. L'agent sta attivamente generando testo e consumando token mentre il guardrail sta ancora valutando il prompt di input. Se il guardrail decide di bocciare la request, interromperà l'agent principale in corso d'opera. L'utente è comunque protetto dal vedere l'output, ma paghi lo stesso i token che l'agent primario ha consumato prima di essere interrotto. Puoi configurarlo definendo una semplice funzione che restituisce una decisione di pass o fail, attaccandola al tuo agent e dichiarando la sua modalità. Allinea sempre la tua execution mode alle tue priorità: usa i guardrail in blocking mode per proteggere il tuo portafoglio dai modelli costosi, e i guardrail in parallel mode per proteggere la tua user experience dalla latenza. Questo è tutto per questo episodio. Grazie per l'ascolto e continua a sviluppare!
11

Validare le Azioni: Tool-Level Guardrails

4m 01s

Previeni fughe di dati critici a livello di funzione. Impara a wrappare tool specifici con precisi input e output guardrails.

Download
Ciao, sono Alex di DEV STORIES DOT EU. OpenAI Agents SDK, episodio 11 di 18. Anche l'IA più intelligente può far trapelare accidentalmente un secret del database se tira dentro dati raw direttamente nel suo context. Potresti pensare che i tuoi controlli di sicurezza top-level intercettino tutto, ma questi girano solo all'inizio o alla fine di una conversazione. Se vuoi intercettare dati sensibili a metà del workflow, hai bisogno delle Validating Actions, e nello specifico dei Tool-Level Guardrails. Una trappola comune è presumere che gli agent-level guardrails proteggano i tuoi sistemi sottostanti. Non è così. I guardrail dell'agent processano il prompt iniziale dell'utente o la response finale inviata all'utente. Sono ciechi di fronte al back-and-forth interno quando un agent chiama un database o un'API di terze parti. Se un prompt malevolo inganna il tuo agent facendogli chiamare un tool interno, i controlli a livello di agent non lo fermeranno. Per proteggere i tool stessi, l'OpenAI Agents SDK fornisce i tool guardrails. Questi stanno direttamente sulla function, agendo come un checkpoint obbligatorio subito prima o subito dopo l'esecuzione del tool. Ci sono due tipi che devi conoscere. Il primo è il tool input guardrail. Applichi questo decorator per validare gli argomenti prima che il tool vero e proprio giri. Mettiamo che un agent provi a chiamare un tool che elimina un account utente. L'input guardrail intercetta gli argomenti generati dall'agent. Controlla se lo user ID fornito corrisponde a un formato valido, o se la sessione corrente ha il corretto livello di autorizzazione. Se l'input fallisce questo controllo, il guardrail blocca completamente l'esecuzione del tool. Invece di eseguire l'eliminazione, restituisce un messaggio di errore direttamente all'agent. L'agent quindi legge quell'errore e può riprovare con gli input corretti, senza mai toccare il database reale. Ora, il secondo pezzo di tutto questo è il tool output guardrail. Questo entra in azione dopo che il tool è stato eseguito con successo, ma prima che il risultato venga restituito all'agent. È qui che filtri, oscuri o validi il payload. Prendi come esempio un tool di database lookup. L'agent chiede un profilo da sviluppatore, e il tool recupera il raw record. Tuttavia, quel record per caso contiene un'API key attiva che inizia con le lettere s-k-dash. Se quella raw key torna all'agent, entra nella context window del language model. Questo è un enorme rischio per la sicurezza. Per risolvere questo problema, aggiungi un tool output guardrail a quella specifica funzione di lookup. Il guardrail prende il risultato raw del database, scansiona il testo alla ricerca di quel pattern s-k-dash e sostituisce la key effettiva con una stringa placeholder come redacted. Solo dopo questo processo di pulizia i dati puliti vengono restituiti all'agent. L'agent riceve comunque le informazioni del profilo di cui ha bisogno per rispondere all'utente, ma il secret non esce mai dal confine di esecuzione isolato del tool. Questa è la parte che conta. In complessi workflow multi-agent, diversi agent specializzati potrebbero invocare dei tool in sequenze imprevedibili. Non puoi affidarti al prompting dell'agent per farlo comportare in modo sicuro. Non puoi nemmeno sperare che il filtro di output finale intercetti una key trapelata proprio prima che arrivi all'utente, perché a quel punto la key è già stata esposta al language model. Devi blindare il tool stesso. Attaccando il guardrail direttamente alla function, la logica di sicurezza viaggia con il tool. Non importa quale agent lo chiami o quando venga chiamato nel workflow. La protezione è assoluta. I tool guardrails trattano le tue function come confini zero-trust, assicurando che, per quanto autonomo diventi il tuo agent, non possa mai passare bad data in input, o tirare fuori dati sensibili. Questo è tutto per questo episodio. Grazie per aver ascoltato, e continua a sviluppare!
12

Mettere in Pausa l'Esecuzione: Human-in-the-Loop e RunState

3m 21s

Implementa salvaguardie per le azioni irreversibili imponendo approvazioni human-in-the-loop. Esploriamo la pipeline di serializzazione RunState per mettere in pausa e riprendere i workload.

Download
Ciao, sono Alex di DEV STORIES DOT EU. OpenAI Agents SDK, episodio 12 di 18. Non permetteresti a un nuovo stagista di droppare un database in produzione senza prima chiedere il permesso. Neanche il tuo agent AI dovrebbe poterlo fare. Quando un agent ha accesso a tool altamente distruttivi o sensibili, ti serve un modo per fermarlo, controllare il suo lavoro e dare l'ok manuale. Questo si risolve mettendo in pausa l'esecuzione, ovvero con l'approccio Human-in-the-Loop e il RunState. Se hai bisogno che un umano approvi un'azione, il tuo primo istinto potrebbe essere quello di mettere in pausa lo script Python e aspettare un input da tastiera. Non farlo. Tenere vivo un processo mentre aspetti una risposta via email o un clic su una dashboard spreca risorse del server. Inoltre, si rompe completamente se il server si riavvia o se fai il deploy di nuovo codice. L'OpenAI Agents SDK gestisce la cosa in modo pulito, permettendo al processo Python di terminare del tutto e riprendere più tardi su un server completamente diverso. Tutto inizia dalla definizione del tool. Quando scrivi una funzione per il tuo agent, come un tool chiamato delete production database, applichi un flag impostando needs approval a true. Quando l'agent elabora un prompt e decide che deve chiamare questo specifico tool, il motore si ferma immediatamente. Il tool non viene eseguito. Invece, il runner restituisce il controllo al codice della tua applicazione. Ecco il punto chiave. Quando l'esecuzione si ferma, il runner ti restituisce un oggetto RunState. Questo oggetto contiene l'intero contesto della run fino a quel preciso millisecondo. Conosce la history della conversazione, il processo di pensiero interno dell'agent e la specifica tool call che vuole eseguire subito dopo. Prendi questo oggetto RunState e lo serializzi in una string JSON standard. Salvi quel payload JSON nel tuo database, lo inserisci in una coda, o lo scrivi su disco. Una volta che quello stato è salvato in modo sicuro, il tuo script Python termina. La tua applicazione ora è in idle. Possono passare ore o persino giorni. Alla fine, un engineering manager fa login su una web dashboard, vede la cancellazione del database in pending e clicca approve. Quel clic innesca una nuova web request. Il tuo backend si sveglia e legge il payload JSON salvato dal database. Deserializza quella string per farla tornare un oggetto RunState valido. A questo punto, avvii una nuova esecuzione del runner. Passi la stessa istanza dell'agent, il RunState ripristinato e la decisione umana. Se passi un'approvazione, il runner esegue il tool di cancellazione del database e l'agent continua a rispondere all'utente. Se il manager ha cliccato reject, passi invece un rifiuto. Il runner non esegue il tool. Riporta il rifiuto all'agent come un tool error, forzando l'agent ad adattare il suo piano o a dire all'utente che l'azione è stata negata. Serializzando il RunState, trasformi uno script sincrono in un workflow asincrono, permettendo a umani e agent di collaborare in sicurezza attraverso qualsiasi intervallo di tempo, senza lasciare appeso un singolo processo sul server. Se vuoi aiutarci a mandare avanti lo show, puoi supportarci cercando DevStoriesEU su Patreon. Grazie per essere stato con noi. Spero tu abbia imparato qualcosa di nuovo.
13

Iniettare Dipendenze Locali con RunContextWrapper

3m 59s

Padroneggia la dependency injection nei flussi del tuo agent. Impara a passare in modo sicuro local states e connessioni al database ai tool senza farli trapelare all'LLM.

Download
Ciao, sono Alex di DEV STORIES DOT EU. OpenAI Agents SDK, episodio 13 di 18. Come fai a comunicare a una funzione quale utente sta chattando, senza insegnare per sbaglio all'LLM l'ID privato dell'utente nel database? Se lo inserisci nel system prompt, esponi dati interni e sprechi token. Per passare uno state locale e sicuro ai tuoi tool, usi la dependency injection locale con RunContextWrapper. Un errore comune quando crei degli agent è trattare il language model come intermediario per tutto. Gli sviluppatori spesso cercano di inserire le connection string del database, le API key interne o gli identificatori privati degli utenti direttamente nelle system instruction. Lo fanno sperando che il modello passi diligentemente queste credenziali sensibili alle tool call come parametri. Questo è un grosso rischio per la sicurezza. Inoltre, consuma inutilmente i token della context window e aumenta la probabilità che il modello abbia delle allucinazioni con parametri errati. L'approccio corretto è bypassare completamente il language model per il tuo execution state locale. Il RunContextWrapper fornisce un transport layer sicuro per iniettare le dipendenze direttamente nei tuoi tool e nei lifecycle hook. L'attributo context associato a questo wrapper è uno state Python puramente locale. Il modello non lo vede, non lo legge e non ha bisogno di ragionarci su. Considera uno scenario concreto. Un utente autenticato sta chattando con il tuo agent di customer support e chiede di visualizzare i suoi dati di fatturazione recenti. Il tuo sistema deve recuperare questi dati, il che significa che il tuo tool di fatturazione richiede l'ID interno del database dell'utente per eseguire la query sul database in modo sicuro. Per prima cosa, definisci la tua dipendenza locale nel codice della tua applicazione. Potresti creare una data class strutturata chiamata User Info che contiene l'ID utente interno. Successivamente, scrivi la tua tool function per recuperare la cronologia di fatturazione. Nella signature di questa tool function, definisci un parametro tipizzato specificamente per accettare l'oggetto context. L'SDK comprende questo type hint e sa di non dover esporre questo parametro al language model. All'interno del corpo della funzione, accedi al parametro context, estrai la tua dipendenza User Info e usi quell'ID utente privato per fare una query sicura al tuo backend. Ecco il punto chiave. Quando ti prepari a eseguire la run dell'agent, non passi semplicemente il messaggio grezzo dell'utente. Crei un'istanza del RunContextWrapper. Attacchi la tua data class User Info popolata direttamente al wrapper. Quindi, passi questo wrapper all'execution runner. Il flusso logico gestisce automaticamente il resto. Quando l'utente richiede la sua cronologia di fatturazione, il language model decide di attivare il tuo tool di fatturazione. Il modello fornisce solo gli argomenti che conosce dalla conversazione pubblica, magari filtrando per un mese specifico o un numero di fattura. Non ha assolutamente idea di chi sia l'utente sul tuo backend. Prima che la funzione venga effettivamente eseguita, l'SDK intercetta la chiamata. Ispeziona la signature del tool, nota che il tool richiede il context locale e inietta automaticamente lo state che hai attaccato al RunContextWrapper. Il tool viene eseguito utilizzando l'ID utente sicuro, recupera i record e restituisce i dati al modello per formulare una risposta. Questo stesso identico meccanismo di dependency injection funziona per gli execution hook, permettendoti di passare senza problemi connection pool attivi del database o tracing ID nel tuo event logging. Separando il ragionamento esterno del modello dall'esecuzione interna del tuo codice, la tua infrastruttura rimane sicura e i tuoi prompt restano interamente concentrati sul comportamento. Mantieni le tue execution dependency completamente locali e forza la tua architettura a basarsi interamente sullo state sicuro iniettato a runtime. Grazie per l'ascolto, buona giornata a tutti!
14

L'USB-C per l'IA: Introduzione a MCP

3m 17s

Un'introduzione al Model Context Protocol (MCP). Scopri come questo standard agisce da connettore universale per collegare facilmente gli AI agent alle piattaforme SaaS.

Download
Ciao, sono Alex di DEV STORIES DOT EU. OpenAI Agents SDK, episodio 14 di 18. Smetti di scrivere API wrapper custom ogni volta che il tuo agent deve comunicare con un nuovo servizio. Se sei stanco di mappare manualmente gli endpoint REST sui JSON schema solo per far capire al tuo language model cosa fa un servizio, finalmente c'è uno standard universale. Oggi vediamo il Model Context Protocol, o MCP, e come usarlo. Pensa a MCP come alla porta USB-C per l'AI. Prima dell'USB-C, ogni device aveva bisogno di un cavo di ricarica proprietario specifico. Nel mondo dell'AI, ogni sistema esterno richiede del glue code custom. Se vuoi che un agent legga un database o crei un ticket di supporto, scrivi un REST client. Poi scrivi uno schema intricato per descrivere quel client al model. Infine, scrivi la logica per intercettare la response del model e triggerare la richiesta HTTP vera e propria. MCP sostituisce questo lavoro manuale. È uno standard aperto che definisce esattamente come i tool descrivono se stessi, i loro input e i loro output direttamente a un model AI. Spesso si confonde MCP con le classiche REST API. Una REST API invia dati tra macchine, ma si aspetta che tu sappia esattamente come strutturare la request in anticipo. MCP standardizza il layer di discovery. Un MCP server comunica all'agent esattamente quali tool possiede e quali parametri sono richiesti, parlando l'esatto formato di cui il model ha bisogno. Nell'OpenAI Agents SDK, consumi questi MCP server esterni usando una classe chiamata Hosted MCP Tool. Ecco il punto chiave. Non devi ridefinire affatto il tool schema nel tuo codice Python. Invece, inizializzi l'Hosted MCP Tool passandogli l'URL di un MCP server remoto. Questa connessione opera tramite Server-Sent Events, il che permette al server di fare il push degli update al tuo agent in modo sicuro. Quando attacchi questo Hosted MCP Tool al setup del tuo agent, avviene un handshake. L'agent contatta il server remoto, chiede quali tool sono disponibili, tira giù le descrizioni complete e le registra automaticamente. Facciamo un esempio concreto. Vuoi dare al tuo agent la possibilità di programmare dei meeting. Senza MCP, dovresti studiarti le API di Google Calendar. Dovresti scrivere una funzione Python per autenticarti e creare gli eventi. Poi dovresti scrivere il tool schema in modo che l'agent sappia com'è fatto il titolo di un evento o un timestamp. Con MCP, fai il deploy di un MCP server di Google Calendar già pronto in remoto. Nel codice della tua applicazione, crei una nuova istanza di Hosted MCP Tool e la punti a quell'URL remoto. Passi questa singola istanza al tuo agent. Il server remoto comunica immediatamente all'agent che ha un tool chiamato schedule meeting. Quando il language model decide di programmare quel meeting, l'SDK fa da proxy per la call. Inoltra la request in modo sicuro sulla rete al server remoto, esegue l'azione e restituisce il risultato. Hai scritto zero righe di logica di integrazione col calendario. Il vero potere di MCP è disaccoppiare la logica core del tuo agent dalle integrazioni esterne, permettendoti di sostituire o aggiornare i servizi di backend semplicemente cambiando un URL. Grazie per l'ascolto, happy coding a tutti!
15

Connettere Local MCP Servers tramite Stdio e HTTP

3m 16s

Approfondisci MCP eseguendo server locali standard. Impara a mettere in sandbox l'accesso al filesystem e i tool interni in modo sicuro con MCPServerStdio.

Download
Ciao, sono Alex di DEV STORIES DOT EU. OpenAI Agents SDK, episodio 15 di 18. Dare a un language model l'accesso diretto al tuo filesystem locale può sembrare un vero incubo per la sicurezza. Ma se isoli rigorosamente questo accesso in una sandbox tramite un protocollo standardizzato, diventa un modo sicuro e potente per elaborare i dati locali. Oggi vedremo come connettere i server MCP locali tramite stdio e HTTP. Il Model Context Protocol definisce come i tuoi agent comunicano con tool e fonti di dati esterni. Quando vuoi eseguire questi server all'interno della tua infrastruttura, l'OpenAI Agents SDK offre due metodi di transport locali. Il primo è lo standard input e output, usando la classe chiamata MCPServerStdio. A volte si pensa che questo richieda un setup di networking locale complesso. Non è così. Quando usi il transport stdio, l'SDK semplicemente avvia il server MCP come child process locale. L'agent invia le request scrivendo sullo standard input di quel processo e legge le response dal suo standard output. Considera uno scenario in cui vuoi che il tuo agent legga dei file, ma solo da una specifica directory locale. Istanzii MCPServerStdio e gli passi il comando da eseguire. Per esempio, potresti passare il comando del node package manager npx, seguito dagli argument per lanciare il server filesystem MCP ufficiale, e l'absolute path alla tua target directory. Poiché questo server gira come subprocess, devi gestire il suo lifecycle. Se il tuo script Python finisce o crasha, non vuoi che un processo node orfano rimanga in background. L'SDK impone una gestione pulita del lifecycle richiedendo un context manager asincrono. Definisci un blocco async with per inizializzare il server stdio. Quando l'esecuzione entra nel blocco, l'SDK avvia il child process. Quando l'esecuzione esce dal blocco, esegue il teardown del processo in modo pulito. All'interno di quel blocco, connetti il server in esecuzione al tuo agent. Crei un MCP Client, gli passi la tua istanza del server stdio, e poi fornisci quel client al tuo agent. L'agent ora ha un accesso scoped e temporaneo alla tua directory locale. Ora, cosa succede se vuoi esporre un'API interna privata, o connetterti a un servizio che è già in esecuzione? Non vuoi spawnare un nuovo subprocess per questo. Questo ci porta alla seconda opzione di transport, che è MCPServerStreamableHttp. Invece di passare un comando eseguibile, fornisci a questa classe l'URL del tuo servizio esistente. Questo è perfetto per connettere in modo sicuro il tuo agent a un microservice interno in esecuzione su localhost. L'agent comunica facendo streaming di dati su HTTP. Ecco il punto chiave. L'agent stesso non ha idea di quale transport hai scelto. Il codice di connessione all'interno della tua applicazione è esattamente lo stesso. Usi ancora un context manager, crei ancora un client MCP, e lo passi ancora all'agent. L'SDK astrae completamente il transport layer. La cosa più utile da ricordare qui è che puoi sviluppare un custom tool come script stdio locale per il testing, e in seguito farne il deploy come servizio HTTP standalone in produzione, senza cambiare una singola riga della logica del tuo agent. Questo è tutto per questo episodio. Grazie per l'ascolto, e continua a costruire!
16

Visualizzare i Workflow con il Built-in Tracing

3m 29s

Elimina il debug tramite print statement usando l'observability integrata nell'SDK. Scopri come span e trace automatici collegano interi workflow complessi.

Download
Ciao, sono Alex di DEV STORIES DOT EU. OpenAI Agents SDK, episodio 16 di 18. Fare debug di un sistema multi-agente con i print è un incubo. Guardi i log scorrere, cercando di abbinare manualmente una tool execution alla riga cinquanta con una model generation alla riga duecento. Per fortuna, non dovrai più farlo. Questo episodio parla di come visualizzare i workflow con il tracing integrato. Quando gli sviluppatori iniziano a creare workflow complessi con gli agenti, il loro primo istinto è spesso quello di scrivere dei wrapper di logging personalizzati. Scrivono codice boilerplate per tracciare esattamente quando un agente si avvia, quali argomenti riceve un tool e quanto tempo impiega il modello a rispondere. Non farlo. L'Agents SDK lo gestisce per te, completamente out of the box. Ogni volta che esegui un agente, richiedi una generazione o attivi una tool call, l'SDK racchiude automaticamente quell'azione in uno span. Uno span è semplicemente un record strutturato e temporizzato di una singola operazione. Questi span catturano gli input, gli output e la durata del task. Vengono inviati automaticamente alla dashboard di OpenAI. Questo significa che ottieni una timeline visiva completa dell'esecuzione del tuo workflow senza scrivere una singola riga di codice di telemetria. Ecco il punto chiave. Mentre l'SDK gestisce i dettagli granulari, tu controlli il raggruppamento ad alto livello. Mettiamo che tu abbia uno scenario multi-turn in cui un agente genera una barzelletta, un secondo agente la valuta e il primo agente la perfeziona in base al feedback. Di default, l'SDK traccerà ciascuna di queste model generation e tool call come span distinti. Ma per un essere umano che guarda una dashboard, tutto questo botta e risposta è solo un'unica unità logica di lavoro. Puoi raggruppare queste azioni usando un trace block personalizzato. Apri un context block usando la funzione trace e gli dai un nome descrittivo, come joke generation loop. All'interno di quel blocco, esegui la logica multi-turn del tuo agente. L'SDK rispetta questa gerarchia. Anniderà tutti gli span generati automaticamente per le singole run, valutazioni e perfezionamenti sotto la tua parent trace personalizzata. Quando apri la dashboard di OpenAI, vedi per prima cosa il joke generation loop di top-level. Puoi quindi espanderlo per analizzare l'esatta sequenza di model call e tool execution avvenute all'interno. Questo copre la visibilità, ma per quanto riguarda la privacy? Ci sono momenti in cui non devi assolutamente inviare telemetria. Se il tuo agente gestisce cartelle cliniche sensibili, dati finanziari o richiede una rigorosa compliance Zero Data Retention, inviare i log di input e output a una dashboard è una violazione della sicurezza. Per queste situazioni, l'SDK fornisce un context block con tracing disabilitato. Quando racchiudi l'esecuzione del tuo agente all'interno di questo blocco, l'SDK smette completamente di generare e inviare span. L'esecuzione gira in locale, il risultato viene restituito alla tua applicazione, ma nessun record del prompt, delle tool call o della response apparirà sulla dashboard di OpenAI. Una volta che il codice esce da quel blocco disabilitato, il normale tracing automatico riprende per il resto della tua applicazione. Il tracing nell'SDK significa che smetti di scrivere codice di logging boilerplate, ottieni un visual debugging immediato e mantieni comunque il controllo totale su quando i tuoi dati restano interamente in locale. Questo è tutto per questo episodio. Grazie per l'ascolto, e continua a sviluppare!
17

Voce a Bassa Latenza con i Realtime Agents

3m 50s

Rompi il paradigma standard di request-response. Scopri come i Realtime Agents mantengono connessioni WebSocket live per gestire le interruzioni e il ragionamento multimodale.

Download
Ciao, sono Alex di DEV STORIES DOT EU. OpenAI Agents SDK, episodio 17 di 18. La parte più difficile nel creare un'IA vocale non è generare il parlato. È sapere quando zittirsi all'istante perché l'utente umano ha interrotto a metà frase. Se ti affidi al tradizionale ciclo request-response, la network latency smaschererà sempre il bot. Questo è esattamente il problema risolto dalla Low-Latency Voice con i Realtime Agents. Molti sviluppatori confondono questa architettura con una voice pipeline standard. In un setup tradizionale, catturi l'audio, lo passi a un modello Speech-to-Text, invii quel testo a un language model e infine passi l'output testuale a un sintetizzatore Text-to-Speech. Questa pipeline introduce latenza a ogni passaggio. I Realtime Agents scartano completamente questa pipeline. Usano un singolo modello multimodale che ragiona nativamente sull'audio. L'audio entra direttamente e lo stream audio esce direttamente. Non è necessaria alcuna traduzione intermedia in testo affinché il sistema capisca l'utente. Per ottenere questo risultato, devi rompere il paradigma standard di request-response HTTP. Invece di inviare un payload e aspettare una response completa, il sistema mantiene aperta una connessione persistente. Nell'SDK, gestisci tutto questo usando due componenti principali. Il primo è il RealtimeAgent. Questo oggetto contiene le tue system instruction e qualsiasi funzione o tool a cui il modello deve avere accesso. Definisce la logica, le capacità e la personalità del tuo assistente. Il secondo componente è il RealtimeRunner. Il runner è l'execution engine. Gestisce l'event loop asincrono e si occupa del network stream persistente, in genere tramite una connessione WebSocket o WebRTC. Immagina un bot di customer service telefonico che gestisce una chiamata in arrivo. Colleghi il tuo voice provider, magari integrandolo tramite SIP o WebSocket, facendo routing dell'audio continuo verso la tua applicazione Python. Crei il tuo RealtimeAgent, dotandolo di un tool per fare il fetch degli account utente. Poi, passi quell'agent e il tuo client di connessione di rete al RealtimeRunner. Quando chiami il metodo run sul runner, questo prende il controllo. Mantiene viva la connessione, ascoltando costantemente lo stream audio, mentre gestisce simultaneamente qualsiasi function call che l'agent deve fare. Fa push e pull degli eventi in entrambe le direzioni contemporaneamente. L'utente chiama e chiede il saldo del proprio conto. L'agent triggera il tool di account-fetch, ottiene i dati e inizia immediatamente a fare streaming della sua response vocale verso l'utente. A metà frase, l'utente improvvisamente parla sopra al bot, dicendo che in realtà vuole segnalare una carta smarrita. Ecco il punto chiave. Dato che la connessione WebSocket è costantemente aperta e il modello fa ingest nativamente dello stream audio in entrata in tempo reale, il server rileva all'istante la voce umana. Lancia un evento che interrompe il proprio output audio e registra la truncation. Non devi scrivere logica custom per calcolare esattamente quale chunk audio fosse in riproduzione quando l'utente ha parlato. L'architettura di streaming gestisce l'interruzione in modo trasparente. Il modello assorbe il nuovo contesto audio dall'interruzione e inizia immediatamente a fare streaming della response aggiornata sull'annullamento della carta smarrita. Ottieni dinamiche conversazionali del tutto naturali proprio perché il network layer e il model layer sono costruiti per lo streaming continuo. Il vero potere della Realtime API nell'Agents SDK è trattare la voce come un continuous stream di prim'ordine, piuttosto che come un batch di testo tradotto sotto mentite spoglie. Questo è tutto per questo episodio. Grazie per l'ascolto, e continua a sviluppare!
18

Costruire UI Reattive con gli Streaming Events

3m 43s

Vai oltre lo streaming dei token di testo. Utilizza i semantic streaming events per costruire interfacce frontend ultra-responsive che reagiscono alle azioni dell'agent in tempo reale.

Download
Ciao, sono Alex di DEV STORIES DOT EU. OpenAI Agents SDK, episodio 18 di 18. I tuoi utenti non vogliono solo leggere il testo mentre viene digitato sullo schermo. Vogliono vedere esattamente cosa sta facendo l'IA dietro le quinte. Se stai cercando di creare un loading spinner facendo il parsing di chunk di token grezzi per indovinare quando un search tool è in esecuzione, stai scegliendo la strada più difficile. Creare UI reattive con gli streaming event risolve esattamente questo problema. Spesso gli sviluppatori trattano gli output dell'IA come una semplice macchina da scrivere. Ascoltano uno stream di testo grezzo e scrivono una logica di parsing fragile per capire se l'agent sta per chiamare una funzione. Questo approccio è fragile. Si rompe se il modello cambia leggermente il modo di esprimersi, e lascia il tuo frontend in ritardo rispetto all'effettivo execution state. L'OpenAI Agents SDK offre un'alternativa strutturale. Invece di aspettare delle string, avvii il tuo agent usando un metodo chiamato run streamed sul tuo runner. Questo metodo non restituisce plain text. Al contrario, genera una sequenza asincrona di eventi semantici, ciascuno impacchettato come un oggetto Run Item Stream Event. Pensa a un Run Item Stream Event come a una notifica precisa sul lifecycle interno dell'agent. Mentre l'agent elabora una richiesta, emette segnali distinti e prevedibili. Ti indica esattamente quando un nuovo messaggio viene aggiunto al thread. Ti avvisa quando il controllo passa da un triage agent a un agent specializzato. Cosa fondamentale per il frontend development, ti dice l'esatto millisecondo in cui l'invocazione di un tool inizia e finisce. Applichiamo questo concetto a uno scenario concreto. Vuoi che il tuo frontend mostri uno spinner con scritto Searching database mentre l'agent cerca il record di un cliente. Chiami run streamed e cicli sui risultati. All'interno di quel ciclo asincrono, ispezioni ogni evento non appena arriva. Quando un evento arriva, controlli le sue proprietà per capire che tipo di update rappresenta. Quando un evento indica che è iniziata una tool call, puoi leggere il nome effettivo del tool direttamente dal payload dell'evento. Non devi fare il parsing di alcun linguaggio naturale. Se il nome del tool corrisponde alla tua funzione di ricerca nel database, fai subito il push di uno state update al tuo frontend per renderizzare lo spinner. Quando un evento successivo segnala che l'esecuzione del tool è completa, fai il dispatch di un altro update per nascondere lo spinner. Questi stream event trasportano anche i delta standard dei messaggi. Se l'agent sta generando una lunga risposta testuale, lo stream emette dei chunk event che vai ad appendere alla UI. L'architettura separa l'output conversazionale grezzo dalle azioni semantiche. Indirizzi i chunk di testo alla finestra di chat, e gli eventi di lifecycle del tool e dell'agent al tuo UI state manager. Questa separation of concerns ti permette di creare interfacce che risultano immediatamente reattive e profondamente connesse alla logica dell'agent. Stai reagendo all'effettivo execution path del sistema, non indovinando le sue intenzioni basandoti sulle parole. Ecco il punto chiave. Smetti di trattare l'output del tuo agent come un semplice conversation stream. Trattalo come una state machine event-driven, in cui ogni azione interna rappresenta un'opportunità per tenere il tuo utente visivamente informato. Visto che questo è l'ultimo episodio della serie, ti incoraggio a leggere la documentazione ufficiale e a provare a orchestrare tu stesso questi stream. Se hai idee su cosa dovremmo trattare in una serie futura, visita devstories dot eu e faccelo sapere. Per questo episodio è tutto. Alla prossima!