Outils et function calling pour agents IA

tl;dr: Function calling permet aux LLM d'appeler des outils externes de manière structurée. OpenAI Functions (JSON Schema), Anthropic Tools (similar), Google Function Declaration. Patterns : parallel calling (-60% latence), sequential chaining, validation avec Pydantic.

Qu’est-ce que le function calling ?

Le function calling permet aux LLM de :

  1. Détecter qu’un outil externe est nécessaire
  2. Générer les paramètres structurés pour appeler cet outil
  3. Recevoir le résultat et l’intégrer dans leur raisonnement

Sans function calling :

User: Quelle est la météo à Paris ?
LLM: Je ne peux pas accéder aux données en temps réel. [HALLUCINATION POSSIBLE]

Avec function calling :

User: Quelle est la météo à Paris ?
LLM: [Appelle get_weather(city="Paris")]
Tool: {"temperature": 18, "condition": "nuageux"}
LLM: Il fait 18°C à Paris avec des nuages.

Évolution

AnnéeTechnologieMéthode
2020-2022Prompting manuel“Si l’utilisateur demande la météo, utilise : [ACTION: weather]”
2023OpenAI FunctionsJSON Schema formel, gestion native par le modèle
2024Tools universelsAdoption par Anthropic, Google, Mistral
2025Parallel callingExécution simultanée de plusieurs outils
2025MCPStandardisation avec le Model Context Protocol

Schéma illustrant le function calling pour agents IA dans les systèmes d’agents d’intelligence artificielle

OpenAI Function Calling

Anatomie d’une function OpenAI

function_schema = {
    "type": "function",
    "function": {
        "name": "get_weather",  # Nom de la fonction
        "description": "Obtient la météo actuelle pour une ville donnée",  # Description claire
        "parameters": {  # JSON Schema des paramètres
            "type": "object",
            "properties": {
                "city": {
                    "type": "string",
                    "description": "Nom de la ville (ex: 'Paris', 'Tokyo')"
                },
                "unit": {
                    "type": "string",
                    "enum": ["celsius", "fahrenheit"],
                    "description": "Unité de température"
                }
            },
            "required": ["city"]  # Paramètres obligatoires
        }
    }
}

Implémentation complète

import openai
import json

# ========== 1. DÉFINIR LES FONCTIONS ==========

functions = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Obtient la météo actuelle d'une ville",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "Nom de la ville"
                    },
                    "unit": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"],
                        "default": "celsius"
                    }
                },
                "required": ["city"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "get_stock_price",
            "description": "Obtient le prix d'une action en bourse",
            "parameters": {
                "type": "object",
                "properties": {
                    "ticker": {
                        "type": "string",
                        "description": "Symbole de l'action (ex: 'AAPL', 'TSLA')"
                    },
                    "exchange": {
                        "type": "string",
                        "enum": ["NYSE", "NASDAQ", "EURONEXT"],
                        "description": "Bourse"
                    }
                },
                "required": ["ticker"]
            }
        }
    }
]

# ========== 2. IMPLÉMENTER LES FONCTIONS ==========

def get_weather(city: str, unit: str = "celsius") -> dict:
    """Simule un appel API météo"""
    # En production : appeler une vraie API (OpenWeatherMap, etc.)
    weather_data = {
        "Paris": {"temp": 18, "condition": "nuageux"},
        "Tokyo": {"temp": 25, "condition": "ensoleillé"},
        "New York": {"temp": 22, "condition": "pluvieux"}
    }

    data = weather_data.get(city, {"temp": 20, "condition": "inconnu"})

    if unit == "fahrenheit":
        data["temp"] = data["temp"] * 9/5 + 32

    return {
        "city": city,
        "temperature": data["temp"],
        "condition": data["condition"],
        "unit": unit
    }

def get_stock_price(ticker: str, exchange: str = "NYSE") -> dict:
    """Simule un appel API bourse"""
    prices = {
        "AAPL": 175.50,
        "TSLA": 242.80,
        "GOOGL": 140.25
    }

    return {
        "ticker": ticker,
        "price": prices.get(ticker, 100.0),
        "exchange": exchange,
        "currency": "USD"
    }

# Mapper les noms de fonctions
available_functions = {
    "get_weather": get_weather,
    "get_stock_price": get_stock_price
}

