Comment utiliser l'appel de fonction avec l'API DeepSeek V4 Pro

Guide pratique de l'appel de fonction DeepSeek V4 Pro : schémas d'outils, la boucle complète de l'agent Python, les appels d'outils parallèles, le mode de réflexion, la gestion des erreurs, les coûts de mise en cache et le test des appels d'outils dans Apidog.

INEZA Felin-Michel

INEZA Felin-Michel

13 August 2026

Comment utiliser l'appel de fonction avec l'API DeepSeek V4 Pro

Apidog pour les entreprises

Déploiement sur site

SSO & RBAC

Conforme SOC 2

Découvrir Apidog Enterprise

DeepSeek a sorti V4 Pro de la préversion le 12 août 2026, et la couverture de son lancement met l'accent sur les workflows d'agents : codage, utilisation d'outils et tâches à long terme qui enchaînent des dizaines d'étapes sans perdre le fil. Ce positionnement fait qu'une fonctionnalité de l'API est plus importante que toute autre, l'appel de fonction, et c'est la seule fonctionnalité que les guides de la semaine de lancement n'ont pas abordée. Chaque tutoriel s'arrête jusqu'à présent aux complétions de chat.

Celui-ci va plus loin : définissez un schéma d'outil, effectuez votre premier appel d'outil avec le SDK Python openai standard, construisez la boucle complète de l'agent, puis testez l'ensemble dans Apidog avant le déploiement de votre agent. Si vous n'avez pas encore de clé API DeepSeek, configurez-en une avec notre guide sur comment utiliser l'API DeepSeek V4, puis revenez.

button

TL;DR

Pourquoi l'appel d'outils est le cas d'utilisation phare de V4 Pro

DeepSeek a conçu V4 Pro pour les agents, et la fiche technique ressemble à une liste de contrôle d'exécution d'agent :

Spécification DeepSeek V4 Pro
Architecture MoE Sparsifié : 1,6 T paramètres totaux, 49 B actifs par token
Fenêtre contextuelle 1 million de tokens
Sortie maximale 384 mille tokens
Prix d'entrée 0,435 $/M tokens (échec cache), 0,003625 $/M (succès cache)
Prix de sortie 0,87 $/M tokens
Appel de fonction Tableau `tools` compatible OpenAI et réponses `tool_calls`
Autres surfaces Format Anthropic Messages, API DeepSeek Responses

Chaque ligne correspond à un problème d'agent : la fenêtre de 1 million de tokens contient l'historique complet des résultats d'outils d'un agent long, le plafond de sortie de 384 000 laisse de la place pour de grandes charges utiles structurées, et la mise en cache de préfixes rend l'économie des boucles viable. Le modèle est listé sur OpenRouter sous le nom deepseek-v4-pro-0813 pour les comparaisons de fournisseurs.

Une mise en garde avant le code. Dans la discussion de lancement sur Hacker News, des développeurs ont signalé que la performance de l'appel d'outils est très sensible au harnais : le même modèle obtenait de meilleurs ou de moins bons résultats selon le framework, l'échafaudage des prompts et le style des schémas. Les benchmarks ne vous diront pas comment il gère vos schémas d'outils. Testez avec vos définitions réelles.

Comment fonctionne l'appel de fonction de DeepSeek

L'appel de fonction ne signifie pas que le modèle exécute quoi que ce soit. Il répond avec une requête structurée, "appelez get_order avec {"order_id": "ORD-10442"}", au lieu d'un texte. Votre code exécute la fonction, renvoie le résultat, et le modèle continue avec des données réelles. Le cycle :

  1. Vous envoyez des `messages` plus un tableau `tools` décrivant chaque fonction en JSON Schema.
  2. Le modèle décide qu'un outil est nécessaire et répond avec des `tool_calls` et `finish_reason: "tool_calls"`.
  3. Votre code analyse les arguments et exécute la fonction réelle.
  4. Vous ajoutez le résultat en tant que message `role: "tool"` lié à l'ID de l'appel.
  5. Le modèle demande soit un autre outil, soit produit sa réponse finale.

Si vous avez travaillé avec l'appel de fonction OpenAI, c'est le même format de communication ; la plupart des codes d'agents sont portables en changeant l'URL de base et le nom du modèle. La documentation officielle de DeepSeek couvre également un point de terminaison Messages compatible Anthropic et une API Responses, mais ce guide se limite à la surface compatible OpenAI.

Étape 1 : Configurer le client

Installez le SDK et configurez-le pour DeepSeek :

pip install openai
export DEEPSEEK_API_KEY="sk-..."
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["DEEPSEEK_API_KEY"],
    base_url="https://api.deepseek.com",
)

