Skip to main content
I modelli linguistici sono bravi a riassumere il testo e pessimi nel ricordare i fatti. Questo tutorial toglie i fatti dalla memoria del modello e li mette nel prompt, in modo che ogni frase nell’output possa essere ricondotta a una pagina che hai recuperato un istante prima. Costruiremo uno strumento da riga di comando che risponde a una domanda con un breve brief con citazioni:
Lungo il percorso:
  1. Cercheremo sul web in tempo reale con /augment/search
  2. Decideremo quali di quei risultati vale la pena leggere
  3. Convertiremo le pagine selezionate in Markdown con /augment/scrape
  4. Chiederemo a un chat model di scrivere il brief, citando le fonti tramite numero
  5. Collegheremo le quattro fasi in un unico script
Fare il retrieval da soli, invece di lasciarlo al modello, è ciò che rende il risultato verificabile. Manteniamo l’elenco esatto delle pagine confluite nel prompt e possiamo mostrare al lettore da dove proviene ogni affermazione. Se preferisci che sia Venice a gestire il retrieval all’interno di una singola richiesta, imposta invece venice_parameters.enable_web_search su una chat completion. La guida Ricerca e Scraping Web mette a confronto i due approcci.

Setup

Ti servono Python 3.9 o più recente, il pacchetto requests e una chiave API Venice. Consulta Generare una chiave API se non ne hai una.
Crea research.py e inizia con gli import e un blocco header condiviso che ogni chiamata riutilizzerà:

1. Cercare sul web

/augment/search prende una query e restituisce fino a 20 risultati ordinati. Brave è il provider predefinito e applica la Zero Data Retention. È disponibile anche Google, instradato tramite Venice, in modo che la query non sia mai collegata a te.
Ogni risultato è un oggetto con quattro campi:
Due cose di quella risposta vale la pena conoscere prima di costruirci sopra. Il campo content arriva con dell’HTML all’interno, perché il provider avvolge i termini corrispondenti in tag <strong>. La sostituzione con HTML_TAG mostrata sopra li rimuove, così lo snippet arriva al modello come testo semplice. Il campo date è spesso una stringa vuota. Molte pagine non pubblicano una data leggibile da una macchina, quindi tratta date come un suggerimento da usare quando è presente, non come un campo su cui ordinare o filtrare.
limit deve essere compreso tra 1 e 20, e query deve essere lunga tra 1 e 400 caratteri. Valori al di fuori di questi intervalli restituiscono HTTP 400 con un corpo di validazione. Non vengono corretti automaticamente.

2. Scegliere quali fonti leggere

Fare lo scraping di tutti e dieci i risultati sarebbe lento, costoso e in gran parte ridondante. I motori di ricerca restituiscono diverse pagine dallo stesso sito, e in particolare i siti di documentazione restituiscono la stessa pagina in più lingue, quindi lo stesso contenuto può apparire tre o quattro volte sotto URL diversi. Mantenere solo il risultato con il ranking più alto per ciascun dominio elimina gran parte di questa duplicazione in poche righe:
Eseguendolo sui dieci risultati precedenti, questi si riducono a quattro siti distinti:
Questo è il punto naturale in cui inserire il tuo giudizio. Potresti mettere in allowlist i domini di cui ti fidi, scartare i risultati il cui snippet non menziona mai i termini chiave, o preferire i risultati con una date recente. Ogni filtro che applichi qui è una decisione che il modello non ha più occasione di sbagliare.

3. Fare lo scraping delle pagine selezionate

/augment/scrape recupera un URL pubblico e lo restituisce come Markdown. Prima chiede al sito una rappresentazione Markdown nativa e ricade sull’estrazione basata su browser quando non ce n’è. Alcune pagine falliranno, e uno strumento di ricerca dovrebbe trattarlo come qualcosa di ordinario piuttosto che come un errore fatale:
Entrambi i controlli si guadagnano il loro posto. Il controllo dello status intercetta i siti che rifiutano l’accesso automatizzato, mentre il controllo sulla lunghezza intercetta le pagine che restituiscono 200 ma consegnano un banner sui cookie o un guscio vuoto invece di un articolo.
I fallimenti dello scraping restituiscono un semplice corpo {"error": "..."} con un messaggio leggibile, ad esempio X (formerly Twitter) blocks automated access to their content. X e Reddit sono bloccati del tutto. Per includere post da X in una risposta, usa invece venice_parameters.enable_x_search su una chat completion.
Le richieste non dipendono l’una dall’altra, quindi eseguile in parallelo. Già che ci siamo, limitiamo quanto di ciascuna pagina teniamo:
La terza pagina è tornata esattamente a 12000 caratteri, il che significa che era più lunga del budget ed è stata troncata.
Il char_budget non è un vezzo. I risultati di ricerca includono regolarmente pagine aggregate come sitemap, changelog e file llms-full.txt, e una singola pagina di questo tipo può restituire quasi un milione di caratteri. Senza un limite, un risultato sfortunato decide da solo quanto costa l’intera richiesta.

4. Scrivere il brief

Ora passiamo al modello le pagine che abbiamo raccolto, numerate, e chiediamo citazioni che facciano riferimento a quei numeri. La numerazione nel prompt è ciò che ci permette di trasformare un [2] nell’output di nuovo in un URL più tardi.
Una temperature bassa mantiene la formulazione vicina al testo sorgente. Impostare enable_web_search su off corrisponde al valore predefinito, ma dichiararlo esplicitamente garantisce che il modello non possa introdurre silenziosamente una fonte assente dal nostro elenco di riferimenti.

5. Mettere tutto insieme

L’ultimo pezzo esegue le fasi in ordine e aggiunge l’elenco dei riferimenti che risolve i numeri di citazione:
I messaggi di progresso vanno su stderr, così puoi reindirizzare da solo il brief in un file:
Ecco la parte iniziale del brief prodotto, in forma abbreviata:
Nota che la fonte 3 non è mai citata in questo estratto. È il comportamento che vogliamo. Il modello ha usato le fonti che erano pertinenti e ha lasciato stare le altre, e poiché le citazioni sono numerate lo si vede a colpo d’occhio.

Regolare la pipeline

La maggior parte del tempo di attesa reale va nella chat completion finale, poiché quattro pagine estratte sommano decine di migliaia di token. Queste sono le leve da regolare per prime:

Prossimi passi

La pipeline che hai ora è una base più che un prodotto finito. Alcune direzioni da esplorare:
  • Metti in cache il Markdown estratto per URL, così le domande ripetute non riscaricano le stesse pagine.
  • Memorizza il Markdown come vettori con gli Embeddings e recupera passaggi invece di intere pagine.
  • Fai pianificare al modello diverse query prima di cercare, come fa la demo Agente di ricerca privato.
  • Leggi il brief ad alta voce inoltrandolo a Narrare articoli con il Text-to-Speech.

Ricerca e Scraping Web

Riferimento per gli endpoint Search e Scrape.

Narrare articoli con il Text-to-Speech

Trasforma in audio il testo che hai appena generato.

Embeddings

Indicizza il Markdown estratto invece di riscaricarlo.

Agente di ricerca privato

Un agente più ampio che pianifica le proprie ricerche.