9-Stufen-Tutorial

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.

Stufe 1 von 9

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.

💻
Dein Programm
"Gib mir Wetter Berlin"
"18°C, sonnig"
🖥️
Wetter-Server

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.

📱
Client
(z.B. dein Code)
GET /weather
{ "temp": 18 }
☁️
Server
(die API)

Der Client schickt eine HTTP-Anfrage an eine URL. Der Server empfängt sie und schickt eine HTTP-Antwort zurück.

Merke: Wenn du im Browser eine Seite aufrufst, machst du das Gleiche — nur dass der Browser dir das Ergebnis grafisch anzeigt.

3Die vier wichtigsten Methoden

Jede HTTP-Anfrage hat eine Methode. Du brauchst nur diese vier:

GET
Hol mir etwas.
"Gib mir Nutzer 42"
POST
Schick etwas hin.
"Lege diesen neuen Nutzer an"
PUT
Ersetze etwas.
"Überschreibe Nutzer 42 komplett"
DELETE
Lösche etwas.
"Entferne Nutzer 42"

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.

Methode
POST
URL
https://auxdata.ai/api/v1/agent/42/chat
Headers
Authorization: Bearer ey...
Content-Type: application/json
Body
{ "question": "Wie ist das Wetter?" }

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.

Klicke einen Button, um eine Anfrage zu simulieren.

6Selbsttest

✓ Was du jetzt können solltest

Stufe 2 von 9

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.

Was wir meinen
Florian, 32 Jahre alt,
aus Berlin,
spricht Deutsch und Englisch.
Als JSON
{
  "name": "Florian",
  "alter": 32,
  "stadt": "Berlin",
  "sprachen": ["de", "en"]
}

2Zwei Bausteine — mehr gibt es nicht

JSON kennt zwei Strukturen: das Objekt und das Array.

{ }
Objekt
Schlüssel → Wert
{
  "name": "Berlin",
  "land": "DE"
}

Eine Sammlung von benannten Eigenschaften. Wie ein Steckbrief.

[ ]
Array
Liste von Werten
[
  "Berlin",
  "Hamburg",
  "München"
]

Eine geordnete Liste. Wie eine Einkaufsliste.

Faustregel: { } = einzelnes "Ding" mit Eigenschaften. [ ] = mehrere "Dinge" hintereinander.

3Die Datentypen

Sechs Werttypen, mehr braucht JSON nicht.

String
Text in Anführungszeichen
"Hallo Welt"
Number
Zahl, ohne Anführungszeichen
42 oder 3.14
Boolean
Ja oder Nein
true oder false
Null
"nichts" / leer
null
Object
Verschachteltes Objekt
{ "x": 1 }
Array
Verschachtelte Liste
[ 1, 2, 3 ]

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.

JSON
{ "agent": { "id": 42, "name": "Wetterbot" }, "container": [ { "id": 1, "name": "FAQ" }, { "id": 2, "name": "Doku" } ] }
Als Baum gedacht
⬤ Ein Objekt
├─ agent: (Objekt)
│   ├─ id: 42
│   └─ name: "Wetterbot"
└─ container: (Liste)
    ├─ [0]: { id: 1, name: "FAQ" }
    └─ [1]: { id: 2, name: "Doku" }

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?

{ "name": "Berlin", "land": "DE", }
Komma nach dem letzten Eintrag. JSON erlaubt kein Komma hinter dem letzten Element.

Fehler 2: Was stimmt hier nicht?

{ name: "Berlin", land: "DE" }
Anführungszeichen um die Schlüssel vergessen. In JSON müssen auch die Schlüssel in doppelten Anführungszeichen stehen.

Fehler 3: Was stimmt hier nicht?

