Migration

Une URL de base et une clé font passer un client OpenAI. Cette page indique aussi ce que l’API ne fait pas, car une migration qui le découvre en production n’est pas une migration.

La forme prête à l’emploi

Pointez l’URL de base du client vers https://api.llmeu.com/v1 et donnez-lui une clé API depuis la console. La forme de la requête ne change pas.

from openai import OpenAI

client = OpenAI(base_url="https://api.llmeu.com/v1", api_key="llmeu_live_xxxxxxxx.your-secret")

resp = client.chat.completions.create(
    model="llmeu-auto",
    messages=[{"role": "user", "content": "Say hello from EU hosting."}],
)
print(resp.choices[0].message.content)

Ce que le point de terminaison de chat accepte

Le validateur de requête dans apps/api/src/app.mjs vérifie ce qui suit ; ce qu’il ne vérifie pas est transmis ou ignoré plutôt que rejeté, afin qu’un client plus récent continue de fonctionner.

  • model et messages sont requis ; messages doit être un tableau non vide.
  • Chaque message nécessite un rôle (system, user, assistant, tool ou developer) et un contenu sous forme de chaîne ou de tableau de parties.
  • stream doit être un booléen lorsqu’il est présent.
  • temperature, top_p, max_tokens, presence_penalty, frequency_penalty, seed et n doivent être des nombres lorsqu’ils sont présents.
  • max_tokens doit être au moins 1.
  • n doit être exactement 1 ; toute autre valeur est refusée.
  • stop peut être une chaîne ou un tableau de chaînes.
  • tools doit être un tableau lorsqu’il est présent.
  • llmeu doit être un objet ; il n’est jamais requis.
  • tool_choice et response_format sont transmis au backend avec les champs ci-dessus ; un champ supplémentaire inconnu n’est pas rejeté.

Extras de requête sous llmeu

Un objet llmeu avec espace de noms dans le corps de la requête ; un client qui ignore les champs inconnus peut l’envoyer sans risque.

Champ Valeur Effet
residencyeu-hosted | eu-owned | de | anyRestreint le routage aux points de terminaison de cette résidence ; un ensemble éligible vide renvoie 409 no_endpoint_for_policy plutôt que d’élargir le filtre.
taskun nom de tâcheLa tâche à laquelle le routeur adapte le modèle.
retentionzeroSeul zéro est implémenté. Demander plus que ce que la politique autorise renvoie 403 retention_exceeds_policy ; une valeur effective autorisée autre que zéro renvoie 501 retention_not_implemented.
data_classpublic | internal | confidential | restrictedVérifié par rapport aux classes de données autorisées par la politique : une classe en dehors renvoie 403 data_class_not_allowed, et une classe inconnue renvoie 400 invalid_data_class.
policy_iduuidNomme une politique de la même organisation ; un id inconnu renvoie 404 policy_not_found.
max_usd_per_1mun nombreUn plafond de prix par million de jetons pour cette requête.
allow_partnerstrue | falseSi les points de terminaison partenaires peuvent être utilisés pour cette requête.

Les clés inconnues dans llmeu sont ignorées ; une clé connue avec une valeur invalide est refusée, car un data_class incorrect doit échouer en fermant plutôt que signifier silencieusement l’absence de classe de données.

curl https://api.llmeu.com/v1/chat/completions \
  -H "Authorization: Bearer $LLMEU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "llmeu-auto",
    "messages": [{"role": "user", "content": "Summarise this contract."}],
    "llmeu": {"residency": "eu-owned", "data_class": "confidential", "retention": "zero"}
  }'

Ce qui n’existe pas

Ces réponses sont délibérées, et un client qui les attend voit le code d’erreur plutôt qu’une substitution silencieuse.

Requête Résultat
POST /v1/completions501 not_implemented — l’ancien point de terminaison completions n’est pas proposé ; utilisez /v1/chat/completions.
n > 1400 unsupported_n — seul n = 1 est pris en charge.
POST /v1/embeddingsLes embeddings nécessitent un modèle d’embedding, et l’id demandé par défaut est bge-m3. Ils sont actuellement servis par le backend local déterministe, dont la réponse porte llmeu.mock: true et la note que des vecteurs de remplacement déterministes sont renvoyés et qu’aucun poids d’embedding n’est servi sur ce déploiement.
/v1/files, /v1/batches, /v1/assistants, /v1/fine_tuning, /v1/audio, /v1/images404 unknown_route — pas routé du tout ; un chemin /v1 que le routeur ne connaît pas répond 404 unknown_route, et tout autre chemin répond 404 not_found.

Récupérer vos données

L’export de compte me.json contient des champs de compte sélectionnés, les organisations, les métadonnées de clé API sans secrets, les politiques actuelles, les 200 dernières traces par organisation et les agrégats d’utilisation quotidiens pour 365 jours. Ce n’est pas une copie complète de toutes les données personnelles ni un historique des politiques.

L’export d’audit NDJSON est par défaut de 7 jours, autorise au maximum 90 jours et plafonne les traces à 5000 ; son manifeste porte counts.truncated, qui marque un export ayant atteint le plafond.

GET /app/exports/me.json
GET /app/exports/audit.ndjson?days=7
GET /app/exports/traces.json
GET /app/exports/usage.json
GET /app/exports/policies.json

La suppression du compte elle-même se fait sur la page de profil et est soumise à la règle de propriété sur la page de la console.

Un cookie de session n’est pas un identifiant d’API

Une session de navigateur authentifie la console, pas l’API. Un client OpenAI qui en envoie une est refusé avec 403 api_key_required et doit utiliser une clé API à la place.

Un refus ici nomme un code, donc une migration peut s’y brancher, et le bloc llmeu sur chaque réponse dit ce qui s’est réellement passé.