← Zurück zum Blog
Modelle von Grund auf · Essay

Hetzner verschenkt Inferenz. Die Modelle haben sie mit Nachdenken verbraucht.

Simon Doba·11. August 2026·9 Min. Lesezeit·aktualisiert 20. August 2026

Hetzner verschenkt Inferenz. Vier Open-Weight-Modelle hinter einer OpenAI-kompatiblen API unter inference.hetzner.com, kostenlos solange sie experimentell ist, ohne SLA, und einer Ankündigung, in der steht: „No promises this becomes a permanent product.“

Ich habe jedem Modell denselben 38-Token-Prompt gegeben und 512 Tokens, um ihn zu beantworten. Drei von vier kamen ganz ohne Antwort zurück.

Update, 20. August 2026

Neun Tage nach der Messung sind drei dieser vier Modelle nicht mehr verfügbar. /api/v1/models liefert heute zwei Einträge: Qwen/Qwen3.6-35B-A3B-FP8, das unten in den Zahlen steht, und Qwen3.8-27B, das nach dem Lauf dazukam und dort nicht steht.

  • Weg: DeepSeek V4 Flash, GLM 5.2, Kimi K2.7 Code.
  • Noch da: Qwen 3.6.
  • Neu, ungemessen: Qwen3.8-27B.

Die drei antworten mit 403 model use not permitted, nicht mit einem 404. Das liest sich wie eine entzogene Berechtigung und nicht wie ein unbekannter Name. So oder so hört ein Client, der auf eines davon festgelegt ist, auf zu funktionieren, und zwar mit einem Statuscode, der nach einem Anmeldeproblem aussieht.

Für alles Weitere folgt daraus zweierlei. Kimi K2.7 war das einzige Modell hier, das bei 512 Tokens eine sichtbare Antwort lieferte, das eine Gegenbeispiel zum Befund ist also genau das, was du nicht mehr ausprobieren kannst. Und GLM 5.2, dessen Wartezeit auf das erste Token über fünf Läufe zwischen 11 und 173 Sekunden schwankte, ist mit weg, womit die unruhigste Zahl des Textes verschwindet.

Alles ab hier ist ein Protokoll vom 11. August und bleibt so stehen, wie es gemessen wurde. Es ist zugleich der Vorbehalt, der sich selbst bestätigt: Die Ankündigung sagte, es gebe keine Zusage, dass daraus ein dauerhaftes Produkt wird, und drei Viertel der Aufstellung haben sich in neun Tagen gedreht. Das ist als Aussage über den Dienst mehr wert als jede Durchsatzzahl, die ich erhoben habe.

Wohin die Tokens gingen

Qwen 3.6, DeepSeek V4 und GLM 5.2 erzeugten jeweils exakt 512 Completion-Tokens und null sichtbare Wörter. Das Budget floss vollständig ins Nachdenken. Die API sagt das ehrlich: finish_reason: length und ein paar tausend Zeichen Reasoning. Aber message.content kommt als null zurück, und ein Client, der nur dieses Feld liest, sieht eine erfolgreiche Anfrage, die nichts gesagt hat.

Nur Kimi K2.7 hat geantwortet, mit 266 Wörtern und vergleichsweise sparsamen 568 Zeichen Nachdenken.

Das passiert, wenn Reasoning-Modelle auf ein Token-Budget treffen, das für Modelle ohne Reasoning gewählt wurde. Es ist das Erste, was man wissen sollte, bevor man das irgendwo einbaut. Ein Token-Budget ist ein Budget in Tokens, nicht in Wörtern, und was ein Token kostet, ist vorher nicht offensichtlich.

Zwei Stellen, an denen ein Standard-Client bricht

„OpenAI-kompatibel“ ist großzügig formuliert.

Die Stream-Frames kommen als data:{...}, ohne Leerzeichen nach dem Doppelpunkt. Server-Sent Events erlauben das, und das OpenAI-SDK kommt damit klar. Ein selbst geschriebener Parser, der auf das dokumentierte data: splittet, liest null Tokens und meldet eine funktionierende Anfrage mit leerer Ausgabe. Genau das tat mein erster Versuch, und ein paar Minuten lang hielt ich die Modelle für das Problem. Dasselbe Muster wie bei dem Reviewer, der einen erfundenen Befund einreichte: Das Werkzeug meldete Erfolg, und der einzige Weg, es besser zu wissen, war, seine Ausgabe gegen etwas außerhalb zu prüfen.

Das Nachdenken kommt auf delta.reasoning. vLLM und das OpenAI-SDK verwenden reasoning_content. Wer nur dieses Feld zählt, misst bei drei dieser vier Modelle null Durchsatz, während die Tokens erzeugt, gegen das Rate-Limit gerechnet und vom eigenen Parser weggeworfen werden.

Der Durchsatz ist in Ordnung. Das Warten nicht.

Sobald Tokens fließen, sind die Zahlen für einen kostenlosen Dienst ordentlich: Qwen 3.6 hielt 41 Tokens pro Sekunde, DeepSeek V4 38, Kimi K2.7 30.

