# Ricerca web in LangChain e LlamaIndex: uno strumento e un retriever

> Ricerca web per LangChain e LlamaIndex: uno strumento search_web, un retriever e un FunctionTool per LlamaIndex. Senza KYC, in criptovalute.

- URL: https://llmwebsearch.com/it/docs/langchain/
- Ultimo aggiornamento: 2026-10-22
- Editore: LLMWebSearch (https://llmwebsearch.com)

Due forme coprono la maggior parte dei framework. Uno strumento permette a un agente di decidere quando cercare. Un retriever collega il web live a una catena di retrieval, dove ogni pagina letta diventa un documento con il suo URL nei metadata.

**Risposta rapida — Come aggiungo la ricerca web live a LangChain o LlamaIndex?**

Avvolgi la chiamata `/search` di **LLMWebSearch** in un `@tool` di LangChain, in un retriever di LangChain o in un `FunctionTool` di LlamaIndex. Ognuno restituisce fonti ordinate con le prime 3 pagine in Markdown e i loro URL, pronti per le citazioni. Nessun nostro pacchetto da installare: il codice qui sotto è l'integrazione. Una ricerca costa 1 credito, a partire da 1,20 USD/1K ricerche da ottobre 2026. Senza KYC; paga in criptovalute.

## A cosa serve ciascun wrapper

| Attributo | Valore |
| --- | --- |
| Strumento LangChain | Un agente chiama `search_web` quando decide di aver bisogno del web |
| Retriever LangChain | Una catena recupera documenti freschi per ogni domanda, senza chiedere |
| FunctionTool LlamaIndex | La stessa funzione `search_web`, per gli agenti LlamaIndex |
| Pacchetti | `langchain-core` o `llama-index-core`, più `requests` |
| Chiave | `LLMWEBSEARCH_API_KEY` nell'environment |
| Fatturazione | Un credito paga una ricerca: fino a 20 risultati classificati, con le pagine dei primi 3 lette e restituite come Markdown. Leggere da 4 a 10 pagine costa 2 crediti. Una chiamata che termina in errore non costa nulla |

## Come costruisco uno strumento di ricerca per un agente LangChain?

Decora una funzione con `@tool` da `langchain_core.tools`. LangChain legge il nome, gli argomenti tipizzati e la docstring per descrivere lo strumento al modello, quindi mantieni la docstring breve e precisa. La funzione restituisce una stringa con fonti numerate, che si adatta a ogni modello di chat e tiene gli URL accanto al testo.

Chiamala direttamente con `.invoke()` per testarla, poi passala nella lista tools del tuo agente.

*Strumento LangChain: search_web*

```python
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])

```

## Come uso il web live come retriever?

Crea una sottoclasse di `BaseRetriever` e restituisci un `Document` per ogni pagina letta. Il testo della pagina va in `page_content`; l'URL, il titolo, il rank e la data vanno in `metadata`, dove le catene che citano le fonti li cercano. I risultati senza contenuto vengono saltati, perché un retriever deve consegnare testo che il modello può citare.

Un retriever viene eseguito a ogni domanda. È giusto per una catena di question-answering su argomenti attuali, e uno spreco per una chat in cui la maggior parte dei turni non richiede ricerca; in quel caso usa lo strumento.

*Retriever LangChain: LLMWebSearchRetriever*

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

```

## Come do la stessa ricerca a un agente LlamaIndex?

Scrivi una funzione semplice e avvolgila con `FunctionTool.from_defaults` da `llama_index.core.tools`. LlamaIndex costruisce il nome e la descrizione dello strumento dal nome, dalla firma e dalla docstring della funzione. Chiamando lo strumento si ottiene un `ToolOutput` il cui `content` è il testo che l'agente leggerà.

La funzione è la stessa di LangChain, così un team che usa entrambi i framework può condividerla.

*LlamaIndex: FunctionTool*

```python
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])

```

## Come tengo sotto controllo la context window?

Imposta `max_chars` nella chiamata API invece di tagliare dopo: viaggiano meno dati e il framework non conserva mai la versione lunga. 5.000 caratteri per pagina e 3 pagine fanno circa 4.000 token, una misura comoda per la maggior parte dei modelli.

Per le retrieval chain che combinano il web live con i tuoi documenti, assegna ai documenti web un peso inferiore o una sezione separata del prompt. Le pagine web cambiano e possono essere sbagliate; i tuoi documenti sono di solito il riferimento.

## Posso memorizzare ciò che restituisce il retriever in un vector database?

Sì, per quanto ci riguarda. Non addestriamo alcun modello sulle tue query né su ciò che l'API restituisce, e non aggiungiamo regole nostre contro la conservazione dei risultati; restano validi i diritti dei siti di cui leggi le pagine. Memorizza l'URL e `published_at` con ogni chunk, così l'agente può citare la pagina e tu puoi eliminare i chunk che invecchiano.

La maggior parte dei team mette in cache i risultati web delle domande frequenti per un giorno o una settimana. Così si riducono le ricerche ripetute, e ogni ricerca evitata è un credito risparmiato.

## LangChain e LlamaIndex: domande frequenti

### Esiste un package langchain-llmwebsearch?

No. Non pubblichiamo nessun package. Il codice in questa pagina è abbastanza breve da essere tuo: copialo, cambia i valori predefiniti e tienilo nel tuo repository.

### Posso rendere il tool async?

Sì. Sostituisci `requests` con `httpx.AsyncClient` e definisci la funzione con `async def`. Il decoratore `@tool` di LangChain decora direttamente le funzioni async; in LlamaIndex, passa la versione async a `FunctionTool.from_defaults` come `async_fn`.

### Come leggo una pagina che l'agente ha trovato altrove?

Aggiungi un secondo tool che invia gli URL a `https://llmwebsearch.com/api/v1/extract`. Leggere pagine di cui hai già gli URL costa 1 credito per ogni gruppo iniziato di 3 pagine restituite con contenuto, fino a 20 URL per chiamata; gli URL rifiutati o falliti non vengono contati. La [extract reference](https://llmwebsearch.com/it/docs/extract/) mostra la richiesta.

---

LLMWebSearch: LLMWebSearch è un'API di ricerca web per agenti AI che restituisce risultati classificati con il contenuto delle pagine principali in Markdown, pagata in criptovalute senza caricare documenti d'identità. I crediti prepagati da 1,20 USD/1K ricerche non scadono mai. Senza KYC — niente documento, niente selfie, niente documenti. Paghi in criptovalute.