{ "alter": '32', "aktiv": True }
Zwei Probleme. JSON erlaubt nur doppelte Anführungszeichen ("), und Booleans heißen true/false (klein geschrieben).
Tipp: Bei kaputtem JSON: kopier es in jsonlint.com. Das Tool sagt dir, wo der Fehler ist.

7Selbsttest

✓ Was du jetzt können solltest

Stufe 3 von 9

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.

Erwartung: Du wirst kein Programm schreiben. Du benutzt nur ein graphisches Tool, in dem du eine URL eintippst, ein paar Felder ausfüllst und auf einen Knopf drückst. Niveau: Online-Formular.

2Welches Tool?

Drei sinnvolle Optionen. Für den Anfang empfehle ich Postman.

Insomnia
Schlankere Alternative, ähnliches Konzept. Komplett ohne Account nutzbar.
insomnia.rest →
REST Client
VSCode-Erweiterung. Nur sinnvoll, falls du mit VSCode arbeitest.
VSCode Marketplace →

3So sieht Postman aus

Vereinfachte Nachbildung der Oberfläche. Klick durch die Reiter und drück "Send".

Übung 1 · GitHub API
Headers (2)
Body
User-Agentpostman-tutorial
Acceptapplication/json
(Kein Body bei GET-Anfragen nötig.)
Response – – –
Drück auf "Send", um die Anfrage abzuschicken.

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.

  1. Postman öffnen. Account-Dialog überspringen ("Skip and go to the app").
  2. Neuer Tab mit dem +-Knopf.
  3. Methode auf GET lassen.
  4. URL eingeben: https://api.github.com/users/octocat
  5. Auf Send klicken.
  6. Unten erscheint die Antwort. Oben rechts siehst du 200 OK.
Spiel ein bisschen rum: Tausche 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.

  1. Neuen Tab in Postman öffnen.
  2. Methode auf POST umstellen.
  3. URL: https://auxdata.ai/api/v1/agent/{agentid}/chat{agentid} durch deine Agent-ID ersetzen.
  4. Reiter Authorization, Typ Bearer Token, Token eintragen.
  5. Reiter Body, dann raw + JSON.
  6. Body eingeben (minimal):
{
  "question": "Hallo, was kannst du?",
  "comuuid": ""
}
  1. Auf Send klicken.
  2. Bei Erfolg: 200 OK mit einem ExecuteChatbotResult-JSON, das u.a. answer, comuuid (für Folge-Anfragen), sources und tokenusage enthält.
Quick-Tipp: Die interaktive Swagger-Oberfläche auxdata.ai/swagger/index.html zeigt dir alle Endpoints und Felder live — du kannst dort auch direkt im Browser Requests absetzen.
Sicherheits-Hinweis zur Swagger UI: Wenn du Token in der Swagger-UI-Oberfläche einträgst, landet er kurzzeitig im Browser-State. Nutze sie nur auf deinem eigenen Rechner und in vertrauenswürdiger Umgebung — und zeige sie nicht in Screenshots oder Bildschirm-Aufzeichnungen, wenn der Token noch eingetragen ist.

6Wenn etwas schiefgeht

Die häufigsten Antworten und was sie wirklich bedeuten.

401
Unauthorized

Token fehlt oder ist falsch. Prüfe das Feld und ob "Bearer" davor steht.

400
Bad Request

Body kaputt oder Pflichtfeld fehlt. Lies die Fehlermeldung im Response-Body.

404
Not Found

URL falsch oder Ressource existiert nicht. Tippfehler? {agentid} ersetzt?

500
Internal Server Error

Fehler beim Server. Kurz warten und nochmal probieren.

Timeout
Keine Antwort

Internet weg oder Server hängt. URL doppelt prüfen.

Goldene Regel: Immer zuerst den Response-Body lesen, bevor du im Internet suchst. Die APIs sagen dir fast immer, was sie nicht mögen.

7Selbsttest

✓ Was du jetzt können solltest

Stufe 4 von 9

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.

Ohne Token
⛔ blocked
🧑
🚪
401 Unauthorized
"Wer bist du? Kein Zutritt."
Mit Token
✓ ok
🧑🎫
🚪
200 OK
"Ausweis okay — bitte rein."

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.

Ein typischer AuxData-Bearer-Token sieht so aus (UUID-Format · Beispiel fiktiv): 00000000-0000-0000-0000-000000000000

Für dich nur ein Stück Text, das du nicht lesen musst. Behandle ihn wie ein Passwort: kopieren, einfügen, geheim halten.

Verschiedene APIs, verschiedene Formate: AuxData benutzt eine UUID wie oben. Andere Dienste haben andere Formate — OpenAI nutzt z.B. lange Strings wie 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:

Authorization-Header (am Beispiel AuxData · UUID fiktiv) Authorization: Bearer 00000000-0000-0000-0000-000000000000

Drei Teile: der Header-Name (Authorization), das Schlüsselwort Bearer mit Leerzeichen, und der eigentliche Token.

Probier es aus:

Authorization: Bearer abc123-demo-token-nicht-echt
⚠ Demo-Feld: Trag hier niemals einen echten Token ein. Auch wenn die Datei lokal läuft — Browser-Eingabefelder können von Erweiterungen ausgelesen werden, Screenshots versehentlich geteilt werden. Diese Demo dient nur dem Zeigen, wie der Header aufgebaut ist.

4Woher kommt der Token?

Tokens haben einen Lebenszyklus.

1
Anlegen
Im Webinterface des Dienstes generieren.
2
Speichern
Sicher ablegen — siehst du meist nur einmal.
3
Benutzen
In jeder Anfrage als Authorization-Header mitschicken.
4
Rotieren
Regelmäßig erneuern oder bei Verdacht widerrufen.

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.
  • .env in .gitignore eintragen.
  • 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.
Real-life: Bots scannen GitHub permanent nach geleakten Tokens. Committest du einen versehentlich, wird er oft innerhalb von Minuten missbraucht.

6Andere Auth-Methoden zum Wiedererkennen

Nicht im Detail können, aber wiedererkennen.

API Key
Quasi dasselbe wie Bearer. Im Header X-API-Key oder als URL-Parameter.
Basic Auth
Username + Passwort, Base64-kodiert. Authorization: Basic dXNlcjpwYXNz. Altmodisch, aber noch verbreitet.
OAuth 2.0
Komplizierter Tanz, dann ein Bearer-Token. Bei "Login with Google" im Spiel. Kurzlebig, dafür refreshbar.
mTLS / Cert
Zertifikate statt Tokens. Selten, meist in Enterprise-Setups.

Für deinen AuxData → OpenAI Adapter ist nur Bearer-Token relevant.

AuxData-Besonderheit: AuxData arbeitet mit Agent-UUID-Tokens, die je Fähigkeit getrennt konfiguriert werden. Jede Fähigkeit hat ein eigenes Token-Feld in der Agent-Konfiguration und einen eigenen Freigabe-Schalter:
ChatChatbotConfig.Uuid + Schalter externalchatbotaccess = true
AI-ServiceAiServiceConfig.Uuid + Schalter externalchatbotaccess = true
SucheSearchConfig.Uuid + Schalter externalsearchaccess = true
Doku-UploadKnowledgeDbConfig.Uuid + Schalter tokenuploadaccess = true
Wenn du HTTP 401 bekommst, obwohl der Token korrekt ist, fehlt entweder die externe Freigabe oder du benutzt den Token einer anderen Fähigkeit.
Quelle: Administrator-Handbuch Kap. 15.2.1

7Selbsttest

✓ Was du jetzt können solltest

Stufe 5 von 9

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.

Pragmatisch: "Swagger-Dokument" und "OpenAPI-Spec" meinen meistens dasselbe. Das AuxData-Doc ist Swagger 2.0 (du siehst es am "swagger": "2.0" am Anfang).

3Die Hauptbestandteile

Fünf Hauptabschnitte, immer dieselben.

info
Stammdaten
Titel, Version, Beschreibung. Beiwerk.
host / basePath
Wo lebt die API?
Bei AuxData: auxdata.ai + /api/v1.
paths
Die Endpunkte
Der wichtigste Abschnitt. Alle URLs mit Methoden und Parametern.
definitions
Die Datenstrukturen
In OpenAPI 3: components/schemas. JSON-Baupläne wie ChatCommand.
securityDefinitions
Authentifizierung
Welche Methoden die API akzeptiert. Bei AuxData: Bearer.

4Einen Endpunkt lesen — Zeile für Zeile

Ausschnitt aus dem AuxData-Swagger. Klick auf jede Zeile.

"/agent/{agentid}/chat": { "post": { "security": [{ "Bearer": [] }], "description": "AI chat request answered by the LLM", "consumes": ["application/json"], "produces": ["application/json"], "parameters": [ { "name": "agentid", "in": "path", "type": "integer", "required": true }, { "name": "request", "in": "body", "schema": { "$ref": "#/definitions/ChatCommand" } } ], "responses": { "200": { "schema": { "$ref": "#/definitions/ExecuteServiceStepResult" } }, "400": { "description": "Bad Request" } } } }
Klick auf eine Zeile. Hier erscheint dann die Erklärung dazu.

5Was bedeutet $ref?

Der einzige "fortgeschrittene" Trick. Eine $ref ist eine Referenz auf eine andere Stelle im selben Dokument.

Klick auf die unterstrichene Referenz:

"parameters": [ { "name": "request", "in": "body", "schema": { "$ref": "#/definitions/ChatCommand" } } ]
// Aufgelöste Definition aus #/definitions/ChatCommand: { "type": "object", "properties": { "question": { "type": "string" }, "comuuid": { "type": "string" }, "stream": { "type": "boolean" }, "anonymize": { "type": "boolean" }, "usePersonalKnowledgeDb": { "type": "boolean" }, "answerMode": { "$ref": "#/definitions/AnswerMode" }, "files": { "type": "array" } } }

Jedes Mal, wenn du $ref siehst, schlägst du in definitions nach.

Praxis-Tipp: Lade das Swagger-Dokument in den Swagger Editor — der rendert eine klickbare Doku, in der alle $refs aufgelöst sind.

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

Stufe 6 von 9

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.

Dein Hauptziel-Endpunkt: POST https://api.openai.com/v1/chat/completions. Genau diesen URL-Pfad bietest du in deinem Adapter selbst an.
Kurz-Vergleich
Chat Completions
Endpoint: POST /v1/chat/completions
Request: messages als Liste
Response: choices[0].message.content
→ Kompatibilität mit Tooling
Responses API
Endpoint: POST /v1/responses
Request: input
Response: 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.

system
Die Anweisung an das Modell
Du bist ein hilfsbereiter Assistent, der kurz und sachlich antwortet.
user
Was der Mensch sagt
Wie ist das Wetter in Berlin?
assistant
Was die KI vorher gesagt hat
18 Grad und sonnig.
user
Was der Mensch jetzt fragt
Und morgen?

Wichtig: bei jeder neuen Frage schickt der Client die ganze Liste wieder mit. OpenAI hat selbst kein Gedächtnis. Zentraler Unterschied zu AuxData.

Kleines Update: Bei neueren Modellen wird statt 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.

{ "id": "chatcmpl-9xKp2...", "object": "chat.completion", "created": 1735689600, "model": "gpt-4o-mini", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "18 Grad und sonnig." }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 18, "completion_tokens": 7, "total_tokens": 25 } }
Klick auf eine 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.

