Ragionamento con tool: Alpha Evolve e Codex per far risolvere problemi formali a un LLM

Ragionamento con tool: Alpha Evolve e Codex per far risolvere problemi formali a un LLM

Il 9 aprile 2026 ho fatto un esperimento nella mia sandbox di sperimentazione AI: chiedere a Claude Sonnet 4.6 senza tool di risolvere la Torre di Hanoi con dieci dischi. Dieci minuti di ragionamento, tre tentativi, accuracy zero. La sequenza corretta richiede 1023 mosse ed è impossibile per un LLM produrla senza errori intermedi che invalidano tutto. Poi ho dato allo stesso modello un tool Python executor con la possibilità di scrivere il proprio solver. Quattordici secondi, accuracy 100%, codice pulito, soluzione corretta. Questa è la distinzione operativa fra ragionamento euristico (quello che fa l'LLM) e ragionamento formale (quello che fa un algoritmo): per i problemi formali, il tool use fa la differenza fra fallimento totale e successo certo. Qui il tutorial operativo su come strutturare il tool use per problemi formali, sui pattern reali di Claude, GPT-5 Codex e Gemini, e su come AlphaEvolve ha esteso questo paradigma alla ricerca matematica.

Perché gli LLM falliscono sui problemi formali senza tool?

Un LLM è un predittore del prossimo token. Internamente approssima soluzioni tramite pattern euristici distillati dal training. Per problemi che richiedono precisione formale (aritmetica a più cifre, ricorsione lunga, verifica di vincoli rigidi) la natura stocastica del predittore produce errori cumulativi che scalano con la lunghezza della soluzione.

Il paper The Illusion of Thinking di Apple, giugno 2025, ha documentato il collasso sistematico dei reasoning model sulla Torre di Hanoi oltre una certa complessità. Non è un bug del modello, è una proprietà strutturale dell'architettura Transformer: un predittore di token non esegue algoritmi, produce sequenze plausibili. Plausibili su 7 mosse, implausibili su 1023.

La soluzione non è rendere l'LLM più grande o più "reasoning-trained". La soluzione è riconoscere cosa sa fare e demandare il resto a tool che eseguono algoritmi formali.

Step 1: anatomia di un tool use request su Claude API

Il protocollo standard 2026 per il tool use è formalizzato via Model Context Protocol (MCP) e via tool schema API di ciascun vendor. Qui un esempio minimo per Claude Python SDK.

from anthropic import Anthropic

client = Anthropic()

tools = [
    {
        "name": "python_executor",
        "description": "Esegue codice Python in un sandbox isolato e restituisce stdout/stderr/exit_code",
        "input_schema": {
            "type": "object",
            "properties": {
                "code": {"type": "string", "description": "Codice Python da eseguire"}
            },
            "required": ["code"]
        }
    }
]

messages = [
    {"role": "user", "content": "Risolvi la Torre di Hanoi con 10 dischi. Scrivi il codice, eseguilo, mostra la sequenza delle mosse (solo prime 20 e ultime 20)."}
]

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=4096,
    tools=tools,
    messages=messages
)

Il modello nella risposta include un tool_use block con il codice che vuole eseguire. Il tuo runtime (non il modello) esegue il codice in sandbox isolato, restituisce il risultato come tool_result, il modello processa il risultato e produce la risposta finale.

Step 2: strutturare il loop agentic con error recovery

Il pattern corretto non è single-shot ma un loop agentic che gestisce errori, retry, e termination conditions.

def run_agentic_loop(initial_prompt: str, max_steps: int = 10):
    messages = [{"role": "user", "content": initial_prompt}]

    for step in range(max_steps):
        response = client.messages.create(
            model="claude-sonnet-4-6",
            max_tokens=4096,
            tools=tools,
            messages=messages
        )

        # se il modello ha finito senza tool call, abbiamo la risposta finale
        if response.stop_reason == "end_turn":
            return response.content[0].text

        # altrimenti eseguiamo i tool call
        messages.append({"role": "assistant", "content": response.content})
        tool_results = []
        for block in response.content:
            if block.type == "tool_use":
                result = execute_tool_safely(block.name, block.input)
                tool_results.append({
                    "type": "tool_result",
                    "tool_use_id": block.id,
                    "content": str(result),
                    "is_error": result.get("error") is not None
                })
        messages.append({"role": "user", "content": tool_results})

    raise RuntimeError("Max steps reached without termination")

Due dettagli critici: max_steps è un circuit breaker obbligatorio (senza, un modello può loopare indefinitamente su errori di sua competenza); is_error: True nei tool_result è necessario per segnalare al modello che l'esecuzione è fallita, altrimenti il modello può interpretare output vuoti come successo.

Step 3: sandboxing sicuro dell'executor

Un Python executor esposto a un agent è una backdoor delegata se non è sandboxed correttamente. Ho trattato in dettaglio il sandboxing di agent nel mio articolo sandboxing di agent LLM che eseguono codice arbitrario. Riassumo qui i vincoli minimi.