# ========== 3. BOUCLE D'EXÉCUTION ==========

def run_agent_with_functions(user_query: str, max_iterations: int = 5):
    """Exécute l'agent avec function calling"""

    messages = [
        {"role": "system", "content": "Tu es un assistant utile."},
        {"role": "user", "content": user_query}
    ]

    for iteration in range(max_iterations):
        print(f"\n{'='*60}")
        print(f"🔄 Itération {iteration + 1}")

        # Appel OpenAI
        response = openai.chat.completions.create(
            model="gpt-4",
            messages=messages,
            tools=functions,
            tool_choice="auto"  # "auto", "none", ou {"type": "function", "function": {"name": "..."}}
        )

        message = response.choices[0].message
        messages.append(message)

        # Vérifier si le modèle veut appeler des fonctions
        if not message.tool_calls:
            # Réponse finale
            print(f"\n✅ Réponse finale : {message.content}")
            return message.content

        # Exécuter les fonctions demandées
        for tool_call in message.tool_calls:
            function_name = tool_call.function.name
            arguments = json.loads(tool_call.function.arguments)

            print(f"\n🔧 Appel de fonction : {function_name}({arguments})")

            # Exécuter la fonction
            if function_name in available_functions:
                function_result = available_functions[function_name](**arguments)
                print(f"📊 Résultat : {function_result}")

                # Ajouter le résultat aux messages
                messages.append({
                    "role": "tool",
                    "tool_call_id": tool_call.id,
                    "name": function_name,
                    "content": json.dumps(function_result)
                })
            else:
                # Fonction inconnue
                messages.append({
                    "role": "tool",
                    "tool_call_id": tool_call.id,
                    "name": function_name,
                    "content": json.dumps({"error": f"Fonction {function_name} inconnue"})
                })

    return "⚠️ Limite d'itérations atteinte"


# ========== 4. EXEMPLE D'UTILISATION ==========

if __name__ == "__main__":
    result = run_agent_with_functions(
        "Donne-moi la météo à Paris et le prix de l'action Tesla"
    )

Sortie

============================================================
🔄 Itération 1

🔧 Appel de fonction : get_weather({'city': 'Paris'})
📊 Résultat : {'city': 'Paris', 'temperature': 18, 'condition': 'nuageux', 'unit': 'celsius'}

🔧 Appel de fonction : get_stock_price({'ticker': 'TSLA'})
📊 Résultat : {'ticker': 'TSLA', 'price': 242.8, 'exchange': 'NYSE', 'currency': 'USD'}

============================================================
🔄 Itération 2

✅ Réponse finale : Il fait actuellement 18°C à Paris avec un temps nuageux. Le prix de l'action Tesla (TSLA) est de 242,80 USD sur le NYSE.

Parallel function calling

GPT-4 peut appeler plusieurs fonctions simultanément :

🔎 Tip
Optimisation clé : Le parallel calling permet d’exécuter plusieurs outils en même temps au lieu de les enchaîner séquentiellement. C’est crucial pour réduire la latence des agents complexes.
response = openai.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "Météo à Paris, Tokyo et New York"}],
    tools=functions,
    tool_choice="auto"
)

# Le modèle retourne 3 tool_calls simultanés
for tool_call in response.choices[0].message.tool_calls:
    print(f"Appel : {tool_call.function.name}({tool_call.function.arguments})")

# Sortie :
# Appel : get_weather({'city': 'Paris'})
# Appel : get_weather({'city': 'Tokyo'})
# Appel : get_weather({'city': 'New York'})

Gain de performance : 3 appels parallèles vs 3 appels séquentiels = -60% de latence

Function calling forcé

# Forcer l'utilisation d'une fonction spécifique
response = openai.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "Il fait beau aujourd'hui"}],
    tools=functions,
    tool_choice={
        "type": "function",
        "function": {"name": "get_weather"}
    }
)

# Le modèle DOIT appeler get_weather, même si ce n'est pas pertinent

Cas d’usage :

  • Forcer une action spécifique (ex: logging, analytics)
  • Valider que l’utilisateur fournit les paramètres corrects

Anthropic Claude Tools

Anthropic utilise une approche similaire avec quelques différences.

Syntaxe Anthropic