OpenAI Request
POST /v1/chat/completions
{
  "model": "gpt-4o-mini",
  "messages": [
    { "role": "user",
      "content": "Hallo!" }
  ],
  "stream": false
}
AuxData Request
POST /api/v1/agent/42/chat
{
  "question": "Hallo!",
  "comuuid": "",
  "stream": false
}
OpenAI
AuxData
Was muss übersetzt werden
model: "gpt-4o-mini"
In URL: /agent/42
Modell-Name → Agent-ID. Mapping nötig.
messages: [...]
question: "..."
Liste → einzelner Text. Letzte User-Message nehmen.
Volle History
comuuid
OpenAI zustandslos, AuxData per UUID → im Adapter-State halten.
choices[0].message.content
answer
Umbenennung.
usage.{prompt,completion,total}_tokens
tokenusage
Token-Zähler umrechnen.
(kein Standard-Feld)
sources
RAG-Quellen passen nicht ins OpenAI-Schema. Optional als Metadaten/Erweiterung mitgeben oder als Markdown-Fußnoten an content 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].

Für später: Streaming ist optional. Du kannst deinen Adapter erstmal ohne bauen.

7Selbsttest

✓ Was du jetzt können solltest

Stufe 7 von 9

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.

📱
Client
spricht "OpenAI"
übersetzt nach AuxData
🌐
Dein Adapter
der Dolmetscher
übersetzt zurück
☁️
AuxData
spricht "AuxData"

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.

