Long-Form-LLM-Generierung mit niedrigen Token-Kosten: ein Engineering-Report
Inhalt
- 1) Warum Single-Shot-Prompting scheiterte
- 2) Architektur, die lange Texte stabil gemacht hat
- Stufe A: Retrieval-Kontext mit strikten Budgets
- Stufe B: Adaptives Input-Budgeting
- Stufe C: Segmentierte Generierung für große Texte
- Stufe D: Konsistenz-Pass
- 3) Token- und Latenz-Kontrollen mit größter Wirkung
- 4) Betriebskontrollen und Observability
- 5) Praktisches Implementierungsmuster
- 6) Trade-offs und worauf man achten sollte
- 7) Empfohlene Defaults für den Start
- Zentrales Fazit
Als wir begonnen haben, lange Texte über eine LLM-Pipeline zu erzeugen, sah das Hauptproblem zuerst nach Modellqualität aus. In der Praxis war es vor allem Systems Engineering: Request-Größe, Latenzvarianz, Proxy-Timeouts und unbegrenzter Output.
Dieser Bericht fasst zusammen, was unter produktionsnahen Bedingungen funktioniert hat, wenn die Ziele waren:
- Lange Texte zuverlässig erzeugen,
- Tokenverbrauch vorhersagbar halten,
- Timeout-Risiko senken,
- Qualität über mehrere Abschnitte erhalten.
1) Warum Single-Shot-Prompting scheiterte #
Der naive Ansatz war ein großer Request mit vollem Quelltext plus viel Kontext. Das führte zu drei Problemen:
- Hohe Input-Token-Kosten bei jedem Lauf,
- Hohe Latenzvarianz je nach Promptlänge und Modelllast,
- Gateway-504s, obwohl das Modell später noch eine Antwort lieferte.
Zentrale Erkenntnis: Eine erfolgreiche Modellantwort ist wertlos, wenn eine vorgelagerte Komponente vorher in den Timeout läuft. Zuverlässigkeit muss auf Pipeline-Ebene entworfen werden, nicht nur auf Modell-Ebene.
2) Architektur, die lange Texte stabil gemacht hat #
Wir sind von One-Shot-Generierung auf eine begrenzte, mehrstufige Pipeline gewechselt.
Stufe A: Retrieval-Kontext mit strikten Budgets #
Statt alles verwandte Material mitzuschicken, haben wir:
- Quelltexte in absatzbasierte Segmente gechunkt,
- Embeddings einmal erzeugt und gecacht,
- Pro Request nur die relevantesten Chunks gewählt,
- Harte Limits gesetzt: Gesamtzahl Chunks, Chunks pro Datei, Snippetlänge und Retrieval-Zeichenbudget.
Das reduzierte wiederholte Tokenverschwendung und machte Requests vorhersagbarer.
Stufe B: Adaptives Input-Budgeting #
Vor jedem Modellaufruf berechnen wir ein dynamisches Budget aus:
- Aktueller Inhaltslänge,
- Promptlänge,
- Erwartetem Overhead des Systemprompts.
Wenn der Input das Budget überschreiten würde:
- Zuerst Retrieval-Kontext reduzieren,
- Dann Hauptinhalt mit kontrollierter Middle-Trim-Strategie kürzen,
- Kopf und Ende behalten, damit Einleitung und Schlusskontext erhalten bleiben.
Das liefert bessere Qualität als harte Abschneidung nur von einer Seite.
Stufe C: Segmentierte Generierung für große Texte #
Bei großen Dokumenten verzichten wir auf Single-Pass-Generierung.
Ablauf:
- Text in überlappende Segmente aufteilen,
- Jedes Segment separat mit kleinerem Max-Output überarbeiten,
- In Originalreihenfolge zusammenführen,
- Einen finalen Konsistenz-Pass über den Gesamttext laufen lassen.
So wird aus einem fragilen Großaufruf eine Reihe robusterer Kleinaufrufe.
Stufe D: Konsistenz-Pass #
Nach dem Zusammenführen läuft ein kurzer globaler Pass mit Fokus auf:
- Terminologiekonsistenz,
- Tonalitätsabgleich,
- Stilharmonisierung.
Wichtig ist hier regelbasiertes Prompting: kein neuer Inhalt, kein strukturelles Umschreiben, keine Meta-Kommentare.
3) Token- und Latenz-Kontrollen mit größter Wirkung #
Diese Kontrollen hatten den größten Effekt:
- Max-Output-Tokens pro Aufruf, angepasst an die Input-Größe,
- Reduziertes Retrieval-Budget bei größeren Dokumenten,
- Weniger Retrieval-Chunks bei sehr großen Inputs,
- Segmentmodus oberhalb einer Inhalts-Schwelle,
- Verkürzter Retrieval-Kontext während Segmentaufrufen,
- Persistenter Embedding-Cache mit Content-Hash als Schlüssel.
Der Cache ist kritisch. Ohne ihn bezahlt ein Long-Form-Workflow Embedding-Kosten immer wieder und verliert den Großteil des Effizienzgewinns.
4) Betriebskontrollen und Observability #
Wir haben strukturiertes Logging rund um jede Stufe eingeführt:
- Request-Metadaten: model, input_chars, context_chars, max_tokens, timeout,
- Retrieval-Metadaten: Cache-Hits, neu eingebettete Dateien, ausgewählte Chunks, Laufzeit,
- Segment-Metadaten: Segmentanzahl, Output-Größe je Segment, Status des Konsistenz-Passes,
- Outcome-Metadaten: Quellmodell, Fallback-Grund, Laufzeit pro Datei.
Dadurch wurde Debugging von Bauchgefühl zu messbarem Tuning.
Wenn Aufrufe exakt an der Timeout-Grenze scheiterten, war klar: lokales oder clientseitiges Timeout-Verhalten, nicht mangelnde Modellqualität.
5) Praktisches Implementierungsmuster #
Eine einfache Implementierungsstrategie für Entwickler:
- Limits aus Inhalts- und Promptlänge vorab berechnen,
- Retrieval-Kontext innerhalb dieser Limits aufbauen,
- Bei Überschreiten der Schwelle Segmentmodus aktivieren,
- Für jeden Modellaufruf Max-Output-Tokens setzen,
- Zusammenführen und optional Konsistenz-Pass ausführen,
- Vorschlag plus Metadaten für Observability und Retries persistieren.
Pseudo-Flow:
compute limits
retrieval_context = bounded_retrieval(...)
if segmented_mode:
segments = split_with_overlap(...)
revised_segments = map(revise_segment)
merged = join(revised_segments)
final = consistency_pass(merged)
else:
final = revise_single_pass(...)
store result with source and error metadata
6) Trade-offs und worauf man achten sollte #
Segmentmodus verbessert Zuverlässigkeit und Kostenkontrolle, kann aber Merge-Artefakte erzeugen, wenn die Überlappung zu klein ist. Eine kurze Überlappung plus Konsistenz-Pass löst das meist.
Zu aggressives Trimming senkt die Qualität. Immer erst Retrieval kürzen, dann erst bei Bedarf den Hauptinhalt.
Zu hoher Max-Output erhöht das Timeout-Risiko, zu niedriger verursacht abgeschnittene Antworten. Besser dynamische Bänder nach Input-Größe statt eines festen Werts.
7) Empfohlene Defaults für den Start #
- Segment-Schwelle: etwa 26k Zeichen,
- Segmentgröße: etwa 5k Zeichen mit 300-350 Überlappung,
- Retrieval-Budget: höher bei kleinen Dokumenten, niedriger bei großen,
- Max-Output-Tokens: niedriger bei kleinen Dokumenten, moderat bei großen, aber gedeckelt,
- Timeout: Modell-Timeout über der durchschnittlichen Antwortzeit, Gateway-Timeout über dem Modell-Timeout.
Zentrales Fazit #
Long-Form-LLM-Generierung mit niedrigen Token-Kosten ist primär ein Pipeline-Design-Problem, kein Prompt-Trick. Das erfolgreiche Muster ist:
- Weniger, aber besseres Retrieval,
- Aggressives Input-Budgeting,
- Segmentierung großer Arbeitspakete,
- Output-Caps,
- Vollständige Instrumentierung.
Diese Kombination liefert niedrigere Kosten, weniger 504s und besser vorhersagbare Qualität für reale Engineering-Workflows.