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

> Carregador de páginas web para LangChain e LlamaIndex: uma ferramenta read_url e um document loader em Python. Sem KYC, pagar com cripto.

- URL: https://webreaderapi.com/pt/docs/langchain/
- Última atualização: 2026-10-22
- Editor: WebReaderAPI (https://webreaderapi.com)

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.

**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)*

```python
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*

```python
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*

```python
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*

```python
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.

---

WebReaderAPI: O WebReaderAPI é uma API de leitor web para agentes de IA que converte qualquer página web pública em Markdown limpo, pago com cripto e sem envio de documentos. Os créditos pré-pagos a partir de US$ 0,07/1K páginas nunca expiram, e o robots.txt é respeitado. Sem KYC — sem documento, sem selfie, sem envio de arquivos. Pague com cripto.
