Retour au blog

Premiers pasGuide

Première requête vers CheapTokens en Python avec requests, sans SDK

Un script Python de 20 lignes avec seulement requests : un chat completion, un timeout, la gestion des erreurs HTTP, et l'affichage de la réponse, de finish_reason et de l'usage.

Par CheapTokens TeamPublié le 4 min de lecture

Script Python appelant l'endpoint chat completions de CheapTokens avec requests
Sur cette page
  1. Le script complet
  2. Ce que fait chaque ligne
  3. Lire la réponse
  4. Quand ça ne marche pas
  5. Combien coûte un appel
  6. Et ensuite

Vous n'avez pas besoin du paquet openai pour dialoguer avec une API compatible OpenAI. Un seul appel requests.post, une clé Bearer et un corps JSON suffisent, et vous voyez exactement ce qui passe sur le réseau. Ce guide construit ce script pour CheapTokens (https://api.cheaptokens.dev/v1/chat/completions) et se termine par l'affichage de la réponse, de finish_reason et de l'usage des tokens.

C'est un bon choix si vous êtes sur une machine verrouillée où seul requests est installé, si une petite tâche cron ne doit pas embarquer un SDK, ou si vous voulez simplement comprendre ce que le SDK fait pour vous. Le guide de la première requête couvre le SDK, curl et Node ; ici, c'est la version Python pur.

Le script complet#

Placez d'abord votre clé dans une variable d'environnement (voir comment stocker une clé API en sécurité), puis enregistrez ceci sous ask.py :

python
import os
import requests

url = "https://api.cheaptokens.dev/v1/chat/completions"
headers = {"Authorization": f"Bearer {os.environ['CHEAPTOKENS_API_KEY']}"}
payload = {
    "model": "deepseek-ai/DeepSeek-V4-Flash-0731",
    "messages": [
        {"role": "user", "content": "Explain what a token is in two sentences."}
    ],
    "max_tokens": 200,
}

try:
    r = requests.post(url, headers=headers, json=payload, timeout=30)
    r.raise_for_status()
except requests.exceptions.Timeout:
    raise SystemExit("No reply within 30 seconds - try again or raise the timeout")
except requests.exceptions.HTTPError as e:
    raise SystemExit(f"HTTP {e.response.status_code}: {e.response.text}")

data = r.json()
choice = data["choices"][0]
print(choice["message"]["content"])
print("finish_reason:", choice["finish_reason"])
print("usage:", data["usage"])

Lancez python ask.py. L'identifiant du modèle est l'identifiant complet de la passerelle, deepseek-ai/DeepSeek-V4-Flash-0731 ; si vous ne savez pas quoi mettre, listez les modèles avec GET /v1/models. Pour essayer un autre modèle, remplacez par zai-org/GLM-5.3-Flash et ne changez rien d'autre : un seul solde couvre tous les modèles.

Le parcours d'une requête : clé, POST, raise_for_status, choices, usage
Une requête de votre script à la réponse affichée

Ce que fait chaque ligne#

Voici les cinq idées sur lesquelles repose le script. Le Quickstart requests (docs vivantes, vérifiées le 2 novembre 2026) en explique la plupart, et la référence Chat Completions d'OpenAI définit les champs de la réponse.

Cartes mémo

Cinq choses dans le script

C'est la troisième puce que les gens oublient. Un script qui se bloque indéfiniment dans une tâche cron est bien pire qu'un script qui échoue bruyamment au bout de 30 secondes.

Lire la réponse#

Une réponse réussie est du JSON. Les parties qui vous intéressent, selon la référence Chat Completions :

  • choices[0].message.content est le texte. Il peut valoir null, donc n'appelez pas de méthodes de chaîne dessus à l'aveugle.
  • choices[0].finish_reason indique pourquoi le modèle s'est arrêté : stop (il a terminé), length (la limite max_tokens l'a coupé), tool_calls, content_filter.
  • usage.prompt_tokens, usage.completion_tokens et usage.total_tokens sont ce qui vous est facturé : entrée, sortie et leur somme.

La réponse a cette forme (les nombres sont des exemples) :

json
{
  "choices": [
    {
      "message": {"role": "assistant", "content": "A token is a small piece of text..."},
      "finish_reason": "stop"
    }
  ],
  "usage": {"prompt_tokens": 18, "completion_tokens": 52, "total_tokens": 70}
}
Essayez vous-mêmeEssayez : mettez max_tokens à 5 et relancez le script. Que dit finish_reason ?Afficher la réponse

Il dit length : le modèle a été arrêté par votre limite max_tokens, donc la réponse s'arrête en milieu de phrase. Augmentez la limite et vous obtenez de nouveau stop. Toute l'histoire est dans Réponse IA coupée ? Corriger finish_reason "length".

Quand ça ne marche pas#

Le script transforme la plupart des échecs en une ligne de sortie. Voici ce que chacun signifie généralement :

Associer les paires

Associez chaque message à sa cause habituelle

  • HTTP 401La clé est absente, mal saisie ou n'est pas celle que vous vouliez envoyer
  • HTTP 404Le chemin de l'URL ou l'identifiant du modèle est faux
  • requests.exceptions.TimeoutAucun octet reçu dans le délai imparti
  • KeyError: 'CHEAPTOKENS_API_KEY'La variable d'environnement n'est pas définie dans ce terminal

Pour les corps d'erreur réels et une vérification pas à pas de la clé, de l'URL de base et de l'identifiant du modèle, consultez Erreur API 401 ou 404 : mauvaise clé, URL de base ou identifiant de modèle. Deux pièges plus discrets : si vous voyez KeyError: 'choices', vous avez analysé un corps d'erreur comme un succès, ce qui signifie que raise_for_status() a été ignoré. Et si votre machine a un fichier ~/.netrc, requests peut utiliser ses identifiants au lieu de l'en-tête Authorization que vous avez défini.

Combien coûte un appel#

Avec les nombres d'exemple de la réponse ci-dessus (environ 18 tokens en entrée, 52 en sortie), un appel à DeepSeek-V4-Flash coûte $0.0000055. C'est un montant imperceptible, alors changez d'échelle. Disons que votre script résume 1 000 tickets de support par jour, environ 800 tokens en entrée et 300 en sortie chacun :

Modèle Par requête 1 000 requêtes OpenRouter, 1 000 requêtes
GLM-5.3-Flash $0.000028 $0.028 $0.0517
DeepSeek-V4-Flash $0.000042 $0.042 $0.098
MiniMax-M2.7 $0.000085 $0.085 $1.02

800 tokens d'entrée et 300 tokens de sortie par requête. Les prix par million de tokens sont actuels et évoluent avec nos tarifs ; la colonne OpenRouter indique des prix de référence pour la même charge de travail.

Les prix sont fixes par modèle, sans heures de pointe, donc le même script coûte la même chose à 3 h du matin et à midi. Les prix actuels par modèle sont sur la page de tarifs, et la doc liste les endpoints.

Et ensuite#

Une fois que ça marche, les étapes suivantes habituelles sont une boucle sur de nombreuses entrées, une nouvelle tentative sur 429 (voir 429 Too Many Requests : réessais avec backoff), ou le même appel en streaming. Si vous préférez ne pas gérer HTTP vous-même, la voie du SDK n'est qu'à un changement de base_url.