C'est toute la configuration. Chaque exemple utilise `model="deepseek-v4-pro"`, qui correspond à la version GA DeepSeek-V4-Pro-0813.

Étape 2 : Définir un schéma d'outil

Nous allons construire un agent de support pour une boutique en ligne. Son premier outil recherche les commandes. Une définition d'outil comporte trois parties : un nom, une description et un JSON Schema pour les paramètres.

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_order",
            "description": (
                "Recherche une commande client par son ID. Renvoie le statut de la commande, "
                "le transporteur, le numéro de suivi et la date de livraison estimée. Utilisez ceci "
                "chaque fois que l'utilisateur demande où se trouve une commande ou quel est son état."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "order_id": {
                        "type": "string",
                        "description": "L'ID de la commande, formaté comme 'ORD-10442'."
                    }
                },
                "required": ["order_id"],
            },
        },
    }
]

La description n'est pas une décoration : le modèle décide quand appeler un outil en la lisant. Les descriptions vagues sont la principale raison pour laquelle un modèle ignore un outil ou en choisit un mauvais.

La fonction locale que le schéma décrit, simulée pour un service de commande réel :

def get_order(order_id: str) -> dict:
    """Simulation de votre service de commande réel."""
    fake_db = {
        "ORD-10442": {
            "status": "shipped",
            "carrier": "DHL",
            "tracking_number": "4281337005",
            "estimated_delivery": "2026-08-15",
        },
        "ORD-10587": {
            "status": "processing",
            "estimated_ship_date": "2026-08-14",
        },
    }
    return fake_db.get(order_id, {"error": f"ID de commande inconnu : {order_id}"})

Étape 3 : Effectuer votre premier appel d'outil

Envoyez une question à laquelle le modèle ne peut pas répondre sans l'outil :

messages = [
    {"role": "system", "content": "Vous êtes un agent de support pour une boutique en ligne."},
    {"role": "user", "content": "Où est ma commande ORD-10442?"},
]

response = client.chat.completions.create(
    model="deepseek-v4-pro",
    messages=messages,
    tools=tools,
)

message = response.choices[0].message
print(message.tool_calls[0].function.name) # get_order
print(message.tool_calls[0].function.arguments) # {"order_id": "ORD-10442"}

Au lieu de répondre, le modèle vous demande d'exécuter `get_order`. La charge utile de la réponse brute ressemble à ceci :

{
  "id": "chatcmpl-8f3a1c",
  "object": "chat.completion",
  "model": "deepseek-v4-pro",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "",
        "tool_calls": [
          {
            "id": "call_0_f1c29a44",
            "type": "function",
            "function": {
              "name": "get_order",
              "arguments": "{\"order_id\": \"ORD-10442\"}"
            }
          }
        ]
      },
      "finish_reason": "tool_calls"
    }
  ],
  "usage": {
    "prompt_tokens": 312,
    "completion_tokens": 24,
    "total_tokens": 336,
    "prompt_cache_hit_tokens": 0,
    "prompt_cache_miss_tokens": 312
  }
}

Trois détails importants. `finish_reason` est `"tool_calls"`, ce qui indique à votre boucle que le modèle souhaite l'exécution. Chaque appel porte un `id` que vous devez renvoyer avec le résultat. Et `arguments` est une *chaîne* JSON que vous analysez vous-même, attendez-vous donc à ce qu'elle soit occasionnellement mal formée.

Étape 4 : Exécuter la fonction et renvoyer le résultat

Exécutez la fonction, puis ajoutez deux messages : le tour de l'assistant contenant les `tool_calls`, et un message `tool` portant votre résultat.

import json

tool_call = message.tool_calls[0]
args = json.loads(tool_call.function.arguments)
result = get_order(args)

messages.append(message) # le tour de l'assistant contenant les tool_calls
messages.append({
    "role": "tool",
    "tool_call_id": tool_call.id, # doit correspondre à l'id de la réponse
    "content": json.dumps(result),
})

final = client.chat.completions.create(
    model="deepseek-v4-pro",
    messages=messages,
    tools=tools,
)
print(final.choices[0].message.content)
# Votre commande ORD-10442 a été expédiée avec DHL et devrait arriver
# d'ici le 15 août 2026. Numéro de suivi : 4281337005.

Le lien `tool_call_id` est strict : chaque entrée `tool_calls` nécessite un message `tool` correspondant avant le prochain tour du modèle, sinon la requête échoue.

Étape 5 : La boucle complète de l'agent