Davor fällt es auseinander. Die mediane Zeit bis zum ersten Token reichte von 2,1 Sekunden bei Qwen bis 26,8 Sekunden bei GLM 5.2. Die fünf Läufe von GLM, in der Reihenfolge, in der sie passierten:

  • 122,94 s · 172,65 s · 26,77 s · 18,09 s · 11,71 s

Ein Modell wird nicht innerhalb von fünf Minuten fünfzehnmal schneller. Diese Spanne ist eine Warteschlange, die sich leert. Das heißt: Welche Zahl ich für GLM nennen kann, hängt allein davon ab, wann ich gefragt habe. Verursacht habe ich sie nicht. Der gesamte Benchmark verbrauchte 17.920 Output-Tokens gegen ein Limit von 200.000 pro Minute, kein Request kam als 429 zurück, und GLM lief als letztes. Wäre ich die Verstopfung gewesen, wäre es langsamer geworden, nicht schneller. Die anderen drei sind stabiler, die fünf Läufe von Qwen lagen zwischen 1,68 und 2,20 Sekunden, aber derselbe Vorbehalt gilt für sie in kleinerem Maßstab.

Beim Batchen ist sie stark

Acht 256-Token-Anfragen gleichzeitig an Qwen 3.6 bremsten keine einzelne aus: Der Durchsatz pro Anfrage blieb bei rund 36 Tokens pro Sekunde gegenüber 34 bei einer allein, während der Gesamtdurchsatz von 15 auf 217 Tokens pro Sekunde stieg. So verhält sich ein Backend, das fürs Batchen gebaut ist, und genau dafür ist diese API attraktiv: Offline-Arbeit, Massenklassifikation, alles, wo niemand auf einen blinkenden Cursor schaut.

DeepSeek V4 war unter derselben Behandlung deutlich unruhiger und fiel bei acht parallelen Anfragen auf 15 Tokens pro Sekunde, um bei vier wieder zu steigen. Auf einem einzigen Lauf je Parallelitätsstufe würde ich darauf kein Argument bauen; ich berichte es, weil das Rauschen bei einem Dienst ohne Kapazitätsgarantie selbst der Befund ist.

Wo die Antworten anfangen

512 war meine Wahl, nicht die der Modelle. Also habe ich noch einmal gemessen, bei 1.024, 2.048 und 4.096 Tokens. Die Antwort ist keine Kurve, sondern eine Kante.

Bei 1.024 Tokens liefern Qwen 3.6 und DeepSeek V4 immer noch nichts — und 1.024 ist ein Wert, bei dem niemand zweimal hinsieht. Erst zwischen dort und 2.048 fangen sie an zu antworten, mit 270 und 572 Wörtern. GLM 5.2 kippt früher und schafft bei 1.024 schon 125 Wörter. Kimi K2.7 antwortet bei jeder Größe und pendelt sich bei rund 700 Wörtern ein.

Die zweite Tabelle in der Figur ändert, wie ich das einstellen würde. Bei 4.096 hört jedes Modell von selbst auf, zwischen 1.046 und 2.680 Tokens. Keines schöpft das Budget aus. Die größere Zahl ist keine genutzte Kapazität, sie ist nur das, was das Nachdenken zu Ende kommen lässt, bevor die Antwort anfängt. Oberhalb von 2.048 kauft sie eine langsamere Anfrage und sonst nichts.

Das Nachdenken ist dabei ein Sockel, kein Anteil. Qwen verbraucht dafür zwischen 2.179 und 7.020 Zeichen, unabhängig vom Budget; Kimi zwischen 400 und 620. Genau darin liegt der Unterschied zwischen einem Modell, das bei 512 antwortet, und dreien, die es nicht tun.

Der Code

Das ist der Code, mit dem ich gemessen habe. Streaming-Parser und Zeitmessung — alles, was die Zahlen oben erzeugt hat. Der Rest meines Runners liest Argumente ein und bildet Mediane.

