---
title: Faire une IA qui recherche sur le web
author: Frederic AOUSTIN
version: 1.O
---

# Faire une ia qui recherche sur le web

![category](developpement)
![tag](python)
![tag](ia)


Quand on parle **IA** on parle souvent de *LLM* ... et on s'aperçoit qu'il en existe de différentes tailles (et la je parle de la taille de fichier).
Mais si les dernières versions peuvent être très importante on peut en faire tourner sur des laptops et le fichier télécharger de fait que quelques gigas.

Et pourtant certains LLM peuvent répondre a des questions sur des domaines très différents ... on se doute donc que leur *connaissance* ne provient pas
uniquement de leur fichier mais qu'ils vont chercher de l'informations ailleurs.

Et en effet l'orchestrateur qui propose le LLM comme *openWebUI* propose en faite au LLM d'aller chercher de l'info dans une base RAG par exemple mais aussi
sur internet. En injectant le resultat de recherche de contenu web, le LLM peut alors synthétiser des informations et répondre à vos questions.

Pour réaliser ce travail l'orchestrateur doit pouvoir proposer deux type d'outil

- un outil pour la recherche web
- un outil pour transformer le contenu d'un site en **markdown** tout en gérants les javascripts, le recursif

La solution la plus connue pour réaliser ce travail est **Firecrawl** mais il s'agit d'un outil payant.

Nous allons donc aborder des solutions open-sources et gratuites: **Searngx** et **Crawl4Ai**

| Fonctionnalité | Firecrawl Cloud | Firecrawl Self-hosted | Ta stack (SearXNG + Crawl4AI) |
|---|---|---|---|
| **SCRAPING** |  |  |  |
| Scraping HTML statique | ✅ | ✅ | ✅ |
| Scraping JavaScript / SPA | ✅ | ✅ | ✅ Playwright |
| Output Markdown LLM-ready | ✅ | ✅ | ✅ |
| Nettoyage du contenu | ✅ | ✅ | ✅ |
| Screenshots | ✅ | ✅ | ✅ |
| Extraction PDF | ✅ | ✅ | ✅ |
| **CRAWL** |  |  |  |
| Crawl récursif | ✅ | ✅ | ✅ |
| Respect robots.txt | ✅ | ✅ | ✅ |
| Profondeur configurable | ✅ | ✅ | ✅ |
| Sitemap mapping | ✅ | ✅ | ✅ |
| **EXTRACTION** |  |  |  |
| Extraction schéma JSON | ✅ | ✅ | ✅ (avec LLM) |
| Extraction LLM-powered | ✅ | ✅ | ✅ |
| Sélecteurs CSS/XPath | ✅ | ✅ | ✅ |
| **RECHERCHE** |  |  |  |
| Recherche web intégrée | ✅ | ❌ | ✅ SearXNG |
| Moteurs multiples | ❌ (Google only) | ❌ | ✅ 70+ moteurs |
| Recherche privée | ❌ | ❌ | ✅ aucun tracking |
| **ANTI-BOT** |  |  |  |
| Proxies rotatifs cloud | ✅ | ❌ | ❌ |
| Résolution CAPTCHA | ✅ | ❌ | ❌ |
| Fingerprinting navigateur | ✅ avancé | ⚠️ basique | ⚠️ basique |
| Contournement Cloudflare | ✅ | ❌ | ❌ |
| Contournement LinkedIn/Amazon | ✅ | ❌ | ❌ |
| **MCP & INTÉGRATION** |  |  |  |
| Serveur MCP intégré | ✅ | ✅ | ✅ SSE |
| Transport Streamable HTTP | ✅ | ✅ | ❌ (SSE only v0.9.0) |
| API REST | ✅ | ✅ | ✅ |
| OpenAPI / Swagger | ✅ | ✅ | ✅ /openapi.json |
| **INFRASTRUCTURE** |  |  |  |
| Self-hosted 100% | ❌ | ⚠️ partiel | ✅ |
| Search fonctionnelle en self-hosted | — | ❌ | ✅ |
| Souveraineté des données | ❌ | ⚠️ | ✅ |
| Aucun appel API externe | ❌ | ❌ | ✅ |
| **COÛT** |  |  |  |
| Modèle tarifaire | 💰 crédits/mois | 🔧 infra own | 🆓 gratuit |
| Limite de crawls | ✅ (quota) | ✅ (quota) | ❌ illimité |
| Licence | Propriétaire | AGPL-3.0 | Apache 2.0 |

Nous allons mettre en place l'architecture suivante

```mermaid
flowchart TD
    crawl4ai["Craw4AI"]
    mcpo["mcpo"]
    searxng["SearXNG"]
    redis["Redis"]
    openwebui["OpenWebUI"]
    openwebui --> mcpo
    openwebui --> searxng
    searxng -.-> redis
    mcpo --> crawl4ai
```

## SearXNG: la recherche web

Nous allons ajouter ce module par docker


```docker
services:

  # ── 1. SearXNG — moteur de recherche privé (70+ sources) ──
  searxng:
    image: searxng/searxng:latest
    container_name: searxng
    restart: unless-stopped
    ports:
      - "8081:8080"
    volumes:
      - ./searxng-config:/etc/searxng:rw
    environment:
#      - SEARXNG_BASE_URL=http://localhost:8081
      - SEARXNG_SECRET_KEY=${SEARXNG_SECRET_KEY:-changeme-generate-a-real-secret}
    networks:
      - mcp-net

networks:
  mcp-net:
    driver: bridge

```

vous devez aussi avoir au minimum dans le fichier ./searxng-config/settings.xml

