Introduzione
Nel primo articolo di questa serie abbiamo definito cosa sono gli agenti AI e quando usarli. Ora è il momento di entrare nel vivo dei meccanismi che li governano. Tre concetti fondamentali formano la spina dorsale di ogni sistema agente moderno: il loop OODA per la struttura decisionale, il pattern ReAct per l'alternanza ragionamento-azione, e il tool calling per l'interazione con il mondo esterno.
Questi non sono concetti accademici astratti: sono i pattern implementativi che ogni developer deve padroneggiare per costruire agenti efficaci, affidabili e debuggabili. LangGraph, CrewAI e AutoGen li implementano tutti internamente, ma comprendere i fondamenti teorici è ciò che distingue un developer che usa un framework da uno che ne comprende l'architettura e sa risolvere i problemi quando si presentano.
Cosa Imparerai in Questo Articolo
- Il loop OODA (Observe-Orient-Decide-Act) e la sua applicazione ai sistemi AI
- Il pattern ReAct: come alternare ragionamento e azione in modo strutturato
- Il meccanismo di tool calling: dal concetto all'implementazione
- Confronto tra ReAct, Chain-of-Thought e Function Calling puro
- Pattern avanzati: Tree-of-Thought e Plan-First
- Gli errori comuni da evitare nella progettazione di agenti
Il Loop OODA: Observe-Orient-Decide-Act
Il loop OODA (Observe, Orient, Decide, Act) è un framework decisionale sviluppato dal Colonnello John Boyd dell'US Air Force negli anni '70, originariamente per modellare il processo decisionale dei piloti da combattimento in situazioni ad alta velocità e incertezza. Boyd osservo che i piloti che vincevano i dogfight non erano necessariamente quelli con gli aerei più veloci, ma quelli che completavano il ciclo decisionale più rapidamente dei loro avversari.
Questo modello si è dimostrato straordinariamente versatile: dalla strategia militare al business, dalla cybersecurity all'intelligenza artificiale. Applicato ai sistemi agentici, il loop OODA fornisce il framework strutturale per comprendere come un agente AI elabora informazioni e prende decisioni.
Le Quattro Fasi del Loop OODA
1. Observe (Osservare)
La fase di osservazione consiste nella raccolta di dati dall'ambiente. Per un agente AI, le fonti di osservazione includono:
- Input dell'utente: il messaggio, la domanda o l'istruzione ricevuta
- Risultati dei tool: i dati restituiti dalle chiamate a strumenti esterni (risultati di ricerca, dati da API, contenuto di file)
- Stato della memoria: il contesto delle interazioni precedenti, le informazioni salvate nella memoria a lungo termine
- Feedback dell'ambiente: messaggi di errore, codici di stato HTTP, eccezioni, metriche di sistema
- Stato corrente del task: quali sotto-obiettivi sono stati completati, quali restano da eseguire
La qualità della fase di osservazione determina la qualità di tutto il resto del ciclo. Un agente che non raccoglie dati sufficienti o che ignora segnali importanti (come un codice di errore HTTP 429 rate-limit) produrra decisioni subottimali.
2. Orient (Orientarsi)
Boyd considerava questa la fase più critica dell'intero loop. L'orientamento consiste nel contestualizzare e interpretare i dati raccolti durante l'osservazione. Non basta avere i dati: bisogna capire cosa significano nel contesto corrente.
Per un agente AI, l'orientamento comprende:
- Analisi: scomporre i dati ricevuti in componenti significative
- Pattern matching: riconoscere situazioni simili a quelle già incontrate
- Prioritizzazione: stabilire cosa è urgente, cosa è importante, cosa può attendere
- Valutazione del contesto: come si inseriscono i nuovi dati nel quadro complessivo del task
- Identificazione di gap informativi: quali informazioni mancano per prendere una decisione informata
In pratica, questa fase corrisponde al ragionamento dell'LLM: il modello analizza il contesto completo (prompt di sistema, cronologia, risultati dei tool) e formula una comprensione della situazione corrente. La qualità del system prompt è fondamentale qui: un prompt che guida il modello a considerare esplicitamente il contesto, a valutare le alternative e a identificare i rischi produce un orientamento molto più efficace.
3. Decide (Decidere)
Sulla base dell'orientamento, l'agente seleziona l'azione da compiere. La decisione può essere:
- Invocare un tool: chiamare una funzione esterna per ottenere dati o eseguire un'operazione
- Generare una risposta: produrre l'output finale per l'utente
- Richiedere input aggiuntivo: chiedere chiarimenti all'utente
- Riformulare il piano: abbandonare l'approccio corrente e provare una strategia alternativa
- Terminare: concludere che l'obiettivo è stato raggiunto (o che non è raggiungibile con le risorse disponibili)
4. Act (Agire)
L'agente esegue la decisione presa. Questa fase trasforma l'intenzione in azione concreta: il tool viene invocato, la risposta viene generata, la richiesta di chiarimento viene formulata. Dopo l'azione, il loop riprende dalla fase di osservazione: l'agente raccoglie i risultati dell'azione e inizia un nuovo ciclo.
Il Loop OODA Applicato a un Agente AI
| Fase OODA | Agente AI | Componente Tecnico |
|---|---|---|
| Observe | Raccogliere input utente, risultati tool, stato memoria | Input processing, context assembly |
| Orient | Analizzare il contesto, identificare gap, prioritizzare | LLM reasoning, system prompt guidance |
| Decide | Scegliere: tool call, risposta finale, o richiesta input | LLM output parsing, action selection |
| Act | Eseguire il tool, generare output, modificare stato | Tool execution, response generation |
Il Tempo di Ciclo: La Metrica Chiave
Boyd insisteva sul fatto che il vantaggio competitivo non sta nella qualità di una singola decisione, ma nella velocità con cui si completa l'intero ciclo. Lo stesso principio si applica agli agenti AI: un agente che completa rapidamente cicli OODA multipli, adattandosi ad ogni iterazione, è più efficace di un agente che cerca di raggiungere la perfezione in un singolo ciclo lungo.
In termini pratici, questo significa progettare agenti con tool atomici e veloci piuttosto che tool monolitici e lenti. Un tool che esegue una singola query veloce e restituisce i risultati in millisecondi permette all'agente di iterare rapidamente; un tool che aggrega dati da 10 fonti diverse e richiede 30 secondi blocca l'intero ciclo.
Il Pattern ReAct: Reasoning + Acting
Il pattern ReAct (Reasoning + Acting), introdotto nel 2022 dai ricercatori di Princeton e Google nel paper "ReAct: Synergizing Reasoning and Acting in Language Models", rappresenta una svolta fondamentale nel design degli agenti AI. Prima di ReAct, esistevano due approcci separati: il Chain-of-Thought (CoT), che migliorava le capacità di ragionamento del modello ma non prevedeva azioni esterne, e i sistemi di action planning, che eseguivano azioni ma senza un ragionamento trasparente.
ReAct unifica questi due approcci in un unico loop strutturato dove il modello alterna esplicitamente fasi di pensiero e fasi di azione:
Thought: Devo trovare le vendite globali di EV nel 2025.
Cerchero prima i dati aggregati più recenti.
Action: web_search("global electric vehicle sales 2025 data")
Observation: I risultati mostrano che nel 2025 sono stati venduti
18.2 milioni di EV a livello globale, con una crescita
del 25% rispetto al 2024...
Thought: Ho i dati aggregati. Ora ho bisogno della suddivisione
per produttore per identificare i leader di mercato.
Action: web_search("top EV manufacturers market share 2025")
Observation: BYD guida con il 23% del mercato, seguita da Tesla
con il 18%, Hyundai-Kia con il 9%...
Thought: Ho dati sufficienti per la prima parte del report.
Posso ora sintetizzare le informazioni raccolte
in un formato strutturato per l'utente.
Action: generate_response(report strutturato con dati e trend)
La Struttura del Loop ReAct
Il loop ReAct segue un pattern ciclico rigoroso con tre componenti che si ripetono:
- Thought (Pensiero): il modello articola esplicitamente il suo ragionamento. Cosa sa finora? Cosa gli manca? Quale tool dovrebbe usare e perchè? Il pensiero e visibile nel trace dell'agente, il che rende il comportamento trasparente e debuggabile.
- Action (Azione): sulla base del pensiero, il modello seleziona un tool da invocare con parametri specifici. L'azione è concreta e verificabile: si può controllare quale tool è stato chiamato, con quali argomenti, e se la chiamata è andata a buon fine.
- Observation (Osservazione): il risultato dell'azione viene restituito al modello. L'osservazione diventa parte del contesto per il pensiero successivo, creando un feedback loop continuo che guida il ragionamento verso l'obiettivo.
Pseudocodice del Loop ReAct
def react_loop(user_query, tools, max_iterations=10):
context = [system_prompt, user_query]
for i in range(max_iterations):
# Il modello genera Thought + Action
response = llm.generate(context)
# Parse della risposta
thought = extract_thought(response)
action = extract_action(response)
# Se l'azione è "final_answer", termina il loop
if action.name == "final_answer":
return action.arguments["answer"]
# Esegui il tool
try:
observation = execute_tool(action.name, action.arguments)
except ToolError as e:
observation = f"Errore: {str(e)}"
# Aggiungi thought, action e observation al contesto
context.append(f"Thought: {thought}")
context.append(f"Action: {action.name}({action.arguments})")
context.append(f"Observation: {observation}")
# Limite di iterazioni raggiunto
return "Impossibile completare il task nel limite di iterazioni"
perchè ReAct Funziona Meglio del Solo Ragionamento
Il vantaggio fondamentale di ReAct rispetto al Chain-of-Thought puro è che il modello non è costretto a ragionare esclusivamente sulla base delle sue conoscenze interne (che possono essere obsolete, incomplete o errate). Attraverso le azioni, il modello può acquisire informazioni fresche dal mondo reale e usarle per affinare il proprio ragionamento.
I benefici concreti del pattern ReAct includono:
- Trasparenza del ragionamento: ogni passaggio logico è visibile nel trace, facilitando il debugging e l'analisi post-mortem quando l'agente produce risultati inattesi
- Grounding nei fatti: le osservazioni dai tool ancorano il ragionamento a dati reali, riducendo le allucinazioni e le confabulazioni del modello
- Adattabilita: l'agente può cambiare strategia in tempo reale basandosi sui risultati delle azioni, senza essere vincolato a un piano rigido
- Performance superiori: gli studi empirici dimostrano che ReAct supera sia il solo CoT che il solo action planning su benchmark di ragionamento e decision-making
Tool Calling: Il Ponte tra AI e Mondo Reale
Il tool calling (chiamato anche "function calling" da OpenAI) è il meccanismo attraverso cui un agente AI interagisce concretamente con il mondo esterno. Senza tool calling, un LLM può solo generare testo; con il tool calling, può eseguire ricerche web, interrogare database, creare file, inviare email, chiamare API e molto altro.
Il meccanismo funziona in tre passaggi fondamentali:
- Il modello genera una richiesta di tool call strutturata: invece di produrre testo libero, il modello genera un oggetto JSON che specifica quale tool invocare e con quali parametri. Il modello è stato addestrato a produrre questo formato quando determina che un'azione esterna è necessaria.
- Il runtime esegue la funzione corrispondente: il framework (LangGraph, CrewAI, o il runtime custom) riceve la richiesta, valida i parametri, esegue la funzione e cattura il risultato.
- Il risultato viene restituito al modello: l'output del tool viene aggiunto al contesto della conversazione come "observation", e il modello può proseguire il ragionamento con le nuove informazioni.
Definizione di un Tool: Lo Schema
Ogni tool deve essere definito con uno schema chiaro che il modello possa comprendere. Lo schema include tre elementi fondamentali: il nome del tool, una descrizione in linguaggio naturale (che l'LLM usa per capire quando usarlo), e la specifica dei parametri (che l'LLM usa per capire come usarlo).
{
"name": "search_database",
"description": "Cerca record nel database dei clienti. Usa questo tool quando l'utente chiede informazioni su clienti specifici, ordini o dati storici. Supporta ricerca per nome, email o ID ordine.",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Il termine di ricerca (nome cliente, email o ID ordine)"
},
"filter_type": {
"type": "string",
"enum": ["name", "email", "order_id"],
"description": "Il tipo di campo su cui filtrare"
},
"limit": {
"type": "integer",
"default": 10,
"description": "Numero massimo di risultati da restituire"
}
},
"required": ["query", "filter_type"]
}
}
Flusso di una Tool Call
Vediamo il flusso completo di una tool call, dal momento in cui il modello decide di usare un tool fino alla restituzione del risultato:
1. L'utente chiede: "Trova gli ordini del cliente Mario Rossi"
|
v
2. L'LLM analizza la richiesta e i tool disponibili
|
v
3. L'LLM genera una tool call strutturata:
{
"tool": "search_database",
"arguments": {
"query": "Mario Rossi",
"filter_type": "name",
"limit": 5
}
}
|
v
4. Il runtime:
a) Valida gli argomenti contro lo schema del tool
b) Esegue la funzione search_database("Mario Rossi", "name", 5)
c) Cattura il risultato
|
v
5. Il risultato viene restituito all'LLM:
{
"results": [
{"order_id": "ORD-2024-1542", "date": "2024-03-15", "total": 249.99},
{"order_id": "ORD-2024-1897", "date": "2024-06-22", "total": 89.50}
],
"total_count": 2
}
|
v
6. L'LLM genera la risposta finale per l'utente:
"Ho trovato 2 ordini per Mario Rossi:
- ORD-2024-1542 del 15/03/2024: 249.99 EUR
- ORD-2024-1897 del 22/06/2024: 89.50 EUR"
La Descrizione del Tool: L'Elemento Più Importante
La descrizione del tool è l'elemento più critico dell'intero meccanismo di tool calling, eppure è spesso trascurata. L'LLM non esegue codice: legge la descrizione in linguaggio naturale e decide se e quando invocare il tool basandosi esclusivamente su quella descrizione.
Una descrizione efficace deve rispondere a tre domande:
- Cosa fa il tool? Una spiegazione chiara e concisa della funzionalità
- Quando usarlo? I casi d'uso specifici in cui il tool è appropriato (e implicitamente, quando NON usarlo)
- Come usarlo? Informazioni sui parametri, vincoli, formati attesi
Esempio: Descrizione Buona vs Cattiva
Descrizione cattiva: "Cerca nel database."
Troppo vaga. L'LLM non sa quale database, che tipo di dati contiene, quando è appropriato usare questo tool vs. altri disponibili, o che formato deve avere la query.
Descrizione buona: "Cerca record nel database dei clienti aziendali. Usa questo tool quando l'utente chiede informazioni su clienti, ordini o fatture. Supporta ricerca per nome cliente (parziale o completo), email, ID ordine (formato ORD-YYYY-NNNN) o numero di fattura. Restituisce massimo 50 risultati ordinati per data decrescente."
Specifica, contestuale, e include informazioni su formati e limiti che aiutano l'LLM a generare parametri corretti.
Confronto: ReAct vs Chain-of-Thought vs Function Calling
Per consolidare la comprensione dei pattern presentati, confrontiamoli in una tabella che ne evidenzia le differenze strutturali, i vantaggi e le limitazioni:
Tabella Comparativa dei Pattern di Ragionamento
| Caratteristica | Chain-of-Thought (CoT) | Function Calling Puro | ReAct |
|---|---|---|---|
| Ragionamento esplicito | Si (step-by-step) | No (implicito) | Si (Thought visibile) |
| Azioni esterne | No | Si | Si |
| Accesso a dati freschi | No (solo training data) | Si (via tool) | Si (via tool) |
| Debuggabilita | Alta (trace visibile) | Media (solo I/O tool) | Molto alta (thought + action) |
| Rischio allucinazioni | Alto (nessun grounding) | Basso (dati reali) | Basso (grounding + reasoning) |
| Costo token | Medio | Basso | Alto (thought + action + obs) |
| Caso d'uso ideale | Ragionamento matematico, logica | Task semplici con API | Task complessi multi-step |
| Adottato da | Prompt engineering avanzato | OpenAI Function Calling | LangGraph, agenti moderni |
La scelta del pattern dipende dal caso d'uso. Per task puramente cognitivi (ragionamento matematico, analisi logica), il Chain-of-Thought è sufficiente. Per task semplici che richiedono una singola azione esterna (chiamare un'API, interrogare un database), il function calling puro è efficiente e economico. Per task complessi che richiedono ragionamento iterativo con azioni multiple, ReAct è il gold standard.
Pattern Avanzati: Tree-of-Thought e Plan-First
Oltre ai pattern fondamentali, la ricerca nel campo degli agenti AI ha prodotto approcci più sofisticati per migliorare la qualità del ragionamento e la capacità di pianificazione. Due pattern meritano particolare attenzione.
Tree-of-Thought (ToT)
Il Tree-of-Thought, proposto nel 2023, estende il Chain-of-Thought da una catena lineare a una struttura ad albero. Invece di seguire un singolo percorso di ragionamento, il modello esplora multiple alternative in parallelo, valuta ciascun ramo e seleziona il più promettente.
In pratica, questo significa che l'agente:
- Genera diverse possibili strategie per risolvere il problema
- Valuta ciascuna strategia con un punteggio di fattibilità e probabilità di successo
- Esplora il ramo più promettente, ma mantiene gli altri come fallback
- Se il ramo scelto fallisce, fa backtracking e prova un'alternativa
Il ToT è particolarmente efficace per problemi con soluzioni non ovvie (puzzle, pianificazione strategica, decisioni con trade-off complessi), ma ha un costo computazionale elevato perchè richiede generazioni multiple per ogni nodo dell'albero.
Plan-First (Pianificazione Anticipata)
L'approccio Plan-First inverte la logica del ReAct tradizionale. Invece di alternare pensiero e azione incrementalmente, l'agente formula un piano completo prima di eseguire qualsiasi azione, poi esegue il piano passo dopo passo, adattandolo se necessario.
Il flusso Plan-First segue questa struttura:
[FASE 1: PIANIFICAZIONE]
Input: "Crea un report sulle performance del team Q4 2025"
Piano generato dall'agente:
Step 1: Recuperare i dati di sprint completati Q4 2025
Step 2: Calcolare velocity media e trend
Step 3: Identificare i blockers più frequenti
Step 4: Generare grafici delle metriche chiave
Step 5: Sintetizzare il report in formato strutturato
[FASE 2: ESECUZIONE]
Eseguire il piano step-by-step, con possibilità di:
- Re-pianificare se un step fallisce
- Aggiungere step intermedi se necessario
- Saltare step non più rilevanti
Il Plan-First è vantaggioso per task lunghi e complessi dove una visione d'insieme è fondamentale. Il rischio è che il piano iniziale si basi su assunzioni errate che emergono solo durante l'esecuzione, richiedendo una ri-pianificazione costosa. Per questo, le implementazioni moderne combinano Plan-First con la flessibilità di ReAct: si pianifica all'inizio, ma si mantiene la capacità di adattare il piano ad ogni iterazione.
L'Interazione tra OODA, ReAct e Tool Calling
I tre concetti presentati in questo articolo non sono alternativi ma complementari e interconnessi. OODA fornisce il framework decisionale di alto livello, ReAct implementa il pattern di ragionamento-azione all'interno di quel framework, e il tool calling è il meccanismo tecnico che rende possibili le azioni.
Come si Integrano i Tre Concetti
| Livello | Concetto | Ruolo |
|---|---|---|
| Strategico | Loop OODA | Framework decisionale: come strutturare il ciclo di ragionamento e azione |
| Tattico | Pattern ReAct | Pattern implementativo: come alternare pensiero e azione in modo esplicito |
| Operativo | Tool Calling | Meccanismo tecnico: come l'agente esegue concretamente le azioni esterne |
In un agente LangGraph, ad esempio, il grafo di stato implementa il loop OODA (ogni nodo corrisponde a una fase), i nodi di ragionamento seguono il pattern ReAct (Thought-Action-Observation), e le azioni si materializzano attraverso il tool calling (il modello genera tool call JSON, il runtime le esegue). Comprendere tutti e tre i livelli è essenziale per progettare agenti che siano al contempo efficaci, debuggabili e manutenibili.
Errori Comuni da Evitare
La progettazione di agenti AI presenta insidie specifiche che possono compromettere l'efficacia, l'affidabilità e la sicurezza del sistema. Ecco gli errori più comuni e come prevenirli.
I 7 Errori Più Frequenti nella Progettazione di Agenti
-
1. Loop infiniti: l'agente continua a iterare senza convergere verso una soluzione.
Causa tipica: il criterio di terminazione e ambiguo o assente. Soluzione: impostare sempre
un
max_iterationse implementare un meccanismo di detection del loop (se le ultime N azioni sono identiche, terminare con un messaggio di errore). - 2. Descrizioni dei tool vaghe: se la descrizione del tool non è precisa, l'LLM non sapra quando usarlo o lo usera in modo improprio. Ogni descrizione deve specificare cosa fa il tool, quando usarlo, e quali parametri aspettarsi. Testare le descrizioni con query ambigue è una pratica fondamentale.
- 3. Mancanza di stop conditions: l'agente non sa quando ha finito. Il prompt di sistema deve includere istruzioni esplicite su cosa costituisce un completamento riuscito e quando l'agente deve interrompere il loop e restituire il risultato.
- 4. Context overflow: ogni iterazione del loop aggiunge token al contesto. Dopo molte iterazioni, si rischia di superare la context window dell'LLM, causando troncamento o errori. Implementare strategie di compressione del contesto (riassumere le iterazioni precedenti, mantenere solo le informazioni rilevanti).
- 5. Mancata gestione degli errori: i tool possono fallire (timeout, rate limiting, dati invalidi). L'agente deve essere progettato per gestire errori gracefully: retry con backoff, tool alternativi, degradazione controllata verso una risposta parziale.
- 6. Tool troppo granulari o troppo monolitici: tool che fanno troppo poco costringono l'agente a troppe iterazioni; tool che fanno troppo riducono la flessibilità e rendono difficile il debugging. La granularità ottimale e un singolo concetto, una singola responsabilità per tool.
- 7. Assenza di guardrails: senza limiti operativi, un agente può eseguire azioni distruttive (cancellare dati, inviare email errate, effettuare acquisti non autorizzati). Implementare sempre: limiti di costo per sessione, whitelist delle azioni permesse, punti di approvazione umana per azioni irreversibili.
Conclusioni
In questo articolo abbiamo esplorato i tre pilastri fondamentali che governano il comportamento di ogni agente AI moderno. Il loop OODA fornisce il framework decisionale di alto livello, strutturando il ciclo continuo di osservazione, orientamento, decisione e azione. Il pattern ReAct implementa questo framework con un'alternanza esplicita di pensiero e azione che rende il ragionamento dell'agente trasparente e debuggabile. Il tool calling fornisce il meccanismo tecnico che permette all'agente di tradurre le intenzioni in operazioni concrete nel mondo reale.
Abbiamo anche introdotto pattern avanzati come il Tree-of-Thought e il Plan-First, e analizzato gli errori più comuni nella progettazione di agenti. Con queste fondamenta teoriche solide, siamo pronti per passare all'implementazione pratica.
Nel prossimo articolo, "LangChain e LangGraph: Costruire Agenti con Grafi di Stato", inizieremo a scrivere codice. Vedremo come installare LangGraph, definire un grafo di stato, implementare nodi di ragionamento e azione, e costruire il nostro primo agente funzionante con tool calling e memoria. Dal concetto al codice: il viaggio continua.