📱
Client
LangChain, Open WebUI, ...
HTTP
OpenAI-Format
🌐
Dein Adapter
läuft z.B. auf
localhost:8000
HTTP
AuxData-Format
☁️
AuxData
auxdata.ai/api/v1/...

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:

1
Client schickt OpenAI-Anfrage
Der Client glaubt, er redet mit OpenAI.
POST localhost:8000/v1/chat/completions
{ "model": "auxdata-agent-42", "messages": [...] }
2
Adapter übersetzt nach AuxData
Aus model wird die Agent-ID, aus messages wird question.
{ "question": "Wie ist das Wetter?", "comuuid": "abc-123" }
3
Adapter ruft AuxData auf
Genau das, was du in Stufe 3 manuell in Postman gemacht hast.
POST auxdata.ai/api/v1/agent/42/chat
Authorization: Bearer 00000000-0000-0000-0000-000000000000
4
Adapter übersetzt AuxData-Antwort zurück
Aus answer wird choices[0].message.content.
{ "choices": [{ "message": {...} }], "usage": {...} }
5
Adapter liefert OpenAI-Antwort an Client
Der Client bekommt das Format, das er erwartet.
HTTP/1.1 200 OK

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.

📱
Client
OpenAI
🌐
Adapter
übersetzt
☁️
AuxData
AuxData
{ "model": "agent-42", "messages": [...] }
Klick auf "Animation starten".

