Sin KYC — sin ID, sin selfie, sin documentos. Paga con criptomonedas: BTC, USDT, USDC, ETH, SOL, LTC
Idioma: Español
Obtén una clave API

Docs · LangChain · LlamaIndex

Búsqueda web en LangChain y LlamaIndex: una herramienta y un retriever

Dos formas cubren la mayoría de los frameworks. Una herramienta permite que un agente decida cuándo buscar. Un retriever conecta la web en vivo a una cadena de recuperación, donde cada página leída se convierte en un documento con su URL en los metadatos.

Última actualización: · 5 min de lectura

Respuesta rápida

¿Cómo añado búsqueda web en vivo a LangChain o LlamaIndex?

Envuelve la llamada a /search de LLMWebSearch en un @tool de LangChain, un retriever de LangChain o un FunctionTool de LlamaIndex. Cada uno devuelve fuentes clasificadas con las 3 páginas principales en Markdown y sus URLs, listas para citar. No hay que instalar ningún paquete nuestro: el código de abajo es la integración. Una búsqueda cuesta 1 crédito, desde 1,20 US$/1K búsquedas a fecha de octubre de 2026. Sin KYC; paga con criptomonedas.

Para qué sirve cada wrapper

Herramienta de LangChainUn agente llama a search_web cuando decide que necesita la web
Retriever de LangChainUna cadena obtiene documentos nuevos para cada pregunta, sin preguntar
FunctionTool de LlamaIndexLa misma función search_web, para agentes de LlamaIndex
Paqueteslangchain-core o llama-index-core, más requests
ClaveLLMWEBSEARCH_API_KEY en el entorno
FacturaciónUn crédito paga una búsqueda: hasta 20 resultados clasificados, con las páginas de los 3 primeros leídas y devueltas como Markdown. Leer de 4 a 10 páginas pasa a 2 créditos. Una llamada que termina en error no cuesta nada

¿Cómo creo una herramienta de búsqueda para un agente de LangChain?

Decora una función con @tool de langchain_core.tools. LangChain lee el nombre, los argumentos tipados y el docstring para describir la herramienta al modelo, así que mantén el docstring corto y preciso. La función devuelve una sola cadena con fuentes numeradas, que encaja con cualquier modelo de chat y mantiene las URLs junto al texto.

Llámala directamente con .invoke() para probarla y luego pásala en la lista tools de tu agente.

Herramienta de LangChain: search_web
import os

import requests
from langchain_core.tools import tool

API = "https://llmwebsearch.com/api/v1/search"
HEADERS = {"Authorization": "Bearer " + os.environ["LLMWEBSEARCH_API_KEY"]}


@tool
def search_web(query: str, read: int = 3) -> str:
    """Search the live web. Returns numbered sources with URLs; the first `read` include page text."""
    body = {"q": query, "max_results": 5, "read": max(0, min(read, 10)), "max_chars": 5000}
    resp = requests.post(API, headers=HEADERS, json=body, timeout=60)
    resp.raise_for_status()
    parts = []
    for i, r in enumerate(resp.json()["results"], start=1):
        text = r["content"] if r["content_status"] == "ok" else "(snippet only) " + r["snippet"]
        parts.append(f"[{i}] {r['title']} - {r['url']}\n{text}")
    return "\n\n".join(parts)


print(search_web.invoke({"query": "postgres connection pool size"})[:500])

¿Cómo uso la web en vivo como retriever?

Crea una subclase de BaseRetriever y devuelve un Document por cada página leída. El texto de la página va en page_content; la URL, el título, el ranking y la fecha van en metadata, donde las cadenas que citan sus fuentes los buscan. Los resultados sin contenido se omiten, porque un retriever debe entregar texto que el modelo pueda citar.

Un retriever se ejecuta en cada pregunta. Eso es correcto para una cadena de respuesta a preguntas sobre temas de actualidad, y un desperdicio para un chat en el que la mayoría de los turnos no necesitan búsqueda; en ese caso, usa la herramienta.

Retriever de LangChain: LLMWebSearchRetriever
import os
from typing import List

import requests
from langchain_core.callbacks import CallbackManagerForRetrieverRun
from langchain_core.documents import Document
from langchain_core.retrievers import BaseRetriever


