Sem KYC — sem documento, sem selfie, sem envio de arquivos. Pague com cripto: BTC, USDT, USDC, ETH, SOL, LTC
Idioma: Português
Obtenha uma chave de API

Docs · LangChain · LlamaIndex

LangChain e LlamaIndex: um carregador de páginas web e uma ferramenta read_url

Duas formas de usar a API em uma stack de IA em Python: carregar páginas como documentos para recuperação ou dar a um agente uma ferramenta read_url. As mesmas 20 linhas de integração servem para LangChain e LlamaIndex.

Última atualização: · 5 min de leitura

Resposta rápida

Como carrego páginas web no LangChain ou LlamaIndex como Markdown limpo?

Chame o endpoint /read da WebReaderAPI e envolva cada resposta em um Document: o Markdown como conteúdo, final_url e o título como metadados. Para agentes, exponha a mesma chamada como uma ferramenta read_url. Cada página custa 1 crédito, 2 com navegador, a partir de US$ 0,07/1K páginas em outubro de 2026. Nenhum pacote nosso é necessário. Sem KYC; pagar com cripto.

Por que documentos Markdown e não HTML bruto?

Porque a recuperação funciona sobre texto, e o Markdown mantém a estrutura que importa enquanto descarta o resto. Os títulos sobrevivem, então um splitter pode cortar nas mudanças de tópico. Listas e tabelas sobrevivem, então passos e especificações ficam juntos. Navegação, banners de cookies e anúncios somem, então não poluem seus embeddings nem desperdiçam tokens.

Os metadados vêm da mesma chamada: final_url como a fonte a citar, title, published_at e language para filtragem.

reader.py: o helper compartilhado (salve ao lado do seu código)
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

Como construção um document loader do LangChain?

Transforme cada página em um langchain_core.documents.Document e depois divida por títulos com MarkdownHeaderTextSplitter do pacote langchain-text-splitters. Cada chunk mantém o caminho dos títulos nos metadados, e você adiciona a URL de origem para que toda resposta possa apontar de volta para a página.

Páginas ignoradas, como as recusadas pelo robots.txt, lançam PageError com o código; registre no log e continue.

LangChain: carregar e dividir páginas
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 "")

Como dou a um agente LangChain uma ferramenta read_url?

Decore uma função com @tool de langchain_core.tools. A docstring vira a descrição da ferramenta que o modelo lê, então diga o que a ferramenta retorna e quando usá-la. Retorne texto simples: uma linha de título, a fonte e o Markdown, cortado com max_chars para caber no seu modelo.

Vincule a ferramenta a qualquer modelo de chat que suporte tool calling, ou passe-a para o construtor do seu agente. O modelo então chama read_url com uma URL da conversa ou de um resultado de pesquisa.

LangChain: a ferramenta read_url
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)

Como faço o mesmo no LlamaIndex?

O LlamaIndex usa sua própria classe Document com text e metadata, e FunctionTool.from_defaults para transformar uma função em ferramenta. O helper continua o mesmo. Construa um índice a partir dos documentos com VectorStoreIndex.from_documents, que usa o modelo de embedding que suas configurações do LlamaIndex indicarem.

LlamaIndex: indexar um crawl, e uma ferramenta read_url
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)

Qual o tamanho de crawl que um pequeno índice RAG precisa?

Menos do que você imagina. A documentação de um produto costuma ter algumas centenas de páginas, e um crawl com include_paths definido para a seção de docs lê apenas essas. A 1 crédito por página, um site de docs com 300 páginas custa cerca de 300 créditos; 10.000 páginas (US$ 3,75) o atualiza muitas vezes.

Re-rastreie em uma frequência que corresponda à frequência com que a fonte muda, e compare final_url e word_count com a execução anterior para re-embedar apenas as páginas que mudaram. Os créditos pré-pagos nunca expiram: as páginas não usadas ficam na sua conta até você usá-las.

LangChain e LlamaIndex: dúvidas frequentes

Existe um pacote do WebReaderAPI para LangChain ou LlamaIndex?

Não. O helper e a ferramenta desta página são a integração inteira, então você pode adaptá-los livremente. WebReaderAPI é uma API HTTPS simples que qualquer cliente HTTP em Python pode chamar.

Qual versão do LangChain isso exige?

Qualquer versão recente com langchain_core, langchain-text-splitters e init_chat_model. O decorador de ferramenta e a classe Document têm se mantido estáveis nas versões recentes.

Como evito reler páginas que não mudaram?

Armazene final_url, word_count e a data de cada leitura. Releia em uma frequência definida e re-embed apenas uma página quando a contagem de palavras ou o hash do conteúdo mudar. Cada releitura custa um crédito, então escolha um ritmo que corresponda à fonte.

E se algumas páginas forem recusadas?

Elas lançam PageError com um código como blocked_by_robots, e não custam nada. Se um site recusa nossa requisição, devolvemos a resposta dele: nunca resolvemos CAPTCHAs, nunca entramos em contas e nunca tentamos contornar um bloqueio ou um paywall.

A partir de US$ 0,07/1K páginas · sem KYC

Obtenha uma chave de API