Un pipeline de données IA ne vaut que par le texte qu'on lui fournit, et le web ouvert est la source la plus riche de connaissances fraîches et spécifiques à un domaine pour ancrer un modèle. Le problème est d'obtenir ce texte dans une forme utilisable : la plupart des pages sont un enchevêtrement de navigation, de publicités et de contenu rendu par JavaScript qu'une simple requête HTTP ne verra jamais. Ce guide vous montre comment construire un pipeline de données IA avec LangChain et Crawlbase, en utilisant la Crawling API comme source de documents afin que les pages arrivent sous forme de markdown propre, puis en les découpant, les intégrant et les interrogeant avec la génération augmentée par récupération (RAG).

La forme du pipeline est simple et s'exécute de bout en bout en Python : Crawlbase récupère et nettoie la page, LangChain la découpe en morceaux et les intègre dans un magasin vectoriel, et au moment de la requête vous récupérez les morceaux les plus pertinents et les transmettez à un LLM comme contexte. Crawlbase gère la rotation des proxys, les blocages et le rendu afin que votre code de pipeline reste concentré sur les données, pas sur la lutte contre les défenses anti-bots. Tout ce qui suit est exécutable ; remplacez vos propres URLs et tokens et vous avez un système RAG fonctionnel sur du contenu web en direct.

Pourquoi Crawlbase comme source de documents LangChain

LangChain est livré avec des chargeurs de documents pour les fichiers, les bases de données et quelques sources web, mais le chargement de vraies pages web à grande échelle est là où la plupart des pipelines calent. Une requête brute vers un site moderne retourne soit un shell JavaScript sans contenu, soit une page de blocage, et même quand vous obtenez du HTML, il est rempli de passe-partout qui pollue vos embeddings. Des morceaux de mauvaise qualité signifient une récupération de mauvaise qualité, ce qui signifie un LLM qui cite avec assurance la bannière de cookies.

La Crawling API résout proprement la couche d'acquisition. Vous lui envoyez une URL, elle rend la page derrière une IP résidentielle de confiance, et elle peut retourner le contenu sous forme de markdown propre plutôt que de HTML brut. Ce markdown est exactement ce que vous voulez comme document LangChain : de la prose lisible avec les titres préservés et la navigation, les scripts et les balises publicitaires supprimés. Alimenter du markdown pré-nettoyé dans votre découpeur est le levier qualité le plus important dans un pipeline RAG ancré sur le web, et c'est la même idée explorée dans le scraping web en markdown prêt pour les LLM.

Cette séparation des préoccupations est ce qui rend le pipeline maintenable. Crawlbase gère l'accès web : rotation des IPs, résolution des CAPTCHAs, rendu JavaScript et retour de sorties structurées. LangChain gère l'orchestration : découpage, embedding, récupération et le prompt qui cadre la réponse. Le modèle gère le raisonnement. Vous pouvez modifier la façon dont vous découpez ou quel modèle vous interrogez sans toucher à la façon dont les données sont récupérées, et l'inverse est vrai aussi.

Markdown plutôt que HTML brut

La Crawling API accepte un paramètre format=markdown (et un helper get_markdown dans le client officiel) qui retourne la page sous forme de markdown propre plutôt que de HTML. Pour le RAG, c'est important : le markdown conserve les titres et les listes comme structure que votre découpeur peut respecter, tout en supprimant le passe-partout qui deviendrait sinon des morceaux bruités et de faible valeur dans votre magasin vectoriel.

Architecture : de l'URL à la réponse ancrée

Le pipeline comporte quatre étapes, chacune avec une seule tâche. Acquérir : la Crawling API récupère chaque URL et retourne du markdown propre. Découper : le découpeur de texte de LangChain divise chaque document en morceaux chevauchants suffisamment petits pour être intégrés et récupérés précisément. Intégrer et stocker : chaque morceau est transformé en vecteur et écrit dans un magasin vectoriel (nous utilisons Chroma localement). Récupérer et générer : au moment de la requête, vous intégrez la question, extrayez les morceaux les plus proches et les transmettez à un LLM comme contexte d'ancrage.

Les trois premières étapes sont un travail d'ingestion hors ligne que vous exécutez quand vos sources changent. La quatrième s'exécute chaque fois qu'un utilisateur pose une question. Séparer l'ingestion et l'interrogation est ce qui permet au pipeline de passer à l'échelle : vous crawlez et intégrez une fois, puis répondez à de nombreuses questions à moindre coût sur les vecteurs stockés. Le pattern plus large, notamment pourquoi le nettoyage est important avant tout embedding, est couvert dans comment structurer et nettoyer les données web scrapées pour l'IA et le ML.

