Skip to main content
Les modèles de langage sont doués pour résumer du texte et mauvais pour mémoriser des faits. Ce tutoriel sort les faits de la mémoire du modèle et les place dans le prompt, de sorte que chaque phrase de la sortie puisse être retracée jusqu’à une page que vous avez récupérée quelques instants plus tôt. Nous allons construire un outil en ligne de commande qui répond à une question par une courte synthèse sourcée :
En chemin, nous allons :
  1. Rechercher sur le web en direct avec /augment/search
  2. Décider lesquels de ces résultats méritent d’être lus
  3. Convertir les pages sélectionnées en Markdown avec /augment/scrape
  4. Demander à un modèle de chat de rédiger la synthèse, en citant les sources par numéro
  5. Assembler les quatre étapes dans un seul script
Effectuer nous-mêmes la récupération, plutôt que de laisser le modèle le faire, est ce qui rend le résultat auditable. Nous conservons la liste exacte des pages qui ont alimenté le prompt et pouvons montrer au lecteur d’où provient chaque affirmation. Si vous préférez laisser Venice gérer la récupération dans une seule requête, définissez plutôt venice_parameters.enable_web_search sur une chat completion. Le guide Recherche et extraction web compare les deux approches.

Configuration

Vous avez besoin de Python 3.9 ou plus récent, du paquet requests et d’une clé API Venice. Consultez Générer une clé API si vous n’en avez pas.
Créez research.py et commencez par les imports et un bloc d’en-têtes partagé que chaque appel réutilise :

1. Rechercher sur le web

/augment/search prend une requête et renvoie jusqu’à 20 résultats classés. Brave est le fournisseur par défaut et applique la non-conservation des données (Zero Data Retention). Google est également disponible et est acheminé via Venice, de sorte que la requête n’est jamais liée à vous.
Chaque résultat est un objet comportant quatre champs :
Deux points de cette réponse méritent d’être connus avant d’aller plus loin. Le champ content arrive avec du HTML à l’intérieur, car le fournisseur enveloppe les termes correspondants dans des balises <strong>. La substitution HTML_TAG ci-dessus les supprime pour que l’extrait parvienne au modèle en texte brut. Le champ date est fréquemment une chaîne vide. Beaucoup de pages ne publient aucune date lisible par machine, donc traitez date comme un indice utilisable lorsqu’il est présent plutôt que comme un champ sur lequel vous pouvez trier ou filtrer.
limit doit être compris entre 1 et 20, et query doit contenir entre 1 et 400 caractères. Des valeurs hors de ces plages renvoient un HTTP 400 avec un corps de validation. Elles ne sont pas ajustées automatiquement pour vous.

2. Choisir les sources à lire

Extraire les dix résultats serait lent, coûteux et largement redondant. Les moteurs de recherche renvoient plusieurs pages du même site, et les sites de documentation en particulier renvoient la même page dans plusieurs langues, si bien qu’un même contenu peut apparaître trois ou quatre fois sous des URL différentes. Ne conserver que le résultat le mieux classé par domaine élimine l’essentiel de cette duplication en quelques lignes :
L’exécuter sur les dix résultats ci-dessus les réduit à quatre sites distincts :
C’est l’endroit naturel pour ajouter votre propre jugement. Vous pourriez autoriser explicitement les domaines auxquels vous faites confiance, écarter les résultats dont l’extrait ne mentionne jamais les termes clés, ou préférer les résultats portant une date récente. Chaque filtre que vous appliquez ici est une décision que le modèle n’aura plus l’occasion de mal prendre.

3. Extraire les pages sélectionnées

/augment/scrape récupère une URL publique et la renvoie en Markdown. Il demande d’abord au site sa représentation Markdown native et se rabat sur une extraction basée sur un navigateur lorsqu’il n’y en a pas. Certaines pages échoueront, et un outil de recherche devrait traiter cela comme une routine plutôt que comme un incident fatal :
Les deux garde-fous ont leur place. La vérification du statut attrape les sites qui refusent l’accès automatisé, et la vérification de la longueur attrape les pages qui renvoient 200 mais rendent une bannière de cookies ou une coquille vide au lieu d’un article.
Les échecs d’extraction renvoient un corps simple {"error": "..."} avec un message lisible, par exemple X (formerly Twitter) blocks automated access to their content. X et Reddit sont bloqués purement et simplement. Pour inclure des publications de X dans une réponse, utilisez plutôt venice_parameters.enable_x_search sur une chat completion.
Les requêtes ne dépendent pas les unes des autres, donc exécutez-les en parallèle. Pendant que nous y sommes, plafonnons la portion de chaque page que nous conservons :
La troisième page est revenue à exactement 12000 caractères, ce qui signifie qu’elle dépassait le budget et a été tronquée.
Le char_budget n’est pas un simple confort. Les résultats de recherche incluent régulièrement des pages agrégées telles que des sitemaps, des changelogs et des fichiers llms-full.txt, et une seule d’entre elles peut renvoyer près d’un million de caractères. Sans plafond, un résultat malchanceux détermine le coût de toute la requête.

4. Rédiger la synthèse

Nous transmettons maintenant au modèle les pages que nous avons collectées, numérotées, et demandons des citations qui renvoient à ces numéros. La numérotation dans le prompt est ce qui nous permettra plus tard de retrouver, à partir d’un [2] dans la sortie, l’URL correspondante.
Une temperature basse maintient la formulation proche du texte source. Régler enable_web_search sur off correspond à la valeur par défaut, mais l’expliciter garantit que le modèle ne peut pas introduire discrètement une source absente de notre liste de références.

5. Assembler le tout

La dernière pièce exécute les étapes dans l’ordre et ajoute la liste de références qui résout les numéros de citation :
Les messages de progression vont sur stderr, ce qui vous permet de rediriger la synthèse seule vers un fichier :
Voici le début de la synthèse produite, abrégée :
Notez que la source 3 n’est jamais citée dans cet extrait. C’est le comportement souhaité. Le modèle a utilisé les sources pertinentes et laissé les autres de côté, et parce que les citations sont numérotées, vous pouvez le voir d’un coup d’œil.

Ajuster le pipeline

L’essentiel du temps d’horloge est consacré à la dernière chat completion, car quatre pages extraites cumulent des dizaines de milliers de tokens. Voici les leviers vers lesquels se tourner en premier :

Étapes suivantes

Le pipeline dont vous disposez maintenant est une base plutôt qu’un produit fini. Quelques directions à explorer :
  • Mettez en cache le Markdown extrait par URL afin que les questions répétées ne récupèrent pas les mêmes pages.
  • Stockez le Markdown sous forme de vecteurs avec les Embeddings et récupérez des passages plutôt que des pages entières.
  • Laissez le modèle planifier plusieurs requêtes avant de rechercher, comme le fait la démo Agent de recherche privé.
  • Lisez la synthèse à voix haute en la faisant passer dans Narrer des articles avec la synthèse vocale.

Recherche et extraction web

Référence des points de terminaison Search et Scrape.

Narrer des articles avec la synthèse vocale

Transformez le texte que vous venez de générer en audio.

Embeddings

Indexez le Markdown extrait au lieu de le récupérer à nouveau.

Agent de recherche privé

Un agent plus large qui planifie ses propres recherches.