Zonder KYC — geen ID, geen selfie, geen documenten. Betalen met crypto: BTC, USDT, USDC, ETH, SOL, LTC
Taal: Nederlands
Vraag een API-sleutel aan

Docs · LangChain · LlamaIndex

LangChain en LlamaIndex: een webpagina-loader en een read_url-tool

Twee manieren om de API te gebruiken in een Python AI-stack: pagina's laden als documenten voor retrieval, of een agent een read_url-tool geven. Dezelfde 20 regels glue dienen zowel LangChain als LlamaIndex.

Laatst bijgewerkt: · 5 min leestijd

Kort antwoord

Hoe laad ik webpagina's in LangChain of LlamaIndex als schone Markdown?

Roep het /read-endpoint van WebReaderAPI aan en verpak elk antwoord in een Document: de Markdown als content, final_url en de titel als metadata. Voor agents exposeer je dezelfde call als een read_url-tool. Pagina's kosten 1 credit per stuk, 2 met een browser, vanaf US$ 0,07/1K pagina's per oktober 2026. Je hebt geen package van ons nodig. Zonder KYC; betalen met crypto.

Waarom Markdown-documenten in plaats van ruwe HTML?

Omdat retrieval op tekst werkt, en Markdown de structuur behoudt die ertoe doet terwijl de rest wegvalt. Koppen blijven behouden, zodat een splitter kan knippen op onderwerpwisselingen. Lijsten en tabellen blijven behouden, zodat stappen en specificaties bij elkaar blijven. Navigatie, cookiebanners en advertenties zijn weg, zodat ze je embeddings niet vervuilen of tokens verspillen.

De metadata komt uit dezelfde call: final_url als bron om te citeren, title, published_at en language voor filteren.

reader.py: de gedeelde helper (sla het op naast je code)
import os

import requests

API = "https://webreaderapi.com/api/v1/read"
HEADERS = {"Authorization": "Bearer " + os.environ["WEBREADER_API_KEY"]}


class PageError(Exception):
    pass


def read_page(url, **options):
    resp = requests.get(API, headers=HEADERS, params={"url": url, **options}, timeout=75)
    body = resp.json()
    if resp.status_code != 200:
        raise PageError(body["error"]["code"])
    return body

Hoe bouw ik een LangChain document loader?

Zet elke pagina om in een langchain_core.documents.Document en splits die vervolgens op koppen met MarkdownHeaderTextSplitter uit het langchain-text-splitters-package. Elk chunk behoudt het kop-pad in zijn metadata, en je voegt de bron-URL toe zodat elk antwoord terug kan wijzen naar zijn pagina.

Overgeslagen pagina's, zoals die geweigerd door robots.txt, gooien een PageError op met de code; log ze en ga verder.

LangChain: pagina's laden en splitsen
from langchain_core.documents import Document
from langchain_text_splitters import MarkdownHeaderTextSplitter

from reader import PageError, read_page

splitter = MarkdownHeaderTextSplitter(headers_to_split_on=[("#", "h1"), ("##", "h2"), ("###", "h3")])


def load_pages(urls):
    chunks = []
    for url in urls:
        try:
            page = read_page(url)
        except PageError as exc:
            print("skipped", url, exc)
            continue
        for part in splitter.split_text(page["markdown"]):
            part.metadata.update({"source": page["final_url"], "title": page.get("title", "")})
            chunks.append(part)
    return chunks


docs = load_pages(["https://example.com/docs/install", "https://example.com/docs/configure"])
print(len(docs), "chunks", isinstance(docs[0], Document) if docs else "")

Hoe geef ik een LangChain-agent een read_url-tool?

Versier een functie met @tool uit langchain_core.tools. De docstring wordt de tool-beschrijving die het model leest, dus zeg wat de tool teruggeeft en wanneer je hem gebruikt. Geef platte tekst terug: een titelregel, de bron en de Markdown, afgekapt met max_chars passend bij je model.

Bind de tool aan elk chatmodel dat tool calling ondersteunt, of geef hem door aan je agent-constructor. Het model roept dan read_url aan met een URL uit het gesprek of uit een zoekresultaat.

LangChain: de read_url-tool
import os

from langchain.chat_models import init_chat_model
from langchain_core.tools import tool

from reader import PageError, read_page


@tool
def read_url(url: str, max_chars: int = 20000) -> str:
    """Read a public web page and return its main content as Markdown, with its title and source URL."""
    try:
        page = read_page(url, max_chars=max_chars)
    except PageError as exc:
        return "Could not read the page: " + str(exc)
    return "# " + (page.get("title") or url) + "\nSource: " + page["final_url"] + "\n\n" + page["markdown"]