Container effimero per ogni chiamata (docker container con --rm --network none). Seccomp filter che blocca syscall pericolose. Capability drop (CAP_NET_RAW, CAP_SYS_ADMIN). Timeout hard (30 secondi per chiamata). Memory limit (512MB). Scrittura filesystem solo in /tmp tmpfs ephemeral. Se il tuo executor è un semplice exec(code) Python in-process, stai introducendo una RCE delegata in produzione.

Se vuoi approfondire come costruisco pipeline agentic con tool use sicuro e governance dei costi, nel mio hub dedicato allo sviluppo AI trovo articoli tecnici con metodologia applicata e perimetro dichiarato.

Step 4: scelta del modello in base al task formale

Per task formali il trade-off fra vendor non è lineare. Tre scenari ricorrenti.

Task di coding agentic di lunga durata. GPT-5.3-Codex (rilasciato 5 febbraio 2026) è specializzato per questo. State-of-the-art su SWE-Bench Pro con copertura su quattro linguaggi (Python, JavaScript/TypeScript, Java, Go). OpenAI riporta >7 ore di lavoro autonomo su refactor complessi. Se il tuo task è "risolvi 50 issue GitHub autonomamente", Codex è la scelta 2026.

Task di ragionamento matematico/scientifico. GPT-5.4 (5 marzo 2026) al 57,7% su SWE-Bench Pro e migliore conoscenza world-knowledge del Codex. Claude Opus 4.7 al 64,3% su SWE-Bench Pro (con caveat di possibile memorization su una parte di problemi, come segnalato da OpenAI). Gemini 3.1 Pro con Computer Use nativo per workflow che richiedono browser automation.

Task con tool use molto stretto (solo executor). Differenze fra vendor si assottigliano. Claude e GPT-5 si comportano entrambi bene. La scelta dipende più da pricing, latenza, integrazione esistente.

Step 5: come AlphaEvolve estende il paradigma del tool use a ricerca scientifica

AlphaEvolve di DeepMind (paper 17 giugno 2025, Novikov et al.) è l'esempio più rigoroso del 2025 di agent evoluzionario che combina LLM e verifier esterno. Non è un LLM, è un ensemble: Gemini Flash per ampiezza esplorativa, Gemini Pro per profondità, verifier automatico (human-coded, non LLM) che filtra le proposte.

Il risultato mathematico più celebre: algoritmo per moltiplicare matrici 4x4 complesse in 48 scalar multiplications, primo miglioramento in 56 anni sull'algoritmo di Strassen. Ha risolto nuove configurazioni per il kissing number problem in 11 dimensioni (593 sfere). Ha prodotto costruzioni nuove per il finite field Kakeya problem in 3, 4, 5 dimensioni, in collaborazione con Fields Medalist Terence Tao.

La lezione architetturale trasferibile a pipeline enterprise: il miglioramento viene dalla combinazione di LLM creativo + verifier deterministico + loop evoluzionario, non dall'LLM da solo. Se il tuo task ha una funzione di verifica deterministica (test unitari, check di vincoli, validatore) puoi costruire un agent che itera cento varianti finché il verifier non è soddisfatto. Non è sempre economico (costa in token) ma è il pattern che estrae valore massimo dalla creatività del modello.

Step 6: error handling e retry policy

Quattro errori ricorrenti nella mia pipeline sandbox, con contromisure.

Loop infinito di self-correction. Il modello fallisce, riprova, rifallisce uguale, riprova. Contromisura: circuit breaker su max_steps, exponential backoff sul retry, se il modello ripropone lo stesso codice due volte consecutive, termina.

Allucinazione di API non esistenti. Il modello invoca funzioni che non ha dichiarato nel proprio schema. Contromisura: validation strict dello schema tool_use_id contro la tool list registrata; rifiuta chiamate out-of-schema.

Overreliance sul reasoning trace. Il modello ragiona correttamente e poi produce codice che non corrisponde al ragionamento. Contromisura: il codice va validato per conto suo, mai fidarti del trace come garanzia.

Tool output troncato. Il tool restituisce 50KB di output ma solo i primi 4KB arrivano al modello per context budget. Contromisura: tool output summarization prima del feedback al modello.

Step 7: misurare recovery rate quando il tool fallisce

La metrica operativa che tengo in dashboard per ogni agent tool-enabled: il recovery rate dopo il primo fallimento. Quando un tool fallisce al primo tentativo (es. ZeroDivisionError), quante volte il modello riesce a risolvere nel tentativo successivo? Su Claude Sonnet 4.6 nella mia sandbox il recovery rate è circa 78%; su modelli più piccoli scende sotto il 50%.

Se il recovery rate è basso, il tuo agent è in realtà un chatbot con un tool attaccato, non un sistema autonomo. Un recovery rate <60% rende l'automazione non affidabile in produzione senza human-in-the-loop intensivo.