import anthropic

client = anthropic.Anthropic(api_key="your-api-key")

# ========== DÉFINIR LES TOOLS ==========

tools = [
    {
        "name": "get_weather",
        "description": "Obtient la météo actuelle pour une ville",
        "input_schema": {  # Équivalent de "parameters" chez OpenAI
            "type": "object",
            "properties": {
                "city": {
                    "type": "string",
                    "description": "Nom de la ville"
                },
                "unit": {
                    "type": "string",
                    "enum": ["celsius", "fahrenheit"],
                    "description": "Unité de température"
                }
            },
            "required": ["city"]
        }
    }
]

# ========== BOUCLE D'EXÉCUTION ==========

messages = [{"role": "user", "content": "Météo à Paris ?"}]

while True:
    response = client.messages.create(
        model="claude-3-5-sonnet-20241022",
        max_tokens=1024,
        tools=tools,
        messages=messages
    )

    print(f"\n🤖 Stop reason: {response.stop_reason}")

    # Vérifier si Claude veut utiliser un outil
    if response.stop_reason == "tool_use":
        # Extraire le tool use
        tool_use = next(block for block in response.content if block.type == "tool_use")

        print(f"🔧 Tool: {tool_use.name}")
        print(f"📥 Input: {tool_use.input}")

        # Exécuter la fonction
        tool_result = get_weather(**tool_use.input)

        print(f"📊 Result: {tool_result}")

        # Ajouter la réponse de l'assistant
        messages.append({"role": "assistant", "content": response.content})

        # Ajouter le résultat de l'outil
        messages.append({
            "role": "user",
            "content": [
                {
                    "type": "tool_result",
                    "tool_use_id": tool_use.id,
                    "content": json.dumps(tool_result)
                }
            ]
        })

    else:
        # Réponse finale
        final_text = next(
            (block.text for block in response.content if hasattr(block, "text")),
            None
        )
        print(f"\n✅ Réponse finale : {final_text}")
        break

Différences OpenAI vs Anthropic

AspectOpenAIAnthropic
Nom du conceptFunctions / ToolsTools
Schéma JSONparametersinput_schema
Format de sortietool_calls arraycontent blocks
ID de l’appeltool_call_idtool_use_id
Réponse outilMessage role “tool”Message role “user” avec tool_result
Parallel calling✅ Natif✅ Natif
Forcingtool_choicetool_choice

Recommandation : OpenAI pour simplicité, Anthropic pour précision et contexte long

Google Gemini function calling

Syntaxe Google

import google.generativeai as genai

genai.configure(api_key="your-api-key")

# ========== DÉFINIR LES FUNCTIONS ==========

def get_weather(city: str, unit: str = "celsius") -> dict:
    """Obtient la météo d'une ville"""
    # Implémentation...
    pass

# Déclarer la fonction pour Gemini
function_declarations = [
    {
        "name": "get_weather",
        "description": "Obtient la météo actuelle d'une ville",
        "parameters": {
            "type_": "OBJECT",  # Notez le underscore
            "properties": {
                "city": {
                    "type_": "STRING",
                    "description": "Nom de la ville"
                },
                "unit": {
                    "type_": "STRING",
                    "enum": ["celsius", "fahrenheit"]
                }
            },
            "required": ["city"]
        }
    }
]

# ========== CRÉER LE MODÈLE ==========

model = genai.GenerativeModel(
    model_name="gemini-1.5-pro",
    tools=function_declarations
)

chat = model.start_chat()

# ========== BOUCLE ==========

response = chat.send_message("Météo à Paris ?")

# Vérifier les function calls
if response.candidates[0].content.parts[0].function_call:
    function_call = response.candidates[0].content.parts[0].function_call

    print(f"🔧 Function: {function_call.name}")
    print(f"📥 Args: {dict(function_call.args)}")

    # Exécuter
    result = get_weather(**dict(function_call.args))

    # Renvoyer le résultat
    response = chat.send_message(
        genai.protos.Content(
            parts=[
                genai.protos.Part(
                    function_response=genai.protos.FunctionResponse(
                        name=function_call.name,
                        response={"result": result}
                    )
                )
            ]
        )
    )

    print(f"✅ Réponse : {response.text}")

