Update API documentation with Llama 3.1 quirks
This commit is contained in:
+108
-34
@@ -1,7 +1,7 @@
|
||||
# Ionos LLM API: Quirks und Workarounds
|
||||
|
||||
**Stand:** 2026-05-03 — empirisch ermittelt gegen
|
||||
`https://openai.inference.de-txl.ionos.com/v1/chat/completions`.
|
||||
**Stand:** 2026-05-03 (zweite Session, in Doctate umgesetzt) — empirisch
|
||||
ermittelt gegen `https://openai.inference.de-txl.ionos.com/v1/chat/completions`.
|
||||
Verhalten kann sich aendern; Datum oben mit dem aktuellen Test-Befund
|
||||
abgleichen, bevor man auf diese Notizen baut.
|
||||
|
||||
@@ -15,15 +15,22 @@ abgleichen, bevor man auf diese Notizen baut.
|
||||
`https://api.ionos.com/docs/inference-openai/v1/`. Das ist eine
|
||||
Redoc-Seite mit eingebetteter OpenAPI-3.0.3-Spec — die einzige
|
||||
verlaessliche Quelle fuer unterstuetzte Parameter, Defaults und Limits.
|
||||
- Llama 3.1 405B FP8 hat einen **vLLM-Tokenizer-Bug**: das
|
||||
End-of-Turn-Token `<|eot_id|>` wird als Klartext-String
|
||||
`assistant\n\n` ausgegeben statt als Special-Token. Folge: der
|
||||
offizielle `stop`-Parameter mit `<|eot_id|>` feuert nie, das Modell
|
||||
laeuft bis `max_tokens` voll.
|
||||
- **Empfohlene Loesung fuer Doctate**: `response_format: json_schema`.
|
||||
Schema-erzwungenes Decoding stoppt natuerlich am schliessenden `}`,
|
||||
funktioniert modell-agnostisch und braucht keine Provider-spezifischen
|
||||
Workarounds.
|
||||
- Llama 3.1 405B FP8 hat ein bekanntes **End-of-Turn-Termination-Problem**:
|
||||
in der Sandbox kam `<|eot_id|>` als ASCII-`assistant\n\n` zurueck, was
|
||||
Quelle der ersten Diagnose war. Aber das eigentliche Problem ist breiter
|
||||
und modell-inhaerent: Llama 3.1 verfaellt mit Greedy-Decoding und/oder
|
||||
konflikthaltigen Prompts in Endlos-Schleifen (bestaetigt von Ionos selbst,
|
||||
HuggingFace-Discussion #32, vLLM-Issues #13530, #13828).
|
||||
- **Empfohlene Loesung fuer Doctate (Drei-Komponenten-Kombi):**
|
||||
`temperature: 0.6 + top_p: 0.9` (Sampling) + `response_format:
|
||||
json_schema` (Form-Garantie) + expliziter Format-Hinweis als zweite
|
||||
`system`-Message (sagt dem Modell WAS in `document` zu schreiben ist).
|
||||
Alle drei sind notwendig; jede einzelne weggelassen kippt in einen
|
||||
anderen Failure-Mode (Timeout, Endlos-Schleife, oder silent
|
||||
`{"document": ""}`).
|
||||
- **Wichtig**: gpt-oss-120b braucht weder Sampling noch Format-Hinweis —
|
||||
es ist schema-aware trainiert und laeuft mit dem Default-Body sauber.
|
||||
Die Drei-Komponenten-Loesung ist Llama-spezifisch, nicht universell.
|
||||
|
||||
## So kommt man an die richtige API-Info
|
||||
|
||||
@@ -176,6 +183,8 @@ Gateway-Timeout.
|
||||
|
||||
### Empirische Datentabelle
|
||||
|
||||
#### Session 1 (Diagnose, Sandbox-Inputs)
|
||||
|
||||
Alle Tests mit `meta-llama/Meta-Llama-3.1-405B-Instruct-FP8`,
|
||||
Input `"Sag hallo."` (ausser T22 = realer Doctate-Body, ~1.5k Prompt-Tokens):
|
||||
|
||||
@@ -193,8 +202,41 @@ Input `"Sag hallo."` (ausser T22 = realer Doctate-Body, ~1.5k Prompt-Tokens):
|
||||
| T22 | T21 + realer Doctate-Body (1539 Prompt-Tokens) | **22.77 s, finish=stop, 482 Tokens** | 22.7 |
|
||||
|
||||
Konsistenz: **`finish_reason: "length"` heisst Modell wollte
|
||||
weiter** — kein sauberer Stop. Nur die letzten vier Loesungswege
|
||||
bekommen sauberes `"stop"`.
|
||||
weiter** — kein sauberer Stop.
|
||||
|
||||
#### Session 2 (Reproduktion gegen Production-Pipeline, 30 s Timeout)
|
||||
|
||||
Alle Tests gegen den realen Doctate-Body von Case `aecf5890` (236
|
||||
char user_content, ~1040-1115 Prompt-Tokens). Skripte unter
|
||||
`/tmp/doctate-llama-test/run{1..6}.py`. Production-`LLAMA_SYSTEM_PROMPT`
|
||||
verbatim (2819 chars).
|
||||
|
||||
| Test | Sampling | json_schema | Format-Hinweis | Wallclock | finish | Output |
|
||||
|---|---|---|---|---|---|---|
|
||||
| T1 | nein (`temp=0.5`) | ja | nein | **30 s Timeout** | – | nichts geliefert |
|
||||
| T2 | nein (`temp=0.5`) | ja | im Prompt inline | 3.26 s | stop | sauber, 61 Tokens |
|
||||
| T3 | ja (`0.6 + 0.9 + freq=0.1 + stop`) | nein (Ionos-Doku verbatim) | nein | **30 s Timeout** | – | nichts geliefert |
|
||||
| T4 | ja (`0.6 + 0.9`) | ja | nein | 0.98 s | stop | **`{"document":""}` (silent deletion)** |
|
||||
| T5 | ja (`0.6 + 0.9`) | ja | im Prompt inline | 3× ⌀ 3.05 s | stop | sauber, 61 Tokens, 3× stabil |
|
||||
| T6 | ja (`0.6 + 0.9`) | ja | als zweite `system`-Message | 3× ⌀ 3.13 s | stop | sauber, 61 Tokens, 3× stabil — **Production-Konfig** |
|
||||
|
||||
**Wichtige Befunde aus Session 2:**
|
||||
|
||||
1. **json_schema allein reicht nicht (T1)**: Production-Pfad mit
|
||||
`temperature: 0.5` ohne `top_p` timeoutet, weil Llama Schema-Resampling
|
||||
als Endlos-Schleife verkraftet.
|
||||
2. **Sampling allein reicht nicht (T3)**: Selbst die exakte Ionos-Doku-
|
||||
Empfehlung mit `stop: ["<|eot_id|>", "<|end_of_text|>"]` timeoutet
|
||||
gegen unseren 2.8k-Char-Prompt. Die Doku-Empfehlung ist fuer kuerzere
|
||||
Prompts validiert.
|
||||
3. **Sampling + Schema ohne Hinweis kippt in silent deletion (T4)**:
|
||||
Modell respektiert die Form, weiss aber inhaltlich nicht was tun.
|
||||
`{"document": ""}` waere fuer Doctate als leere Notiz im UI gelandet
|
||||
— gefaehrlicher als Timeout, weil der Worker `remove_failure_marker`
|
||||
aufruft. **Worker.rs hat seither einen Empty-Guard.**
|
||||
4. **Drei-Komponenten-Kombi laeuft 3x stabil (T5, T6)**: Sampling +
|
||||
Schema + Format-Hinweis. T6 (separate `system`-Message) ist
|
||||
architektonisch sauberer und gewaehlt fuer die Doctate-Implementation.
|
||||
|
||||
## Loesungswege im Vergleich
|
||||
|
||||
@@ -202,33 +244,60 @@ bekommen sauberes `"stop"`.
|
||||
|---|---|---|---|---|
|
||||
| `stop: ["assistant"]` | sehr schnell | nein | nein | Patch fuer Provider-Bug; bricht im englischen Text |
|
||||
| Eigener End-Marker via System-Prompt | sehr schnell | mittel | ja | Modell kann Marker bei langem Output vergessen |
|
||||
| `response_format: json_schema` | schnell | ja | **ja** | Server erzwingt Stop ueber Grammar-Decoding |
|
||||
| Modellwechsel auf `gpt-oss-120b` / `Llama-3.3-70B` | sehr schnell | ja | – | Quirks A+B betreffen diese Modelle nicht |
|
||||
| `response_format: json_schema` allein | – | nein | nein | **In Production NICHT ausreichend** (T1, T4) — kippt entweder in Timeout oder silent deletion |
|
||||
| **Drei-Komponenten-Kombi** (Sampling + Schema + Format-Hinweis) | schnell (3 s) | ja | – | **In Doctate umgesetzt fuer Llama** (T5, T6) |
|
||||
| Modellwechsel auf `gpt-oss-120b` / `Llama-3.3-70B` | sehr schnell | ja | – | Schema-aware, brauchen die Drei-Komponenten-Kombi nicht |
|
||||
|
||||
Empfehlung: **`response_format: json_schema`** als Default-Pfad fuer
|
||||
Doctate, weil derselbe Code-Pfad auf gpt-oss-120b und Llama 3.3 70B
|
||||
unveraendert weiter funktioniert. Wenn das Schema-Decoding bei
|
||||
zukuenftigen, viel groesseren Outputs Latenzprobleme macht, wechselt
|
||||
man auf einen schnelleren Modell-Endpoint, nicht zurueck auf
|
||||
String-Hacks.
|
||||
**Empfehlung pro Modell-Familie:**
|
||||
- Schema-aware Modelle (gpt-oss-120b, vermutlich Llama 3.3 70B):
|
||||
`temperature: 0.5 + response_format: json_schema`. Body bleibt klein
|
||||
und stabil.
|
||||
- Llama 3.1 405B FP8: nur als **Drei-Komponenten-Kombi** brauchbar —
|
||||
`temperature: 0.6 + top_p: 0.9 + response_format: json_schema +
|
||||
expliziter Format-Hinweis als zweite system-Message`. Wer eine
|
||||
Komponente weglaesst, faengt sich Timeout (T1, T3) oder silent
|
||||
deletion (T4) ein.
|
||||
|
||||
## Doctate-Implementation (`server/src/analyze/backend.rs`)
|
||||
|
||||
Die Drei-Komponenten-Kombi lebt als Per-Backend-Konfiguration:
|
||||
|
||||
```rust
|
||||
const LLAMA_TEMPERATURE: f32 = 0.6;
|
||||
const LLAMA_TOP_P: f32 = 0.9;
|
||||
const LLAMA_FORMAT_INSTRUCTION: &str = "AUSGABEFORMAT: ...";
|
||||
|
||||
ionos_backend("llama_3_1_405b", "Llama 3.1 405B", "...405B-Instruct-FP8")
|
||||
.with_system_prompt(LLAMA_SYSTEM_PROMPT)
|
||||
.with_temperature(LLAMA_TEMPERATURE)
|
||||
.with_top_p(LLAMA_TOP_P)
|
||||
.with_format_instruction(LLAMA_FORMAT_INSTRUCTION),
|
||||
```
|
||||
|
||||
`chat_once` injiziert `format_instruction` als zweite `system`-Message
|
||||
zwischen `system_prompt` und `user`-Content, falls `Some`. Backends
|
||||
ohne `format_instruction` (gpt-oss) erzeugen den exakten Body wie vor
|
||||
dem Llama-Fix — byte-stabil, gepinnt durch
|
||||
`gpt_oss_has_no_format_instruction_and_no_top_p`-Test.
|
||||
|
||||
`worker.rs` hat einen **Empty-Guard** nach `vocab.replace`: leere
|
||||
`document`-Strings (Failure-Mode T4) loesen einen Failure-Marker statt
|
||||
einer leeren `document.md` aus.
|
||||
|
||||
## Entscheidungsbaum
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Neuer Aufruf gegen Ionos] --> B{Brauche ich strukturierten Output?}
|
||||
B -->|Ja oder unsicher| C[response_format: json_schema setzen]
|
||||
B -->|Nein, freier Text| D{Modell?}
|
||||
D -->|gpt-oss-120b oder Llama 3.3 70B| E[Standard-Aufruf reicht]
|
||||
D -->|Llama 3.1 405B FP8| F[max_tokens MUSS gesetzt sein]
|
||||
F --> G{Wie soll gestoppt werden?}
|
||||
G -->|Sauber via Schema| C
|
||||
G -->|String-Hack ok| H["stop: array enthaelt 'assistant'"]
|
||||
G -->|Eigener Marker| I[System-Prompt instruiert + stop matcht]
|
||||
C --> J[Output ist JSON, server-seitig parsen]
|
||||
E --> K[Output direkt nutzen]
|
||||
H --> K
|
||||
I --> K
|
||||
A[Neuer Backend-Profil-Eintrag in backend.rs] --> B{Modell?}
|
||||
B -->|gpt-oss-120b<br/>schema-aware| C[Default: temp 0.5,<br/>use_json_schema=true,<br/>kein top_p, keine format_instruction]
|
||||
B -->|Llama 3.1 405B FP8| D[Drei-Komponenten-Kombi:<br/>temp 0.6 + top_p 0.9 + schema<br/>+ format_instruction]
|
||||
B -->|Llama 3.3 70B<br/>noch nicht getestet| E[Erst gegen Doctate-Body testen,<br/>vermutlich wie gpt-oss]
|
||||
B -->|Anderes neues Modell| F{Schema-aware trainiert?}
|
||||
F -->|Ja| C
|
||||
F -->|Nein| D
|
||||
C --> G[Body byte-stabil zu pre-Llama-Fix]
|
||||
D --> H[Worker-Empty-Guard schuetzt vor silent deletion]
|
||||
E --> G
|
||||
```
|
||||
|
||||
## Quellen und Verweise
|
||||
@@ -254,6 +323,11 @@ einem neuen Bug auf diese Workarounds setzt, immer zuerst pruefen, ob:
|
||||
`assistant\n\n` ankommt — dann ist Quirk A behoben und die
|
||||
String-Hacks koennen weg.
|
||||
3. Die OpenAPI-Spec neue/geaenderte Parameter zeigt.
|
||||
4. Die Drei-Komponenten-Kombi fuer Llama 3.1 weiterhin noetig ist:
|
||||
schnellster Check ist, das `format_instruction`-Feld testweise auf
|
||||
`None` zu setzen und einen Doctate-Case neu zu triggern. Wenn der
|
||||
Output sauber kommt, kann der Format-Hinweis weg. Wenn er
|
||||
`{"document":""}` ist, gilt diese Doku noch.
|
||||
|
||||
Datum oben aktualisieren, wenn man verifiziert hat, dass diese
|
||||
Dokumentation noch dem realen Backend-Verhalten entspricht.
|
||||
|
||||
Reference in New Issue
Block a user