model = init_chat_model(os.environ.get("CHAT_MODEL", "openai:gpt-4.1-mini")).bind_tools([read_url])
reply = model.invoke("Summarise https://example.com/blog/first-post in three bullet points.")
print(reply.tool_calls)

Hoe doe ik hetzelfde in LlamaIndex?

LlamaIndex gebruikt zijn eigen Document-klasse met text en metadata, en FunctionTool.from_defaults om een functie om te zetten in een tool. De helper blijft hetzelfde. Bouw een index van de documenten met VectorStoreIndex.from_documents, dat gebruikmaakt van welk embedding-model je LlamaIndex-instellingen ook noemen.

LlamaIndex: een crawl indexeren, en een read_url-tool
import os
import time

import requests
from llama_index.core import Document, VectorStoreIndex
from llama_index.core.tools import FunctionTool

from reader import HEADERS, PageError, read_page


def crawl_pages(start_url, limit=200):
    job = requests.post("https://webreaderapi.com/api/v1/crawl", headers=HEADERS, json={"url": start_url, "limit": limit}, timeout=30).json()
    pages, cursor = [], None
    while True:
        params = {"cursor": cursor} if cursor else {}
        res = requests.get("https://webreaderapi.com/api/v1/jobs/" + job["job_id"], headers=HEADERS, params=params, timeout=30).json()
        pages += [r for r in res["results"] if "error" not in r]
        cursor = res.get("next_cursor")
        if not cursor and res["status"] == "done":
            return pages
        if not cursor:
            time.sleep(5)


pages = crawl_pages("https://docs.example.com/")
docs = [Document(text=p["markdown"], metadata={"source": p["final_url"], "title": p.get("title", "")}) for p in pages]
index = VectorStoreIndex.from_documents(docs)
print(index.as_query_engine().query("How do I install the product?"))


def read_url(url: str, max_chars: int = 20000) -> str:
    """Read a public web page and return its main content as Markdown."""
    try:
        return read_page(url, max_chars=max_chars)["markdown"]
    except PageError as exc:
        return "Could not read the page: " + str(exc)


read_tool = FunctionTool.from_defaults(fn=read_url, name="read_url")
print(os.environ.get("CHAT_MODEL", "set CHAT_MODEL for your agent"), read_tool.metadata.name)

Hoe groot moet een crawl zijn voor een kleine RAG-index?

Kleiner dan je misschien denkt. De documentatie van een product is vaak een paar honderd pagina's, en een crawl met include_paths ingesteld op de docs-sectie leest alleen die. Bij 1 credit per pagina kost een docs-site van 300 pagina's ongeveer 300 credits; 10.000 pagina's (US$ 3,75) ververst hem vele malen.

Her-crawl volgens een schema dat past bij hoe vaak de bron verandert, en vergelijk final_url en word_count met de vorige run om alleen de gewijzigde pagina's opnieuw te embedden. Prepaid credits verlopen nooit: ongebruikte pagina's blijven op je account staan tot je ze gebruikt.

LangChain en LlamaIndex: veelgestelde vragen

Is er een WebReaderAPI-package voor LangChain of LlamaIndex?

Nee. De helper en tool op deze pagina zijn de hele integratie, dus je kunt ze vrij aanpassen. WebReaderAPI is een gewone HTTPS-API die elke Python HTTP-client kan aanroepen.

Welke LangChain-versie is hiervoor nodig?

Elke recente met langchain_core, langchain-text-splitters en init_chat_model. De tool-decorator en de Document-klasse zijn stabiel gebleven over recente releases.

Hoe voorkom ik dat ik pagina's opnieuw lees die niet zijn veranderd?

Sla final_url, word_count en de datum van elke read op. Lees opnieuw volgens een schema, en embed een pagina alleen opnieuw wanneer het woordenaantal of de content-hash verandert. Elke her-read kost een credit, dus kies een ritme dat past bij de bron.

Wat als sommige pagina's geweigerd worden?

Ze gooien een PageError op met een code zoals blocked_by_robots, en ze kosten niets. Als een site ons verzoek weigert, geven we het antwoord terug: we lossen nooit CAPTCHA's op, loggen niet in op accounts en proberen nooit een blokkade of paywall te omzeilen.

Vanaf US$ 0,07/1K pagina's · zonder KYC

Vraag een API-sleutel aan