Particularités Google

  • type_ avec underscore (au lieu de type)
  • Retour de fonction via function_response proto
  • Supporte les types complexes (arrays, nested objects)
  • Multimodal : peut combiner texte + images + function calling

Validation avec pydantic

⚠️ Warning
Toujours valider les inputs : Les LLM peuvent générer des paramètres incorrects (mauvais types, valeurs hors limites). Pydantic assure une validation stricte avant d’exécuter les outils pour éviter les erreurs runtime.

Problème : Les LLM peuvent générer des paramètres invalides.

Solution : Utiliser Pydantic pour validation stricte.

from pydantic import BaseModel, Field, validator
from typing import Literal, Optional
from datetime import datetime

# ========== MODÈLE PYDANTIC ==========

class WeatherInput(BaseModel):
    """Validation des inputs pour get_weather"""

    city: str = Field(
        ...,
        min_length=2,
        max_length=50,
        description="Nom de la ville"
    )

    unit: Literal["celsius", "fahrenheit"] = Field(
        default="celsius",
        description="Unité de température"
    )

    date: Optional[str] = Field(
        default=None,
        description="Date au format YYYY-MM-DD (optionnel)"
    )

    @validator("city")
    def validate_city(cls, v):
        """Valide que la ville n'est pas vide"""
        if not v.strip():
            raise ValueError("La ville ne peut pas être vide")
        return v.strip().title()  # Capitalise

    @validator("date")
    def validate_date(cls, v):
        """Valide le format de date"""
        if v is None:
            return None
        try:
            datetime.strptime(v, "%Y-%m-%d")
            return v
        except ValueError:
            raise ValueError("Format de date invalide. Utilisez YYYY-MM-DD")

# ========== GÉNÉRER LE SCHÉMA JSON ==========

def pydantic_to_openai_schema(model: BaseModel) -> dict:
    """Convertit un modèle Pydantic en schéma OpenAI"""
    schema = model.schema()

    return {
        "type": "function",
        "function": {
            "name": model.__name__.replace("Input", "").lower(),
            "description": model.__doc__ or "",
            "parameters": {
                "type": "object",
                "properties": schema["properties"],
                "required": schema.get("required", [])
            }
        }
    }

weather_function = pydantic_to_openai_schema(WeatherInput)

# ========== FONCTION VALIDÉE ==========

def get_weather_validated(city: str, unit: str = "celsius", date: Optional[str] = None) -> dict:
    """Version validée de get_weather"""
    try:
        # Valider les inputs
        validated = WeatherInput(city=city, unit=unit, date=date)

        # Logique métier
        return {
            "city": validated.city,
            "temperature": 18,
            "unit": validated.unit,
            "date": validated.date or "today"
        }

    except ValueError as e:
        return {"error": str(e)}

# ========== UTILISATION ==========

functions = [weather_function]

response = openai.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "Météo à paris demain"}],
    tools=functions
)

# Les paramètres sont maintenant validés automatiquement

Avantages Pydantic :

  • ✅ Validation stricte des types
  • ✅ Valeurs par défaut
  • ✅ Validators personnalisés
  • ✅ Documentation auto-générée
  • ✅ Conversion vers JSON Schema automatique

Patterns avancés

Sequential Chaining (Chaînage)

Appeler des fonctions dont les résultats dépendent les uns des autres.

def sequential_agent(query: str):
    """Agent avec chaînage de fonctions"""

    # Étape 1 : Identifier l'entreprise
    response1 = openai.chat.completions.create(
        model="gpt-4",
        messages=[{"role": "user", "content": f"Trouve le symbole boursier de : {query}"}],
        tools=[get_ticker_symbol_function],
        tool_choice={"type": "function", "function": {"name": "get_ticker_symbol"}}
    )

    ticker = json.loads(response1.choices[0].message.tool_calls[0].function.arguments)["ticker"]

    # Étape 2 : Obtenir le prix
    response2 = openai.chat.completions.create(
        model="gpt-4",
        messages=[{"role": "user", "content": f"Prix de l'action {ticker}"}],
        tools=[get_stock_price_function],
        tool_choice={"type": "function", "function": {"name": "get_stock_price"}}
    )

    price_args = json.loads(response2.choices[0].message.tool_calls[0].function.arguments)
    price = get_stock_price(**price_args)

    return f"Le prix de {query} ({ticker}) est {price['price']} USD"

