Migration
Basis-URL und Schlüssel genügen, um einen OpenAI-Client umzustellen. Diese Seite nennt auch, was die API nicht tut, denn eine Migration, die das erst im Produktivbetrieb entdeckt, ist keine Migration.
Die Drop-in-Form
Die Basis-URL des Clients auf https://api.llmeu.com/v1 richten und einen API-Schlüssel aus der Konsole verwenden. Die Anfrageform ändert sich nicht.
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)
Was der Chat-Endpunkt akzeptiert
Der Anfrage-Validator in apps/api/src/app.mjs prüft Folgendes; was er nicht prüft, wird durchgereicht oder ignoriert statt abgelehnt, damit ein neuerer Client weiter funktioniert.
- model und messages sind erforderlich; messages muss ein nicht leeres Array sein.
- Jede Nachricht braucht eine Rolle (system, user, assistant, tool oder developer) und content als Zeichenkette oder Array von Teilen.
- stream muss, wenn vorhanden, ein boolescher Wert sein.
- temperature, top_p, max_tokens, presence_penalty, frequency_penalty, seed und n müssen, wenn vorhanden, Zahlen sein.
- max_tokens muss mindestens 1 sein.
- n muss genau 1 sein; alles andere wird abgelehnt.
- stop darf eine Zeichenkette oder ein Array von Zeichenketten sein.
- tools muss, wenn vorhanden, ein Array sein.
- llmeu muss ein Objekt sein; erforderlich ist es nie.
- tool_choice und response_format werden zusammen mit den obigen Feldern an das Backend weitergegeben; ein unbekanntes Zusatzfeld wird nicht abgelehnt.
Anfrage-Erweiterungen unter llmeu
Ein namensraumgebundenes llmeu-Objekt im Anfragekörper; ein Client, der unbekannte Felder ignoriert, kann es gefahrlos senden.
| Feld | Wert | Wirkung |
|---|---|---|
| residency | eu-hosted | eu-owned | de | any | Engt das Routing auf Endpunkte dieser Residenz ein; eine leere zulässige Menge ergibt 409 no_endpoint_for_policy statt einer Erweiterung des Filters. |
| task | ein Aufgabenname | Die Aufgabe, auf die der Router das Modell abstimmt. |
| retention | zero | Nur zero ist implementiert. Eine Anfrage oberhalb der Richtlinie ergibt 403 retention_exceeds_policy; eine erlaubte effektive Aufbewahrung ungleich zero ergibt 501 retention_not_implemented. |
| data_class | public | internal | confidential | restricted | Wird gegen die erlaubten Datenklassen der Richtlinie geprüft: eine Klasse außerhalb ergibt 403 data_class_not_allowed, eine unbekannte Klasse 400 invalid_data_class. |
| policy_id | uuid | Benennt eine Richtlinie derselben Organisation; eine unbekannte ID ergibt 404 policy_not_found. |
| max_usd_per_1m | eine Zahl | Eine Preisobergrenze pro Million Tokens für diese Anfrage. |
| allow_partners | true | false | Ob für diese Anfrage Partner-Endpunkte verwendet werden dürfen. |
Unbekannte Schlüssel innerhalb von llmeu werden ignoriert; ein bekannter Schlüssel mit ungültigem Wert wird abgelehnt, denn eine falsche data_class muss geschlossen fehlschlagen statt still keine Datenklasse zu bedeuten.
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"}
}'
Was es nicht gibt
Diese Antworten sind beabsichtigt; ein Client, der sie erwartet, sieht den Fehlercode statt einer stillen Ersetzung.
| Anfrage | Ergebnis |
|---|---|
| POST /v1/completions | 501 not_implemented — der alte Completions-Endpunkt wird nicht angeboten; /v1/chat/completions verwenden. |
| n > 1 | 400 unsupported_n — nur n = 1 wird unterstützt. |
| POST /v1/embeddings | Embeddings brauchen ein Embedding-Modell; die standardmäßig angefragte ID ist bge-m3. Sie werden derzeit vom deterministischen lokalen Backend bedient, dessen Antwort llmeu.mock: true trägt und den Hinweis, dass deterministische Platzhaltervektoren zurückgegeben werden und in dieser Bereitstellung keine Embedding-Gewichte laufen. |
| /v1/files, /v1/batches, /v1/assistants, /v1/fine_tuning, /v1/audio, /v1/images | 404 unknown_route — überhaupt nicht geroutet; ein /v1-Pfad, den der Router nicht kennt, ergibt 404 unknown_route, jeder andere Pfad 404 not_found. |
Daten wieder herausbekommen
Der Kontoexport me.json enthält ausgewählte Kontofelder, Organisationen, API-Schlüsselmetadaten ohne Geheimnisse, aktuelle Richtlinien, die neuesten 200 Traces je Organisation und tägliche Nutzungsaggregate für 365 Tage. Er ist keine vollständige Kopie aller personenbezogenen Daten und keine historische Richtlinienfassung.
Der NDJSON-Audit-Export umfasst standardmäßig 7 Tage, höchstens 90 Tage und maximal 5000 Traces; sein Manifest enthält counts.truncated, das einen Export markiert, der die Grenze erreicht hat.
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
Das Löschen des Kontos erfolgt auf der Profilseite und unterliegt der Eigentumsregel auf der Konsolenseite.
Ein Sitzungs-Cookie ist keine API-Berechtigung
Eine Browser-Sitzung authentifiziert die Konsole, nicht die API. Ein OpenAI-Client, der eine sendet, wird mit 403 api_key_required abgelehnt und muss einen API-Schlüssel verwenden.
Eine Ablehnung nennt hier einen Code, auf den eine Migration verzweigen kann, und der llmeu-Block jeder Antwort sagt, was tatsächlich geschah.