Code anzeigen
const res = await fetch(`${BASE}/chat/completions`, {
  method: 'POST',
  headers: { Authorization: `Bearer ${KEY}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    model, messages: [{ role: 'user', content: PROMPT }],
    max_tokens: 512, temperature: 0,
    stream: true, stream_options: { include_usage: true },
  }),
});

const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = '', first = null, last = null, visible = '', reasoning = '', usage = null;

for (;;) {
  const { done, value } = await reader.read();
  if (done) break;
  buffer += decoder.decode(value, { stream: true });
  const lines = buffer.split('\n');
  buffer = lines.pop();
  for (const line of lines) {
    // 'data:' ohne Leerzeichen. Wer auf das dokumentierte 'data: ' splittet,
    // liest null Tokens und meldet eine erfolgreiche Anfrage ohne Ausgabe.
    if (!line.startsWith('data:')) continue;
    const payload = line.slice(5).trim();
    if (!payload || payload === '[DONE]') continue;
    const frame = JSON.parse(payload);
    if (frame.usage) usage = frame.usage;
    const delta = frame.choices?.[0]?.delta;
    if (!delta) continue;
    const text = delta.content ?? '';
    // delta.reasoning, nicht das reasoning_content von vLLM und OpenAI-SDK.
    // Nur delta.content zu zählen misst bei drei der vier Modelle null.
    const think = delta.reasoning ?? delta.reasoning_content ?? '';
    if (!text && !think) continue;
    if (first === null) first = performance.now();
    last = performance.now();
    visible += text;
    reasoning += think;
  }
}

// Aktiver Durchsatz ohne die Wartezeit. End-to-end teilt durch die ganze Anfrage.
const activeTps = usage.completion_tokens / ((last - first) / 1000);

Richte es auf jeden OpenAI-kompatiblen Endpunkt. Wenn du es gegen diese API laufen lässt und andere Zahlen bekommst, ist das der Befund und kein Widerspruch — siehe die Vorbehalte weiter unten.

Was das ist und was nicht

  • Ein Client, ein Ort, ein Nachmittag. Ein Privatanschluss in Berlin, fünf Läufe pro Modell. Gegen einen Dienst, der ausdrücklich kein SLA hat, auf Hardware, die sich alle teilen, die dieselbe Ankündigung gelesen haben.
  • Gemessen ist, was ein Nutzer bekommen hat, nicht was die Hardware kann. Jede Zahl hier wäre an einem anderen Tag eine andere, die von GLM deutlich.
  • Übertragbar ist die Methode. Die Messschleife steht oben, vollständig. Sie schreibt sowohl das Roh-JSON als auch das Modul, das diese Figur liest. Ein neuer Durchlauf bewegt also das Diagramm, statt dass ich die Zahlen von Hand hinübertrage.
  • Der Budget-Durchlauf ist dünner als der erste. Zwei Stichproben je Zelle, bei GLM 5.2 nur eine, weil es mit 8 Tokens pro Sekunde allein rund 60 Prozent der Laufzeit ausmacht. Die Nullen sind eindeutig — entweder kamen Wörter zurück oder nicht. Die Wortzahlen sind der Mittelwert aus diesen zwei Läufen, bei GLM aus einem einzigen; sie beschreiben die Größe der Stufe, nicht ihre Höhe. Es ist ausserdem ein eigener Nachmittag: Kimis Zelle bei 512 zeigt 290 Wörter, wo der erste Durchgang im Median 266 hatte. Gleiches Modell, andere Warteschlange, keine Korrektur.

Würde ich sie nutzen

Für Batch-Arbeit, bei der Latenz egal ist: ja, und gern. Kostenlose Kapazität auf europäischer Hardware, mit der erklärten Absage daran, Anfrageinhalte zu speichern, ist ein wirklich gutes Angebot — und der Durchsatz hält unter Last.

Für alles Interaktive: nicht, solange die Wartezeit auf das erste Token von der Tageszeit abhängt. Und nicht über einen Standard-OpenAI-Client, solange delta.reasoning nicht entweder reasoning_content heißt oder in der Doku klar steht, dass es das nicht tut.

Genau solche Dinge soll eine experimentelle Plattform zutage fördern. Vermutlich ist das der Grund, sie so auszuliefern. Die Ankündigung bittet um genau dieses Feedback.

Und setz das Budget auf 2.048. Darunter können drei dieser vier Modelle gar nichts zurückgeben, und für zwei von ihnen reichen auch 1.024 nicht. Darüber hört jedes Modell von selbst auf — die größere Zahl kauft dir also eine langsamere Anfrage und kein einziges Wort mehr.

Next

Was weiterhin fehlt, ist die Tageszeit. Eine Handvoll Läufe an einem Nachmittag kann ein langsames Modell nicht von einem ausgelasteten trennen, und die Spanne von GLM 5.2 sagt, dass genau diese Unterscheidung bei mindestens einem davon die ganze Geschichte ist. Dafür bräuchte es dasselbe Skript eine Woche lang nach Zeitplan, und das ist ein anderer Post.

Falls du selbst einen Client auf diese API gerichtet hast: Kam beim ersten Versuch sichtbare Ausgabe zurück, oder hast du auch eine Weile geglaubt, die Modelle seien kaputt? Mich interessiert, ob das leere content alle trifft oder ob ich mit den 512 selbst hineingelaufen bin.

Gemessen am 11. August 2026 über einen Privatanschluss in Berlin, fünf gestreamte Läufe pro Modell. Jede Zahl in der Figur stammt aus scripts/bench-inference.mjs und dem daneben eingecheckten Rohbericht. Hetzner erklärt ausdrücklich, dass der Dienst kein SLA hat; an einem anderen Tag wären die Zahlen andere, bei GLM 5.2 deutlich andere.

Artikel teilen

Baust du an etwas Ähnlichem?

Ich schreibe hier über Setups, die ich selbst benutze. Wenn du an etwas Vergleichbarem arbeitest, würde mich interessieren, wie dein Workflow aussieht.

Schreib mir

Cookie-Einstellungen

Wir nutzen Cookies für Analyse und Verbesserung unserer Website. Datenschutzerklärung