Configurer le projet

Vous avez besoin de Python 3.10 ou plus récent. Créez un environnement virtuel et installez les bibliothèques : le client Crawlbase officiel pour l'acquisition, les packages LangChain pour l'orchestration, Chroma pour le magasin vectoriel, et l'intégration OpenAI pour les embeddings et le modèle de chat.

bash
python -m venv .venv
source .venv/bin/activate

pip install crawlbase langchain langchain-community langchain-openai langchain-chroma

Vous avez également besoin de deux identifiants : un token Crawlbase depuis votre tableau de bord, et une clé de fournisseur d'embedding/LLM (ici, une clé OpenAI). Le package crawlbase vous donne le client CrawlingAPI ; langchain-chroma encapsule le magasin Chroma local ; langchain-openai fournit à la fois les embeddings et le modèle de chat. Exportez vos clés en tant que variables d'environnement pour qu'aucune donnée sensible ne réside dans le code.

bash
export CRAWLBASE_TOKEN="your_crawlbase_token"
export OPENAI_API_KEY="your_openai_key"

Étape 1 : Récupérer du markdown propre avec la Crawling API

Commencez par l'acquisition. Le client officiel expose une méthode get qui prend une URL et des options ; passer format=markdown retourne la page sous forme de markdown propre dans le corps de la réponse. Encapsulez cela dans une petite fonction qui transforme chaque page récupérée en un Document LangChain, portant l'URL source dans les métadonnées pour pouvoir la citer plus tard.

python
import os
from crawlbase import CrawlingAPI
from langchain_core.documents import Document

api = CrawlingAPI({"token": os.environ["CRAWLBASE_TOKEN"]})

def load_page(url):
    # format=markdown returns clean markdown, not raw HTML
    response = api.get(url, {"format": "markdown"})
    if response["status_code"] != 200:
        raise RuntimeError(f"Fetch failed for {url}: {response['status_code']}")
    body = response["body"]
    text = body.decode("utf-8") if isinstance(body, bytes) else body
    return Document(page_content=text, metadata={"source": url})

urls = [
    "https://example.com/docs/getting-started",
    "https://example.com/docs/pricing",
]
docs = [load_page(u) for u in urls]
print(f"Loaded {len(docs)} documents")

Pour les pages à forte charge JavaScript, ajoutez "ajax_wait": "true" et un "page_wait" en millisecondes au dictionnaire d'options, et utilisez un token JavaScript. Parce que l'acquisition est isolée dans load_page, l'ajout de ces options ne touche aucune étape en aval. Si un site répond avec un statut non-200, la fonction lève une exception avec le code afin qu'une source défaillante soit visible plutôt que de polluer votre magasin avec une page d'erreur.

Crawlbase Crawling API

Votre pipeline RAG ne vaut que par le texte qui y entre. La Crawling API rend la page derrière une IP résidentielle tournante et retourne du markdown propre en un seul appel, afin que vos morceaux soient du vrai contenu plutôt que des barres de navigation et des pages de blocage. Branchez-la comme source de documents LangChain et pointez-la sur quelques URLs publiques avec le niveau gratuit en premier.

Étape 2 : Découper les documents en morceaux

Les pages entières sont trop grandes pour être intégrées utilement : un seul vecteur pour un long document mélange des sujets distincts et nuit à la précision de la récupération. Découpez plutôt chaque document en morceaux chevauchants. Le RecursiveCharacterTextSplitter de LangChain essaie d'abord de couper sur les limites de paragraphes et de phrases, de sorte que les morceaux restent cohérents, et comme le markdown de Crawlbase préserve les titres et les listes, ces coupures tombent sur des coutures naturelles.

python
from langchain_text_splitters import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,
    chunk_overlap=150,
)

chunks = splitter.split_documents(docs)
print(f"Split into {len(chunks)} chunks")

Un chunk_size d'environ 1000 caractères avec un chevauchement de 150 caractères est une valeur par défaut raisonnable pour la prose. Le chevauchement porte un peu de contexte à travers les limites afin qu'un fait coupé en deux morceaux ne soit pas perdu. Ajustez les deux selon votre contenu : les pages plus denses et plus techniques récupèrent souvent mieux avec des morceaux plus petits, tandis que les longs articles tolèrent des morceaux plus grands. Les métadonnées de load_page sont copiées automatiquement sur chaque morceau, de sorte que chacun connaît encore son URL source.