Les agents réels enchaînent les appels : rechercher une commande, vérifier une politique de remboursement, rédiger un e-mail, chaque étape dépendant de la précédente. Le modèle : continuer à appeler le modèle et à exécuter ce qu'il demande jusqu'à ce qu'il renvoie une réponse normale.

TOOLS_BY_NAME = {"get_order": get_order}

def run_agent(client, messages, tools, max_rounds=10):
    """Exécute le modèle jusqu'à ce qu'il produise une réponse finale ou atteigne la limite."""
    for _ in range(max_rounds):
        response = client.chat.completions.create(
            model="deepseek-v4-pro",
            messages=messages,
            tools=tools,
        )
        message = response.choices[0].message
        messages.append(message)

        if not message.tool_calls: # pas de requêtes d'outils : nous avons terminé
            return message.content

        for tool_call in message.tool_calls:
            fn = TOOLS_BY_NAME.get(tool_call.function.name)
            try:
                if fn is None:
                    raise ValueError(f"Outil inconnu : {tool_call.function.name}")
                args = json.loads(tool_call.function.arguments)
                result = fn(args)
            except Exception as exc:
                result = {"error": str(exc)} # renvoyer les échecs au modèle
            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": json.dumps(result),
            })

    raise RuntimeError(f"L'agent n'a pas terminé dans les {max_rounds} tours")

Les frameworks et les SDK d'agents sont des élaborations de cette boucle. La limite `max_rounds` transforme un modèle bloqué à rappeler un outil défaillant en un échec propre au lieu d'une facture ouverte.

Appels d'outils parallèles

Demandez deux recherches, "comparez le statut de ORD-10442 et ORD-10587", et V4 Pro les regroupera souvent en un seul tour :

"tool_calls": [
  {
    "id": "call_0_a7d1",
    "type": "function",
    "function": { "name": "get_order", "arguments": "{\"order_id\": \"ORD-10442\"}" }
  },
  {
    "id": "call_1_b3e9",
    "type": "function",
    "function": { "name": "get_order", "arguments": "{\"order_id\": \"ORD-10587\"}" }
  }
]

La boucle `run_agent` gère déjà cela : la boucle interne `for` répond à chaque appel avec son propre `tool_call_id` (chaque appel nécessite un résultat correspondant avant le tour suivant), et vous êtes libre d'exécuter le lot de manière concurrente. C'est une philosophie différente de l'appel d'outil programmatique de GPT-5.6, où le modèle écrit le code d'orchestration dans un bac à sable ; DeepSeek maintient l'exécution, et la limite de confiance, dans votre environnement d'exécution.

Mode de réflexion et outils

V4 Pro est livré avec trois modes de réflexion, vous permettant d'augmenter l'effort de raisonnement pour les tours de planification difficiles et de le sauter pour les recherches de routine (voir la documentation officielle pour les noms de modes et les valeurs par défaut). Avec la réflexion activée, l'API renvoie la trace du modèle sous forme de `reasoning_content` en plus des appels d'outils :

response = client.chat.completions.create(
    model="deepseek-v4-pro",
    messages=messages,
    tools=tools,
    extra_body={"thinking": {"type": "enabled"}},
)

message = response.choices[0].message
print(message.reasoning_content) # la trace de planification
print(message.tool_calls) # les appels qu'il a choisis

La trace montre pourquoi le modèle a choisi un outil, ce qui est généralement le cas lorsqu'un mauvais schéma se révèle. Supprimez `reasoning_content` avant d'ajouter le tour de l'assistant à l'historique, et réservez la réflexion pour les tours à forte planification, la facturation du raisonnement est de 0,87 $/M en sortie.

Gestion des erreurs : quand le modèle se trompe dans un appel

Les appels d'outils mal formés sont rares, mais une boucle d'agent amplifie chaque mode de défaillance. Le modèle essentiel : ne jamais planter sur un mauvais appel, renvoyer le problème comme résultat de l'outil, et laisser le modèle réessayer. Cela couvre les arguments qui échouent `json.loads` ainsi que les valeurs qui enfreignent vos règles métier :

from jsonschema import ValidationError, validate

schema = tools[0]["function"]["parameters"]

try:
    args = json.loads(tool_call.function.arguments)
    validate(instance=args, schema=schema)
    result = get_order(**args)
except (json.JSONDecodeError, ValidationError) as exc:
    result = {
        "error": f"Arguments invalides : {exc}",
        "hint": "Appelez get_order à nouveau avec une chaîne order_id comme 'ORD-10442'.",
    }