4Wie das im Code aussieht

Vollständiger Adapter, vereinfacht in Pseudo-Code. Etwa 25 Zeilen.

# Mein Adapter — vereinfacht app = FastAPI() @app.post("/v1/chat/completions") async def chat(request): # 1. Aus OpenAI-Request die Daten ziehen agent_id = parse_agent_id(request.model) user_message = request.messages[-1].content comuuid = lookup_comuuid(request.messages) # 2. AuxData-Format bauen aux_request = { "question": user_message, "comuuid": comuuid } # 3. Bei AuxData anfragen (Token aus env var) aux_response = await httpx.post( f"https://auxdata.ai/api/v1/agent/{agent_id}/chat", json=aux_request, headers={"Authorization": "Bearer " + AUXDATA_TOKEN} ) # 4. UUID speichern save_comuuid(request.messages, aux_response.comuuid) # 5. Antwort ins OpenAI-Format umbauen return { "choices": [{"message": {"content": aux_response.answer}}], "usage": convert_token_usage(aux_response.tokenusage) }
Keine Sorge wegen dem Code: In Stufe 8 gehen wir solchen Code Zeile für Zeile durch. Hier nur visuell, dass der Adapter handhabbar klein ist.

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.

So funktioniert 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.

LangChain / LlamaIndex
Sprechen ab Werk mit OpenAI. Mit deinem Adapter funktionieren sie mit AuxData.
Open WebUI / LibreChat
Lokale ChatGPT-ähnliche UIs. Plötzlich hast du eine schöne UI für deine Agents.
Continue.dev / Cursor
Code-Assistenten in der IDE. Funktionieren wie mit dem Original.
LiteLLM / OpenRouter
AuxData wird zu einem weiteren auswählbaren Anbieter.
OpenAI SDKs
In zwei Zeilen auf andere base_url umhängen.
Eigene Skripte
Gegen den OpenAI-Standard schreiben — nicht an AuxData gefesselt.

7Selbsttest

✓ Was du jetzt können solltest

Stufe 8 von 9

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.

Du brauchst Python nicht "können": Du musst es nur lesen können. Trainieren wir hier.

2Die wichtigsten Python-Vokabeln

Sechs Begriffe, die du brauchst.

import
Werkzeug holen
Lädt eine Bibliothek, damit ihre Funktionen verfügbar sind.
def
Funktion definieren
def chat(): beginnt eine Funktion namens "chat".
async / await
Auf etwas warten
Bei API-Aufrufen wartet das Programm auf eine Antwort. await macht das explizit.
@app.post(...)
Decorator: URL → Funktion
FastAPI versteht: bei POST an diese URL, ruf diese Funktion auf.
class
Datenstruktur definieren
Bauplan für ein Objekt. Mit Pydantic: "Mein Request hat genau diese Felder".
: Type
Type Hint
question: str heißt: das Feld ist ein String.

3Voraussetzungen

Drei Dinge. Nur zur Übersicht.

1. Python ≥ 3.10 installiert. Bei Windows von python.org.
2. Drei Pakete installiert:
pip install fastapi uvicorn httpx
3. Datei 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.

Dies ist ein minimaler Lernadapter, kein Produktionscode. Er ist absichtlich knapp, damit du jeden Block verstehst. Welche konkreten Schritte zu einem produktionsreifen Adapter fehlen — Streaming, robustes Error-Handling, persistenter State, Auth pro Client — siehst du in Stufe 9.
1
Imports — die Werkzeuge holen
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.")
Was hier passiert: Bibliotheken holen, Konfiguration aus der Umgebung lesen, App anlegen und beim Startup prüfen, dass der Token gesetzt ist.

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.
2
Datenstrukturen — wie OpenAI-Requests aussehen
class Message(BaseModel):
    role: str
    content: str

class ChatRequest(BaseModel):
    model: str
    messages: list[Message]
    stream: bool | None = False
