🎻
🎻 Movimento 1 di 4 📖 Capitolo 10 di 42 ⏱️ ~8 min lettura 📊 Livello: Fondamentale

Il Test sui Tool – Ancorare l'AI alla Realtà

Avevamo un team dinamico e un orchestratore intelligente. Ma gli agenti, per quanto ben progettati, erano ancora dei "filosofi digitali". Potevano ragionare, pianificare e scrivere, ma non potevano agire sul mondo esterno. La loro conoscenza era limitata a quella intrinseca del modello LLM, un'istantanea del passato, priva di dati in tempo reale.

Il Paradosso dei Filosofi Digitali: La Ricerca della Via Più Efficiente

C'è un aspetto affascinante e cruciale di come funziona l'intelligenza artificiale che vale la pena comprendere: un'AI cerca sempre la via più semplice e meno "costosa" per risolvere un problema. Questo non è un difetto, ma una caratteristica intrinseca del design degli LLM.

Quando un modello linguistico genera una risposta, sta effettuando calcoli probabilistici su miliardi di parametri per trovare la sequenza di parole statisticamente più plausibile. Il "costo" che l'AI cerca di minimizzare è multiforme:

Ecco perché un agente AI, se gli chiedete di "fare una ricerca di mercato sui competitor", tenderà a produrre una risposta generica basata sui suoi dati di training piuttosto che cercare informazioni aggiornate online. La via più "economica" è usare la conoscenza già in memoria, non fare una ricerca costosa su fonti esterne.

Questo comportamento è il risultato di tre fattori fondamentali:

  1. Ottimizzazione Algoritmica: Gli algoritmi di apprendimento sono progettati per trovare la soluzione più efficiente
  2. Logica Probabilistica: I modelli calcolano la sequenza più probabile di parole, non cercano "verità profonde"
  3. Assenza di Esperienza Vissuta: L'AI non ha il concetto umano di "sfida" o "percorso complesso per amore dell'arte" - la sua logica è puramente funzionale

Un sistema AI che non può accedere a informazioni aggiornate è destinato a produrre contenuti generici, obsoleti e, in ultima analisi, inutili. Per rispettare il nostro Pilastro #11 (Deliverable Concreti e Azionabili), dovevamo dare ai nostri agenti la capacità di "vedere" e "interagire" con il mondo esterno. Dovevamo dar loro dei Tool.

La Decisione Architetturale: Un "Tool Registry" Centrale

La nostra prima decisione fu di non associare i tool direttamente ai singoli agenti nel codice. Questo avrebbe creato un forte accoppiamento e reso difficile la gestione. Invece, abbiamo creato un Tool Registry centralizzato.

Codice di riferimento: backend/tools/registry.py (ipotetico, basato sulla nostra logica)

Questo registry è un semplice dizionario che mappa un nome di tool (es. "websearch") a una classe eseguibile.

# tools/registry.py
class ToolRegistry:
    def __init__(self):
        self._tools = {}

    def register(self, tool_name):
        def decorator(tool_class):
            self._tools[tool_name] = tool_class()
            return tool_class
        return decorator

    def get_tool(self, tool_name):
        return self._tools.get(tool_name)

tool_registry = ToolRegistry()

# tools/web_search_tool.py
from .registry import tool_registry

@tool_registry.register("websearch")
class WebSearchTool:
    async def execute(self, query: str):
        # Logica per chiamare un'API di ricerca come DuckDuckGo
        ...

Questo approccio ci ha dato un'incredibile flessibilità:

Il Primo Tool: websearch – La Finestra sul Mondo

Il primo e più importante tool che abbiamo implementato è stato websearch. Questo singolo strumento ha trasformato i nostri agenti da "studenti in una biblioteca" a "ricercatori sul campo".

Quando un agente deve eseguire un task, l'SDK di OpenAI gli permette di decidere autonomamente se ha bisogno di un tool. Se l'agente "pensa" di aver bisogno di cercare sul web, l'SDK formatta una richiesta di esecuzione del tool. Il nostro Executor intercetta questa richiesta, chiama la nostra implementazione del WebSearchTool e restituisce il risultato all'agente, che può quindi usarlo per completare il suo lavoro.

Cosa è il Function Calling: Il Ponte tra AI e Mondo Reale

Per chi non usa SDK ma API dirette OpenAI, è cruciale comprendere il meccanismo sottostante: il Function Calling. Questa funzionalità estende le capacità dei modelli linguistici permettendo loro di non limitarsi a generare testo, ma di suggerire l'esecuzione di funzioni specifiche per rispondere alle richieste.

Come Funziona: Il Dialogo in 5 Fasi

  1. Definizione Tool: Descrivi al modello quali funzioni ha a disposizione tramite uno schema JSON
  2. Richiesta Utente: L'utente fa una domanda che potrebbe richiedere dati esterni
  3. Tool Call: Il modello analizza la richiesta e decide di chiamare una funzione, restituendo un oggetto JSON con nome funzione e parametri
  4. Esecuzione Funzione: Il tuo codice esegue la funzione e ottiene il risultato
  5. Risposta Final: Invii il risultato al modello, che genera la risposta finale per l'utente

📋 Esempio Pratico: Assistente Meteo

1. Schema Tool:

{
  "type": "function",
  "name": "get_weather", 
  "description": "Ottiene meteo attuale per una località",
  "parameters": {
    "type": "object",
    "properties": {
      "location": {"type": "string", "description": "Città e stato"}
    },
    "required": ["location"]
  }
}

