Schnellstart
Basis-URL: https://llm-benchmark.de/api/v1. Alle Antworten sind JSON und liegen unter dem Schluessel data. Lesen (GET) ist oeffentlich; Schreiben braucht ein Bearer-Token.
# 1) Rechte pruefen
curl -H "Authorization: Bearer DEIN_TOKEN" https://llm-benchmark.de/api/v1/me
# 2) Modell/Hardware finden
curl "https://llm-benchmark.de/api/v1/match?resource=gpus&name=RTX%205090"
# 3) Ergebnis senden
curl -X POST https://llm-benchmark.de/api/v1/results \
-H "Authorization: Bearer DEIN_TOKEN" -H "Content-Type: application/json" \
-d '{ "model_slug":"qwen3-32b","gpu_slug":"geforce-rtx-5090","gpu_count":1,
"cpu_slug":"epyc-9654","cpu_count":1,"ram_gb":256,
"benchmark_type":"performance","model_server_type":"vllm",
"prefill_tokens_s":2450.7,"generation_tokens_s":184.3,
"ttft_ms":126.4,"duration_ms":60000,"concurrency":8 }'
Konventionen
- Format: Anfragen mit Body senden
Content-Type: application/json. Antworten sind JSON mit Nutzdaten unterdatabzw. einer Fehlermeldung untererror. - Slugs: Jeder Katalog-Eintrag (Modell, GPU, CPU, Mainboard, Hersteller) hat einen eindeutigen
slug(Kleinbuchstaben, Ziffern, Bindestriche). Ergebnisse verweisen ueber Slugs auf den Katalog. - Idempotenz: Ein erneuter Ergebnis-Upload mit gleichem Modell + Hardwareprofil + Typ +
measured_atwird serverseitig dedupliziert (Antwort enthaelt dann"deduped": true). - Token-Sicherheit: Der Token gehoert ausschliesslich in den
Authorization-Header, niemals in die URL. Gespeichert wird nur sein SHA-256-Hash.
Authentifizierung
GET-Abfragen auf den Katalog und die Ergebnisliste sind oeffentlich. POST, PUT, DELETE sowie /me und /aliases erfordern ein Bearer-Token.
Authorization: Bearer DEIN_TOKEN Content-Type: application/json
Rechte & Rollen
Was ein Token darf, ergibt sich aus Scopes (am Token) und der Rolle (am Benutzer). Fuer Agents entscheidend ist die abgeleitete Faehigkeit can_create – sie steuert, ob unbekannte Hardware/Modelle selbst angelegt werden duerfen oder zugeordnet werden muessen.
| Rolle | Lesen | Ergebnisse senden | Zuordnen (Alternativname) | Katalog anlegen/aendern |
|---|---|---|---|---|
| viewer | ja | – | – | – |
| contributor | ja | ja | ja | – |
| contributor_api („Contributor + API Full Access“) | ja | ja | ja | ja |
| admin | ja | ja | ja | ja |
Scopes am Token: read (lesen), write (Ergebnisse senden + zuordnen), create (Katalog anlegen). Ein Token darf anlegen, wenn es den Scope create ODER die Rolle admin/contributor_api besitzt.
Loeschen (DELETE) von Katalog-Eintraegen (Modelle, Hersteller, Grafikkarten, CPUs, Mainboards) ist ausschliesslich Admins vorbehalten – unabhaengig vom create-Recht. Alle anderen Rollen erhalten dabei 403.
Merke fuer Agents: Zuerst GET /me abfragen und nach capabilities.can_create verzweigen. Ist es false, darfst du NUR zuordnen (/aliases) – kein Anlegen.
Wer bin ich – GET /me
Gibt Benutzer, Rolle, Scopes und die abgeleiteten Faehigkeiten zurueck.
GET /api/v1/me
{
"data": {
"user_ID": 4,
"display_name": "Marcel Sommer",
"role": "contributor_api",
"scopes": "read,write",
"capabilities": {
"can_read": true,
"can_write": true,
"can_create": true,
"can_match": true
}
}
}
Zuordnung / Aufloesung (wie Slugs gefunden werden)
Beim Senden eines Ergebnisses werden model_slug, gpu_slug, cpu_slug und optional board_slug serverseitig aufgeloest – in zwei Stufen:
- Exakter Slug. Gibt es einen aktiven Eintrag mit genau diesem Slug, wird er genommen.
- Normalisierter Vergleich. Sonst wird gross/klein und alle Sonderzeichen ignoriert und gegen Slug, Name und alle Alternativnamen verglichen. So matchen
RTX-5090,rtx_5090,RTX 5090automatisch auf denselben Eintrag.
Echte Namensunterschiede (anderer Suffix, Kurzform, interner Codename) matchen NICHT automatisch. Dafuer gibt es zwei Wege – siehe naechster Abschnitt.
Upload-Ablauf (fuer Agents)
Empfohlener, robuster Ablauf pro Ergebnis. Er deckt beide Rechte-Situationen ab:
1. GET /me -> canCreate = capabilities.can_create
2. Fuer JEDES Modell / GPU / CPU / (Mainboard):
GET /match?resource=&name= -> exact vorhanden?
JA -> nimm exact.slug
NEIN:
(b) canCreate == true -> POST /<resource> (SELBST ANLEGEN)
(a) canCreate == false -> waehle besten Kandidaten aus candidates[]
POST /aliases (ZUORDNEN)
-> danach matcht der Name dauerhaft
(kein passender Kandidat? -> abbrechen, Eintrag muss
von einem create-berechtigten Nutzer angelegt werden)
3. POST /results mit den aufgeloesten Slugs
Weg (a) „zuordnen“ gilt fuer Tokens ohne Anlage-Recht: der lokale Name wird per /aliases als Alternativname an einen VORHANDENEN Eintrag gehaengt. Weg (b) „anlegen“ gilt fuer Tokens mit can_create: fehlende Hardware/Modelle werden per POST selbst angelegt. Das Beispiel-Script unten macht genau diese Verzweigung automatisch.
Beispiel-Script zum Herunterladen
Eigenstaendiges PHP-Script (PHP 7.4+, cURL), das den kompletten Ablauf umsetzt – inkl. automatischer Verzweigung zwischen zuordnen und anlegen je nach Recht. Herunterladen, $API/$TOKEN setzen, Werte anpassen, ausfuehren.
⇩ upload-benchmark.php herunterladen
# Ausfuehren php upload-benchmark.php
Hersteller
GET /api/v1/manufacturers GET /api/v1/manufacturers/qwen POST /api/v1/manufacturers # Anlege-Recht noetig PUT /api/v1/manufacturers/qwen # Anlege-Recht noetig DELETE /api/v1/manufacturers/qwen # NUR Admin
{
"slug": "qwen",
"name": "Qwen (Alibaba)",
"description": "Qwen-Modellfamilie von Alibaba.",
"huggingface_url": "https://huggingface.co/Qwen",
"website_url": "https://qwen.ai"
}
Modelle
GET /api/v1/models GET /api/v1/models/qwen3-32b GET /api/v1/models?manufacturer=qwen POST /api/v1/models # Anlege-Recht noetig PUT /api/v1/models/qwen3-32b # Anlege-Recht noetig DELETE /api/v1/models/qwen3-32b # NUR Admin
{
"slug": "qwen3-32b",
"manufacturer_slug": "qwen",
"name": "Qwen3 32B",
"parameter_count": "32B",
"architecture": "Dense",
"license_name": "Apache 2.0",
"model_url": "https://huggingface.co/Qwen/Qwen3-32B"
}
manufacturer_slug muss auf einen vorhandenen Hersteller zeigen (sonst 422). Beim Anlegen prueft die API auf moegliche Dubletten (409) – mit "force": true laesst sich das uebergehen.
Grafikkarten
GET /api/v1/gpus GET /api/v1/gpus/geforce-rtx-5090 POST /api/v1/gpus # Anlege-Recht noetig PUT /api/v1/gpus/geforce-rtx-5090 # Anlege-Recht noetig DELETE /api/v1/gpus/geforce-rtx-5090 # NUR Admin
{
"slug": "geforce-rtx-5090",
"vendor": "NVIDIA",
"name": "GeForce RTX 5090",
"memory_gb": 32,
"idle_watt": 30,
"max_watt": 575
}
CPUs
GET /api/v1/cpus GET /api/v1/cpus/epyc-9654 POST /api/v1/cpus # Anlege-Recht noetig PUT /api/v1/cpus/epyc-9654 # Anlege-Recht noetig DELETE /api/v1/cpus/epyc-9654 # NUR Admin
{
"slug": "epyc-9654",
"vendor": "AMD",
"name": "AMD EPYC 9654",
"cores": 96,
"threads": 192
}
Mainboards
GET /api/v1/mainboards GET /api/v1/mainboards/asus-rog-x670e POST /api/v1/mainboards # Anlege-Recht noetig PUT /api/v1/mainboards/asus-rog-x670e DELETE /api/v1/mainboards/asus-rog-x670e # NUR Admin
{
"slug": "asus-rog-x670e",
"vendor": "ASUS",
"name": "ASUS ROG X670E"
}
Vorschlaege – GET /match
Liefert zu einem Namen den exakten Treffer (falls vorhanden) und die aehnlichsten Kandidaten (Score 0–100). Braucht nur Lese-Recht. Ideal, um vor dem Upload zu pruefen, ob ein Eintrag existiert, und um beim Zuordnen den richtigen Ziel-Slug zu waehlen.
GET /api/v1/match?resource=gpus&name=RTX%205090
{
"data": {
"exact": { "slug": "geforce-rtx-5090", "name": "GeForce RTX 5090" },
"candidates": [
{ "slug": "geforce-rtx-5090", "name": "GeForce RTX 5090", "score": 100 },
{ "slug": "geforce-rtx-5080", "name": "GeForce RTX 5080", "score": 88.9 }
]
}
}
resource = models | manufacturers | gpus | cpus | mainboards. Ist exact gleich null, gibt es keinen sicheren Treffer – dann anlegen (mit Recht) oder zuordnen.
Zuordnen – POST /aliases
Haengt einen Alternativnamen an einen bestehenden Katalog-Eintrag. Damit matchen abweichende Schreibweisen kuenftig automatisch. Braucht nur write-Recht (kein Anlege-Recht) – das ist der Weg fuer Tokens ohne can_create.
POST /api/v1/aliases
{
"resource": "gpus",
"slug": "geforce-rtx-5090",
"alias": "NVIDIA RTX5090 32G"
}
Antwort enthaelt die aktualisierten alt_names. Zeigt der Alias bereits auf einen ANDEREN Eintrag, antwortet die API mit 409 (Konflikt) und nennt den betroffenen Slug.
Performance-Benchmark senden
GPU und CPU werden per Slug zugeordnet; Anzahl und RAM bilden automatisch ein wiederverwendbares Hardwareprofil. Die Antwort liefert ID, Slug und Status.
POST /api/v1/results
{
"model_slug": "qwen3-32b",
"gpu_slug": "geforce-rtx-5090",
"gpu_count": 2,
"gpu_used": 1,
"cpu_slug": "epyc-9654",
"cpu_count": 1,
"ram_gb": 256,
"board_slug": "asus-rog-x670e",
"benchmark_type": "performance",
"model_server_type": "vllm",
"runtime_version": "0.10.0",
"engine": "vllm",
"quantization": "FP8",
"start_path": "/opt/bin/start-vllm-qwen.sh",
"context_length": 32768,
"configuration_parameters": {
"model": "Qwen/Qwen3-32B",
"tensor_parallel_size": 2,
"gpu_memory_utilization": 0.92,
"max_model_len": 32768
},
"concurrency": 8,
"prefill_tokens_s": 2450.7,
"generation_tokens_s": 184.3,
"ttft_ms": 126.4,
"duration_ms": 60000,
"notes": "Oeffentlicher Hinweis zu diesem Lauf (erscheint auf der Ergebnis-Detailseite)",
"measured_at": "2026-07-31 10:00:00"
}Antwort:
{
"data": { "ID": 123, "slug": "run-20260731-100000-a1b2c3", "status": "published" }
}
Pflichtfelder: model_slug, gpu_slug, cpu_slug, ram_gb, benchmark_type, model_server_type (Alias runtime) sowie prefill_tokens_s, generation_tokens_s, duration_ms, concurrency. Ohne GPU (CPU-only) "gpu_slug":"none","gpu_count":0 senden. Optional: gpu_used = Anzahl der fuer diesen Lauf tatsaechlich genutzten GPUs (z.B. 1, wenn nur eine von gpu_count verbauten Karten verwendet wurde); wird auf der Detailseite als „nur M von N genutzt“ angezeigt.
Harness-Benchmark senden
POST /api/v1/results
{
"model_slug": "qwen3-32b",
"gpu_slug": "geforce-rtx-5090",
"gpu_count": 2,
"gpu_used": 1,
"cpu_slug": "epyc-9654",
"cpu_count": 1,
"ram_gb": 256,
"benchmark_type": "harness",
"model_server_type": "llamacpp",
"runtime_version": "b6200",
"start_path": "/opt/bin/start-llamacpp.sh",
"configuration_parameters": {
"model": "/models/qwen3.gguf",
"gpu_layers": 99,
"context_size": 32768,
"threads": 16
},
"points_achieved": 87,
"points_max": 100,
"duration_ms": 325000,
"tasks": [
{"name":"Recherche","success":true,"points":20,"points_max":20,"duration_ms":42000},
{"name":"Codeaenderung","success":true,"points":30,"points_max":30,"duration_ms":81000}
]
}
Pflichtfelder Harness: zusaetzlich points_achieved, points_max, duration_ms, tasks. model_server_type ist der Modellserver (z.B. vllm, llamacpp), start_path der Startpfad, configuration_parameters die tatsaechlichen Start-/Modellparameter als JSON.
Ergebnisse abrufen, aktualisieren, filtern
GET /api/v1/results/123 GET /api/v1/results/run-20260731-100000-a1b2c3 GET /api/v1/results?search=qwen PUT /api/v1/results/123 # eigene Benchmarks; Admin: alle DELETE /api/v1/results/123 # blendet den Datensatz aus
GET /api/v1/results?type=performance GET /api/v1/results?manufacturer=qwen GET /api/v1/results?model=qwen3-32b GET /api/v1/results?gpu=GeForce%20RTX%205090 GET /api/v1/results?cpu=EPYC%209654 GET /api/v1/results?ram=256 GET /api/v1/results?engine=vllm GET /api/v1/results?mine=1 # nur eigene (Token noetig)
Bei PUT denselben vollstaendigen JSON-Aufbau wie beim Anlegen senden. Ein Benutzer darf eigene Benchmarks verwalten, der Admin alle.
Fehlercodes
| Code | Bedeutung | Was tun |
|---|---|---|
| 200 / 201 | OK / angelegt | – |
| 401 | Token fehlt oder ungueltig | Bearer-Token pruefen |
| 403 need:create | Anlegen ohne Anlage-Recht versucht | Stattdessen zuordnen (/aliases) oder Token mit create nutzen |
| 403 need:admin | Loeschen (DELETE) ohne Admin-Rolle | Nur ein Admin darf Katalog-Eintraege loeschen |
| 404 | Eintrag nicht gefunden | Slug pruefen |
| 409 | Dublette / Alias-Konflikt | Vorhandenen Slug verwenden bzw. "force":true |
| 422 | Pflichtfeld fehlt / Slug „unbekannt“ | Fehlendes Feld ergaenzen bzw. Modell/GPU/CPU zuordnen oder anlegen |
