Perché il tuo agente IA fallisce sui siti reali
Il tuo agente funziona sulle pagine contro cui l'hai testato. Poi lo punti sul web aperto e le risposte diventano vaghe, o sicure di sé e sbagliate, oppure dice che la pagina era vuota mentre tu il contenuto lo vedi nel browser.
L'istinto è mettere mano al prompt. Di solito il prompt va bene. Il guasto è avvenuto prima che il modello vedesse alcunché: nello strato che scarica una URL e la trasforma in testo.
Abbiamo misurato quello strato su pagine reali. Ecco i cinque modi in cui si rompe, con l'aspetto esatto di ciascuno.
1. La pagina non ha testo finché non gira JavaScript
atlassian.com/software/jira/pricing, scaricata nel modo consueto, è 1,37 MB di HTML che producono un token di contenuto leggibile. Non un paragrafo: un token, un a capo.
I prezzi sono lì dentro. Stanno dentro uno <script>, come stato applicativo, in attesa che un browser costruisca la pagina con quelli.
Scarica la stessa URL con un browser headless e diventa 3.048 token che iniziano con:
## **Transparent pricing for every team.**
Stessa URL. Stesso giorno. Zero contenuto oppure la pagina intera, a seconda che tu abbia eseguito JavaScript o no.
È il guasto che sembra un problema del modello e non lo è. Il tuo agente ha detto «la pagina non menziona i prezzi» perché, nei byte che gli hanno dato, era vero.
2. Ma il rendering non è la soluzione che vorresti
La risposta ovvia è renderizzare tutto. Provaci su stripe.com/docs:
FetchError: Rendered fetch failed: Navigation timeout of 25000 ms exceeded
Una pagina che un download semplice restituisce in meno di un secondo non ha finito di caricare in un browser headless in 25 secondi. La versione non renderizzata, con tutti i suoi difetti, almeno è tornata.
Renderizzare ti costa un processo di browser per pagina, da diverse centinaia di millisecondi a diversi secondi di latenza, e una nuova classe di guasti: timeout, risorse bloccate, pagine che non sparano mai load. Se il tuo agente renderizza per impostazione predefinita, è più lento e meno affidabile su una parte del web, non di più.
La forma che funziona è: prima il download economico, controlla se hai ricevuto qualcosa, ed escala al rendering solo per le pagine tornate vuote. Quel controllo è proprio la parte che si salta.
3. Stai pagando markup che non usi mai
Sulle dodici pagine note che abbiamo misurato, la mediana di ciò che sopravvive dal server al modello sta sotto l'1%. shopify.com/pricing invia 410.515 token e ne produce 2.479.
Se il tuo agente infila HTML grezzo nella finestra di contesto, stai pagando <div> contenitore e SVG inline a prezzo di token in ingresso, spingendo fuori le pagine che volevi leggere anche. Estrai prima di inviare. Meglio ancora: chiedi se il sito ti dà Markdown direttamente. Alcuni lo fanno già: delle dodici pagine testate, cinque servivano una rappresentazione in Markdown, una delle quali la nostra.
4. L'estrazione tiene la parte sbagliata
L'estrazione è un'euristica. Cerca l'articolo e scarta l'arredamento, e su pagine che non hanno forma di articolo indovina male.
stripe.com/docs si riduce a 1.057 caratteri che iniziano così:
$ stripe payment_intents create --amount 1099 --currency "usd"
È un frammento reale della pagina. È anche un esempio da terminale invece di una frase che spieghi cosa fa Stripe. Un agente a cui danno solo quello deve dedurre il prodotto da un campione di codice.
Quindi: non fidarti mai che un'estrazione riuscita sia un'estrazione utile. Guardia economica — se quel che hai estratto non ha testo in forma di frase, o sono meno di qualche centinaio di caratteri su una pagina che ha inviato mezzo megabyte, trattalo come lettura fallita ed escala, invece di passarlo al modello come un fatto.
5. La stessa URL non restituisce la stessa pagina
Scaricare shopify.com/pricing in modo semplice ha restituito inglese. Renderizzare quella URL identica dalla macchina identica ha restituito spagnolo: Pago mensual32 € EUR/mes dove il download semplice diceva Pay monthly€32 EUR/mo.
Qui non c'è niente di rotto. Il browser headless ha inviato segnali Accept-Language e di geolocalizzazione diversi da quelli del nostro download semplice, e ha ricevuto una rappresentazione diversa e corretta. Ma se metti in cache solo per URL, o confronti la lettura di oggi con quella di ieri, quella differenza sembrerà che il sito abbia cambiato i prezzi.
Invia un Accept-Language esplicito. Indicizza la cache su ciò che hai davvero chiesto.
Il guasto che non c'è stato
Ci aspettavamo blocchi. Abbiamo sondato le dodici pagine due volte — una come browser, una identificandoci come OAI-SearchBot — e confrontato i codici di stato attraverso Cloudflare, Vercel e CloudFront.
Nessuna ha trattato il bot in modo diverso. Nemmeno una.
Non significa che nessuno blocchi gli agenti: molti lo fanno, e devi comunque leggere robots.txt e rispettarlo. Significa che se il tuo agente fallisce su un campione ampio del web, il blocco difficilmente ne è la ragione. La stanza vuota è molto più comune della porta chiusa.
Uno strato di lettura che regge il contatto col web
1. Chiedi prima Markdown → Accept: text/markdown, oppure /pagina.md
2. Download semplice → economico, senza JS
3. Controlla cosa è arrivato → ha forma di frase? è lungo abbastanza per i byte inviati?
4. Escala se no → renderizza, con timeout e budget
5. Arrenditi onestamente → «non sono riuscito a leggere questa pagina»
Il passo 5 conta più di quanto sembri. Un agente che segnala una pagina illeggibile è debuggabile. Un agente che passa un a capo al modello e lo lascia improvvisare è quello che si inventa i tuoi prezzi.
La versione breve
- Quasi tutti i fallimenti di un agente sono fallimenti di lettura, non di ragionamento.
- Vuoto-senza-JavaScript è di gran lunga il maggiore, e il rendering lo risolve: a un costo, e non sempre.
- Verifica ogni estrazione prima di fidartene.
- Il blocco si prende l'attenzione. È il vuoto a fare i danni.
Controlla come si legge una pagina · Cosa vede davvero un agente · Servire Markdown agli agenti