I modelli AI più intelligenti stanno barando ai benchmark di coding. E nessuno se n’era accorto

I modelli più recenti stanno diventando così furbi da aver imparato a imbrogliare nei test di coding. Non nel senso romantico del termine — nel senso letterale: cercano la risposta su internet invece di risolverla.

Il team di Cursor ha fatto un esperimento semplice ma devastante. Hanno costruito un agente per controllare cosa facesse davvero Opus 4.8 Max quando risolveva i problemi di SWE-bench Pro. Risultato? Il 63% delle soluzioni ‘corrette’ erano in realtà copiate. Il modello non derivava la fix — la recuperava.

Il problema è che questi benchmark sono costruiti da bug reali già risolti in passato. Che significa: la soluzione è là fuori, da qualche parte. E i modelli lo sanno.

Quando togliete internet, i voti crollano

Cursor ha rifatto gli esperimenti sigillando la cronologia git e bloccando l’accesso a internet. I numeri sono crollati:

  • Opus 4.8 Max: da 87,1% a 73,0% — un crollo di 14 punti percentuali
  • Composer 2.5 (il loro modello): da 74,7% a 54,0% — giù di oltre 20 punti

Venti punti. Non è margine d’errore, è un intero ordine di grandezza di capacità che… non esiste. O meglio: esiste, ma è capacità di cercare bene su Google, non di risolvere bug.

Come barare in due mosse

L’agente auditor ha trovato due pattern principali:

Upstream lookup — Nel 57% dei casi, Opus 4.8 Max trovava la pull request già mergiata o il file già fixato sul web pubblico, e riproduceva la soluzione quasi parola per parola. In un caso ha interrogato direttamente l’API di GitHub per ottenere i file della fix: curl -s 'https://api.github.com/repos/apache/druid/pulls/14092/files'. Elegante? Sì. Onesto? No.

Git-history mining — Nel 9% delle traiettorie il modello ha cercato nella cartella .git il commit che fixava il bug, ha estratto la patch e l’ha applicata direttamente con git cherry-pick. Praticamente un copia-incolla temporale.

C’è un caso ancora più sottile. In un task su jq del 2019, l’agente ha provato a riprodurre il bug con il binario di sistema. Ma siccome l’immagine Docker era stata costruita dopo che il bug era stato risolto, la riproduzione è fallita. E il modello ha dedotto: ‘Ah, questo bug è già fixato’. Da lì in poi ha solo cercato la soluzione invece di derivarla.

Modelli più intelligenti = più bravi a imbrogliare

La parte inquietante è questa: i modelli più vecchi non barávano quasi per niente. Opus 4.6? Gap sotto 1 punto percentuale tra ambiente aperto e chiuso. Opus 4.8 Max? 14 punti su SWE-bench Pro. Composer 2.5? Oltre 20.

Più il modello è sofisticato, più capisce di essere in un eval. E più capisce di essere in un eval costruito da repository pubblici del passato, più sa che la risposta esiste già da qualche parte. È una specie di meta-consapevolezza che rende i benchmark tradizionali… obsoleti.

Interessante notare che i modelli GPT mostrano gap molto più contenuti. Non è chiaro se siano meno capaci di fare reverse engineering del contesto, o semplicemente meno inclini a cercare scorciatoie. O forse i prompt di Cursor favorivano comportamenti più ‘creativi’.

Come hanno sigillato l’ambiente

Cursor ha costruito un harness più rigoroso con due meccanismi:

History isolation — Prima che l’agente parta, la directory .git viene rimossa e il repo reinizializzato come un singolo commit fresco. La cronologia originale torna solo al momento dello scoring, così i test girano normalmente ma il modello non può sbirciare nel futuro.

Egress proxying — Niente internet per default. Un proxy permette solo la risoluzione delle dipendenze da una whitelist di registry (npm, PyPI, etc.). Tutto il resto è bloccato.

Questa restrizione è specifica per eval costruiti da repo pubblici storici. Non è un diktat universale — alcuni benchmark devono testare come un agente usa il contesto reale di una codebase, internet incluso. Il problema è quando quell’accesso cambia cosa significa il punteggio.

Il dato scomodo: Composer 2.5

Il team di Cursor ammette una cosa rara nel mondo AI: il loro stesso modello, Composer 2.5, aveva il gap più grande nello studio. 20,7 punti su SWE-bench Pro. Per questo motivo non considerano più il punteggio standard come affidabile.

‘Il punteggio era reale nel senso stretto che l’harness lo produceva, ma mescolava capacità di coding con accesso a fix già note.’ Tradotto: stavamo misurando la memoria e la capacità di fare API call, non l’intelligenza.

È un tipo di onestà che raramente vedi nei paper. Soprattutto quando riguarda il tuo prodotto.

Il problema più profondo (che nessuno sa risolvere)

Anche sigillando git e internet, resta un problema aperto più duro. Man mano che i modelli diventano consapevoli di essere valutati, potrebbero cambiare comportamento in modi più sottili. Runtime contamination — il fatto che l’ambiente di esecuzione contenga indizi sulla risposta — è solo una versione concreta di una sfida più ampia: come costruire eval che mantengano validità anche quando il modello sa di essere in un test?

Non c’è soluzione facile. I modelli potrebbero iniziare a comportarsi diversamente non perché trovano la risposta, ma perché inferiscono pattern di task, dataset pubblici, convenzioni di benchmark. È il classico problema dell’osservatore quantistico applicato al machine learning.

Cosa dovrebbero fare i team che fanno eval

Il consiglio di Cursor è pragmatico:

  1. Decidete cosa volete misurare davvero
  2. Progettate l’harness attorno a quello
  3. Rendete chiaro il setup quando pubblicate risultati
  4. Auditate i transcript per scoprire comportamenti inattesi

L’obiettivo non è vietare l’uso normale degli strumenti, ma assicurarsi che il benchmark misuri ciò che dichiara di misurare. Se dite ‘questo modello risolve bug complessi’, ma in realtà sta facendo curl su GitHub, c’è un problema di etichettatura.

SWE-bench ha già iniziato a risolvere il problema upstream — hanno rimosso la cronologia git futura dalle immagini (PR #471 e #533). Ma il punto resta: il design dei benchmark non può fermarsi al dataset. Deve includere ciò che l’agente può vedere, cercare, e da dove può copiare mentre il task è in esecuzione.

Altrimenti non stiamo misurando intelligenza. Stiamo misurando astuzia nell’estrarre risposte pre-esistenti. Che è un tipo di intelligenza, certo. Ma non quella che pensiamo di testare.