Tutoriel
Construire un proxy OpenAI API en Python : d'abord écrire le vôtre à la main, puis le faire dialoguer avec tous les modèles
Un proxy FastAPI fonctionnel, avec authentification, limitation de débit et streaming ; et comment l'API compatible OpenAI de HiAPI permet au même proxy de servir simultanément DeepSeek, Claude, GPT et d'autres modèles.
TL;DR
- Un proxy OpenAI API est un petit serveur situé entre votre application et l'API du modèle. Il conserve la vraie clé et ajoute les capacités que l'API elle-même n'offre pas : clés par client, limitation de débit, journalisation et rotation des clés. Voici une version FastAPI fonctionnelle d'environ 50 lignes.
- L'API texte de HiAPI est compatible OpenAI :
POST /v1/chat/completionsetPOST /v1/responsesse trouvent surhttps://api.hiapi.ai/v1. En pointant le SDK officielopenaiou votre proxy vers cette base URL, vous pouvez appeler avec une seule clé les modèles texte DeepSeek, Claude, GPT, Kimi, GLM et Grok. - Les images et les vidéos, c'est différent : elles prennent de quelques secondes à plusieurs minutes, et s'exécutent donc sur l'endpoint asynchrone
POST /v1/tasksde HiAPI. Ne mettez pas ce type de requêtes dans un proxy synchrone.
Étape 1 : un proxy de relais minimal
Le proxy valide la clé interne envoyée par le client, la remplace par la vraie clé amont, puis renvoie la réponse en streaming.
pip install fastapi uvicorn httpx
# proxy.py
import os
import httpx
from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import StreamingResponse
from starlette.background import BackgroundTask
UPSTREAM = os.environ.get("UPSTREAM_BASE", "https://api.openai.com/v1")
UPSTREAM_KEY = os.environ["UPSTREAM_KEY"]
INTERNAL_KEYS = set(os.environ["INTERNAL_KEYS"].split(",")) # comma-separated
app = FastAPI()
client = httpx.AsyncClient(timeout=120.0)
def auth(request: Request) -> str:
header = request.headers.get("authorization", "")
key = header.removeprefix("Bearer ").strip()
if key not in INTERNAL_KEYS:
raise HTTPException(401, "invalid internal key")
return key
@app.post("/v1/{path:path}")
async def forward(path: str, request: Request):
tenant = auth(request)
body = await request.body()
upstream_req = client.build_request(
"POST", f"{UPSTREAM}/{path}", content=body,
headers={"Authorization": f"Bearer {UPSTREAM_KEY}",
"Content-Type": request.headers.get("content-type", "application/json")},
)
upstream = await client.send(upstream_req, stream=True)
# Stream back so long answers and SSE don't time out; close the upstream stream when done
return StreamingResponse(upstream.aiter_raw(), status_code=upstream.status_code,
media_type=upstream.headers.get("content-type"),
background=BackgroundTask(upstream.aclose))
Lancez-le :
UPSTREAM_KEY=your-upstream-key INTERNAL_KEYS=tenant-a,tenant-b \
uvicorn proxy:app --host 0.0.0.0 --port 8000
Le client utilise le SDK OpenAI comme d'habitude, en définissant l'adresse du proxy comme base URL :
from openai import OpenAI
client = OpenAI(api_key="tenant-a", base_url="http://localhost:8000/v1")
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "Hello"}],
)
print(resp.choices[0].message.content)
Les conversations, le streaming et les embeddings passent tous par le même gestionnaire, car le proxy n'analyse jamais l'intérieur du corps de la requête.
Étape 2 : ajouter les capacités que l'API amont n'offre pas
Limitation de débit par locataire. Sans elle, un seul client très actif peut épuiser tout votre quota.
import time
from collections import defaultdict
_window: dict[str, list[float]] = defaultdict(list)
LIMIT = 60 # requests per 60 s
def check_rate_limit(tenant: str):
now = time.time()
_window[tenant] = [t for t in _window[tenant] if now - t < 60]
if len(_window[tenant]) >= LIMIT:
raise HTTPException(429, "rate limit exceeded")
_window[tenant].append(now)
Appelez cette fonction immédiatement après auth(). Si vous avez plusieurs processus serveur, déplacez le compteur dans Redis (INCR plus EXPIRE).
Journalisation. Enregistrez le locataire, le chemin, le code de statut, la latence et le nombre de tokens. Ne journalisez jamais l'en-tête Authorization.
Rotation des clés. Chargez UPSTREAM_KEY depuis un service de gestion de secrets et rafraîchissez-la périodiquement. Quand la clé amont change en coulisses, les clients continuent d'utiliser leurs propres clés de locataire.
Règles de coût. Analysez le corps de la requête et refusez celles qui dépassent la politique, par exemple un modèle coûteux sur un forfait gratuit, ou un max_tokens supérieur à votre plafond.
Étape 3 : placer plusieurs fournisseurs de modèles derrière le même proxy
Un proxy relié à un seul fournisseur est simple. Ajouter Anthropic, DeepSeek ou Moonshot implique des en-têtes d'authentification, des structures de requête et des formats d'erreur différents ; le proxy minimal devient alors une couche de traduction.
L'API texte de HiAPI adopte la structure de requête d'OpenAI pour tous ses modèles texte, donc le proxy ci-dessus fonctionne sans modification. Définissez deux variables d'environnement :
UPSTREAM_BASE=https://api.hiapi.ai/v1 UPSTREAM_KEY=your-hiapi-key INTERNAL_KEYS=tenant-a,tenant-b \
uvicorn proxy:app --host 0.0.0.0 --port 8000
Ou bien sautez le proxy et utilisez directement le SDK :
import os
from openai import OpenAI
client = OpenAI(api_key=os.environ["HIAPI_KEY"], base_url="https://api.hiapi.ai/v1")
resp = client.chat.completions.create(
model="deepseek-v4-flash",
messages=[{"role": "user", "content": "Explain sparse attention in two sentences."}],
max_tokens=400,
)
print(resp.choices[0].message.content)
Nous avons exécuté ce code avec le package Python officiel openai (3.35.1), une fois en appel classique et une fois avec stream=True ; les deux appels se sont terminés sans erreur et le SDK a bien analysé les réponses. Un piège lors de ce test : avec max_tokens=20, la réponse était vide, car deepseek-v4-flash a consacré la totalité des 20 tokens au raisonnement (usage.completion_tokens_details.reasoning_tokens valait 22). Laissez plusieurs centaines de tokens de marge aux modèles de raisonnement.
Quelques modèles texte sur HiAPI :
| ID du modèle | Route | Entrée / sortie, en USD par million de tokens |
|---|---|---|
deepseek-v4-flash |
Chat Completions | $0.14 / $0.28 |
deepseek-v4.1-flash |
Chat Completions et Responses | $0.44 / $1.32 |
gpt-5.6-luna |
Responses uniquement | $0.05 / $0.30 |
grok-4.6 |
Chat Completions | $0.84 / $2.52 |
deepseek-v4-pro |
Chat Completions et Responses | $1.50 / $4.50 |
claude-opus-5-5 |
Chat Completions | $2.02 / $10.08 |
kimi-k3 |
Chat Completions | $2.32 / $11.60 |
claude-sonnet-4-6 |
Chat Completions | $3.00 / $15.00 |
Tarifs HiAPI en temps réel, relevés le 20 octobre 2026. GET https://api.hiapi.ai/v1/models liste tous les modèles disponibles pour votre clé.
Les modèles GPT comme gpt-5.6-luna ne sont proposés que sur l'API Responses (client.responses.create), donc un proxy qui relaie /v1/{path} couvre les deux à la fois.
Un ID de modèle inconnu renvoie un HTTP 400 dans le style d'erreur d'OpenAI, accompagné d'un request_id pour contacter le support :
{"error": {"code": "model_not_found", "type": "hiapi_error",
"message": "The requested model does not exist or is not available. Check the exact model ID with GET /v1/models and try again. ...",
"request_id": "..."}}
Étape 4 : les images et les vidéos n'ont pas leur place dans un proxy synchrone
Un proxy synchrone maintient la connexion ouverte jusqu'au retour de la réponse. Pour du texte, c'est parfait. Les images prennent des dizaines de secondes et les vidéos plusieurs minutes, ce qui dépasse le délai d'attente que la plupart des répartiteurs de charge et des navigateurs acceptent.
HiAPI exécute les modèles d'image et de vidéo sur un endpoint asynchrone : soumettez une tâche, récupérez un task id, puis interrogez par polling ou recevez un callback.
curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer $HIAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "z-image",
"input": {"prompt": "a glass data center at golden hour, isometric", "aspect_ratio": "16:9"},
"callback": {"url": "https://your-app.example.com/hiapi/callback", "when": "final"}
}'
# => {"code":200,"message":"success","data":{"taskId":"tk-hiapi-..."}}
Votre proxy peut toujours relayer l'appel de soumission, qui renvoie immédiatement. Le résultat arrive ensuite via votre URL de callback ou GET /v1/tasks/{taskId}. Les liens de sortie expirent au bout d'environ 7 jours, pensez donc à sauvegarder les fichiers.
Liste de vérification pour la production
- Retirez les clés des journaux. Qu'elles soient entrantes ou sortantes, ne journalisez jamais
Authorization. - Utilisez des callbacks pour les tâches média. Interroger des milliers de tâches par polling gaspille des requêtes. Rendez le traitement des callbacks idempotent et indexé par
taskId, car la livraison peut être retentée. - Stockez le task id avant d'interroger. Si le processus plante, reprenez le polling plutôt que de resoumettre et payer deux fois.
- Prévoyez de la place pour les tokens de raisonnement. Réglez
max_tokensbien au-dessus de la longueur de réponse attendue. - Vérifiez ce que votre clé peut utiliser.
GET /v1/modelsrenvoie la liste associée à cette clé.
Questions fréquentes
Puis-je utiliser le SDK Python OpenAI sur HiAPI ?
Oui, pour les modèles texte. Définissez base_url="https://api.hiapi.ai/v1" et utilisez votre clé HiAPI. Les images et les vidéos passent par /v1/tasks, un endpoint que le SDK OpenAI ne couvre pas ; appelez-le avec requests ou httpx.
Ai-je encore besoin de mon propre proxy ?
Uniquement pour les mêmes raisons qu'avec n'importe quel fournisseur : clés par locataire, limitation de débit et journaux d'audit. À l'intérieur du proxy, la conversion par fournisseur n'est plus nécessaire.
Le streaming fonctionne-t-il ?
Oui. stream=True renvoie des événements envoyés par le serveur se terminant par data: [DONE], et le proxy ci-dessus les relaie en streaming sans mise en tampon.
Comment faire tourner une clé HiAPI sans interrompre le service ?
Créez une nouvelle clé dans la console, déployez-la dans votre proxy ou votre coffre de secrets, puis révoquez l'ancienne. Pendant la bascule, les deux clés fonctionnent.
Pour plus de détails : documentation Chat Completions, documentation Responses et HiAPI comme alternative de proxy OpenAI API.
Articles similaires
Voir tous les articles →-
Tutoriel
Comment appeler hailuo-2.3-fast/image-to-video via l'API HiAPI : curl et Python en pratique
La première requête exploitable du palier image-vers-vidéo rapide et économique — de l'ID du modèle au téléchargement du MP4
-
Tutoriel
Comment appeler hailuo-2.3/text-to-video via l'API HiAPI : curl, Python et exemples de requêtes exécutables
-
Tutoriel
Utiliser Kandinsky 6.0 Pro texte-vers-vidéo sur HiAPI : tutoriel curl et Python
Démonstration pratique axée sur la requête : construire l'appel du prompt au clip vidéo, soumettre la requête, interroger l'état d'achèvement et télécharger le résultat