# OpenAI function calling : donnez au modèle un outil search_web

> Recherche web OpenAI function calling : le schéma search_web, la boucle Responses API en Python et l'outil Agents SDK, sans KYC, paiement en crypto.

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

Décrivez une fonction `search_web` au modèle, exécutez l'appel qu'il demande contre notre API, et renvoyez-lui les sources. Le modèle répond alors avec des citations. Cette page présente le schéma JSON, la boucle de la Responses API et la version plus courte avec le OpenAI Agents SDK.

**Réponse rapide — Comment ajouter la recherche web à un modèle OpenAI avec function calling ?**

Déclarez une fonction `search_web` avec un schéma JSON, et quand le modèle l'appelle, envoyez la requête au `https://llmwebsearch.com/api/v1/search` de **LLMWebSearch**. Renvoyez les sources numérotées, avec les 3 meilleures pages en Markdown, sous forme de `function_call_output` ; le modèle répond et les cite. Une requête coûte 1 crédit, à partir de 1,20 $US/1K requêtes depuis octobre 2026. Sans KYC ; paiement en crypto.

## Ce qu'il vous faut

| Attribut | Valeur |
| --- | --- |
| Packages | `openai` et `requests` (ou `openai-agents` pour la version Agents SDK) |
| Clés | `OPENAI_API_KEY` pour le modèle, `LLMWEBSEARCH_API_KEY` pour la recherche |
| Modèle | Tout modèle qui prend en charge le function calling, défini dans `OPENAI_MODEL` |
| API utilisée | Responses API : `client.responses.create` avec `tools` et `input` |
| Facturation de notre côté | 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 |

## À quoi ressemble le schéma de l'outil ?

Un function tool a un `name`, un `description` et un JSON Schema `parameters`. Gardez la description concrète : ce que l'outil renvoie, et que les sources doivent être citées par numéro. Deux paramètres suffisent pour la plupart des agents : la `query`, et combien de meilleurs résultats récupérer en entier (`read`).

Le modèle ne voit jamais votre clé API. Il propose seulement des arguments ; votre code décide comment appeler l'API et quoi renvoyer.

## Comment fonctionne la boucle d'appels ?

Envoyez le message de l'utilisateur avec les outils. Si la réponse contient des items de type `function_call`, analysez le JSON `arguments` de chacun, exécutez la recherche, et ajoutez un `function_call_output` avec le même `call_id`. Appelez ensuite le modèle à nouveau avec la liste d'entrée plus longue. Quand une réponse ne contient aucun appel de fonction, son texte est la réponse.

La boucle ci-dessous s'arrête après cinq tours, une garde contre un modèle qui chercherait sans fin. Le guide du function calling d'OpenAI décrit ces mêmes items `function_call` et `function_call_output`, consulté le 22 octobre 2026.

*search_tool_loop.py (Responses API)*

```python
import json
import os

import requests
from openai import OpenAI

client = OpenAI()
MODEL = os.environ["OPENAI_MODEL"]  # any model that supports function calling
SEARCH = "https://llmwebsearch.com/api/v1/search"

tools = [
    {
        "type": "function",
        "name": "search_web",
        "description": "Search the live web. Returns numbered sources with URLs; the first `read` include page text. Cite sources as [1], [2].",
        "parameters": {
            "type": "object",
            "properties": {
                "query": {"type": "string", "description": "What to search for, as a person would type it."},
                "read": {"type": "integer", "minimum": 0, "maximum": 10, "description": "How many top results to read in full."},
            },
            "required": ["query"],
            "additionalProperties": False,
        },
    }
]


def search_web(query, read=3):
    resp = requests.post(
        SEARCH,
        headers={"Authorization": "Bearer " + os.environ["LLMWEBSEARCH_API_KEY"]},
        json={"q": query, "max_results": 5, "read": read, "max_chars": 5000},
        timeout=60,
    )
    if resp.status_code != 200:
        return "Search failed: " + resp.json().get("error", {}).get("code", str(resp.status_code))
    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)


input_list = [{"role": "user", "content": "How should I size a Postgres connection pool?"}]
for _ in range(5):
    response = client.responses.create(model=MODEL, tools=tools, input=input_list)
    calls = [item for item in response.output if item.type == "function_call"]
    if not calls:
        print(response.output_text)
        break
    input_list += response.output
    for item in calls:
        args = json.loads(item.arguments)
        output = search_web(args["query"], int(args.get("read", 3)))
        input_list.append({"type": "function_call_output", "call_id": item.call_id, "output": output})

```