Étape 3 : Intégrer et stocker dans une base de données vectorielle

Transformez maintenant chaque morceau en vecteur et persistez-le. Un modèle d'embedding mappe le texte vers un point dans un espace à haute dimension où les passages sémantiquement similaires sont proches, ce qui est ce qui rend la récupération par sens possible. Chroma stocke ces vecteurs localement et gère la recherche de similarité ; passer persist_directory écrit l'index sur disque afin que vous ne payiez le coût d'embedding qu'une seule fois.

python
from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma

embeddings = OpenAIEmbeddings(model="text-embedding-3-small")

vector_store = Chroma.from_documents(
    documents=chunks,
    embedding=embeddings,
    persist_directory="./chroma_db",
)
print(f"Stored {len(chunks)} vectors")

Ce bloc marque la fin de l'ingestion. Exécutez-le une fois quand vos sources changent, pas à chaque requête. Pour réutiliser le magasin plus tard, rouvrez-le avec Chroma(persist_directory="./chroma_db", embedding_function=embeddings) au lieu de le reconstruire à partir des documents. Chroma est pratique pour le développement local ; la même interface LangChain donne accès à des magasins hébergés comme Pinecone ou pgvector quand vous dépassez les capacités d'une seule machine, de sorte que le reste de votre code ne change pas.

Étape 4 : Récupérer et générer la réponse

Avec les vecteurs en place, le chemin de requête est court. Transformez le magasin en récupérateur, intégrez la question de l'utilisateur, extrayez les morceaux les plus proches, et transmettez-les à un modèle de chat avec un prompt qui lui dit de répondre uniquement à partir du contexte fourni. Le langage d'expression de LangChain relie ces éléments en une seule chaîne.

python
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser

retriever = vector_store.as_retriever(search_kwargs={"k": 4})
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

prompt = ChatPromptTemplate.from_template(
    "Answer using only the context below.\n\n"
    "Context:\n{context}\n\nQuestion: {question}"
)

def format_docs(docs):
    return "\n\n".join(d.page_content for d in docs)

chain = (
    {"context": retriever | format_docs, "question": RunnablePassthrough()}
    | prompt
    | llm
    | StrOutputParser()
)

answer = chain.invoke("What does the getting-started guide say about setup?")
print(answer)

Définir k=4 récupère les quatre morceaux les plus pertinents ; augmentez pour les questions larges, réduisez pour les précises. Une temperature de 0 maintient le modèle ancré au texte récupéré plutôt qu'en train d'improviser. Comme le prompt restreint la réponse au contexte fourni, les réponses restent ancrées dans ce que vous avez réellement crawlé, et comme chaque morceau porte ses métadonnées source, vous pouvez afficher des citations en inspectant les documents récupérés directement avec retriever.invoke(question).

Exécuter le pipeline complet

Mettez les quatre étapes dans l'ordre dans un seul script et vous avez un pipeline complet : load_page sur vos URLs, découpage, intégration dans Chroma, puis construction de la chaîne et invocation. La première exécution crawle et intègre, ce qui prend un moment ; les exécutions suivantes qui rouvrent le magasin persisté répondent en bien moins d'une seconde car le travail coûteux est déjà fait. Ajoutez plus d'URLs à la liste et relancez l'ingestion pour élargir ce que le système connaît.

De là, la même structure s'étend naturellement. Planifiez le travail d'ingestion pour actualiser les sources selon une cadence, pointez-le sur des sitemaps pour crawler des sections entières, ou remplacez Chroma par un magasin vectoriel hébergé à mesure que votre corpus grandit. Pour le crawling à volume élevé, vous pouvez déplacer l'acquisition vers la Crawling API asynchrone ou la piloter depuis un agent via le Web MCP, et acheminer tout via le Smart AI Proxy quand vous avez besoin de rotation d'IP devant votre propre récupérateur. Le contrat du pipeline ne change pas : texte propre en entrée, réponses ancrées en sortie. Pour plus sur l'aspect extraction de ceci, consultez comment fonctionne l'extraction de données par IA.

Récapitulatif