Was hier passiert: Klassen, die OpenAI-Request-Format abbilden. FastAPI prüft automatisch — falsches Feld = automatischer Fehler.

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].
3
Helfer — die zwei Übersetzungs-Tricks
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
Was hier passiert: Drei Helfer.
  • 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.
Das ist die Demo-Lösung des State-Problems aus Stufe 7. Achtung — wie im Kommentar erklärt, ist dieser Fingerprint fragil: ändert sich die erste User-Message (Autocorrect, Tippfehler-Korrektur), wechselt der Key und der Kontext geht verloren. Für Produktion brauchst du entweder einen normalisierten Fingerprint oder einen explizit vom Client mitgegebenen Session-ID-Header.
4
Der eigentliche Endpunkt
@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
    }
Was hier passiert: @app.post(...) empfängt OpenAI-Requests. Drinnen: Agent, User-Nachricht, comuuid rausziehen, AuxData-Payload bauen.
5
Bei AuxData anfragen
    # 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()
Was hier passiert: Header und URL bauen, HTTP-Anfrage stellen, auf Antwort warten (await), bei Fehler weiterleiten, sonst JSON parsen.
6
Antwort ins OpenAI-Format umbauen
    # 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)
        }
    }
Was hier passiert: comuuid in Map speichern. Antwort-Dict im OpenAI-Format zusammensetzen. 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.