Pattern concreti: tre casi di tool use nella mia pipeline

Tre esempi operativi da 18 mesi di agent tool-enabled nel mio laboratorio.

Caso 1: validation di partite IVA italiane. Un agent riceve una lista di partite IVA estratte da documenti OCR, deve validarle. L'algoritmo di check-digit è deterministico (Luhn-like specifico italiano). Sprint 1: chiesto al modello di validare "ragionando". Accuracy 73% su 500 esempi a causa di errori di calcolo intermedi. Sprint 2: fornito un tool validate_piva(code) che implementa l'algoritmo. Accuracy 99,8%. Il 0,2% residuo è costituito da input ambigui (spazi nascosti, caratteri Unicode invisibili). Il costo operativo è sceso perché il modello chiama il tool una volta per partita IVA senza ragionare.

Caso 2: calcoli fiscali per fatturazione elettronica. Un agent calcola aliquote, ritenute, bolli. Senza tool e a bassa complessità il modello sa rispondere; con regimi fiscali complessi (regime forfettario vs ordinario + ritenuta d'acconto + cassa professionale) accuracy crolla a 40%. Fornito un tool che chiama un calcolatore fiscale deterministico (scritto in Python da un dottore commercialista), accuracy torna al 100%. Il modello fa da orchestrator, non da calcolatore.

Caso 3: debug di stack trace PHP. Come descritto nel mio articolo su AI-assisted debugging, l'agent ha un tool read_file(path, start, end) e un tool grep_codebase(pattern). Senza questi tool il modello può solo ragionare sul testo dello stack trace; con, naviga attivamente il codice e trova root cause in minuti invece che in ore. Qui il tool non sostituisce l'LLM, lo estende con capacità di retrieval mirate.

Il pattern "verifier pair": come AlphaEvolve lo ha codificato

Un contributo architetturale importante di AlphaEvolve è la formalizzazione del pattern verifier pair: il LLM produce un candidato di soluzione (creativo ma fallibile), un verifier deterministico (non-LLM, human-coded) valuta se la soluzione è corretta. Se non lo è, feedback torna al LLM, che produce un nuovo candidato. Loop evoluzionario.

Questo pattern è replicabile in scala PMI. Esempio: un agent che genera regole di business per un gestionale, un verifier che esegue le regole contro un set di test case storici, feedback automatico al modello. Il verifier non deve essere sofisticato; deve essere deterministico e veloce. 50 iterazioni di LLM + verifier costano tipicamente meno di un'ora di lavoro di uno sviluppatore senior, ma producono soluzioni validate in modo oggettivo.

La lezione architetturale: quando progetti un agent, chiediti sempre se il task ha un verifier deterministico. Se sì, costruiscilo prima del prompt engineering. Il verifier è il moltiplicatore di qualità; l'LLM è il generatore di candidati. Se il verifier è troppo lento per essere in loop, puoi cachare risposte verificate e far apprendere al modello via few-shot progressivo dagli esempi che passano la verifica; anche questo è un pattern scalabile su hardware modesto e preserva la qualità nel medio termine, anche quando i costi API dovrebbero imporre una riduzione del numero di iterazioni.

Edge case: quando il tool use NON risolve il problema

Tre categorie di task dove anche con tool l'LLM resta limitato.

  • Problemi NP-hard con soluzione enumerativa illimitata. L'LLM scrive il solver corretto ma il solver non termina in tempo utile.
  • Problemi dove la specifica è ambigua. Anche con executor perfetto, se la specifica del task è ambigua il modello risolve il problema sbagliato.
  • Problemi dove i dati sono corrotti. L'LLM e il tool entrambi lavorano su garbage input; il verifier detecta inconsistenza ma l'output è garbage out.

Strutturare il tool use in modo corretto è la differenza tra un LLM che fa chiacchiere e un sistema AI che risolve problemi. Le otto lezioni architetturali sopra non sono opzionali: il recovery rate basso in produzione, i loop infiniti non monitorati, il Python executor in-process senza sandbox sono incidenti che capitano e che un consulente senior evita a monte. Se hai un progetto agentic in cui il tool use è componente critica e vuoi capire se l'architettura proposta regge a un task formale reale, il modulo di preventivo gratuito ti risponde in due minuti se il caso rientra nel mio ambito. Il reasoning euristico dell'LLM è la parte creativa del sistema; il tool use e il verifier deterministico sono la parte che fa la differenza fra creativo ma sbagliato e creativo e corretto. L'architettura che regge in produzione nel 2026 non è "un LLM più grande", è un LLM accoppiato a tool ben sandboxed, a un verifier deterministico e a un loop agentic con recovery rate misurabile. Ogni singolo pezzo è ingegneria nota, la somma è quello che separa un chatbot da un sistema AI che sostituisce il tempo di uno sviluppatore senior.

Ultima modifica: