Votre équipe support reçoit chaque jour les mêmes questions : « comment réinitialiser mon mot de passe VPN ? », « le serveur d’impression ne répond plus », « où trouver la procédure d’onboarding ? ». Répondre à la main coûte du temps. Dans ce guide, vous allez brancher un assistant capable de répondre à ces questions en langage naturel, en appelant l’API de DeepSeek depuis Python. À la fin, vous aurez une fonction demander_support() qui prend une question et renvoie une réponse claire, avec un coût mesuré à la fraction de centime près.
🎯 Ce que vous allez apprendre
- Obtenir une clé API DeepSeek et la stocker sans la coder en dur dans vos fichiers.
- Émettre un premier appel de complétion de chat et lire la réponse en Python.
- Afficher la réponse au fil de l’eau (streaming) pour une expérience fluide.
- Conduire une conversation à plusieurs tours en gardant le contexte.
- Mesurer et réduire le coût grâce au cache de contexte intégré.
- Rendre l’appel robuste : délais d’attente, erreurs réseau, nouvelles tentatives.
🛠️ Ce que vous allez construire
Un petit module Python assistant_support.py qui expose une fonction demander_support(question). Cette fonction envoie la question à DeepSeek avec une consigne système qui cadre le rôle (« tu es l’assistant interne du service informatique »), récupère la réponse, et journalise le nombre de jetons consommés. C’est la première brique d’un véritable assistant interne, que les guides suivants enrichiront avec le raisonnement structuré et le déploiement local.
Prérequis
- Python 3.9 ou plus récent installé (
python --versionpour vérifier). - Un compte sur la plateforme DeepSeek avec un solde de crédit (l’API est payante à l’usage, mais les tarifs sont parmi les plus bas du marché — on y revient).
- Connaître les bases de Python : fonctions, dictionnaires, gestion d’exceptions. Test express : si vous savez écrire une fonction qui lit une variable d’environnement, vous êtes prêt.
- ⏱️ Temps estimé : environ 35 minutes.
Étape 1 — Obtenir une clé API et installer le SDK
L’API de DeepSeek est compatible avec le format d’OpenAI. Concrètement, cela signifie que vous n’avez pas besoin d’un client maison : la bibliothèque officielle openai fonctionne telle quelle, il suffit de la faire pointer vers les serveurs de DeepSeek. C’est un choix de conception délibéré qui vous laisse réutiliser tout l’écosystème existant.
Commencez par créer une clé depuis votre espace sur platform.deepseek.com (section API Keys), puis créditez un petit montant sur votre solde. Installez ensuite le SDK dans un environnement virtuel pour ne pas polluer votre système :
python -m venv .venv
source .venv/bin/activate # sous Windows : .venv\Scripts\activate
pip install openai
La commande crée un environnement isolé, l’active, puis installe la bibliothèque. Si pip install se termine par une ligne du type Successfully installed openai-..., l’installation a réussi. Ne saisissez jamais votre clé directement dans le code : on va la lire depuis une variable d’environnement, ce qui évite de la pousser par accident sur un dépôt Git.
export DEEPSEEK_API_KEY="votre_cle_ici" # à mettre dans ~/.bashrc ou ~/.zshrc
Sous Windows PowerShell, l’équivalent est $env:DEEPSEEK_API_KEY="votre_cle_ici". Pour un projet sérieux, préférez un fichier .env chargé par python-dotenv et ajouté à votre .gitignore.
Étape 2 — Le premier appel de complétion
Le cœur de l’API est l’endpoint chat completions : vous envoyez une liste de messages, le modèle renvoie un message d’assistant. Voici le squelette minimal. Notez le paramètre base_url qui redirige le client OpenAI vers DeepSeek — c’est la seule différence avec un appel OpenAI classique.
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["DEEPSEEK_API_KEY"],
base_url="https://api.deepseek.com",
)
reponse = client.chat.completions.create(
model="deepseek-v4-flash",
messages=[
{"role": "system", "content": "Tu es l'assistant interne du service informatique. Reponds de facon concise et actionnable."},
{"role": "user", "content": "Comment reinitialiser mon mot de passe VPN ?"},
],
stream=False,
)
print(reponse.choices[0].message.content)
Le modèle deepseek-v4-flash est la variante rapide et économique de DeepSeek-V4 : c’est le bon choix par défaut pour un assistant de support, où la vitesse de réponse compte plus que le raisonnement profond. Pour les tâches exigeant une réflexion poussée, il existe deepseek-v4-pro, plus capable mais plus cher. À noter : sur les modèles V4, un mode de raisonnement est actif par défaut ; pour un assistant de support où la rapidité prime, on le désactive explicitement avec extra_body, comme dans la fonction de production de l’étape 7. En exécutant ce script, vous devez voir s’afficher une procédure de réinitialisation rédigée par le modèle. Si vous obtenez une erreur d’authentification, c’est que la variable d’environnement n’est pas lue : vérifiez qu’elle est bien exportée dans le terminal courant.
✅ Point d’étape — À ce stade, un appel direct fonctionne et renvoie du texte. Pour vérifier : la sortie console contient une réponse cohérente, et votre solde sur la plateforme a baissé de quelques fractions de centime. Si rien ne s’affiche, ajoutez
print(reponse)pour inspecter l’objet complet.
Étape 3 — Afficher la réponse en streaming
Attendre que toute la réponse soit générée avant de l’afficher donne une impression de lenteur, surtout pour les réponses longues. Le streaming renvoie la réponse jeton par jeton, comme une frappe en direct. On l’active avec stream=True et on itère sur les fragments reçus.
flux = client.chat.completions.create(
model="deepseek-v4-flash",
messages=[
{"role": "system", "content": "Tu es l'assistant interne du service informatique."},
{"role": "user", "content": "Le serveur d'impression ne repond plus, que verifier ?"},
],
stream=True,
)
for fragment in flux:
delta = fragment.choices[0].delta.content
if delta:
print(delta, end="", flush=True)
print()
Chaque fragment contient un petit morceau de texte dans delta.content. On le teste avant de l’afficher car le tout premier et le tout dernier fragment peuvent être vides (ils portent des métadonnées, pas du texte). Le flush=True force l’affichage immédiat sans attendre un saut de ligne. Résultat : le texte apparaît progressivement, ce qui change radicalement la perception de réactivité côté utilisateur.
Étape 4 — Tenir une conversation à plusieurs tours
L’API est sans état : le modèle ne se souvient de rien entre deux appels. Pour qu’un agent suive une conversation, c’est à vous de renvoyer l’historique complet à chaque tour. Le principe : on accumule les messages dans une liste, et on y ajoute la réponse de l’assistant avant de poser la question suivante.
historique = [
{"role": "system", "content": "Tu es l'assistant interne du service informatique."},
]
def tour(question):
historique.append({"role": "user", "content": question})
r = client.chat.completions.create(
model="deepseek-v4-flash",
messages=historique,
stream=False,
)
reponse = r.choices[0].message.content
historique.append({"role": "assistant", "content": reponse})
return reponse
print(tour("Mon VPN se deconnecte toutes les 5 minutes."))
print(tour("Et si je suis sur une connexion mobile ?"))
Au deuxième tour, le modèle comprend que « et si je suis sur une connexion mobile » se rapporte au problème de VPN, parce que l’historique le lui rappelle. Attention : plus l’historique grossit, plus chaque appel coûte cher en jetons d’entrée. Pour une conversation longue, pensez à tronquer les anciens messages ou à résumer périodiquement le contexte.
Étape 5 — Comprendre le coût et le cache de contexte
Chaque réponse de l’API contient un objet usage qui détaille les jetons consommés. C’est l’outil indispensable pour piloter votre budget. DeepSeek facture séparément les jetons d’entrée et de sortie, et applique un tarif fortement réduit aux jetons d’entrée déjà vus récemment — c’est le cache de contexte, activé automatiquement.
r = client.chat.completions.create(
model="deepseek-v4-flash",
messages=historique,
)
u = r.usage
print("entree:", u.prompt_tokens, "| sortie:", u.completion_tokens)
Au moment d’écrire ces lignes, deepseek-v4-flash facture l’entrée à 0,14 $ par million de jetons en cas d’absence de cache, et seulement 0,0028 $ par million quand le cache est touché (un cinquantième du prix), tandis que la sortie est à 0,28 $ par million. À ces niveaux, des milliers de questions de support tiennent dans quelques dizaines de centimes. Le cache se déclenche tout seul lorsque le début de vos messages (typiquement la consigne système, longue et stable) se répète d’un appel à l’autre : raison de plus pour garder une consigne système constante.
✅ Point d’étape — Vous savez maintenant lire la consommation réelle de chaque requête. Lancez deux appels identiques d’affilée : au second,
prompt_tokensdevrait être en grande partie facturé au tarif cache, preuve que le mécanisme fonctionne.
Étape 6 — Rendre l’appel robuste
En production, le réseau coupe, l’API peut renvoyer une erreur temporaire, ou imposer une limite de débit. Un assistant qui plante au premier hoquet est inutilisable. On encapsule donc l’appel dans une logique de nouvelles tentatives avec un délai croissant, et on fixe un délai d’attente maximal.
import time
from openai import APIError, RateLimitError, APITimeoutError
def appel_robuste(messages, tentatives=3):
for i in range(tentatives):
try:
return client.chat.completions.create(
model="deepseek-v4-flash",
messages=messages,
timeout=30,
extra_body={"thinking": {"type": "disabled"}},
)
except (RateLimitError, APITimeoutError, APIError) as e:
attente = 2 ** i
print("erreur:", type(e).__name__, "- nouvelle tentative dans", attente, "s")
time.sleep(attente)
raise RuntimeError("echec apres plusieurs tentatives")
La boucle réessaie jusqu’à trois fois en doublant l’attente à chaque échec (1 s, 2 s, 4 s) : c’est le backoff exponentiel, la stratégie standard pour ne pas marteler un service déjà sous tension. On capture spécifiquement les erreurs de débit et de délai, qui sont récupérables, tout en laissant remonter les erreurs définitives comme une clé invalide.
Étape 7 — Assembler l’assistant et vérifier de bout en bout
On rassemble tout dans une fonction réutilisable. Elle isole la consigne système, journalise le coût, et s’appuie sur l’appel robuste de l’étape précédente.
CONSIGNE = ("Tu es l'assistant interne du service informatique. "
"Reponds en francais, de facon concise et actionnable. "
"Si tu n'es pas sur, dis-le et propose a qui s'adresser.")
def demander_support(question):
messages = [
{"role": "system", "content": CONSIGNE},
{"role": "user", "content": question},
]
r = appel_robuste(messages)
print("[cout] entree", r.usage.prompt_tokens, "sortie", r.usage.completion_tokens)
return r.choices[0].message.content
if __name__ == "__main__":
print(demander_support("Comment demander un acces au dossier partage comptabilite ?"))
En lançant python assistant_support.py, vous devez obtenir une réponse structurée suivie d’une ligne de coût. C’est votre première brique fonctionnelle : une fonction unique, testée, mesurée et résistante aux pannes passagères, prête à être branchée derrière une interface web ou un bot interne.
🐞 Pièges fréquents
| Symptôme / erreur | Cause probable | Correctif |
|---|---|---|
AuthenticationError / 401 |
Clé absente ou mal lue dans l’environnement | Vérifier echo $DEEPSEEK_API_KEY dans le terminal qui lance le script |
| Réponse vide ou tronquée | Limite de jetons de sortie atteinte | Augmenter max_tokens ou raccourcir la question |
402 / solde insuffisant |
Crédit épuisé sur la plateforme | Recréditer le solde ; l’API ne fonctionne pas à découvert |
| Coût qui explose | Historique de conversation jamais tronqué | Limiter le nombre de tours conservés ou résumer le contexte |
| Le cache ne se déclenche jamais | Consigne système qui varie à chaque appel | Garder un préfixe système strictement identique |
Travailler avec un budget serré et une connexion instable
Trois réflexes maximisent la valeur de chaque appel. D’abord, plafonnez max_tokens sur la sortie : c’est elle qui coûte le plus cher, et une réponse de support n’a pas besoin d’être un roman. Ensuite, exploitez le cache en figeant la consigne système, ce qui fait fondre le coût d’entrée des requêtes répétitives. Enfin, sur une liaison capricieuse, le streaming combiné au délai d’attente de 30 secondes évite de rester bloqué : si la connexion tombe en cours de route, la logique de nouvelles tentatives reprend la main. Pour développer hors ligne ou tester sans consommer de crédit, le déploiement local d’un modèle DeepSeek est une option que nous couvrons dans un autre guide de la série.
✅ Récapitulatif
Vous êtes parti d’un compte vide et vous repartez avec une fonction demander_support() opérationnelle. En chemin, vous avez vu que l’API de DeepSeek se pilote avec le SDK d’OpenAI moyennant un simple base_url, comment streamer une réponse, comment maintenir une conversation à plusieurs tours, comment lire et réduire le coût via le cache de contexte, et comment encaisser les erreurs réseau sans planter. C’est exactement le socle sur lequel reposent les agents plus avancés.
🧾 Aide-mémoire
| Élément | Rôle |
|---|---|
base_url="https://api.deepseek.com" |
Rediriger le client OpenAI vers DeepSeek |
deepseek-v4-flash |
Modèle rapide et économique (choix par défaut) |
deepseek-v4-pro |
Modèle plus capable pour les tâches difficiles |
stream=True |
Réponse jeton par jeton |
reponse.usage |
Jetons d’entrée et de sortie consommés |
timeout=30 |
Délai d’attente maximal par appel |
💪 À vous de jouer
Ajoutez à demander_support() un paramètre urgent=False qui, lorsqu’il vaut True, bascule sur deepseek-v4-pro et ajoute à la consigne système l’instruction de proposer une solution de contournement immédiate. Mesurez la différence de coût entre les deux modèles sur la même question.
Voir une solution
def demander_support(question, urgent=False):
modele = "deepseek-v4-pro" if urgent else "deepseek-v4-flash"
consigne = CONSIGNE + (" Propose d'abord un contournement immediat." if urgent else "")
messages = [
{"role": "system", "content": consigne},
{"role": "user", "content": question},
]
r = client.chat.completions.create(
model=modele,
messages=messages,
extra_body={"thinking": {"type": "disabled"}},
)
return r.choices[0].message.content
Ici on appelle directement create() pour rester concis ; en production, on ferait passer ce choix de modèle par appel_robuste. Vous constaterez que pro coûte sensiblement plus en sortie, à réserver aux cas qui le méritent.
Dans la même série
- Déployer DeepSeek-R1 en local avec Ollama — faire tourner un modèle sur votre machine, sans clé ni crédit.
- Exploiter le raisonnement de DeepSeek et produire du JSON fiable — passer du texte libre à des données structurées.
Pour approfondir
- 🔝 Revenir au guide principal : DeepSeek : modèles, API et déploiement local
- Documentation officielle de l’API : api-docs.deepseek.com
FAQ
Faut-il payer pour utiliser l’API DeepSeek ?
Oui, l’API est facturée à l’usage et nécessite un solde de crédit préalable. Les tarifs comptent parmi les plus bas du marché, de l’ordre de quelques dizaines de centimes pour des milliers de requêtes courtes.
Puis-je réutiliser du code écrit pour OpenAI ?
Dans la grande majorité des cas, oui : il suffit de changer base_url et le nom du modèle. Les structures de requête et de réponse suivent le même format.
Quelle différence entre flash et pro ?deepseek-v4-flash privilégie la vitesse et le coût, deepseek-v4-pro la capacité de raisonnement. Pour du support de premier niveau, flash suffit largement.
Comment éviter de divulguer ma clé API ?
Ne la codez jamais en dur. Lisez-la depuis une variable d’environnement ou un fichier .env exclu du dépôt Git via .gitignore.