Was im Lernadapter noch fehlt (kommt in Stufe 9): Der Code fängt die offensichtlichsten Client-Fehler bereits ab, bleibt aber bewusst klein. Für Produktion brauchst du trotzdem einen stabileren Conversation-Key (z.B. normalisierter Fingerprint oder explizite Session-ID), persistente Speicherung statt In-Memory-Map, OpenAI-konforme Error-Objekte ({ "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.

Für den Anfang: Lass diese Dinge weg. Bring den Adapter erst zum Laufen.

7Selbsttest

✓ Was du jetzt können solltest

Stufe 9 von 9 · Final

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.

Pro-Tipp: Bau diese drei Dinge nicht alle auf einmal ein. Geh zuerst mit dem einfachen Adapter aus Stufe 8 in Einsatz.

2Streaming — Antworten in Häppchen

Bei "stream": true antwortet der Server nicht mit einem JSON, sondern schickt viele kleine SSE-Events.

Klick auf "Stream starten".
So sieht der Nutzer das beim Tippen:

Jede Zeile beginnt mit data: gefolgt von einem JSON-Stück mit delta.content. Am Ende data: [DONE].

Beides nutzt SSE: Sowohl /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.

Echtes vs. Fake-Streaming: Der Code oben zerlegt die fertige Antwort in Häppchen (Fake). Echtes Streaming wäre AuxDatas eigenen Stream durchreichen.
⚠ Achtung — wichtige Falle: OpenAI streamt Deltas (jedes Event enthält nur den neuen Text-Schnipsel im 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.

AuxData liefert z.B.
{
  "code": 401,
  "message": "Token invalid",
  "service": "agent.chat"
}
Du übersetzt zu
{
  "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.

In-Memory dict
+ Null Setup
– Weg bei Restart
– Nur 1 Prozess
Redis
+ Schnell, mehrere Server
+ Auto-Expiry per TTL
– Extra Service
PostgreSQL
+ Wenn schon vorhanden
– Overkill nur dafür

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:

Stufen 1–9 verstanden
Du weißt was eine API ist, kannst Swagger lesen, kennst beide Formate und das Adapter-Konzept.
1
AuxData-Token holen
Im Webinterface generieren, Test-Anfrage in Postman.
2
Stufe-8-Code zum Laufen bringen
Python installieren, Code kopieren, Token einsetzen, uvicorn starten.
3
Mit Postman gegen eigenen Adapter testen
POST an localhost:8000/v1/chat/completions.
4
Echten Client anschließen
Open WebUI installieren, deinen Adapter als OpenAI-URL eintragen.
5
Lücken nach Bedarf schließen
Erst wenn nötig: Streaming, persistenter State, Logging, Multi-User-Keys.

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.

9
Stufen abgeschlossen
~50
Konzepte verinnerlicht
1
Adapter bereit
Bonusmodul · Anhang

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.

Was dieses Bonusmodul ist und was nicht: Dieses Bonusmodul ist ein Ausblick, keine zweite Bauanleitung. Dieses Tutorial bleibt beim Adapter. MCP, HTTP-Services, Function-Calls, Workflows und weitere Integrationen werden hier nur eingeordnet. Daraus kann später ein eigenes Integrationsmodul entstehen — mit eigenen Quellen, eigenen praktischen Beispielen und einer eigenen Lernstrecke.
Quellengrundlage: Die folgenden Inhalte stammen aus dem AuxData-Benutzerhandbuch, Administrator-Handbuch (Kap. 15 für die Public API, Kap. 4 für Wissensdatenbank, Kap. 5 für AI-Services, Kap. 7.3 für MCP) und der Teams-Integrations-Doku (Stand 22.04.2026). Wo etwas nicht direkt aus den Handbüchern belegt ist, ist das im Text markiert. Für ein vollwertiges Integrationsmodul wären zusätzliche Quellen (offizielle MCP-Spezifikation, eigene AuxData-Integrationsdokumente) nötig.

2Die sieben Public-API-Endpunkte

Komplette Übersicht, was AuxData von außen anbietet:

Methode + Pfad
Wofür
Antworttyp
POST /agent/{id}/chat
Chat mit allen Containern des Agenten
ExecuteChatbotResult
POST /agent/{id}/container/{cid}/chat
Chat nur mit einem bestimmten Container
ExecuteChatbotResult
POST /agent/{id}/document
Semantische Suche über alle Container (reines RAG, ohne Chat-Antwort)
DetailSearchResult
POST /agent/{id}/container/{cid}/document
Semantische Suche nur in einem Container
DetailSearchResult
PUT /agent/{id}/container/{cid}/document
Datei in die Wissensdatenbank hochladen (multipart/form-data)
UploadedFilesResult[]
PUT /agent/{id}/container/{cid}/document/enhanced
Eine Datei als Base64-JSON, mit Bilderkennung und manueller Kontext-Anreicherung
UploadDocumentResult
POST /agent/{id}/executeservice/{sid}
Vordefinierten AI-Service ausführen mit Parameter-Map
ExecuteServiceResult

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.

Wenn du das in deinem Adapter nutzen willst: Per 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 (![](url)) ans content-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.

Customer-Support-Bot mit RAG
Alle FAQ- und Doku-PDFs in einen Container hochladen, dann den AuxData-Chat über deinen Adapter in eine Webchat-UI hängen. Antworten mit Quellenangaben.
Slack/Teams-Wissensbot
Statt OpenAI-Adapter direkt die Teams-Integration nutzen. Für Slack: Adapter + Slack-Bot kombinieren.
Automatischer Email-Triage
Eingehende E-Mails per AI-Service kategorisieren und vorbeantworten. Mit Intervallplan alle 5 Min ausführen.
Dokumenten-Pipeline
SharePoint → Filesync → AuxData-Wissens-Container → durchsuchbar via API. Komplett ohne eigene Backend-Logik.
Multi-Agent-Router
Adapter, der je nach OpenAI-Modellname ("auxdata-sales", "auxdata-support") an unterschiedliche Agents weiterleitet. Ein einzelner OpenAI-Client greift transparent auf mehrere Bots zu.
Eigener KI-Service-Marktplatz
Über /executeservice alle eigenen AI-Services als REST-Endpoints anbieten und an Drittsysteme andocken.
Roadmap-Idee (ganz lose): Langfristig kann daraus eine kleine AuxData-Tutorialreihe werden — Adapter, Integrationen, Administration, Workflows, Wissensdatenbanken, produktive Betriebsfragen. Dieses Tutorial bleibt bewusst das Adapter-Modul. Alles andere wartet auf eigene Module.

✓ Was du jetzt zusätzlich weißt

Abschlussquiz

Bereit für das Zertifikat?

13 Fragen aus allen neun Stufen. Bestanden ab 10 von 13 richtigen Antworten. Du kannst beliebig oft wiederholen.

Frage 1 von 13
Lade Frage...
🏆 Zertifikat

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.

FL
FL Pro Consulting
Florian Ludwig
Zertifikat
Certificate of Completion
Hiermit wird bestätigt, dass
Dein Name hier
das Tutorial erfolgreich abgeschlossen und das Abschlussquiz bestanden hat:
AuxData → OpenAI Adapter
Das 9-Stufen-Tutorial vom API-Grundwissen zum lauffähigen Adapter
— Datum —Ausstellungsdatum
VERIFIED
COMPLETION
Florian LudwigFL Pro Consulting