Points clés

  • L'acquisition est le levier qualité. Le markdown propre de la Crawling API surpasse le HTML brut car le passe-partout devient des morceaux bruités qui sabotent la récupération.
  • Quatre étapes, des frontières claires. Acquérir, découper, intégrer, récupérer-et-générer, afin de pouvoir changer l'une sans toucher les autres.
  • Découpez avec chevauchement. RecursiveCharacterTextSplitter à ~1000 caractères avec 150 de chevauchement maintient les morceaux cohérents et les faits intacts à travers les limites.
  • Ingérez une fois, interrogez souvent. Persistez le magasin vectoriel afin que le travail d'embedding coûteux ne se produise que quand les sources changent.
  • Ancrez le modèle. Restreignez le prompt au contexte récupéré et maintenez la temperature basse pour que les réponses restent ancrées à ce que vous avez crawlé.
  • Portez les métadonnées source. Étiquetez chaque document avec son URL afin de pouvoir citer les pages exactes derrière chaque réponse.

Foire aux questions

Pourquoi utiliser Crawlbase plutôt qu'un chargeur web LangChain intégré ?

Les chargeurs intégrés supposent qu'une page retourne du HTML utilisable sur une requête simple, ce que les sites modernes font rarement : ils rendent le contenu dans le navigateur et bloquent le trafic automatisé. La Crawling API rend la page derrière une IP résidentielle tournante et retourne du markdown propre, de sorte que vos documents sont du vrai contenu plutôt que des shells vides ou des pages de blocage. Cette propreté améliore directement la qualité des morceaux et la précision de la récupération.

Dois-je demander du HTML ou du markdown pour un pipeline RAG ?

Du markdown. Passez format=markdown pour que la page revienne sous forme de prose lisible avec les titres et les listes préservés et la navigation, les scripts et les balises publicitaires supprimés. Ces repères structurels aident le découpeur à couper sur des limites naturelles, et supprimer le passe-partout évite que du texte de faible valeur ne finisse dans votre magasin vectoriel. Demandez du HTML uniquement quand vous devez analyser des éléments spécifiques avec des sélecteurs plutôt qu'intégrer la page.

Comment gérer les pages à forte charge JavaScript ?

Utilisez un token JavaScript et ajoutez ajax_wait et page_wait aux options que vous passez à api.get. La Crawling API rend alors la page dans un vrai navigateur, attend le contenu asynchrone, et retourne le markdown terminé. Comme l'acquisition est isolée dans la fonction load_page, activer le rendu n'affecte pas le découpage, l'intégration ou la récupération en aval.

Quelle taille de morceau et quel chevauchement dois-je utiliser ?

Commencez par environ 1000 caractères par morceau avec 150 caractères de chevauchement pour la prose générale. Des morceaux plus petits améliorent la précision sur le contenu technique dense ; des morceaux plus grands conviennent aux longs articles où le contexte s'étend sur des paragraphes. Le chevauchement porte un peu de contexte à travers les limites afin qu'un fait partagé entre deux morceaux soit toujours récupérable. Traitez ces valeurs comme des valeurs par défaut et ajustez-les en fonction de vos propres résultats de récupération.

Dois-je utiliser OpenAI pour les embeddings et le LLM ?

Non. Le pipeline est agnostique au fournisseur par conception. Remplacez OpenAIEmbeddings et ChatOpenAI par tout modèle d'embedding et modèle de chat supporté par LangChain, y compris les modèles locaux, et le code de découpage, stockage et récupération reste le même. Crawlbase se trouve entièrement du côté de l'acquisition, donc votre choix de modèle n'affecte jamais la façon dont les données sont récupérées.

Comment maintenir la base de connaissances à jour ?

Relancez les étapes d'ingestion (acquérir, découper, intégrer) selon un calendrier sur les URLs qui changent, et rouvrez le magasin persisté pour les requêtes entre les deux. Pour les corpus volumineux ou fréquemment mis à jour, pointez le crawl sur des sitemaps et déplacez l'acquisition vers la Scraper API asynchrone afin de pouvoir ingérer de nombreuses pages sans bloquer votre application.

Commencer à construire

Crawlez n'importe quel site à grande échelle, sans combattre l'infrastructure.

Crawlbase gère les proxies, les empreintes et les CAPTCHA afin que votre équipe livre des pipelines de données au lieu de maintenir la plomberie de crawl. 1 000 requêtes gratuites, sans carte requise.

En libre-service · Sans appel commercial requis · Volumes de crawl entreprise disponibles