class LLMWebSearchRetriever(BaseRetriever):
    """Live web search results as Documents, one per page that was read."""

    max_results: int = 5
    read: int = 3
    max_chars: int = 6000

    def _get_relevant_documents(self, query: str, *, run_manager: CallbackManagerForRetrieverRun) -> List[Document]:
        resp = requests.post(
            "https://llmwebsearch.com/api/v1/search",
            headers={"Authorization": "Bearer " + os.environ["LLMWEBSEARCH_API_KEY"]},
            json={"q": query, "max_results": self.max_results, "read": self.read, "max_chars": self.max_chars},
            timeout=60,
        )
        resp.raise_for_status()
        docs = []
        for r in resp.json()["results"]:
            if r["content_status"] != "ok":
                continue
            meta = {"source": r["url"], "title": r["title"], "position": r["position"], "published_at": r.get("published_at")}
            docs.append(Document(page_content=r["content"], metadata=meta))
        return docs


retriever = LLMWebSearchRetriever(read=3)
for doc in retriever.invoke("pgbouncer transaction mode limitations"):
    print(doc.metadata["position"], doc.metadata["source"], len(doc.page_content))

¿Cómo doy la misma búsqueda a un agente de LlamaIndex?

Escribe una función normal y envuélvela con FunctionTool.from_defaults de llama_index.core.tools. LlamaIndex construye el nombre y la descripción de la herramienta a partir del nombre, la firma y el docstring de la función. Al llamar a la herramienta se devuelve un ToolOutput cuyo content es el texto que leerá el agente.

La función es la misma que la de LangChain, así que un equipo que use ambos frameworks puede compartirla.

LlamaIndex: FunctionTool
import os

import requests
from llama_index.core.tools import FunctionTool


def search_web(query: str, read: int = 3) -> str:
    """Search the live web and return numbered sources; the first `read` include their page text."""
    resp = requests.post(
        "https://llmwebsearch.com/api/v1/search",
        headers={"Authorization": "Bearer " + os.environ["LLMWEBSEARCH_API_KEY"]},
        json={"q": query, "max_results": 5, "read": max(0, min(read, 10)), "max_chars": 5000},
        timeout=60,
    )
    resp.raise_for_status()
    parts = []
    for i, r in enumerate(resp.json()["results"], start=1):
        text = r["content"] if r["content_status"] == "ok" else "(snippet only) " + r["snippet"]
        parts.append(f"[{i}] {r['title']} - {r['url']}\n{text}")
    return "\n\n".join(parts)


search_tool = FunctionTool.from_defaults(fn=search_web)
print(search_tool.metadata.name)
print(search_tool.call(query="postgres connection pool size").content[:300])

¿Cómo mantengo controlada la ventana de contexto?

Configura max_chars en la llamada a la API en lugar de recortar después: viajan menos datos y el framework nunca guarda la versión larga. 5.000 caracteres por página y 3 páginas son unos 4.000 tokens, cómodo para la mayoría de los modelos.

Para las cadenas de recuperación que combinan la web en vivo con tus propios documentos, asigna a los documentos web un peso menor o una sección de prompt aparte. Las páginas web cambian y pueden estar mal; tus propios documentos suelen ser la referencia.

¿Puedo almacenar lo que devuelve el retriever en una base de datos vectorial?

Sí, por lo que a nosotros respecta. No entrenamos ningún modelo con tus consultas ni con lo que devuelve la API, y no añadimos ninguna regla propia contra almacenar resultados; los derechos de los sitios cuyas páginas lees siguen aplicándose. Guarda la URL y published_at con cada fragmento, así el agente puede citar la página y tú puedes descartar los fragmentos que se quedan obsoletos.

La mayoría de los equipos guardan en caché los resultados web de las preguntas frecuentes durante un día o una semana. Eso reduce las búsquedas repetidas, y cada búsqueda evitada es un crédito ahorrado.

LangChain y LlamaIndex: preguntas habituales

¿Existe un paquete langchain-llmwebsearch?

No. No publicamos ningún paquete. El código de esta página es lo bastante corto para que sea tuyo: cópialo, cambia los valores por defecto y guárdalo en tu repositorio.

¿Puedo hacer la herramienta asíncrona?

Sí. Sustituye requests por httpx.AsyncClient y define la función con async def. El decorador @tool de LangChain decora funciones asíncronas directamente; en LlamaIndex, pasa la versión asíncrona a FunctionTool.from_defaults como async_fn.

¿Cómo leo una página que el agente encontró en otro sitio?

Añade una segunda herramienta que envíe URLs a https://llmwebsearch.com/api/v1/extract. Leer páginas cuyas URL ya tienes cuesta 1 crédito por cada grupo iniciado de 3 páginas devueltas con contenido, hasta 20 URL por llamada; las URL rechazadas o fallidas no se cuentan. La referencia de extract muestra la solicitud.

Desde 1,20 US$/1K búsquedas · sin KYC

Obtén una clave API