Aller au contenu principal
Leçon 7 sur 14 · Function Calling avec Grok

Pydantic et définition des outils avec le SDK xAI

Leçon 7 sur 14 Mis à jour le 3 novembre 2026 Développeur
Sur cette page
  1. Simplifier la définition des outils
  2. Approche Pydantic
  3. La fonction tool() du SDK xAI
  4. Un décorateur maison pour aller plus vite
  5. Comparaison des trois approches
  6. Bonnes pratiques pour les descriptions
  7. Points clés à retenir

Leçon corrigée le 3 novembre 2026 d’après la documentation Function calling de xAI et le SDK xai-sdk 1.21.0 : le SDK ne propose ni décorateur @client.tool() ni exécution automatique des fonctions ; les outils se construisent avec tool() (à partir d’un schéma Pydantic, par exemple) et les résultats se renvoient avec tool_result. Source : Function calling.

Simplifier la définition des outils

Écrire des schémas JSON à la main est verbeux et sujet aux erreurs. Deux approches permettent de générer les définitions d’outils à partir de votre code Python : les modèles Pydantic, que le SDK xAI transforme en outils avec sa fonction tool(), et un petit décorateur maison qui lit la signature de vos fonctions.

Approche Pydantic

Pydantic est une bibliothèque Python qui permet de définir des modèles de données avec validation automatique. L’API Grok peut utiliser ces modèles pour générer les schémas JSON des outils.

from pydantic import BaseModel, Field
from typing import Optional

class WeatherParams(BaseModel):
    city: str = Field(description="Nom de la ville")
    unit: Optional[str] = Field(
        default="celsius",
        description="Unité de température",
        enum=["celsius", "fahrenheit"]
    )

Ce modèle Pydantic génère automatiquement le schéma JSON équivalent à ce que vous auriez écrit manuellement. Les avantages :

  • Type checking : Python vérifie les types à l’exécution
  • Validation : Pydantic valide les données automatiquement
  • Documentation : les Field(description=...) servent de documentation
  • Réutilisabilité : le même modèle sert pour la validation et la documentation API

Modèles complexes

Pydantic gère les structures imbriquées, les listes et les types avancés :

from typing import List, Optional
from pydantic import BaseModel, Field

class Address(BaseModel):
    street: str = Field(description="Numéro et nom de rue")
    city: str = Field(description="Ville")
    zip_code: str = Field(description="Code postal")
    country: str = Field(default="FR", description="Code pays ISO")

class CreateOrderParams(BaseModel):
    product_id: str = Field(description="Identifiant du produit")
    quantity: int = Field(description="Quantité commandée", ge=1, le=100)
    shipping_address: Address = Field(description="Adresse de livraison")
    notes: Optional[str] = Field(
        default=None,
        description="Instructions spéciales de livraison"
    )
    tags: List[str] = Field(
        default=[],
        description="Tags pour le suivi de commande"
    )

Les contraintes ge (greater or equal) et le (less or equal) sont traduites en contraintes JSON Schema que le modèle respecte.

La fonction tool() du SDK xAI

Le SDK xAI ne prend pas une classe Pydantic telle quelle : il attend une définition d’outil, que construit sa fonction tool() à partir d’un nom, d’une description et d’un schéma JSON. Pydantic fournit justement ce schéma, avec model_json_schema() :

from xai_sdk.chat import tool

outils = [
    tool(
        name="get_weather",
        description="Obtenir la météo actuelle d'une ville",
        parameters=WeatherParams.model_json_schema(),
    ),
]

Utilisation avec le SDK

L’outil se déclare à la création de la conversation. Le SDK n’exécute pas vos fonctions : quand Grok demande un appel, votre code l’exécute, ajoute le résultat avec tool_result, puis relance la génération.

import json

from xai_sdk import Client
from xai_sdk.chat import tool_result, user

client = Client(api_key="votre-cle-api")

chat = client.chat.create(model="grok-4.5", tools=outils)
chat.append(user("Météo à Bordeaux ?"))
response = chat.sample()

if response.tool_calls:
    chat.append(response)
    for appel in response.tool_calls:
        args = WeatherParams.model_validate_json(appel.function.arguments)
        resultat = {"temp": 22, "unit": args.unit, "city": args.city}  # votre implémentation
        chat.append(tool_result(json.dumps(resultat)))
    response = chat.sample()

print(response.content)

model_validate_json vérifie au passage que les arguments produits par le modèle respectent le schéma : un argument manquant ou d’un mauvais type lève une erreur avant que votre fonction ne soit appelée.

Un décorateur maison pour aller plus vite

Le SDK ne fournit pas de décorateur @tool. Rien n’empêche d’en écrire un, en quelques lignes, qui lit la signature et la docstring d’une fonction :

import inspect

from pydantic import create_model
from xai_sdk.chat import tool


def outil(fonction):
    """Construit la définition xAI d'une fonction à partir de sa signature et de sa docstring."""
    champs = {
        nom: (p.annotation, ... if p.default is inspect.Parameter.empty else p.default)
        for nom, p in inspect.signature(fonction).parameters.items()
    }
    schema = create_model(fonction.__name__, **champs).model_json_schema()
    description = (inspect.getdoc(fonction) or fonction.__name__).split("\n\n")[0]
    return tool(name=fonction.__name__, description=description, parameters=schema)


def get_weather(city: str, unit: str = "celsius") -> dict:
    """Obtenir la météo actuelle d'une ville (ex. Paris, Lyon)."""
    return {"temp": 22, "unit": unit, "city": city}


outils = [outil(get_weather)]

Le nom de la fonction devient celui de l’outil, le premier paragraphe de la docstring sa description, et les paramètres sans valeur par défaut deviennent obligatoires. Les descriptions de chaque paramètre, en revanche, ne sont pas extraites : pour des paramètres ambigus, revenez à un modèle Pydantic avec Field(description=...).

Comparaison des trois approches

ApprocheAvantagesLimites
Schéma JSON écrit à la mainContrôle total, aucune dépendanceVerbeux, erreurs de frappe non détectées
Modèle Pydantic + tool()Validation des arguments, descriptions par champUne classe par outil
Décorateur maisonLe plus concisPas de description par paramètre, code à maintenir

Bonnes pratiques pour les descriptions

Quelle que soit l’approche, la description est ce que lit le modèle pour décider d’appeler l’outil. Dites quand l’utiliser, ce qu’il renvoie, et le format des paramètres :

class SearchProductsParams(BaseModel):
    query: str = Field(description="Termes de recherche : nom du produit ou mots-clés")
    category: str = Field(default="all", description="Catégorie : electronics, clothing, food ou all")
    max_results: int = Field(default=10, ge=1, le=50, description="Nombre maximum de résultats")


recherche = tool(
    name="search_products",
    description=(
        "Rechercher des produits dans le catalogue e-commerce. À utiliser quand "
        "l'utilisateur cherche un produit par nom, description ou catégorie. "
        "Renvoie une liste de produits avec prix, disponibilité et lien."
    ),
    parameters=SearchProductsParams.model_json_schema(),
)

Points clés à retenir

  • Pydantic génère les schémas JSON à partir de modèles Python, avec validation des arguments
  • Le SDK xAI construit les outils avec tool(name=..., description=..., parameters=...)
  • Le SDK n’exécute pas vos fonctions : votre code le fait, puis renvoie le résultat avec tool_result
  • Le SDK n’a pas de décorateur @tool ; un décorateur maison est possible, au prix des descriptions par paramètre
  • Soignez les descriptions : ce sont elles que le modèle lit pour choisir un outil