Unité 4.4 : Intégration d'AI Model Hub
Introduction
Vous ajoutez une fonctionnalité d'IA à TaskBoard : lorsqu'un utilisateur soumet une longue description de tâche, l'API appelle un grand modèle de langage pour générer un résumé en une ligne, puis stocke ce résumé dans PostgreSQL. AI Model Hub met à disposition des modèles hébergés derrière une API REST compatible OpenAI, de sorte que vous n'avez pas à exécuter de GPU et n'avez pas à gérer les poids des modèles. Vous envoyez un prompt à un point de terminaison d'inférence, vous recevez des jetons en retour, et vous payez au prorata des jetons.
Cette unité commence par l'appel HTTP. Vous verrez les formes exactes de la requête et de la réponse, vous les intégrez dans Python à l'aide de requests et du client OpenAI, vous ajoutez la logique de nouvelle tentative et de délai d'attente nécessaire à l'inférence en production, puis vous connectez la fonctionnalité au reste de TaskBoard via des appels synchrones et un chemin asynchrone basé sur une file Kafka. Chaque bloc de code cible le point de terminaison réel d'IONOS CLOUD et des identifiants de modèles réels, de sorte que vous pouvez copier, définir votre jeton et exécuter.
1. Le point d'accès d'inférence et l'authentification
AI Model Hub propose deux options d'API : une API native AI Model Hub et une API compatible OpenAI. L'API compatible OpenAI reproduit la structure des requêtes et des réponses d'OpenAI, ce qui vous permet de réutiliser vos outils et SDK OpenAI existants en modifiant uniquement l'URL de base et les identifiants. Pour l'intégration d'applications, c'est l'option recommandée, car les formats des requêtes et des réponses sont déjà familiers et les bibliothèques de clients officielles d'OpenAI fonctionnent sans modification.
L'URL de base compatible OpenAI est https://openai.inference.de-txl.ionos.com/v1. L'authentification utilise un jeton Bearer, qui est un JSON Web Token (JWT) avec une date d'expiration. Les guides pratiques d'AI Model Hub supposent que le jeton est stocké dans la variable d'environnement IONOS_API_TOKEN. Étant donné que le jeton est un JWT avec une revendication exp, une erreur d'authentification survenant soudainement indique généralement que le jeton a expiré, et non que l'appel est incorrect. Vérifiez la revendication exp et régénérez le jeton si elle est dépassée.
1.1 Premier appel avec curl
Envoyez une complétion de conversation pour confirmer votre jeton et la connectivité avant d'écrire du code applicatif. Le point d'accès est POST /v1/chat/completions et le corps de la requête contient un identifiant model et un tableau messages.
export IONOS_API_TOKEN="your-jwt-token"
curl -s https://openai.inference.de-txl.ionos.com/v1/chat/completions \
-H "Authorization: Bearer ${IONOS_API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"model": "meta-llama/Llama-3.3-70B-Instruct",
"messages": [
{"role": "user", "content": "Summarize in one sentence: the deploy pipeline failed because the registry token expired."}
],
"temperature": 0.2,
"max_tokens": 60
}'
La réponse est un objet de complétion de type OpenAI. Le texte généré se trouve dans choices[0].message.content, et usage signale prompt_tokens, completion_tokens, et total_tokens, dont vous avez besoin pour le suivi des coûts.
{
"id": "chatcmpl-123",
"object": "chat.completion",
"model": "meta-llama/Llama-3.3-70B-Instruct",
"choices": [
{
"index": 0,
"message": {"role": "assistant", "content": "The deploy pipeline failed because the container registry token had expired."},
"finish_reason": "stop"
}
],
"usage": {"prompt_tokens": 28, "completion_tokens": 14, "total_tokens": 42}
}
1.2 Liste des modèles disponibles
L'API compatible OpenAI expose un point de terminaison de modèles pour récupérer la liste des modèles disponibles et leurs détails. Utilisez-le pour découvrir les chaînes d'identifiants de modèles exactes plutôt que de coder en dur une estimation, car c'est l'identifiant que le champ model requiert.
curl -s https://openai.inference.de-txl.ionos.com/v1/models \
-H "Authorization: Bearer ${IONOS_API_TOKEN}" | python3 -m json.tool
L'identifiant de modèle que vous transmettez doit correspondre exactement au catalogue. Pour les modèles de chat utilisés dans cette unité, les identifiants sont meta-llama/Llama-3.3-70B-Instruct, openai/gpt-oss-120b et mistralai/Mistral-Small-24B-Instruct. Une faute de frappe dans l'identifiant est l'une des causes les plus fréquentes d'échec lors de la première tentative.
2. Appel de Model Hub depuis le code applicatif
Dans le service API de TaskBoard, vous effectuez les inférences à partir de Python. Vous disposez de deux options claires : piloter directement l'API HTTP à l'aide de requests, ou utiliser le client officiel openai configuré sur l'URL de base d'IONOS CLOUD. Les deux approches accèdent à la même fin de point. La voie requests limite les dépendances au minimum ; le client OpenAI vous offre gratuitement des assistants typés, des itérateurs de flux et des hooks de nouvelle tentative.
2.1 HTTP direct avec requests
Il s'agit de l'intégration avec le moins de dépendances. C'est également la manière la plus claire de voir exactement ce qui transite sur le réseau, ce qui est utile lors du débogage.
import os
import requests
BASE_URL = "https://openai.inference.de-txl.ionos.com/v1"
TOKEN = os.environ["IONOS_API_TOKEN"]
def summarize(description: str) -> str:
resp = requests.post(
f"{BASE_URL}/chat/completions",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"model": "meta-llama/Llama-3.3-70B-Instruct",
"messages": [
{"role": "system", "content": "You write one-sentence task summaries."},
{"role": "user", "content": description},
],
"temperature": 0.2,
"max_tokens": 60,
},
timeout=30,
)
resp.raise_for_status()
return resp.json()["choices"][0]["message"]["content"].strip()
Toujours définir une valeur explicite pour timeout. La latence d'inférence varie selon la longueur du prompt et la taille du modèle, et un socket bloqué sans délai d'expiration bloquera un thread de travail dans votre API.
2.2 Le client OpenAI pointé vers IONOS CLOUD
Étant donné que l'API est compatible avec OpenAI, le package Python officiel openai fonctionne lorsque vous remplacez base_url et api_key. C'est l'option la plus ergonomique pour le code applicatif.
import os
from openai import OpenAI
client = OpenAI(
base_url="https://openai.inference.de-txl.ionos.com/v1",
api_key=os.environ["IONOS_API_TOKEN"],
)
def summarize(description: str) -> str:
completion = client.chat.completions.create(
model="meta-llama/Llama-3.3-70B-Instruct",
messages=[
{"role": "system", "content": "You write one-sentence task summaries."},
{"role": "user", "content": description},
],
temperature=0.2,
max_tokens=60,
)
return completion.choices[0].message.content.strip()
2.3 Réponses en streaming
Pour les interfaces utilisateur interactives, vous pouvez diffuser les jetons au fur et à mesure de leur génération en définissant stream sur true. Lors du streaming, les statistiques d'utilisation ne sont pas incluses par défaut. Pour obtenir les statistiques d'utilisation dans le dernier fragment, vous devez définir explicitement stream_options avec include_usage activé.
stream = client.chat.completions.create(
model="openai/gpt-oss-120b",
messages=[{"role": "user", "content": "Explain what a poison message is."}],
stream=True,
stream_options={"include_usage": True},
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
Le flux se termine par une ligne de données finale contenant usage suivie d'un marqueur [DONE]. Si vous ignorez stream_options, vous perdez les compteurs de jetons dont vous avez besoin pour la comptabilité des coûts.
3. Choisir un modèle : fenêtre de contexte et prix
La sélection du modèle est une décision de code guidée par deux chiffres : le nombre de jetons que le modèle accepte (fenêtre de contexte) et le coût par million de jetons. Les résumés de TaskBoard sont courts, donc le modèle le moins cher qui soit capable est le choix par défaut approprié ; réservez les modèles plus grands pour les tâches qui en ont réellement besoin.
Le tableau suivant compare les modèles de chat utilisés dans cette unité. Les prix sont exprimés en EUR par million de jetons.
| Identifiant du modèle | Fenêtre de contexte (jetons) | Prix d'entrée (EUR / 1M) | Prix de sortie (EUR / 1M) |
|---|---|---|---|
mistralai/Mistral-Small-24B-Instruct |
128000 | 0.10 | 0.30 |
openai/gpt-oss-120b |
128000 | 0.15 | 0.65 |
meta-llama/Llama-3.3-70B-Instruct |
128000 | 0.65 | 0.65 |
Comme indiqué ci-dessus, les trois modèles acceptent une fenêtre de contexte de 128000 jetons, donc pour une invite de résumé courte, le facteur déterminant est le prix. mistralai/Mistral-Small-24B-Instruct est le moins cher à la fois en entrée et en sortie, et constitue un choix par défaut solide pour les résumés de TaskBoard. Passez à un modèle plus grand uniquement lorsque la qualité des résumés sur de vraies descriptions de tâches est manifestement meilleure et justifie le supplément par jeton.
3.1 Configuration du modèle tenant compte des coûts
Rendez le modèle une valeur de configuration, et non une valeur littérale dispersée dans le code, afin de pouvoir le changer par environnement sans redéployer la logique.
import os
SUMMARY_MODEL = os.environ.get("SUMMARY_MODEL", "mistralai/Mistral-Small-24B-Instruct")
def estimate_cost_eur(prompt_tokens: int, completion_tokens: int,
in_price: float, out_price: float) -> float:
return (prompt_tokens / 1_000_000) * in_price + (completion_tokens / 1_000_000) * out_price
print(estimate_cost_eur(28, 14, 0.10, 0.30)) # 28 prompt + 14 completion tokens, Mistral-Small pricing
3.2 Embeddings pour les caractéristiques sémantiques
Lorsque TaskBoard a besoin d'une recherche sémantique sur les tâches, vous générez des vecteurs avec un modèle d'embedding plutôt qu'un modèle de chat. Le point d'accès est POST /v1/embeddings. Le modèle BAAI/bge-m3 renvoie des vecteurs de 1024 dimensions et est facturé à 0,02 EUR par million de jetons.
def embed(text: str) -> list[float]:
resp = client.embeddings.create(model="BAAI/bge-m3", input=text)
return resp.data[0].embedding # 1024 floats
vec = embed("Fix the expired registry token in the deploy pipeline")
assert len(vec) == 1024
Stockez les vecteurs résultants à l'endroit où se trouve votre couche de recherche. L'intégration est déterministe pour une entrée et un modèle donnés, de sorte qu'un texte identique produit toujours le même vecteur, ce qui en fait un candidat idéal pour la mise en cache.
4. Gestion des erreurs en production
Les appels d'inférence échouent de manière différente par rapport à vos points d'accès CRUD : le modèle est soumis à une limitation de débit, la demande expirée sous charge, ou la réponse est un JSON bien formé mais le contenu est vide ou au mauvais format. Le code de production doit gérer les trois cas. Le plus important sur IONOS CLOUD est la limitation de débit.
4.1 Limitations de débit et recul sur 429
La limitation de débit générale de l'API est de 5 requêtes par seconde (base), avec une tolérance de rafale de 10. Lorsque vous dépassez la limite, le service renvoie HTTP 429 Too Many Requests. Traitez le 429 comme un signal pour reculer et réessayer, et non comme une défaillance définitive. Utilisez un recul exponentiel afin qu'une rafale d'activité sur TaskBoard ne sollicite pas excessivement le point d'accès.
import time
import requests
def chat_with_retry(payload: dict, max_attempts: int = 5) -> dict:
delay = 1.0
for attempt in range(max_attempts):
resp = requests.post(
f"{BASE_URL}/chat/completions",
headers={"Authorization": f"Bearer {TOKEN}"},
json=payload,
timeout=30,
)
if resp.status_code == 429:
retry_after = float(resp.headers.get("Retry-After", delay))
time.sleep(retry_after)
delay *= 2
continue
resp.raise_for_status()
return resp.json()
raise RuntimeError("inference rate-limited after retries")
Respectez l'en-tête Retry-After lorsque le service le fournit, et utilisez votre propre délai exponentiel en cas d'absence. Limitez le nombre de tentatives afin qu'une panne prolongée se manifeste sous forme d'erreur plutôt que d'une boucle infinie.
4.2 Délais d'attente et validation des réponses
Une réponse 200 ne garantit pas un contenu utilisable. Le modèle peut renvoyer une chaîne vide ou un texte qui contrevient à vos hypothèses en aval. Validez avant d'enregistrer.
def safe_summary(description: str) -> str:
payload = {
"model": SUMMARY_MODEL,
"messages": [
{"role": "system", "content": "Reply with exactly one sentence."},
{"role": "user", "content": description},
],
"max_tokens": 60,
}
data = chat_with_retry(payload)
choices = data.get("choices") or []
if not choices:
raise ValueError("no choices in inference response")
content = (choices[0]["message"]["content"] or "").strip()
if not content:
raise ValueError("empty summary returned")
return content
Pour l'extraction structurée, l'API de complétion de conversation prend en charge un response_format avec un schéma JSON et strict activé, ce qui contraint le modèle à émettre un JSON valide correspondant à votre schéma. C'est la méthode fiable pour obtenir une sortie analysable par machine au lieu d'un texte libre que vous devez analyser de manière défensive.
5. Modèles d'intégration et contrôle des coûts
Vous pouvez effectuer des inférences de deux manières dans TaskBoard. L'inférence synchrone s'exécute à l'intérieur de la requête qui a besoin du résultat. L'inférence asynchrone met le travail en file d'attente et le traite hors bande. Le bon choix dépend de savoir si l'utilisateur attend la réponse.
5.1 Synchrone : résumer à la création
Lorsque l'utilisateur soumet une tâche et s'attend à recevoir le résumé immédiatement, appelez l'inférence à l'intérieur du gestionnaire de requête et écrivez le résumé dans PostgreSQL dans la même transaction.
def create_task(db, description: str) -> int:
summary = safe_summary(description)
row = db.execute(
"INSERT INTO tasks (description, summary) VALUES (%s, %s) RETURNING id",
(description, summary),
).fetchone()
db.commit()
return row[0]
Maintenez le chemin synchrone derrière un délai d'attente et un budget de nouvelles tentatives afin qu'un modèle lent n'entrave pas indéfiniment la requête destinée à l'utilisateur.
5.2 Asynchrone : file d'attente d'inférence via Kafka
Lorsque le résumé n'est pas nécessaire immédiatement, découplez-le. L'API écrit la tâche immédiatement et génère un événement de modification de tâche vers Kafka (voir l'unité 4.3) ; un travailleur consomme l'événement, appelle l'inférence et met à jour la ligne. Cela permet de garder la requête de création rapide et d'isoler la latence d'inférence et les limites de débit du chemin utilisateur.
def handle_event(event: dict, db): # worker side: consume task event, summarize, persist
task_id = event["task_id"]
description = event["description"]
try:
summary = safe_summary(description)
except (ValueError, RuntimeError):
# route to a dead-letter topic; do not block the consumer group
produce_dead_letter(event)
return
db.execute("UPDATE tasks SET summary = %s WHERE id = %s", (summary, task_id))
db.commit()
Le modèle asynchrone lisse également les pics de charge : la limite de 5 requêtes par seconde est beaucoup plus facile à respecter lorsqu'un seul consommateur vide une file d'attente à un taux contrôlé, plutôt que lorsque de nombreux travailleurs web appellent l'inférence simultanément.
5.3 Mise en cache des résultats dans Redis
L'inférence est l'appel le plus coûteux de cette fonctionnalité, il ne faut donc pas en payer le prix deux fois. Mettre en cache à l'aide d'un hachage du modèle et de l'entrée. Des descriptions identiques ne coûtent alors plus rien après le premier appel. Cela s'associe naturellement à la mise en cache existante de TaskBoard dans la base de données In-Memory DB (Redis) de l'unité 4.1.
import hashlib
import redis
r = redis.Redis(host="taskboard-redis", port=6379, ssl=True)
def cached_summary(description: str) -> str:
key = "sum:" + hashlib.sha256(
(SUMMARY_MODEL + "|" + description).encode()
).hexdigest()
hit = r.get(key)
if hit:
return hit.decode()
summary = safe_summary(description)
r.set(key, summary, ex=86400) # 24h TTL
return summary
Étant donné que l'inférence est sans état et que les invites et les résultats sont supprimés à la fin de chaque session, la seule trace durable d'un résultat est celle que vous choisissez de conserver. La mise en cache constitue donc à la fois un levier de réduction des coûts et votre dépôt de résultats calculés.
5.4 Résidence des données et confidentialité
AI Model Hub fonctionne en tant que service sans état : les invites et les résultats sont supprimés à la fin de chaque session, ne sont pas journalisés ni enregistrés, et ne sont pas réutilisés pour l'entraînement des modèles. Les données des clients ne sont utilisées pour l'entraînement dans aucune circonstance. Tous les services d'AI Model Hub, y compris les points d'accès d'inférence des modèles et les bases de données vectorielles gérées, sont hébergés dans des centres de données certifiés ISO 27001 en Allemagne, et le traitement est entièrement conforme au RGPD. Pour TaskBoard, cela signifie que les descriptions de tâches envoyées pour la synthèse restent dans la limite du centre de données allemand et n'entrent jamais dans un jeu de données d'entraînement.
5.5 Accès agentique en lecture seule avec le IONOS CLOUD MCP Server
Lorsque l'intégration dont vous avez besoin n'est pas « appeler un modèle » mais « permettre à un agent IA d'inspecter votre infrastructure IONOS CLOUD », le IONOS CLOUD MCP Server est le chemin destiné aux développeurs. Il s'agit d'un binaire local qui implémente le Model Context Protocol (MCP), communiquant en JSON-RPC via stdio avec un client IA ou un agent autonome. Il accorde à ce client un accès en lecture seule à plus de 100 outils répartis sur six produits : Compute Engine, Object Storage, Cloud DNS, Certificate Manager, Billing et Activity Log. Les outils sont conçus pour l'inspection uniquement, de sorte que le binaire ne peut pas créer, mettre à jour ni supprimer aucune ressource.
Le MCP Server est une alternative à la configuration de vos propres appels API ou SDK directs pour les scénarios de lecture agentique et d'automatisation. Au lieu d'écrire du code client pour chaque API de produit, vous exécutez le binaire en tant que sous-processus local ; le client IA découvre les outils et les appelle dans une boucle agentique, et le binaire appelle directement l'API IONOS CLOUD via HTTPS en utilisant votre jeton API. Pour les flux de travail entièrement souverains, il s'associe à AI Model Hub, afin que l'étape d'inférence et l'étape d'inspection de l'infrastructure restent toutes deux dans le périmètre IONOS CLOUD. Considérez les sorties des outils comme des données qui quittent ce périmètre dès que le client IA les lit.
Fiche de référence rapide de l'API
Points de terminaison API clés pour l'intégration avec AI Model Hub :
| Méthode | Point de terminaison | Description |
|---|---|---|
GET |
/v1/models |
Liste les modèles disponibles et leurs détails |
POST |
/v1/chat/completions |
Génère une complétion de chat (définir stream pour le flux) |
POST |
/v1/embeddings |
Génère des vecteurs de plongée pour le texte d'entrée |
POST |
/v1/images/generations |
Génère des images à partir d'un prompt texte |
URL de base (compatible OpenAI) : https://openai.inference.de-txl.ionos.com/v1
Documentation de l'API native : https://api.ionos.com/docs/inference-modelhub/v1
Authentification : Authorization: Bearer <IONOS_API_TOKEN> (JWT avec la revendication exp)
Atelier de code
Objectif : Ajouter la synthèse par IA à TaskBoard. Appeler AI Model Hub pour résumer une description de tâche, gérer une erreur 429 avec un recul (backoff), et mettre le résultat en cache dans Redis afin qu'une synthèse répétée ne coûte aucun jeton.
Prérequis :
- Un compte IONOS CLOUD avec un jeton API (JWT) dans
IONOS_API_TOKEN - Python 3.10 ou supérieur avec
pip install openai requests redis - Une instance Redis accessible (ou un
redislocal pour l'atelier)
Étape 1 : Exporter votre jeton et confirmer la connectivité
export IONOS_API_TOKEN="your-jwt-token"
curl -s https://openai.inference.de-txl.ionos.com/v1/models \
-H "Authorization: Bearer ${IONOS_API_TOKEN}" | python3 -m json.tool | head
Sortie attendue :
{
"object": "list",
"data": [
{ "id": "meta-llama/Llama-3.3-70B-Instruct", ... }
Étape 2 : Effectuer un premier appel de résumé
from openai import OpenAI
import os
client = OpenAI(base_url="https://openai.inference.de-txl.ionos.com/v1",
api_key=os.environ["IONOS_API_TOKEN"])
c = client.chat.completions.create(
model="mistralai/Mistral-Small-24B-Instruct",
messages=[{"role": "user", "content": "Summarize in one sentence: registry token expired so the deploy failed."}],
max_tokens=60, temperature=0.2)
print(c.choices[0].message.content)
print("tokens:", c.usage.total_tokens)
Sortie attendue :
The deployment failed because the container registry token had expired.
tokens: 41
Étape 3 : Ajouter la nouvelle tentative en cas d'erreur 429 avec un retour exponentiel
import time, requests, os
BASE="https://openai.inference.de-txl.ionos.com/v1"
def call(payload, attempts=5):
delay=1.0
for _ in range(attempts):
r=requests.post(f"{BASE}/chat/completions",
headers={"Authorization":f"Bearer {os.environ['IONOS_API_TOKEN']}"},
json=payload, timeout=30)
if r.status_code==429:
time.sleep(float(r.headers.get("Retry-After", delay))); delay*=2; continue
r.raise_for_status(); return r.json()
raise RuntimeError("rate-limited")
Sortie attendue : aucune erreur lors d'un appel normal ; un code 429 déclenche une attente et une nouvelle tentative au lieu d'un plantage.
Étape 4 : Valider la réponse avant de l'utiliser
def summary(text):
data=call({"model":"mistralai/Mistral-Small-24B-Instruct",
"messages":[{"role":"user","content":text}],"max_tokens":60})
out=(data["choices"][0]["message"]["content"] or "").strip()
if not out: raise ValueError("empty summary")
return out
print(summary("The CI job failed on the embeddings step."))
Sortie attendue :
The CI job failed during the embeddings step.
Étape 5 : Mettre les résultats en cache dans Redis
import hashlib, redis
r=redis.Redis(host="localhost", port=6379)
MODEL="mistralai/Mistral-Small-24B-Instruct"
def cached(text):
k="sum:"+hashlib.sha256((MODEL+"|"+text).encode()).hexdigest()
hit=r.get(k)
if hit: return hit.decode()
s=summary(text); r.set(k, s, ex=86400); return s
Étape 6 : Vérifier que le cache élimine le coût de la seconde requête
import time
t=time.time(); cached("Same description here."); print("miss", round(time.time()-t,2))
t=time.time(); cached("Same description here."); print("hit ", round(time.time()-t,2))
Sortie attendue :
miss 0.9
hit 0.0
Étape 7 : Générer un vecteur pour la recherche sémantique
e=client.embeddings.create(model="BAAI/bge-m3", input="Fix the expired registry token")
print(len(e.data[0].embedding))
Sortie attendue :
1024
Liste de contrôle de validation :
- [ ]
/v1/modelsrenvoie une liste de modèles avec votre jeton - [ ] Une complétion de chat renvoie du contenu et un nombre de jetons
usage - [ ] Un code 429 déclenche un recul et une nouvelle tentative plutôt qu'une exception
- [ ] Un résumé répété est servi depuis Redis sans coût en jetons
- [ ]
BAAI/bge-m3renvoie un vecteur de 1024 dimensions
Nettoyage :
redis-cli --scan --pattern 'sum:*' | xargs -r redis-cli del
Erreurs courantes
Erreurs de développement à éviter lors de l'intégration avec AI Model Hub :
-
Considérer une erreur 429 comme fatale
- Problème : Une rafale d'activité sur TaskBoard renvoie
HTTP 429 Too Many Requestset votre gestionnaire lève une exception, ce qui provoque l'échec des requêtes des utilisateurs. - Pourquoi cela arrive : La limite de débit générale de l'API est de 5 requêtes par seconde (base) avec une capacité de rafale de 10 ; les travailleurs web concurrents la dépassent facilement.
- Correction : Gérer le code 429, respecter
Retry-Afteret effectuer une nouvelle tentative avec un retour exponentiel. Confier l'inférence à un worker alimenté par Kafka pour contrôler la concurrence.
- Problème : Une rafale d'activité sur TaskBoard renvoie
-
Confondre un JWT expiré avec un bug de code
- Problème : Les appels qui fonctionnaient hier renvoient aujourd'hui une erreur d'authentification, et vous commencez à déboguer les en-têtes et les charges utiles.
- Pourquoi cela arrive : Le jeton Bearer est un JWT avec une revendication
expet une date d'expiration fixe. Une fois cette date dépassée, tous les appels échouent à l'authentification. - Correction : Décoder la revendication
expdu jeton et le régénérer lorsqu'il est expiré. Traiter d'abord les échecs d'authentification comme une vérification du cycle de vie du jeton, et non comme un bug de format de requête.
-
Appeler l'inférence de manière synchrone et payer des doublons
- Problème : Des pics de latence surviennent lors de la création de tâches et la facture en jetons augmente, car des descriptions identiques sont résumées à plusieurs reprises.
- Pourquoi cela arrive : L'inférence s'exécute dans le chemin de la requête sans mise en cache, si bien que la même entrée consomme des jetons à chaque fois.
- Correction : Mettre en cache à l'aide d'un hachage du modèle et de l'entrée dans Redis avec une durée de vie (TTL), et déplacer les résumés non urgents vers un worker Kafka asynchrone afin que la requête de création reste rapide.
Résumé
Vous pouvez désormais intégrer AI Model Hub dans le code applicatif. Vous appelez le point d'accès compatible OpenAI situé à https://openai.inference.de-txl.ionos.com/v1 avec un JWT Bearer, le pilotez depuis requests ou le client OpenAI officiel, utilisez le flux (streaming) lorsque l'interface utilisateur l'exige, et générez des embeddings avec BAAI/bge-m3. Vous sélectionnez les modèles selon la fenêtre de contexte et le prix par jeton, et vous encapsulez chaque appel avec une temporisation, un recul en cas de 429 et une validation de la réponse. Vous avez intégré cette fonctionnalité dans TaskBoard, à la fois de manière synchrone et via un travailleur alimenté par une file Kafka, et vous mettez les résultats en cache dans Redis afin que les entrées répétées ne coûtent rien.
Points clés :
- L'API compatible OpenAI située à
/v1/chat/completions,/v1/embeddings,/v1/modelset/v1/images/generationspermet au client OpenAI officiel de fonctionner en remplaçantbase_urletapi_key - L'authentification est un JWT Bearer dans
IONOS_API_TOKEN; une revendicationexpexpirée est la cause la plus fréquente des échecs d'authentification soudains - La limite de débit générale est de 5 requêtes par seconde en base, avec une pointe de 10 ; la dépasser renvoie un HTTP 429, que vous gérez avec
Retry-Afteret un recul exponentiel - Le choix du modèle est une décision de coût : les trois modèles de chat partagent une fenêtre de contexte de 128000 jetons, si bien que le prix les distingue,
mistralai/Mistral-Small-24B-Instructétant le moins cher - Le service est sans état et hébergé en Allemagne ; les invites et les sorties sont supprimées à chaque session et ne sont jamais utilisées pour l'entraînement, si bien que la mise en cache Redis est à la fois votre levier de coût et votre seul stockage durable des résultats
- Le IONOS CLOUD MCP Server est un binaire local offrant aux agents IA un accès en lecture seule à plus de 100 outils couvrant Compute Engine, Object Storage, Cloud DNS, Certificate Manager, Billing et Activity Log via MCP (JSON-RPC sur stdio) ; il constitue une alternative aux appels directs à l'API ou au SDK pour les scénarios de lecture agentique et s'associe à AI Model Hub pour les workflows souverains
Terminologie importante :
- API compatible OpenAI : Un point d'accès qui reproduit la structure des requêtes et des réponses d'OpenAI, permettant aux SDK OpenAI de fonctionner avec IONOS CLOUD en modifiant l'URL de base et la clé
- Fenêtre de contexte : Le nombre maximal de jetons (invite plus complétion) qu'un modèle accepte dans une seule requête ; 128000 pour les modèles de chat de cette unité
- Tarification par jeton : Coût facturé par million de jetons d'entrée et de sortie ; suivi via l'objet
usagedans chaque réponse - Recul exponentiel : Une stratégie de nouvelle tentative qui double l'attente entre les tentatives après un 429, empêchant une tempête de nouvelles tentatives de type « essaim »
- Inférence sans état : Chaque requête est autonome ; AI Model Hub supprime les invites et les sorties à la fin de la session et ne les journalise, ne les stocke ni n'entraîne sur elles
- IONOS CLOUD MCP Server : Un binaire local implémentant le Model Context Protocol (JSON-RPC sur stdio) qui expose des outils d'inspection en lecture seule couvrant six produits IONOS CLOUD à un client IA, en appelant directement l'API IONOS CLOUD sans aucun fournisseur tiers d'IA dans le chemin de données
Prochaines étapes
Continuer l'apprentissage : Unité 4.5 : Vérification des connaissances - Intégration de service
Sujets connexes :