# Recherche web dans LangChain et LlamaIndex : un outil et un retriever

> Recherche web pour LangChain et LlamaIndex avec un outil search_web et un retriever renvoyant un Document par page. Sans KYC, paiement en crypto.

- URL: https://llmwebsearch.com/fr/docs/langchain/
- Dernière mise à jour: 2026-10-22
- Éditeur: LLMWebSearch (https://llmwebsearch.com)

Deux formes couvrent la plupart des frameworks. Un outil permet à un agent de décider quand effectuer une recherche. Un retriever branche le web en direct sur une chaîne de retrieval, où chaque page lue devient un document avec son URL dans les métadonnées.

**Réponse rapide — Comment ajouter une recherche web en direct à LangChain ou LlamaIndex ?**

Enveloppez l'appel `/search` de **LLMWebSearch** dans un `@tool` LangChain, un retriever LangChain ou un `FunctionTool` LlamaIndex. Chacun renvoie des sources classées avec les 3 meilleures pages en Markdown et leurs URL, prêtes pour les citations. Aucun package de notre part à installer : le code ci-dessous constitue l'intégration. Une recherche coûte 1 crédit, à partir de 1,20 $US/1K requêtes en octobre 2026. Sans KYC ; payez en crypto.

## À quoi sert chaque wrapper

| Attribut | Valeur |
| --- | --- |
| Outil LangChain | Un agent appelle `search_web` lorsqu'il décide qu'il a besoin du web |
| Retriever LangChain | Une chaîne récupère des documents frais à chaque question, sans les demander |
| FunctionTool LlamaIndex | La même fonction `search_web`, pour les agents LlamaIndex |
| Packages | `langchain-core` ou `llama-index-core`, plus `requests` |
| Clé | `LLMWEBSEARCH_API_KEY` dans l'environnement |
| Facturation | Un crédit paie une recherche : jusqu'à 20 résultats classés, avec les pages des 3 premiers lues et renvoyées en Markdown. Lire 4 à 10 pages coûte 2 crédits. Un appel qui se termine sur une erreur ne coûte rien |

## Comment créer un outil de recherche pour un agent LangChain ?

Décorez une fonction avec `@tool` de `langchain_core.tools`. LangChain lit le nom, les arguments typés et la docstring pour décrire l'outil au modèle, gardez donc la docstring courte et précise. La fonction renvoie une chaîne avec des sources numérotées, ce qui convient à tous les modèles de chat et garde les URL à côté du texte.

Appelez-la directement avec `.invoke()` pour la tester, puis passez-la dans la liste tools de votre agent.

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

```

## Comment utiliser le web en direct comme retriever ?

Sous-classez `BaseRetriever` et renvoyez un `Document` par page lue. Le texte de la page va dans `page_content` ; l'URL, le titre, le rang et la date vont dans `metadata`, où les chaînes qui citent leurs sources les recherchent. Les résultats sans contenu sont ignorés, car un retriever doit fournir un texte que le modèle peut citer.

Un retriever s'exécute à chaque question. C'est adapté à une chaîne de question-réponse sur des sujets d'actualité, et superflu pour un chat où la plupart des tours n'ont pas besoin de recherche ; utilisez l'outil dans ce cas.

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

```

## Comment donner la même recherche à un agent LlamaIndex ?

Écrivez une fonction simple et enveloppez-la avec `FunctionTool.from_defaults` de `llama_index.core.tools`. LlamaIndex construit le nom et la description de l'outil à partir du nom, de la signature et de la docstring de la fonction. L'appel de l'outil renvoie un `ToolOutput` dont l'`content` est le texte que l'agent lira.

La fonction est la même que celle de LangChain, une équipe qui utilise les deux frameworks peut donc la partager.

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

```

## Comment garder la fenêtre de contexte sous contrôle ?

Définissez `max_chars` sur l'appel API plutôt que de tronquer ensuite : moins de données circulent et le framework ne conserve jamais la version longue. 5 000 caractères par page et 3 pages font environ 4 000 tokens, confortable pour la plupart des modèles.

Pour les chaînes de retrieval qui combinent le web en direct avec vos propres documents, donnez aux documents web un poids plus faible ou une section de prompt distincte. Les pages web changent et peuvent être fausses ; vos propres documents sont généralement la référence.

## Puis-je stocker ce que le retriever renvoie dans une base de données vectorielle ?

Oui, en ce qui nous concerne. Nous n'entraînons aucun modèle sur vos requêtes ni sur ce que renvoie l'API, et nous n'ajoutons aucune règle de notre cru contre la conservation des résultats ; les droits des sites dont vous lisez les pages s'appliquent toujours. Stockez l'URL et `published_at` avec chaque chunk, pour que l'agent puisse citer la page et que vous puissiez supprimer les chunks qui vieillissent.

La plupart des équipes mettent en cache les résultats web des questions fréquentes pendant un jour ou une semaine. Cela réduit les recherches répétées, et chaque recherche évitée est un crédit économisé.

## LangChain et LlamaIndex : questions fréquentes

### Existe-t-il un package langchain-llmwebsearch ?

Non. Nous ne publions aucun package. Le code de cette page est assez court pour vous appartenir : copiez-le, changez les valeurs par défaut et gardez-le dans votre dépôt.

### Puis-je rendre l'outil async ?

Oui. Remplacez `requests` par `httpx.AsyncClient` et définissez la fonction avec `async def`. Le décorateur `@tool` de LangChain décore directement les fonctions async ; dans LlamaIndex, passez la version async à `FunctionTool.from_defaults` en tant que `async_fn`.

### Comment lire une page que l'agent a trouvée ailleurs ?

Ajoutez un second outil qui envoie des URLs à `https://llmwebsearch.com/api/v1/extract`. Lire des pages dont vous avez déjà les URLs coûte 1 crédit par groupe de 3 pages entamé, renvoyées avec leur contenu, jusqu'à 20 URLs par appel ; les URLs refusées ou en échec ne sont pas comptées. La [référence extract](https://llmwebsearch.com/fr/docs/extract/) montre la requête.

---

LLMWebSearch: LLMWebSearch est une API de recherche web pour agents IA qui renvoie des résultats classés avec le contenu des meilleures pages en Markdown, payée en crypto sans envoi de pièce d'identité. Les crédits prépayés à partir de 1,20 $US/1K requêtes n'expirent jamais. Sans KYC — pas de pièce d'identité, pas de selfie, pas de documents. Payez en crypto.
