AuxData → OpenAI Adapter
Vom "Was ist eine API?" zum lauffähigen Adapter, der AuxData für das gesamte OpenAI-Ökosystem öffnet.
Worum es geht
Dieses Tutorial bringt dich Schritt für Schritt von absoluten API-Grundlagen bis zu einem funktionierenden Adapter, der die AuxData-API in einem OpenAI-kompatiblen Format ausliefert. Jede Stufe baut auf der vorherigen auf — Stufen 1–5 sind theoretische Grundlagen, Stufen 6–9 konzentrieren sich auf den Adapter selbst.
Klick auf eine Karte unten, um zu starten — oder benutz die Sidebar zum freien Navigieren.
Quellen und Stand
Das Tutorial stützt sich auf die folgenden offiziellen Quellen. Stand der Prüfung: 28.05.2026.
- OpenAPI Specification: spec.openapis.org/oas/latest
- Learn OpenAPI: learn.openapis.org
- Swagger Tool-Doku: swagger.io/docs
- AuxData Swagger JSON: auxdata.ai/swagger/doc.json (abgerufen 28.05.2026)
- AuxData Swagger UI: auxdata.ai/swagger/index.html
- AuxData Administrator-Handbuch (lokales PDF, Stand 24.04.2026), insbesondere Kap. 4 Wissensdatenbank, Kap. 5 AI-Services, Kap. 15 Public REST API
- AuxData Benutzerhandbuch (lokales PDF, Stand 24.04.2026)
- AuxData "Integration in MS Teams" (lokales PDF, Stand 22.04.2026)
- OpenAI Chat Completions: platform.openai.com/docs/api-reference/chat
- OpenAI Responses API: platform.openai.com/docs/api-reference/responses
- OpenAI Streaming Guide: platform.openai.com/docs/guides/streaming-responses
Was ist eigentlich eine API?
Bevor du irgendetwas anderes verstehst, brauchst du ein Bauchgefühl für diesen einen Begriff.
1Die Grundidee
Eine API ist im Kern eine vereinbarte Sprache zwischen zwei Programmen. Mehr nicht.
Stell dir vor, zwei Menschen sprechen unterschiedliche Muttersprachen. Damit sie sich verstehen, einigen sie sich vorher auf eine gemeinsame Sprache und auf bestimmte Sätze, die immer dieselbe Bedeutung haben. Bei Programmen ist das genauso: das eine fragt etwas an, das andere antwortet — und beide haben sich vorher auf ein Format geeinigt.
Das war's auf der konzeptionellen Ebene. Alles, was jetzt kommt, sind nur Details: wie sie sprechen, worüber sie sprechen, und wer darf was sagen.
2Web-API: Sprechen übers Internet
Eine Web-API ist eine API, bei der die zwei Programme über das Internet miteinander reden — meist per HTTP, demselben Protokoll, das auch dein Browser benutzt.
Der Client schickt eine HTTP-Anfrage an eine URL. Der Server empfängt sie und schickt eine HTTP-Antwort zurück.
3Die vier wichtigsten Methoden
Jede HTTP-Anfrage hat eine Methode. Du brauchst nur diese vier:
Frage stellen → GET. Etwas erschaffen oder Aktion auslösen → POST.
4Aufbau einer HTTP-Anfrage
Vier Teile. Wenn du diese verstehst, kannst du jede API benutzen.
Content-Type: application/json
Status-Codes, die du dir merken solltest:
200— Alles gut.400— Anfrage war kaputt.401— Token ungültig.404— Nicht gefunden.500— Server-Fehler.
5Probier es aus
Klick durch und sieh, was bei verschiedenen Anfragen passiert.
6Selbsttest
✓ Was du jetzt können solltest
JSON lesen können
Das Format, in dem APIs ihre Daten austauschen. Klingt mysteriös, ist aber lächerlich einfach.
1Die Grundidee
JSON ist einfach Text in einer bestimmten Form. Mehr nicht.
Der Name steht für "JavaScript Object Notation", aber das musst du nicht merken. Es ist nur eine Konvention, wie man Daten so aufschreibt, dass jedes Programm sie versteht.
aus Berlin,
spricht Deutsch und Englisch.
"name": "Florian",
"alter": 32,
"stadt": "Berlin",
"sprachen": ["de", "en"]
}
2Zwei Bausteine — mehr gibt es nicht
JSON kennt zwei Strukturen: das Objekt und das Array.
{ "name": "Berlin", "land": "DE" }
Eine Sammlung von benannten Eigenschaften. Wie ein Steckbrief.
[ "Berlin", "Hamburg", "München" ]
Eine geordnete Liste. Wie eine Einkaufsliste.
{ } = einzelnes "Ding" mit Eigenschaften. [ ] = mehrere "Dinge" hintereinander.3Die Datentypen
Sechs Werttypen, mehr braucht JSON nicht.
Wichtig: Strings stehen immer in Anführungszeichen, Zahlen nie. "42" und 42 sind in JSON zwei verschiedene Dinge.
4Verschachtelung
Objekte können Arrays enthalten, Arrays können Objekte enthalten, und das beliebig tief.
5Ein echtes Beispiel: AuxData
Das hier ist ein ChatCommand aus dem AuxData-Swagger.
{ "question": "Wie ist das Wetter in Berlin?", "comuuid": "abc-123-def", "stream": true, "anonymize": false, "answerMode": 2, "usePersonalKnowledgeDb": false, "files": [], "usermail": "florian@example.com" }
In Worten gelesen: Ein Objekt mit acht Eigenschaften. Eine Frage als Text, eine Konversations-ID, ein Flag ob gestreamt werden soll, ein Antwortmodus als Zahl, eine leere Datei-Liste, eine User-E-Mail.
6Die häufigsten Stolperfallen
JSON ist streng. Diese drei Fehler passieren jedem Anfänger.
Fehler 1: Was stimmt hier nicht?
Fehler 2: Was stimmt hier nicht?
Fehler 3: Was stimmt hier nicht?
"), und Booleans heißen true/false (klein geschrieben).7Selbsttest
✓ Was du jetzt können solltest
Deine erste echte API-Anfrage
Der Moment, in dem es klickt. Du fasst zum ersten Mal eine echte API an.
1Warum diese Stufe so wichtig ist
Bis hierhin war alles abstrakt. Jetzt baust du eine HTTP-Anfrage zusammen, drückst auf "Send", und siehst eine echte Antwort zurückkommen.
2Welches Tool?
Drei sinnvolle Optionen. Für den Anfang empfehle ich Postman.
3So sieht Postman aus
Vereinfachte Nachbildung der Oberfläche. Klick durch die Reiter und drück "Send".
(Kein Body bei GET-Anfragen nötig.)
Die drei wichtigsten Teile: Methode (Dropdown), URL (Mitte), Send-Knopf. Headers und Body sind separate Reiter. Antwort landet ganz unten.
4Übung 1: Eine öffentliche API anfassen
GitHub bietet eine API an, die jeder ohne Anmeldung benutzen darf.
- Postman öffnen. Account-Dialog überspringen ("Skip and go to the app").
- Neuer Tab mit dem
+-Knopf. - Methode auf
GETlassen. - URL eingeben:
https://api.github.com/users/octocat - Auf Send klicken.
- Unten erscheint die Antwort. Oben rechts siehst du
200 OK.
octocat gegen einen anderen GitHub-Username. Oder probier /users/octocat/repos.5Übung 2: AuxData mit Bearer-Token
Eine API, die Authentifizierung verlangt. Genau das brauchst du später für den Adapter.
Voraussetzung: AuxData-Agent-UUID-Token (siehe AuxData-Admin-Backend, Kapitel 15) und Agent-ID. Achtung: der Token muss für die Fähigkeit "Chat" explizit zur externen Nutzung freigegeben sein — sonst bekommst du 401.
- Neuen Tab in Postman öffnen.
- Methode auf POST umstellen.
- URL:
https://auxdata.ai/api/v1/agent/{agentid}/chat—{agentid}durch deine Agent-ID ersetzen. - Reiter Authorization, Typ Bearer Token, Token eintragen.
- Reiter Body, dann raw + JSON.
- Body eingeben (minimal):
{ "question": "Hallo, was kannst du?", "comuuid": "" }
- Auf Send klicken.
- Bei Erfolg:
200 OKmit einemExecuteChatbotResult-JSON, das u.a.answer,comuuid(für Folge-Anfragen),sourcesundtokenusageenthält.
6Wenn etwas schiefgeht
Die häufigsten Antworten und was sie wirklich bedeuten.
Token fehlt oder ist falsch. Prüfe das Feld und ob "Bearer" davor steht.
Body kaputt oder Pflichtfeld fehlt. Lies die Fehlermeldung im Response-Body.
URL falsch oder Ressource existiert nicht. Tippfehler? {agentid} ersetzt?
Fehler beim Server. Kurz warten und nochmal probieren.
Internet weg oder Server hängt. URL doppelt prüfen.
7Selbsttest
✓ Was du jetzt können solltest
Authentifizierung verstehen
Wer darf was? Das eine Konzept, das hinter fast jeder modernen API steckt — der Bearer-Token.
1Das Problem
Eine API ist eine offene Tür im Internet. Ohne Türsteher kann jeder reinspazieren, alles abfragen, alles ändern.
Authentifizierung ist die Antwort: jede Anfrage muss vorweisen, wer sie schickt — sonst lehnt der Server sie ab. Wie ein Ausweis am Empfang.
2Was ist ein Bearer-Token?
Ein Bearer-Token ist nichts weiter als ein langer, zufälliger String, der wie ein Passwort funktioniert.
"Bearer" heißt "Träger" — wer den Token besitzt, gilt als berechtigt. Wie ein Konzertticket: wer es vorzeigt, kommt rein.
Für dich nur ein Stück Text, das du nicht lesen musst. Behandle ihn wie ein Passwort: kopieren, einfügen, geheim halten.
sk-proj-abc123..., viele Identity-Provider liefern JWTs mit drei punktgetrennten Base64-Blöcken (eyJhbGc....eyJzdWI....SflKxw...). Aus deiner Sicht egal: kopieren, einfügen, hinter Bearer setzen, funktioniert.3So kommt er in die Anfrage
Der Token wandert im Authorization-Header mit, in einer bestimmten Form:
Drei Teile: der Header-Name (Authorization), das Schlüsselwort Bearer mit Leerzeichen, und der eigentliche Token.
Probier es aus:
4Woher kommt der Token?
Tokens haben einen Lebenszyklus.
Wichtig: viele Dienste zeigen den Token nur ein einziges Mal beim Anlegen. Schließt du das Fenster ohne Kopie, ist er weg.
5Sicherheit — die wichtigsten Regeln
Ein Token ist wie ein Hausschlüssel. Verlierst du ihn, kann jeder ungefragt rein.
✓ Mach das
- Token in einer
.env-Datei speichern, nie im Code. .envin.gitignoreeintragen.- Pro Anwendung einen eigenen Token erstellen.
- Bei Leck: sofort widerrufen und neuen erstellen.
- Nur server-seitig benutzen — nie im Browser-JS.
✗ Mach das nicht
- Tokens in Git-Repos einchecken. Auch nicht in privaten.
- Tokens in Screenshots, Chats, Tickets teilen.
- Tokens in Frontend-Code (HTML/JS) verwenden.
- Tokens in Logs schreiben — auch nicht "kurz zum Debuggen".
- Denselben Token in Produktion und Test verwenden.
6Andere Auth-Methoden zum Wiedererkennen
Nicht im Detail können, aber wiedererkennen.
X-API-Key oder als URL-Parameter.Authorization: Basic dXNlcjpwYXNz. Altmodisch, aber noch verbreitet.Für deinen AuxData → OpenAI Adapter ist nur Bearer-Token relevant.
HTTP 401 bekommst, obwohl der Token korrekt ist, fehlt entweder die externe Freigabe oder du benutzt den Token einer anderen Fähigkeit.7Selbsttest
✓ Was du jetzt können solltest
Swagger / OpenAPI lesen
Das Dokument, das jede API komplett beschreibt — und das du selbst lesen können wirst.
1Die Grundidee: eine Speisekarte für die API
Ein Swagger-Dokument ist eine maschinenlesbare Speisekarte: "Diese URLs gibt es, das musst du schicken, das kommt zurück."
2Swagger vs. OpenAPI — kurz aufgeräumt
Die Begriffe werden ständig vermischt.
OpenAPI ist heute der offizielle Name der Spezifikation — also die Regeln, wie eine API-Beschreibung aussehen muss. Swagger ist im modernen Sprachgebrauch eher der Sammelname für Werkzeuge, die OpenAPI-Dateien anzeigen, bearbeiten oder daraus Code erzeugen — Swagger UI, Swagger Editor, Swagger Codegen.
Die aktuelle Version der Spezifikation ist OpenAPI 3.2.0 (Release 19.09.2025, Quelle: spec.openapis.org/oas/latest). In der Praxis triffst du aber häufig noch ältere Versionen — Swagger 2.0, OpenAPI 3.0 oder 3.1. Beim Lesen schaust du in das Feld "openapi" oder "swagger" ganz am Anfang des Dokuments.
"swagger": "2.0" am Anfang).3Die Hauptbestandteile
Fünf Hauptabschnitte, immer dieselben.
auxdata.ai + /api/v1.components/schemas. JSON-Baupläne wie ChatCommand.4Einen Endpunkt lesen — Zeile für Zeile
Ausschnitt aus dem AuxData-Swagger. Klick auf jede Zeile.
5Was bedeutet $ref?
Der einzige "fortgeschrittene" Trick. Eine $ref ist eine Referenz auf eine andere Stelle im selben Dokument.
Klick auf die unterstrichene Referenz:
Jedes Mal, wenn du $ref siehst, schlägst du in definitions nach.
6Drei kleine Begriffe
Diese Wörter tauchen ständig auf.
required: true — das Feld muss mitgeschickt werden.
enum: ["A", "B", "C"] — das Feld darf nur einen dieser Werte haben.
"in": "path" / "body" / "header" / "query" — sagt, wo der Parameter hingehört (URL-Platzhalter, JSON-Body, HTTP-Header, URL-Parameter).
7Selbsttest
✓ Was du jetzt können solltest
OpenAI Chat Completions verstehen
Die andere Seite deines Adapters — und ab jetzt wird alles ganz konkret.
1Worum es geht
Für deinen Adapter zählt vor allem Chat Completions — weil viele Tools (LangChain, LiteLLM, Open WebUI, die meisten SDKs) genau diesen Endpoint erwarten. Dein Adapter soll kompatibel sein, nicht die neueste OpenAI-API nachbauen.
OpenAI selbst empfiehlt für neue, native Projekte inzwischen die modernere Responses API. Die ist anders aufgebaut und passt besser zu Tools wie Agents und der Verarbeitung von Bildern/Audio. Für reine Adapter-Kompatibilität bleibt Chat Completions aber der relevante Standard.
POST https://api.openai.com/v1/chat/completions. Genau diesen URL-Pfad bietest du in deinem Adapter selbst an.POST /v1/chat/completionsRequest:
messages als ListeResponse:
choices[0].message.content→ Kompatibilität mit Tooling
POST /v1/responsesRequest:
inputResponse:
output (SDKs bieten oft output_text als Komfortzugriff)→ neue OpenAI-native Projekte
2Der Trick: Nachrichten als Liste
OpenAI denkt einen Chat als Liste von Nachrichten. Jede Nachricht hat eine Rolle und einen Inhalt.
Wichtig: bei jeder neuen Frage schickt der Client die ganze Liste wieder mit. OpenAI hat selbst kein Gedächtnis. Zentraler Unterschied zu AuxData.
system oft die Rolle developer verwendet — funktional dasselbe (Anweisung an das Modell), nur anderer Name. Du kannst in der Praxis beide vorfinden.3Eine komplette Anfrage
Vollständiger Request an OpenAI. Versuch ihn zu lesen, bevor du weitermachst.
POST https://api.openai.com/v1/chat/completions Authorization: Bearer sk-abc... Content-Type: application/json { "model": "gpt-4o-mini", "messages": [ { "role": "system", "content": "Du bist hilfsbereit." }, { "role": "user", "content": "Wie ist das Wetter in Berlin?" } ], "temperature": 0.7, "stream": false }
Drei Pflichtfelder: model, messages, Bearer-Token im Header. Der Rest ist optional.
4Die Antwort lesen
Klick auf jede Zeile.
Meistens interessiert dich nur choices[0].message.content. Das ist die Antwort der KI.
5OpenAI vs. AuxData — direkt nebeneinander
Hier siehst du, warum du den Adapter brauchst.
{ "model": "gpt-4o-mini", "messages": [ { "role": "user", "content": "Hallo!" } ], "stream": false }
{ "question": "Hallo!", "comuuid": "", "stream": false }
model: "gpt-4o-mini"/agent/42messages: [...]question: "..."comuuidchoices[0].message.contentanswerusage.{prompt,completion,total}_tokenstokenusagesourcescontent anhängen.6Streaming — was das eigentlich ist
Wenn ChatGPT seine Antwort Wort für Wort tippt — das ist Streaming.
Statt einer fertigen JSON-Antwort sendet der Server viele kleine Häppchen über die Zeit verteilt. Der Client zeigt sie sofort an.
Technisch: Server-Sent Events (SSE). Jedes Häppchen kommt als data: {...}\n\n. Am Ende data: [DONE].
7Selbsttest
✓ Was du jetzt können solltest
Was ein Proxy / Adapter ist
Der Übersetzer in der Mitte. Hier verbinden sich alle bisherigen Stücke zu einem Bild.
1Der Dolmetscher am Telefon
Zwei Menschen telefonieren, sprechen aber verschiedene Sprachen. In der Mitte sitzt ein Dolmetscher. Er hört, übersetzt, gibt weiter — in beide Richtungen.
Beide Seiten denken, sie reden direkt miteinander. Tatsächlich reden sie nur mit dem Dolmetscher.
2Wo der Adapter sitzt
Dein Adapter ist ein eigenes kleines Programm mit eigener URL.
OpenAI-Format
localhost:8000
AuxData-Format
Der Trick: dein Adapter bietet eine URL an, die aussieht wie OpenAI — http://localhost:8000/v1/chat/completions. Der Client merkt davon nichts.
3Was im Adapter wirklich passiert
Hier ist der komplette Ablauf in fünf Schritten:
{ "model": "auxdata-agent-42", "messages": [...] }
model wird die Agent-ID, aus messages wird question.Authorization: Bearer 00000000-0000-0000-0000-000000000000
answer wird choices[0].message.content.Drei Schritte (1, 3, 5) sind reines Weiterleiten. Die eigentliche Arbeit steckt in Schritt 2 und 4: übersetzen.
Live-Vorschau: Klick auf "Animation starten" und beobachte, wie ein Request durch den Adapter wandert und sich verwandelt.
4Wie das im Code aussieht
Vollständiger Adapter, vereinfacht in Pseudo-Code. Etwa 25 Zeilen.
5Das knifflige Teil: Konversations-State
OpenAI ist zustandslos, AuxData merkt sich Konversationen per comuuid. Diesen Gap musst du im Adapter überbrücken.
Anfrage 1: { "messages": [{ "role": "user", "content": "Hallo!" }] } Anfrage 2: { "messages": [ { "role": "user", "content": "Hallo!" }, { "role": "assistant", "content": "Hallo, wie kann ich helfen?" }, { "role": "user", "content": "Was kannst du?" } ] }
Für AuxData soll Anfrage 2 in derselben Konversation wie Anfrage 1 weiterlaufen. Lösung: ein Hash über die ersten N Messages dient als Schlüssel in einer Map.
comuuid bei AuxData (laut Administrator-Handbuch): Bei einer neuen Konversation schickst du "comuuid": "" (leer). AuxData generiert dann eine UUID und gibt sie in der Antwort zurück. Für jede Folge-Anfrage musst du genau diese UUID wieder im Request mitsenden — sonst gilt es als neue Konversation und der Kontext geht verloren.6Warum dieser Ansatz so mächtig ist
Mit deinem Adapter öffnest du AuxData für das gesamte OpenAI-Ökosystem.
7Selbsttest
✓ Was du jetzt können solltest
Echten Code lesen
Du musst nichts tippen. Nur einen fertigen FastAPI-Adapter lesen und verstehen — Block für Block.
1Warum Python und FastAPI?
FastAPI-Code liest sich fast wie Konfiguration. Wenig Zeremoniecode, viel Logik.
Python ist die verbreitetste Sprache für KI-/API-Arbeit. Riesige Mengen an Tutorials und Code-Beispielen.
2Die wichtigsten Python-Vokabeln
Sechs Begriffe, die du brauchst.
def chat(): beginnt eine Funktion namens "chat".await macht das explizit.question: str heißt: das Feld ist ein String.3Voraussetzungen
Drei Dinge. Nur zur Übersicht.
pip install fastapi uvicorn httpx
adapter.py anlegen mit dem Code unten.Gestartet mit uvicorn adapter:app --reload — läuft auf http://localhost:8000.
4Der komplette Adapter — Block für Block
~90 Zeilen, in sechs Blöcken. Erst Code, dann Erklärung.
from fastapi import FastAPI, HTTPException from pydantic import BaseModel import httpx import hashlib import os import time import uuid # Token aus Environment-Variable lesen — niemals hartcodieren AUXDATA_TOKEN = os.environ.get("AUXDATA_TOKEN") AUXDATA_BASE = "https://auxdata.ai/api/v1" app = FastAPI() conversation_map: dict[str, str] = {} # DEMO-STATE: nur im Speicher @app.on_event("startup") async def _check_config(): if not AUXDATA_TOKEN: raise RuntimeError("AUXDATA_TOKEN env var missing — siehe README.")
Sicherheit: Der Token wird per
os.environ.get(...) gelesen (gibt None wenn nicht gesetzt). Der Startup-Hook stoppt den Server mit einer sauberen Fehlermeldung statt mit kryptischem KeyError beim Import. Wer den Adapter startet, weiß sofort was los ist.class Message(BaseModel): role: str content: str class ChatRequest(BaseModel): model: str messages: list[Message] stream: bool | None = False
Hinweis: Wir deklarieren nur die Felder, die wir wirklich an AuxData durchreichen.
temperature, top_p etc. werden vom OpenAI-Client gerne mitgeschickt, sind aber für unseren Adapter im Moment irrelevant — Pydantic ignoriert unbekannte Felder still. Modernes Python ≥3.10 nutzt list[X] und X | None statt List[X]/Optional[X].def parse_agent_id(model: str) -> int: # Erwartet exakt "auxdata-agent-42" → 42. Alles andere ist ein Client-Fehler. prefix = "auxdata-agent-" if not model.startswith(prefix): raise HTTPException( status_code=400, detail=f"Unbekannter Modell-Name: {model!r}. Erwartet: 'auxdata-agent-<id>'." ) try: return int(model.removeprefix(prefix)) except ValueError: raise HTTPException( status_code=400, detail=f"Unbekannter Modell-Name: {model!r}. Erwartet: 'auxdata-agent-<id>'." ) def _conversation_key(messages: list[Message]) -> str: # DEMO-Implementierung. Nicht produktionsreif: # Whitespace-/Autocorrect-Änderungen im ersten User-Turn brechen den Key. # Für echten Einsatz: stabilen Fingerprint (z.B. erste User-Message normalisiert) # oder einen explizit vom Client mitgegebenen session_id-Header verwenden. fingerprint = messages[0].content if messages else "" return hashlib.sha256(fingerprint.encode()).hexdigest() def get_comuuid(messages: list[Message]) -> str: return conversation_map.get(_conversation_key(messages), "") def save_comuuid(messages: list[Message], comuuid: str) -> None: conversation_map[_conversation_key(messages)] = comuuid
parse_agent_id: aus "auxdata-agent-42" wird 42. Bei unbekanntem Format → sauberer 400-Fehler statt kryptischem 500._conversation_key: macht einen SHA-256 über die erste User-Message als Konversations-Fingerabdruck.get_comuuid/save_comuuid: lesen/schreiben die comuuid unter diesem Key.
@app.post("/v1/chat/completions") async def chat_completions(request: ChatRequest): # 1) Daten aus dem OpenAI-Request extrahieren if not request.messages: raise HTTPException(400, "messages darf nicht leer sein") agent_id = parse_agent_id(request.model) user_msg = request.messages[-1].content comuuid = get_comuuid(request.messages) # 2) AuxData-Request bauen aux_payload = { "question": user_msg, "comuuid": comuuid, "stream": False }
@app.post(...) empfängt OpenAI-Requests. Drinnen: Agent, User-Nachricht, comuuid rausziehen, AuxData-Payload bauen.# 3) AuxData aufrufen headers = {"Authorization": f"Bearer {AUXDATA_TOKEN}"} url = f"{AUXDATA_BASE}/agent/{agent_id}/chat" async with httpx.AsyncClient() as client: aux_response = await client.post( url, json=aux_payload, headers=headers, timeout=60 ) if aux_response.status_code != 200: raise HTTPException( status_code=aux_response.status_code, detail=f"AuxData error: {aux_response.text}" ) aux_data = aux_response.json()
await), bei Fehler weiterleiten, sonst JSON parsen.# 4) comuuid speichern if aux_data.get("comuuid"): save_comuuid(request.messages, aux_data["comuuid"]) # 5) OpenAI-Response zurückbauen token_usage = aux_data.get("tokenusage", {}) return { "id": f"chatcmpl-{uuid.uuid4().hex[:24]}", "object": "chat.completion", "created": int(time.time()), "model": request.model, "choices": [{ "index": 0, "message": { "role": "assistant", "content": aux_data.get("answer", "") }, "finish_reason": "stop" }], "usage": { "prompt_tokens": token_usage.get("inputtokensum", 0), "completion_tokens": token_usage.get("outputtokensum", 0), "total_tokens": token_usage.get("tokensum", 0) } }
aux_data["answer"] → choices[0].message.content. Token-Stats umbenennen. Hinweis: Die exakten Feldnamen von TokenUsageStats (inputtokensum, outputtokensum, tokensum) sind in den Handbüchern nicht dokumentiert — gleiche sie vor dem Produktiveinsatz gegen das Swagger-Schema (/swagger/index.html) ab, sonst stehen die Token-Zahlen still auf 0.5Was du anpassen musst
Drei Stellen sind individuell.
Erstens, dein Bearer-Token als Environment-Variable: export AUXDATA_TOKEN="deine-uuid-hier" (Linux/Mac) bzw. $env:AUXDATA_TOKEN="..." (PowerShell). Erst dann uvicorn adapter:app starten.
Zweitens, das Modell-Naming-Schema. Code erwartet "auxdata-agent-42". Anpassbar in parse_agent_id — und bitte mit Fehlerbehandlung, damit ein unbekannter Modell-Name nicht in einer kryptischen ValueError-Fehlermeldung endet.
Drittens, der Port. Default 8000. Anders mit --port 9000.
{ "error": { "message": "...", "type": "..." }}), CORS-Header für Browser-Clients und echtes Streaming.6Wo der Code (noch) nicht reicht
Funktionierende Skizze. Für Produktion fehlen drei Dinge:
Streaming. Aktuell hartcodiert "stream": False. Stufe-9-Thema.
Robustes Error-Handling. Bei Netzwerk-Timeout crasht der Code. try/except drumherum.
Skalierbarer State. conversation_map lebt im Speicher. Bei Restart weg. Lösung: SQLite oder Redis.
7Selbsttest
✓ Was du jetzt können solltest
Streaming, Fehler und State
Die drei Themen, die deinen Adapter produktionsreif machen.
1Was diese Stufe abdeckt
Der Code aus Stufe 8 funktioniert, hat aber drei Lücken.
Wir gehen sie nacheinander an: Streaming, Fehler-Handling, persistenter State. Plus kleine Polierungen.
2Streaming — Antworten in Häppchen
Bei "stream": true antwortet der Server nicht mit einem JSON, sondern schickt viele kleine SSE-Events.
Jede Zeile beginnt mit data: gefolgt von einem JSON-Stück mit delta.content. Am Ende data: [DONE].
/v1/chat/completions als auch die neuere /v1/responses aktivieren Streaming über "stream": true. Das Transport-Format (Server-Sent Events) ist in beiden Fällen identisch — nur die Payload-Felder unterscheiden sich.Drei Fälle, die du im Adapter behandeln kannst:
Fall A — Kein Streaming. Client schickt "stream": false (oder gar nicht). Adapter wartet, bis AuxData fertig ist, und gibt die komplette Antwort als JSON zurück. Einfachste Variante, funktioniert immer.
Fall B — Fake-Streaming aus fertigem Text. Du holst die fertige Antwort von AuxData, zerlegst sie selbst in Wort-Häppchen und schickst sie als SSE — der Nutzer sieht eine "tippende" Antwort, obwohl der Server bereits fertig war. Code dafür (nur für UI-Gefühl, kein echter Latenz-Vorteil):
# Fall B: Fake-Streaming aus fertigem Text import asyncio, json from fastapi.responses import StreamingResponse async def fake_stream(text: str): for word in text.split(): chunk = {"choices": [{"delta": {"content": word + " "}}]} yield f"data: {json.dumps(chunk)}\n\n" await asyncio.sleep(0.05) yield "data: [DONE]\n\n"
Fall C — Echtes Streaming von AuxData zu OpenAI. Du setzt selbst "stream": true in der AuxData-Anfrage, liest dann den eingehenden SSE-Stream, parst jede data:-Zeile, ignorierst Leerzeilen und [DONE], und rechnest die kumulativen Snapshots in Deltas um (Code dafür im nächsten Callout). Das ist die "richtige" Variante mit echtem Latenz-Vorteil.
delta.content). AuxData sendet laut Administrator-Handbuch Kap. 15.3.3 pro Event ein komplettes, JSON-serialisiertes ExecuteChatbotResult. Sehr wahrscheinlich wächst dessen answer-Feld dabei kumulativ (jedes Event enthält den vollständigen bisherigen Text) — das Handbuch sagt das aber nicht explizit, also prüfe es einmal gegen deine Instanz. Trifft die Annahme zu und reichst du die Events 1:1 als OpenAI-Deltas durch, sieht der Nutzer die Antwort doppelt, dreifach, vierfach.Konkret: AuxData antwortet mit Content-Type: text/event-stream und einer Folge von data: { ... }-Zeilen, deren JSON-Inhalt jeweils ein vollständiges ExecuteChatbotResult ist (mit answer, comuuid, sources, state, …). Dein Adapter muss daraus die Differenz zum vorherigen Stand bilden und nur diese als OpenAI-Delta weiterleiten:
# Fall C: echtes AuxData-SSE zu OpenAI-SSE import json async def translate_aux_stream(aux_lines): last_answer = "" async for raw in aux_lines: line = raw.strip() # Leerzeilen und Keep-Alive-Kommentare ignorieren if not line or line.startswith(":"): continue if not line.startswith("data:"): continue payload = line[5:].strip() if payload == "[DONE]": break try: aux_data = json.loads(payload) except json.JSONDecodeError: continue full_answer = aux_data.get("answer", "") or "" # Nur das NEUE Stück gegenüber dem letzten Snapshot weitergeben delta = full_answer[len(last_answer):] last_answer = full_answer if delta: chunk = {"choices": [{"delta": {"content": delta}}]} yield f"data: {json.dumps(chunk)}\n\n" yield "data: [DONE]\n\n"
Quelle: Administrator-Handbuch Kap. 15.3.3
3Fehler-Handling
Jeder Fehler von AuxData muss in einen OpenAI-Fehler übersetzt werden.
{ "code": 401, "message": "Token invalid", "service": "agent.chat" }
{ "error": { "message": "Token invalid", "type": "invalid_request_error", "code": "invalid_api_key" } }
Im FastAPI-Code mit try/except:
try: async with httpx.AsyncClient() as client: aux_response = await client.post(url, json=aux_payload, headers=headers, timeout=60) aux_response.raise_for_status() except httpx.TimeoutException: raise HTTPException(504, "AuxData hat nicht geantwortet.") except httpx.HTTPStatusError as e: raise HTTPException(e.response.status_code, e.response.text) except Exception as e: raise HTTPException(500, f"Interner Fehler: {e}")
4State, der einen Neustart überlebt
Die conversation_map lebt aktuell im Speicher. Für Produktion: was Robusteres.
Für den Anfang reicht SQLite:
import sqlite3 conn = sqlite3.connect("state.db") conn.execute("""CREATE TABLE IF NOT EXISTS conversations (hash TEXT PRIMARY KEY, comuuid TEXT)""") def get_comuuid(messages): key = hash_messages(messages) row = conn.execute( "SELECT comuuid FROM conversations WHERE hash = ?", (key,) ).fetchone() return row[0] if row else "" def save_comuuid(messages, comuuid): key = hash_messages(messages) conn.execute( "INSERT OR REPLACE INTO conversations VALUES (?, ?)", (key, comuuid) ) conn.commit()
5Drei kleine Verbesserungen
Keine Pflicht, aber jede 15 Minuten Arbeit.
Ein /v1/models-Endpoint.
@app.get("/v1/models") def list_models(): return {"object": "list", "data": [ {"id": "auxdata-agent-42", "object": "model", "owned_by": "auxdata"} ]}
Eigene API-Keys ausgeben. Damit kannst du Keys einzelner Nutzer widerrufen.
Logging. Jede Anfrage, Status-Code, Antwortzeit. Rettet dir bei Problemen den Tag.
6Was kommt nach Stufe 9?
Dein konkreter Fahrplan für die nächsten Tage:
uvicorn starten.localhost:8000/v1/chat/completions.7Selbsttest
✓ Was du jetzt können solltest
8Du bist durch
Vor neun Stufen wusstest du nicht genau, was eine API ist. Jetzt hast du einen kompletten mentalen Bauplan im Kopf.
Glückwunsch — Stufen 1 bis 9 geschafft
Du verstehst HTTP, JSON, Swagger, Authentifizierung, OpenAI- und AuxData-Format, das Adapter-Konzept, kannst echten Python-Code lesen und kennst die kniffligen Themen.
Mehr als Chat — AuxData als Plattform
Optionaler Ausblick. Nicht prüfungsrelevant für Quiz und Zertifikat — der Kernkurs ist mit Stufe 9 abgeschlossen.
1Worum es hier geht
Den Adapter aus Stufen 1–9 baust du um POST /agent/{id}/chat herum. Das ist der wichtigste Endpunkt für OpenAI-Kompatibilität — aber er nutzt nur einen Bruchteil der Plattform.
AuxData ist kein reines Chat-Backend, sondern eine komplette KI-Plattform mit Wissensdatenbank, Agenten-Konfiguration, AI-Services, Workflow-Engine und Integrationen. Dieses Bonusmodul zeigt, welche Plattformthemen daneben existieren — als grobe Landkarte, nicht als Bauanleitung.
2Die sieben Public-API-Endpunkte
Komplette Übersicht, was AuxData von außen anbietet:
POST /agent/{id}/chatPOST /agent/{id}/container/{cid}/chatPOST /agent/{id}/documentPOST /agent/{id}/container/{cid}/documentPUT /agent/{id}/container/{cid}/documentPUT /agent/{id}/container/{cid}/document/enhancedPOST /agent/{id}/executeservice/{sid}Alle Endpunkte erwarten Authorization: Bearer <token>, und die Fähigkeit muss im AuxData-Backend pro Agent für externen Zugriff freigegeben sein.
3Wissensdatenbank: Container, Upload, RAG
Das eigentliche Herz der Plattform — und der Grund, warum Chat-Antworten kontextuell sind.
Container sind das Organisationsprinzip der Wissensdatenbank: jeder Agent kann mehrere Container haben, die thematisch trennbar sind ("FAQ", "Produkt-Doku", "Verträge", …). Beim Chatten kannst du dich entweder gegen alle Container gleichzeitig oder gezielt gegen einen einzigen wenden.
Drei Upload-Wege ins Wissen (laut Admin-Handbuch Kap. 4.2):
- • Datei hochladen — PDF, DOCX, TXT etc. werden gechunkt und vektorisiert
- • URL (Web-Crawler) — eine Webseite wird gecrawlt und ins Wissen übernommen
- • Text direkt eingeben — Inhalte ohne Quelldatei
AuxData geht über klassisches RAG hinaus mit LightRAG — Entitäten und Relationen werden erkannt und als Wissensgraph gespeichert (Admin-Handbuch Kap. 4.7). Dadurch werden komplexere Fragen mit Quervernetzung möglich.
PUT /agent/{id}/container/{cid}/document lädst du Dokumente programmatisch hoch. Damit kannst du z.B. einen Workflow bauen, der eingehende E-Mails automatisch in eine Wissens-Container kippt — und ein Chatbot kann sofort darauf antworten.4AI Services: vorgefertigte Workflows
AuxData kennt nicht nur "Chat" als Modus, sondern auch AI-Service-Modus — vorkonfigurierte Workflows mit festen Eingaben und festem Output.
Beispiele aus der Praxis (laut Produktseite und Benutzerhandbuch):
- • Stellenanzeige generieren — Eingaben: Position, Anforderungen, Tonalität
- • Bewerberauswertung — Eingabe: CV-Datei, Output: strukturierte Bewertung
- • Support-Antwort vorformulieren — Eingabe: Kundenanfrage, Output: Antwortentwurf
- • Belegerkennung — PDF-Upload → strukturierte Stammdaten
Per POST /agent/{id}/executeservice/{sid} startest du einen Service mit einem Parameter-Dictionary. Die Antwort enthält das fertige Ergebnis plus Token-Verbrauch.
Wiederkehrende Services (laut Benutzerhandbuch Kap. 7) können sogar mit einem Intervallplan regelmäßig automatisch ausgeführt werden — z.B. ein täglicher Marktreport oder eine wöchentliche Datenbereinigung.
5Multimodale Antworten
Das ExecuteChatbotResult hat nicht nur ein Text-Feld — es kann auch Bilder, Audio und Video enthalten.
{ "answer": "Hier ist das Diagramm dazu:", "images": ["https://...", "data:image/png;base64,..."], "videos": ["https://..."], "audio": ["https://..."], "sources": [ ... ], "tokenusage": { ... } }
OpenAI Chat Completions hat dafür kein direktes Pendant in der Standard-Antwort. In deinem Adapter könntest du:
- • Bild-URLs als Markdown-Bilder (
) anscontent-Feld hängen - • Audio/Video als verlinkte URLs anhängen
- • Oder ein nicht-standardisiertes
aux_media-Feld mitliefern (Clients ignorieren unbekannte Felder)
6Plattform-Features hinter den Kulissen
Features, die der Adapter nicht direkt sieht — aber die das Verhalten von AuxData prägen.
Anonymisierung (im ChatCommand per anonymize: true) ersetzt vor dem LLM-Aufruf personenbezogene Daten durch Platzhalter. Wichtig für DSGVO-konformen Einsatz auch mit Modellen, die außerhalb der EU laufen.
Persönliche Wissensdatenbank — jeder Nutzer kann eigene Dokumente ablegen, die nur er sieht. Per usePersonalKnowledgeDb: true wird sie in eine Chat-Anfrage einbezogen.
Globaler Bot mit Agentensuche (Benutzerhandbuch Kap. 3.5.1) — ein Meta-Bot, der erst herausfindet, welcher Agent für eine Frage am besten passt, und die Anfrage dorthin routet. Praktisch, wenn Nutzer nicht wissen sollen, welcher Bot was kann.
Mehrere Modellanbieter wählbar — pro Agent oder pro AI-Service konfigurierbar. Ein und derselbe Endpunkt kann je nach Konfiguration unterschiedliche LLM-Provider ansprechen (GPT, Claude, Mistral, lokale Modelle). Die konkrete Anzahl unterstützter Modelle steht im Admin-Handbuch Kap. 10.
Internet Live Suche (per internetsearch-Modus im Chat-Request) kombiniert RAG-Wissen mit Echtzeit-Web-Suche.
7Integrationen mit Drittsystemen
AuxData ist nicht nur API — es lässt sich auch direkt in bestehende Tools integrieren.
Microsoft Teams — der AuxData-Chatbot kann als Teams-App eingebunden werden. Nutzer chatten direkt in Teams mit dem Bot, ohne in die AuxData-Oberfläche wechseln zu müssen. Setup läuft über Azure App Registration plus Manifest-Datei. (Eigene Integrations-Doku, Stand 22.04.2026.)
Microsoft 365 / Filesync — Konnektoren synchronisieren Dokumente aus OneDrive/SharePoint/Outlook automatisch in AuxData-Container. So bleibt das Wissen aktuell, ohne dass jemand händisch hochladen muss.
MCP (Model Context Protocol) — ein offenes Protokoll, über das LLMs auf standardisierte Tools, Prompts und Ressourcen zugreifen. Laut Administrator-Handbuch Kap. 7.3 („MCP-Server") fungiert AuxData dabei als MCP-Client: Du bindest externe MCP-Server an und machst deren Tools in Workflows nutzbar, ohne eigene Adapter zu bauen. Für dieses Tutorial reicht die Abgrenzung: Der OpenAI-kompatible Adapter macht AuxData für Chat-Clients nutzbar; MCP bindet umgekehrt fremde Tools in AuxData ein. Details gehören in ein separates Integrationsmodul mit eigenen Quellen — die offizielle MCP-Spezifikation und AuxDatas konkrete Implementierung sollten dort frisch geprüft werden.
HTTP-Services & Function-Calls — ein späteres Integrationsmodul kann zeigen, wie AuxData externe Dienste aufruft, Datenquellen einbindet und Funktionen in Workflows nutzt (Administrator-Handbuch Kap. 7). In diesem Adapter-Tutorial genügt der Merksatz: HTTP ist hier das Fundament, aber nicht jedes HTTP-Thema gehört in den Adapterkurs.
8Was du jetzt damit bauen könntest
Inspirations-Liste, nicht Bauanleitung. Jeder dieser Punkte braucht noch eigenes Setup, Integrationsarbeit und je nach Komplexität ein zusätzliches Tutorial. Aber das Wissen aus den Stufen 1–9 plus dem Plattform-Überblick reicht, um zu erkennen, welche Bausteine du jeweils brauchst.
/executeservice alle eigenen AI-Services als REST-Endpoints anbieten und an Drittsysteme andocken.✓ Was du jetzt zusätzlich weißt
Bereit für das Zertifikat?
13 Fragen aus allen neun Stufen. Bestanden ab 10 von 13 richtigen Antworten. Du kannst beliebig oft wiederholen.
Dein Abschluss-Zertifikat
Trag deinen Namen ein und lade das Zertifikat als PDF herunter oder drucke es direkt aus.
Tipp: Im Druck-Dialog deines Browsers wählst du als Drucker "Als PDF speichern" — damit bekommst du eine PDF-Datei statt eines gedruckten Blatts.
Das 9-Stufen-Tutorial vom API-Grundwissen zum lauffähigen Adapter
COMPLETION