2. Utente: "Che tempo fa a Roma?"

3. Model Response: {"function_call": {"name": "get_weather", "arguments": {"location": "Roma"}}}

4. Tua Funzione: get_weather("Roma") → {"temperature": "22°C", "condition": "sole"}

5. Risposta Finale: "A Roma ci sono 22°C e c'è il sole!"

Perché Function Calling è Essenziale

Senza Function Calling, l'AI è limitata alla conoscenza del suo training (dati fermi a un momento specifico). Con Function Calling, diventa un "agente attivo" capace di ottenere informazioni in tempo reale, eseguire azioni e interagire dinamicamente con sistemi esterni. È il meccanismo che trasforma l'AI da "filosofo digitale" in "operatore pratico".

Flusso di Esecuzione di un Tool:

Architettura del Sistema

graph TD A[Agente riceve Task] --> B{AI decide di usare un tool} B --> C[SDK formatta richiesta per websearch] C --> D{Executor intercetta la richiesta} D --> E[Chiama tool_registry.get_tool websearch] E --> F[Esegue la ricerca reale] F --> G[Restituisce i risultati all'Executor] G --> H[SDK passa i risultati all'Agente] H --> I[Agente usa i dati per completare il Task]

Architettura del Sistema

graph TD A[Agente riceve Task] --> B{AI decide di usare un tool} B --> C[SDK formatta richiesta per websearch] C --> D{Executor intercetta la richiesta} D --> E[Chiama tool_registry.get_tool websearch] E --> F[Esegue la ricerca reale] F --> G[Restituisce i risultati all'Executor] G --> H[SDK passa i risultati all'Agente] H --> I[Agente usa i dati per completare il Task]

"War Story": Il Mistero del Tool Registry Silenzioso

Durante lo sviluppo del nostro ToolRegistry, abbiamo implementato un test critico per verificare che gli agenti usassero effettivamente i tool disponibili.

Codice di riferimento: tests/integration/test_tools_native.py

Il test era specifico: assegnare a ElenaRossi (il nostro Marketing Strategist) un task che richiedeva esplicitamente tre ricerche web distinte: Microsoft earnings, Google AI announcements, e Tesla stock price. Il test monitorava sia il completamento del task che l'effettivo utilizzo dei tool.

I primi test furono frustranti: l'agente completava il task, ma il nostro tool usage tracking mostrava 0 chiamate ai tool.

Log di Debug dal Test Reale:

🔍 TOOL USAGE ANALYSIS:
   'search' mentions: 8
   Microsoft mentions: 3
   Google mentions: 2
   Tesla mentions: 1
🛠️ TOOL EVIDENCE:
   ❌ 'using'
   ❌ 'searched'
   ✅ 'found'
   ✅ 'results'

Il Problema: L'agente stava producendo contenuti dettagliati su argomenti specifici, ma non c'era evidenza di tool usage nelle tracce OpenAI. L'agente utilizzava la sua conoscenza interna per "simulare" una ricerca, creando output convincenti ma potenzialmente obsoleti.

La Lezione Appresa: Il Detective Work del Tool Debugging

Il problema non era solo "pigrizia" dell'AI, ma una combinazione di fattori tecnici che scoprimmo attraverso debugging sistematico:

1. Tool Registration vs Tool Invocation: I tool erano registrati correttamente nel ToolRegistry, ma l'SDK OpenAI non li stava invocando. Il debugging rivelò che il nostro sistema di tool registration personalizzato non era completamente compatibile con il tracing nativo di OpenAI.

2. Prompt Engineering Specifico: Aggiungere istruzioni come "You MUST use web search tools for each search" e "Do NOT make up or assume any information" ha aumentato l'usage rate dal ~30% all'85%.

3. Monitoring Granulare: Implementammo un sistema di monitoring che tracciava non solo il completion del task, ma anche specifici pattern nel testo di output per identificare quando i tool venivano realmente utilizzati vs simulati.

Il nostro test_tools_native.py ora include controlli automatici per parole chiave come "using", "searched", "found", "results" per verificare l'evidenza empirica dell'uso dei tool, trasformando un test binario pass/fail in un'analisi qualitativa del comportamento degli agenti.

📝 Key Takeaways del Capitolo:

Gli Agenti Hanno Bisogno di Tool: Un sistema AI senza accesso a strumenti esterni è un sistema limitato e destinato a diventare obsoleto.

Centralizza i Tool in un Registry: Non legare i tool a agenti specifici. Un registry modulare è più scalabile e manutenibile.

Tool Usage è Complesso: Non basta registrare i tool; devi verificare che vengano invocati, che producano risultati reali, e che l'agente li preferisca alla sua conoscenza interna.

Testa il Comportamento, non solo l'Output: I test sui tool non devono verificare solo che il tool funzioni, ma che l'agente decida di usarlo quando è strategicamente corretto.

Conclusione del Capitolo

Con l'introduzione dei tool, i nostri agenti avevano finalmente un modo per produrre risultati basati sulla realtà. Ma questo ha aperto un nuovo vaso di Pandora: la qualità.

Ora che gli agenti potevano produrre contenuti ricchi di dati, come potevamo essere sicuri che questi contenuti fossero di alta qualità, coerenti e, soprattutto, di reale valore per il business? Era il momento di costruire il nostro Quality Gate.