# Exemple
result = sequential_agent("Apple")
# → "Le prix de Apple (AAPL) est 175.50 USD"

Conditional tools (Outils conditionnels)

Adapter les outils disponibles selon le contexte.

def adaptive_agent(user_query: str, user_subscription: str):
    """Agent avec outils adaptatifs"""

    # Outils de base
    base_tools = [search_tool, calculator_tool]

    # Outils premium
    premium_tools = [
        realtime_data_tool,
        advanced_analytics_tool,
        export_tool
    ]

    # Adapter selon l'abonnement
    if user_subscription == "premium":
        tools = base_tools + premium_tools
        system_msg = "Tu as accès à tous les outils, y compris les données en temps réel."
    else:
        tools = base_tools
        system_msg = "Tu as accès aux outils de base. Pour plus d'outils, suggère un upgrade premium."

    response = openai.chat.completions.create(
        model="gpt-4",
        messages=[
            {"role": "system", "content": system_msg},
            {"role": "user", "content": user_query}
        ],
        tools=tools
    )

    # ...

Fallback sur erreur

def tool_with_fallback(tool_function, fallback_function):
    """Wrapper qui essaie un outil, puis un fallback"""

    def wrapper(**kwargs):
        try:
            return tool_function(**kwargs)
        except Exception as e:
            print(f"⚠️ Erreur avec {tool_function.__name__}: {e}")
            print(f"🔄 Utilisation du fallback...")
            return fallback_function(**kwargs)

    return wrapper

# Exemple : recherche web avec fallback
def search_with_tavily(query: str) -> str:
    """Recherche avec Tavily (payant, meilleur)"""
    # Peut échouer si API down
    return tavily_search(query)

def search_with_duckduckgo(query: str) -> str:
    """Recherche avec DuckDuckGo (gratuit, backup)"""
    return duckduckgo_search(query)

# Créer l'outil avec fallback
search_tool = Tool(
    name="search",
    func=tool_with_fallback(search_with_tavily, search_with_duckduckgo),
    description="Recherche sur le web"
)

Rate limiting par outil

from functools import wraps
import time
from collections import defaultdict

class RateLimiter:
    """Rate limiter par outil"""

    def __init__(self):
        self.calls = defaultdict(list)  # {tool_name: [timestamps]}

    def limit(self, calls_per_minute: int):
        """Décorateur pour limiter les appels"""

        def decorator(func):
            @wraps(func)
            def wrapper(*args, **kwargs):
                tool_name = func.__name__
                now = time.time()

                # Nettoyer les appels de plus d'1 minute
                self.calls[tool_name] = [
                    t for t in self.calls[tool_name]
                    if now - t < 60
                ]

                # Vérifier la limite
                if len(self.calls[tool_name]) >= calls_per_minute:
                    wait_time = 60 - (now - self.calls[tool_name][0])
                    print(f"⏳ Rate limit atteint pour {tool_name}. Attente de {wait_time:.1f}s...")
                    time.sleep(wait_time)

                    # Nettoyer à nouveau
                    self.calls[tool_name] = []

                # Enregistrer l'appel
                self.calls[tool_name].append(now)

                # Exécuter
                return func(*args, **kwargs)

            return wrapper
        return decorator

# Utilisation
rate_limiter = RateLimiter()

@rate_limiter.limit(calls_per_minute=10)
def expensive_api_call(query: str) -> str:
    """API coûteuse limitée à 10 appels/min"""
    return call_expensive_api(query)

Caching des résultats

from functools import lru_cache
import hashlib
import json

def cacheable_tool(ttl_seconds: int = 3600):
    """Décorateur pour cacher les résultats d'outils"""

    cache = {}

    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            # Créer une clé de cache
            cache_key = hashlib.md5(
                json.dumps({"args": args, "kwargs": kwargs}, sort_keys=True).encode()
            ).hexdigest()

            # Vérifier le cache
            if cache_key in cache:
                cached_result, timestamp = cache[cache_key]
                if time.time() - timestamp < ttl_seconds:
                    print(f"⚡ Cache hit pour {func.__name__}")
                    return cached_result

            # Exécuter et cacher
            result = func(*args, **kwargs)
            cache[cache_key] = (result, time.time())

            return result

        return wrapper
    return decorator