Le champ `hint` est important : une correction d'une ligne produit généralement un nouvel essai corrigé au tour suivant. Traitez également les erreurs d'agent comme des événements de sécurité. Un modèle incité à appeler `delete_order` avec des arguments fournis par un attaquant n'est dangereux que dans la mesure de la clé qui le sous-tend, ce qui justifie les clés API à privilèges minimaux pour les agents IA. Limitez la portée des identifiants afin qu'un mauvais appel ne puisse pas devenir un incident.

Testez et déboguez les appels d'outils avec Apidog avant le déploiement

Chaque outil est un mince enveloppement autour d'une API, et le modèle est maintenant un consommateur de cette API. Si le point de terminaison de support est ambigu ou instable, le modèle hérite de tous ses défauts. C'est là que Apidog gagne sa place dans la boucle :

  1. Concevez d'abord l'API de support. Définissez `GET /orders/{order_id}` comme une spécification dans le concepteur visuel d'Apidog ; le JSON Schema de votre outil découle directement de la spécification, de sorte que les deux ne peuvent pas s'écarter silencieusement.
  2. Simulez-le avant l'existence du backend. La simulation intelligente d'Apidog fournit des réponses réalistes à partir du schéma, de sorte que la boucle de l'agent s'exécute contre `get_order` pendant que le service réel est encore en construction.
  3. Inspectez les charges utiles brutes. Envoyez le même corps `messages` + `tools` à `https://api.deepseek.com` depuis Apidog et lisez le JSON brut `tool_calls` directement, une propriété `properties` mal imbriquée ou des arguments doublement encodés apparaissent en une seule inspection.
  4. Transformez les conversations en scénarios de test. Affirmez sur `finish_reason` et les formes d'arguments, et exécutez la suite à chaque changement de schéma ; étant donné la sensibilité du harnais signalée sur Hacker News, une suite de régression sur vos schémas réels est le benchmark qui prédit la production. Voir le branchement d'un agent IA dans un harnais de test Apidog pour un modèle plus approfondi.

Téléchargez Apidog gratuitement pour suivre ; le serveur de simulation et les scénarios de test sont inclus dans le niveau gratuit.

Ce que coûtent les boucles d'agents (et pourquoi la mise en cache est décisive)

Les boucles d'agents relisent l'intégralité de la conversation à chaque tour : au dixième tour, votre prompt système, les schémas d'outils et neuf tours de résultats sont facturés pour la dixième fois. Le cache préfixe automatique de V4 Pro brise cette courbe, l'entrée de chaque tour étant celle du tour précédent plus un petit extra, de sorte que la quasi-totalité du préfixe est facturée à 0,003625 $/M au lieu de 0,435 $/M. Relire une conversation de 100 000 tokens coûte environ 0,0435 $ sans cache mais environ 0,0004 $ avec cache ; `prompt_cache_hit_tokens` dans le bloc d'utilisation indique votre taux de réussite réel.

Pour maintenir ce taux élevé, ne modifiez jamais les messages précédents et maintenez le tableau `tools` stable en termes d'octets d'un tour à l'autre. Notre introduction sur ce qu'est le cache de prompts couvre les mécanismes. Et si `deepseek-v4-flash` à 0,14 $/0,28 $ semble tentant : il est bien pour le routage d'outils en un seul coup, mais il régresse sur les boucles enchaînant plus de 10 appels, donc les réessais absorbent les économies, Pro est le choix par défaut plus sûr pour les agents.

FAQ

Les définitions d'outils coûtent-elles des tokens ?

Oui, le tableau `tools` est une entrée à chaque requête. Maintenez-le stable et il rejoindra le préfixe mis en cache après le premier tour, facturé au taux de succès du cache à partir de ce moment-là.

Puis-je combiner l'appel de fonction avec des sorties structurées ?

Oui. Un modèle courant : les outils récupèrent les données intermédiaires, un schéma de sortie structuré formate la réponse finale, de sorte que le code en aval ne parse jamais de texte libre.

En résumé

L'appel de fonction sur DeepSeek V4 Pro est délibérément simple à implémenter : des schémas compatibles OpenAI, un tableau `tool_calls`, un message `tool` avec un ID. La boucle de l'Étape 5 est toute l'architecture, et la tarification basée sur le cache la rend moins chère que la plupart des équipes ne s'y attendent. Ce que les benchmarks ne peuvent pas vous dire, c'est comment le modèle se comporte avec vos schémas. Concevez délibérément les API de support, simulez-les tôt, et maintenez une suite de régression des scénarios d'appel d'outils dans Apidog afin que les modifications de schéma ne puissent pas casser silencieusement votre agent.

button

Pratiquez le Design-first d'API dans Apidog

Découvrez une manière plus simple de créer et utiliser des API