```yml
# Read the documentation before extending the defaults:
# https://docs.searxng.org/admin/settings/

use_default_settings: true

server:
  secret_key: "<YOUR-SECRET-KEY>"
  image_proxy: true

search:
  formats:
    - html
    - json
```

SEARXNG_SECRET_KEY est une clé interne à Flask (le framework Python sur lequel tourne SearXNG). Elle n'a aucun rapport avec l'authentification des requêtes entrantes.
Elle sert uniquement à signer cryptographiquement les cookies de session côté serveur — c'est un mécanisme standard Flask pour garantir que les cookies n'ont pas été falsifiés par un utilisateur.

Cela vous permet d'avoir accès à un site web de type google sur http://localhost:8081

Mais ce site est accessible aussi pour **openWebUi** via des apis

```bash
# Recherche simple — retourne du JSON
curl "http://localhost:8081/search?q=openai&format=json" | jq '.results[] | {title, url}'

# Avec filtres moteurs
curl "http://localhost:8081/search?q=python+mcp&format=json&engines=google,bing&language=fr-FR" \
  | jq '.results[:5] | .[] | .title'

# Voir les moteurs disponibles
curl "http://localhost:8081/config" | jq '.engines | keys'
```

L'intégartion dans **OpenWebUi** est assez simple et ne passe pas par un serveur mcp.

Il faut aller dans *Panneau de configuration* / **Réglages** / **Moteur de recherche** et activer la partie moteur de recherche

![configuration searxng](./upload/202060627160200.png)

il est possible de rajouter un service **Redis** pour fournir du cache à **SearXNG** et ainsi accellerer les recherches répétitives

Pour cela dans le fichier de configuration il faut rajouter

```yml
redis:
  url: redis://redis:6379/0
```

et dans le docker-compose rajouter un service **redis**

```Docker
   redis:
     image: redis:7-alpine
     container_name: redis-mcp
     restart: unless-stopped
     command: redis-server --save "" --appendonly no --maxmemory 256mb --maxmemory-policy allkeys-lru
     networks:
       - mcp-net
```


Un principal problème pour moi est qu'il n'existe pas de système par défaut d'authentification pour ce site .... donc si vous l'ouvrez vers l'exterieur tout le monde y a accès et les recherches seront effectué par votre machine ce qui n'est pas bon.

on peut interroger en **Python** searxng

```python
import httpx

def search_web(query: str, max_results: int = 10):
    resp = httpx.get("http://localhost:8081/search", params={
        "q": query,
        "format": "json",
        "engines": "google,bing,duckduckgo"
    })
    results = resp.json().get("results", [])[:max_results]
    return [{"title": r["title"], "url": r["url"], "snippet": r.get("content", "")} for r in results]
```


## crawl4AI: crawl de site web

Cet outil à pour but de récupérer le contenu d'une url afin de pouvoir alimenter le context d'un LLM.

**Crawl4AI** est un serveur mcp mais qui utilise le protocole *SSE* pour communiquer avec un orchestrateur. Malheureusement **OpenWebUi** ne supporte pas ce protocole.
Il faut donc rajouter une brique qui va faire office de proxy entre **OpenWebUI** et **Crawl4AI** pour transformer le protocole *SSE* en *openApi* utilisable.
Je n'ai pas trouvez de brique pouvant transformer le *SSE* en *HTTP Streamable*.

Cette brique se nomme **mcpo**

J'utilise *Docker* pour monter ces services

```Docker
services:
  crawl4ai:
    image: unclecode/crawl4ai:latest
    container_name: crawl4ai
    restart: unless-stopped
    ports:
      - "11235:11235"
    shm_size: "2gb"
    environment:
      # Activer le serveur MCP SSE
      - MCP_ENABLED=true
      - CRAWL4AI_API_TOKEN=${CRAWL4AI_API_TOKEN:-}
    networks:
      - mcp-net

  mcpo:
    image: ghcr.io/open-webui/mcpo:main
    container_name: mcpo
    restart: unless-stopped
    ports:
      - "8080:8000"
    volumes:
      - ./mcpo-config:/app/config:ro
    command: ["mcpo", "--host", "0.0.0.0", "--port", "8000",
              "--api-key", "${MCPO_API_KEY:-mcpo-secret}",
              "--config", "/app/config/config.json"]
    networks:
      - mcp-net
    depends_on:
      - crawl4ai

networks:
  mcp-net:
    driver: bridge

```

Vous devez aussi avoir un fichire *.env* contenant vos secrets

```
CRAWL4AI_API_TOKEN=<YOUR-SECRET-CRAWL4AI>
MCPO_API_KEY=<YOUR-SECRET-MCP_API_KEY>
```

Et vous devez trouver dans le fichier *mcpo-config/config.json*

```json
{
  "mcpServers": {
    "crawl4ai": {
      "type": "sse",
      "url": "http://crawl4ai:11235/mcp/sse",
      "headers": {
        "Authorization": "Bearer <YOUR-SECRET-CRAWL41I>"
      }
    }
  }
}
```


Une fois lancé vous pouvez tester les API via l'url http://127.0.0.1:8080/docs

En effet le module mcpo propose une interface swagger pour tester vos tools.

Il faut maintenant l'intégrer dans **openWebUI** en tant que serveur mcp (*panneau de configuraiton* / **Réglages** / **intégration**) et le lié à un de vos LLMS.

Attention: lors de la déclaration il faut choisir le type **OpenAPI**, l'url de **mcpo** et indiquer comme Bearer <YOUR-SECRET-MCP_API_KEY>

![config](./upload/20260627160201.png)