# Utilisation
@cacheable_tool(ttl_seconds=300)  # Cache 5 minutes
def get_stock_price(ticker: str) -> dict:
    """Prix d'action (changent souvent mais pas à la seconde)"""
    return fetch_stock_price(ticker)

Gestion des erreurs

Try-catch systématique

def safe_function_executor(function_name: str, arguments: dict) -> dict:
    """Exécuteur sûr de fonctions"""

    try:
        # Valider la fonction
        if function_name not in available_functions:
            return {
                "success": False,
                "error": f"Fonction '{function_name}' inconnue",
                "available_functions": list(available_functions.keys())
            }

        # Valider les arguments
        func = available_functions[function_name]
        # Utiliser signature pour vérifier les paramètres
        import inspect
        sig = inspect.signature(func)

        # Vérifier les paramètres requis
        for param_name, param in sig.parameters.items():
            if param.default == inspect.Parameter.empty and param_name not in arguments:
                return {
                    "success": False,
                    "error": f"Paramètre requis manquant : {param_name}"
                }

        # Exécuter
        result = func(**arguments)

        return {
            "success": True,
            "result": result
        }

    except TypeError as e:
        return {
            "success": False,
            "error": f"Arguments invalides : {str(e)}"
        }

    except Exception as e:
        return {
            "success": False,
            "error": f"Erreur d'exécution : {str(e)}",
            "type": type(e).__name__
        }

Timeouts

import signal
from contextlib import contextmanager

@contextmanager
def timeout(seconds: int):
    """Context manager pour timeout"""

    def handler(signum, frame):
        raise TimeoutError(f"Timeout après {seconds}s")

    # Set timeout
    signal.signal(signal.SIGALRM, handler)
    signal.alarm(seconds)

    try:
        yield
    finally:
        signal.alarm(0)  # Cancel alarm

# Utilisation
def get_weather_with_timeout(city: str) -> dict:
    """Météo avec timeout de 5s"""
    try:
        with timeout(5):
            return fetch_weather_from_api(city)
    except TimeoutError:
        return {"error": "L'API météo ne répond pas"}

Retry avec backoff exponentiel

from tenacity import retry, stop_after_attempt, wait_exponential

@retry(
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=1, min=2, max=10)
)
def get_weather_with_retry(city: str) -> dict:
    """Météo avec retry automatique"""
    response = requests.get(f"https://api.weather.com/{city}")
    response.raise_for_status()
    return response.json()

# Essaie 3 fois avec délais de 2s, 4s, 8s entre les tentatives

Exercices pratiques

Créer un outil multi-paramètres

Créez un outil send_email avec validation Pydantic :

  • to (email, requis)
  • subject (string, requis)
  • body (string, requis)
  • cc (liste d’emails, optionnel)
  • attachments (liste de chemins, optionnel)

Parallel calling optimisé

Créez un agent qui obtient la météo de 5 villes simultanément et compare les températures.

Outil avec fallback

Créez un outil de traduction avec 3 backends :

  1. DeepL (meilleur, payant)
  2. Google Translate (moyen, limité)
  3. Libre Translate (gratuit, local)

Avec fallback automatique si un service échoue.

Ressources

APIs utiles pour outils

APIUsageGratuit ?
TavilyRecherche web1000/mois
OpenWeatherMapMétéo1000/jour
Alpha VantageBourse500/jour
NewsAPIActualités100/jour
Wikipedia APIConnaissances
TwilioSMSPayant

Documentation

Prochaines étapes

Dans le prochain article, nous explorerons la Mémoire et le Contexte Long-Terme :

  • Stratégies de gestion du context window
  • Mémoire vectorielle avec RAG
  • Compression de contexte
  • Mémoire épisodique et sémantique

Points clés à retenir :

  • Function calling transforme les LLM en agents capables d’agir
  • OpenAI, Anthropic et Google ont des syntaxes légèrement différentes mais des concepts identiques
  • Pydantic assure la validation stricte des paramètres
  • Parallel calling réduit drastiquement la latence
  • Toujours gérer les erreurs et timeouts en production

Retour à la série Agents IA | Module suivant : Mémoire des Agents →