## Existe-t-il une version plus courte avec le Agents SDK ?

Oui. Le OpenAI Agents SDK transforme une fonction Python en outil avec un décorateur et exécute la boucle d'appels à votre place. Sa documentation des outils, consultée le 22 octobre 2026, montre le décorateur `@tool` de `agents.decorators`, avec la description tirée de la docstring et la description de chaque argument depuis sa section `Args`. La même page mentionne aussi la forme `@function_tool`.

`Runner.run_sync` exécute l'agent jusqu'à ce qu'il produise une réponse finale, en appelant `search_web` autant de fois que le modèle le demande.

*search_agent.py (OpenAI Agents SDK)*

```python
import os

import requests
from agents import Agent, Runner
from agents.decorators import tool


@tool
def search_web(query: str, read: int = 3) -> str:
    """Search the live web and return numbered sources with their URLs.

    Args:
        query: What to search for, as a person would type it.
        read: How many top results to read in full, from 0 to 10.
    """
    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)


agent = Agent(
    name="Researcher",
    instructions="Answer from search_web results only and cite them as [1], [2].",
    tools=[search_web],
)
result = Runner.run_sync(agent, "How should I size a Postgres connection pool?")
print(result.final_output)

```

## Pourquoi utiliser un outil API plutôt que la recherche web intégrée d'OpenAI ?

Surtout pour maîtriser ce que le modèle lit et ce que cela coûte. Notre outil transmet à votre code les sources brutes, avec les URL et le texte des pages, pour que vous décidiez ce qui entre dans le contexte, que vous puissiez le journaliser et le stocker. 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.

Le prix est aussi fixe par requête au lieu de dépendre de la quantité de contenu récupéré que le modèle lit. La [comparaison des outils intégrés](https://llmwebsearch.com/fr/compare/built-in-web-search-tools/) met côte à côte les prix par appel d'OpenAI, Anthropic, Google et d'autres, avec les dates.

## Comment empêcher le modèle de trop chercher ?

Dites-le dans les instructions : cherchez une fois, lisez les sources, ne cherchez à nouveau que si elles se contredisent ou passent à côté du sujet. Plafonnez le nombre de tours dans votre propre boucle, comme le fait le script ci-dessus avec cinq.

Gardez `max_chars` modeste. Trois pages de 5 000 caractères font environ 4 000 tokens par requête, et chaque tour les ajoute à l'entrée de l'appel suivant au modèle.

## OpenAI function calling : questions fréquentes

### Est-ce que cela fonctionne avec l'API Chat Completions ?

Oui, avec l'ancien format `tools` de Chat Completions, où la fonction se trouve dans un objet `function` et les résultats reviennent sous forme de messages `tool`. La fonction de recherche elle-même ne change pas.

### Le modèle peut-il lire une page qu'il trouve dans une source ?

Ajoutez une seconde fonction, `read_urls`, qui envoie des URL à `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.

### Quel modèle dois-je utiliser ?

N'importe quel modèle qui prend en charge le function calling. Essayez-en deux ou trois sur vos propres questions : la réponse dépend autant des sources que du modèle, et un modèle plus petit coûte moins cher par tour.

## Sources

1. [Function calling](https://developers.openai.com/api/docs/guides/function-calling) — OpenAI API docs (read 2026-10-22)
2. [Outils (OpenAI Agents SDK)](https://openai.github.io/openai-agents-python/tools/) — OpenAI Agents SDK docs (read 2026-10-22)

---

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.
