Blog

Headroom: Context-Kompression vor dem LLM

Johannes Hayer
Johannes Hayer
·7 Min. Lesezeit·de

Du baust einen Agent.

Er liest Tickets, zieht Logs, ruft Tools auf, sammelt JSON und hängt noch ein paar Trace-Daten dran. Alles korrekt. Alles irgendwie relevant.

Dann geht der nächste LLM-Call raus.

20.500 Tokens.

Und das Absurde ist: Das Model braucht davon vielleicht 6.700. Der Rest ist Wiederholung, Debug-Rauschen und strukturierter Ballast, der sich teuer anfühlt, aber nicht schlauer macht.

Genau dafür ist Headroom interessant.

Nicht als neues Agent-Framework. Nicht als Prompt-Trick. Sondern als lokale Context-Kompressionsschicht direkt vor dem LLM.

Im OpenAI-Test aus dem Video sinkt der Context von ca. 20.500 Tokens auf rund 6.700 Tokens. Knapp 67 Prozent weniger Input. Gleiche Antwortqualität. Und je nach Integration ohne App-Umbau.

AI-Agenten failen selten, weil das Model zu wenig Text bekommt.

Sie failen, weil der Context voll mit Zeug ist, das technisch korrekt, aber für die nächste Entscheidung kaum wertvoll ist: komplette Tool-Outputs, wiederholte Logzeilen, riesige JSON-Blöcke, fast identische Fehlermeldungen, Metadata, die sich bei jedem Call minimal ändert.

Das kostet dreifach:

  • Geld, weil Input-Tokens linear bezahlt werden.
  • Latenz, weil größere Prompts länger verarbeitet werden.
  • Quality, weil relevante Informationen im Noise verschwinden.

Im Video#

Das Video ist die kurze, praktische Version:

  • 00:00 — Das Problem: warum dein Agent zu viele Tokens frisst
  • 00:44 — Was ist Headroom? Intro und Überblick
  • 01:45 — Architektur: wie Headroom aufgebaut ist
  • 04:20 — Python Notebook: Live-Demo mit Vorher/Nachher-Vergleich

Links:

Das Problem: Context ist keine Ablagefläche#

Wenn du einen Agenten baust, ist es verführerisch, einfach alles in den nächsten LLM-Call zu packen.

Der Agent hat ein Ticket gelesen? Rein in den Context.

Er hat Logs geholt? Rein damit.

Er hat Tool-Responses, Trace-Daten, JSON, Status, Metadaten? Auch rein damit.

Am Anfang funktioniert das. Dann wächst die Pipeline. Ein paar Tools mehr. Ein paar längere Outputs. Ein paar Debug-Felder.

Plötzlich schickst du 20.000 Tokens, obwohl das Model vielleicht 5.000 wirklich braucht.

Das Problem ist nicht nur das Context-Limit. Das Problem ist Attention.

Jeder Token konkurriert mit jedem anderen Token.

Die Idee hinter Headroom#

Headroom ist eine lokale Context-Kompressionsschicht für AI-Agenten.

Sie sitzt zwischen deiner Anwendung und dem LLM:

txt
Inputs
  -> Headroom compress
  -> LLM
  -> Metrics

Headroom versucht nicht, den Inhalt kreativ zusammenzufassen.

Das wäre gefährlich. Sobald eine Kompressionsschicht anfängt zu interpretieren, hast du einen neuen Failure-Mode gebaut.

Stattdessen macht Headroom etwas Langweiligeres und Nützlicheres:

  • Wiederholungen erkennen.
  • Strukturierte Daten verdichten.
  • Unwichtige Redundanz entfernen.
  • Einzigartige Information erhalten.
  • Das Context-Window bewusst verwalten.

Der Anspruch ist simpel: weniger Tokens rein, gleiches Signal raus.

Headroom Transformer PipelineHeadroom sitzt lokal vor dem LLM und komprimiert den Context, bevor er teuer wird.

Die Pipeline#

Headroom besteht aus drei Komponenten.

1. Cache Aligner#

Caching funktioniert am besten, wenn der stabile Teil des Prompts stabil bleibt.

Viele Agent-Prompts haben aber dynamische Informationen mitten im Prompt: Timestamps, IDs, Statuswerte, kleine Tool-Resultate. Dadurch verändert sich der Prompt früh, und der Cache-Hit wird schlechter.

Der Cache Aligner verschiebt dynamische Teile eher ans Ende und hält den statischen Prefix stabiler.

Das klingt klein, ist aber eine wichtige Infrastruktur-Entscheidung. Prompt-Caching ist nicht nur ein Feature des Providers. Es ist etwas, wofür du deinen Context aktiv layouten musst.

2. Smart Crusher#

Der Smart Crusher ist die eigentliche Kompressionslogik.

Er sucht nach Mustern, die für Menschen und Modelle offensichtlich redundant sind:

  • identische Logzeilen
  • wiederholte Stacktrace-Fragmente
  • JSON-Arrays mit gleicher Struktur
  • mehrfach auftauchende Metadaten
  • lange Werte, die für den Task keine zusätzliche Information tragen

Wichtig: Das Ziel ist nicht, alles möglichst kurz zu machen. Das Ziel ist, das Signal-Rausch-Verhältnis zu verbessern.

Wenn eine Information einzigartig ist, bleibt sie erhalten. Wenn 200 Logzeilen dasselbe Pattern zeigen, muss das Modell nicht alle 200 sehen.

3. Context Manager#

Der Context Manager ist die Sicherheitsleine.

Er überwacht, wie voll das Context-Window wird, und entscheidet, was priorisiert wird, wenn es eng wird. Denn Kompression allein reicht nicht. Du brauchst eine Policy:

  • Was ist Task-kritisch?
  • Was ist nur Debug-Rauschen?
  • Was darf gekürzt werden?
  • Was muss wortgetreu erhalten bleiben?

Ohne diese Schicht wird Context-Kompression schnell zu blindem Kürzen. Und blindes Kürzen ist nur eine andere Art von Bug.

Drei Wege, Headroom zu nutzen#

Headroom ist nicht als Framework gedacht, das deine komplette Agent-Architektur übernimmt.

Das ist wichtig. Gute Infrastructure-Schichten lösen ein enges Problem und lassen deine Pipeline in Ruhe.

Im Notebook stehen die drei Modi sehr klar:

1. compress() direkt im Code#

Das ist der sauberste Weg, wenn du die Agent-Pipeline selbst kontrollierst. Du baust deine Messages, rufst compress() auf und gibst danach result.messages an den LLM-Client weiter.

python
from headroom import compress
 
result = compress(
    messages,
    model="gpt-4o",
    compress_user_messages=True,
    protect_recent=0,
    target_ratio=0.3,
    min_tokens_to_compress=0,
)
 
compressed_messages = result.messages
print(result.transforms_applied)

Das ist der Modus aus der Notebook-Demo, weil er den Vorher/Nachher-Vergleich am sichtbarsten macht.

2. Proxy#

Der Proxy ist für bestehende Systeme interessant: Headroom sitzt als lokaler Zwischenserver vor deinem Provider.

bash
headroom proxy --port 8787

Deine App spricht dann nicht mehr direkt mit dem LLM-Endpunkt, sondern mit dem lokalen Proxy. Das ist die Variante, wenn du möglichst wenig Code anfassen willst.

3. SDK oder Wrapper#

Der dritte Weg ist ein Wrapper um bestehende Clients oder Agent-Tools. Das Headroom-Repo beschreibt diesen Modus als wrap für Coding-Agents und als SDK für eigene Integrationen.

bash
headroom wrap claude
headroom wrap codex

Oder inline im TypeScript-/Python-Code, wenn du die Kompression explizit an der Call-Site kontrollieren willst.

Das Pattern ist immer gleich: Headroom läuft lokal, komprimiert den Context, misst das Ergebnis und gibt den verdichteten Input weiter.

Was im Notebook passiert#

Das Demo-Notebook baut einen künstlichen, aber realistischen Incident-Kontext: Payment-Logs, Support-Tickets und Root-Cause-Notizen.

Der Rohkontext sieht absichtlich aus wie das, was Agenten in Produktion ständig sehen: viele repetitive Logs, große JSON-Arrays und ein paar wirklich wichtige Fakten.

python
def build_incident_context():
    incident_logs = "\n".join([
        f"2026-06-23 10:14:{i:02d} payment-service ERROR "
        f"checkout_id=chk_{1000+i} provider=stripe status=502 "
        f"retry={i%3} message=upstream timeout from payments-api"
        for i in range(120)
    ])
 
    support_tickets = json.dumps([
        {
            "ticket_id": f"CS-{2000 + i}",
            "customer_tier": "enterprise" if i % 4 == 0 else "pro",
            "channel": "chat" if i % 2 == 0 else "email",
            "issue_type": "payment_failed",
            "status": "waiting_for_retry",
            "country": ["DE", "AT", "CH", "NL"][i % 4],
            "message": "I tried to pay and got an error. Please check my invoice.",
        }
        for i in range(180)
    ], indent=2)
 
    return [
        {"role": "system", "content": "You are helping investigate a payment incident. Keep only high-signal facts."},
        {"role": "user", "content": "Please analyze the incident material and summarize what matters for the on-call response."},
        {"role": "tool", "tool_call_id": "logs", "content": incident_logs},
        {"role": "tool", "tool_call_id": "tickets", "content": support_tickets},
    ]

Das ist ein gutes Testbett, weil es genau die Art von Context simuliert, die bei Agenten teuer wird: Logs und Tickets sind wichtig, aber der Großteil ist Wiederholung.

Danach misst das Notebook den Rohkontext, komprimiert ihn und vergleicht die Token-Zahlen:

python
messages = build_incident_context()
raw_tokens = token_count(messages)
 
result = compress(
    messages,
    model=MODEL,
    compress_user_messages=True,
    protect_recent=0,
    target_ratio=0.3,
    min_tokens_to_compress=0,
)
 
compressed_tokens = token_count(result.messages)
tokens_saved = raw_tokens - compressed_tokens
saved_pct = (tokens_saved / raw_tokens * 100) if raw_tokens else 0
 
print(f"SAVED TOKENS: {tokens_saved}")
print(f"SAVED PCT: {saved_pct:.1f}%")
print(", ".join(result.transforms_applied))

Der wichtige Punkt: Headroom komprimiert nicht blind. Es gibt zurück, welche Transformationen angewendet wurden. Das ist für Debugging wichtig. Eine Optimierung, die du nicht beobachten kannst, wird in Production irgendwann gefährlich.

Live-Vergleich gegen OpenAI#

Das Notebook schickt denselben Task zweimal an OpenAI:

  1. einmal mit dem Rohkontext
  2. einmal mit dem Headroom-komprimierten Kontext

Der Vergleich nutzt die echten prompt_tokens aus der API-Response, nicht nur eine lokale Schätzung.

python
def call_openai(label, context_text):
    msgs = [
        {"role": "system", "content": SYSTEM},
        {"role": "user", "content": f"{context_text}\n\n{QUESTION}"},
    ]
    t0 = time.perf_counter()
    response = client.chat.completions.create(
        model=model,
        messages=msgs,
        max_tokens=150,
    )
    latency_ms = (time.perf_counter() - t0) * 1000
    u = response.usage
    return {
        "label": label,
        "latency_ms": round(latency_ms),
        "prompt_tokens": u.prompt_tokens,
        "completion_tokens": u.completion_tokens,
        "total_tokens": u.total_tokens,
        "reply": response.choices[0].message.content,
    }

Das ist der Teil, der für mich am wichtigsten ist. Lokale Token-Schätzungen sind nützlich, aber am Ende zählt, was der Provider abrechnet und ob die Antwort noch funktioniert.

Im OpenAI-Test aus dem Video geht der Prompt von ca. 20.500 Tokens auf rund 6.700 Tokens runter. Das sind knapp 67 Prozent weniger Tokens. Die gemessene Latenz sinkt im selben Test von 6 ms auf 1 ms.

Das Headroom-Repo zeigt zusätzlich Workloads mit 92 Prozent Einsparung, zum Beispiel Code Search und SRE Incident Debugging. Ich würde diese Zahlen bewusst getrennt lesen: 67 Prozent ist der gezeigte OpenAI-Praxistest im Video, 92 Prozent ist ein stärker komprimierbarer Benchmark aus dem Repo.

Das ist kein Versprechen, dass jede Pipeline 92 Prozent spart. Es ist ein Signal: In echten Agent-Pipelines steckt oft sehr viel Headroom, bevor du das Modell überhaupt wechselst.

Output-Tokens: Die andere Hälfte der Rechnung#

Headroom kann nicht nur den Input reduzieren. Im Notebook gibt es auch eine kleine Demo für Output-Token-Reduction.

Der Punkt: Bei vielen Modellen sind Output-Tokens deutlich teurer als Input-Tokens. Und Modelle schreiben gerne Dinge zurück, die du nicht brauchst:

  • Preambles wie "Natürlich, hier ist..."
  • Wiederholung der Frage
  • nochmal ausgedruckter Context
  • tiefe Erklärungen bei Routine-Schritten

Das Notebook simuliert ein einfaches Verbosity-Steering:

python
VERBOSITY_NOTE = (
    "\n\nBe direct and concise. Do not restate the question, repeat context already "
    "provided, add preambles like 'Great, let me...' or 'Certainly!', or include "
    "closing summaries unless explicitly asked."
)
 
normal = call("NORMAL", BASE_SYSTEM)
shaped = call("VERBOSITY STEERING", BASE_SYSTEM + VERBOSITY_NOTE)
 
saved = normal["completion_tokens"] - shaped["completion_tokens"]
saved_pct = saved / normal["completion_tokens"] * 100

Das ist nicht der Kern von Headroom, aber es zeigt das größere Mentalmodell: Token-Kosten entstehen auf beiden Seiten des Calls. Gute AI-Infrastruktur optimiert Input und Output.

Warum das wichtiger wird#

Viele Teams optimieren AI-Systeme in dieser Reihenfolge:

  1. größeres Modell
  2. besserer Prompt
  3. mehr Context
  4. noch mehr Context

Das ist verständlich, aber teuer.

Ein besserer Reflex ist:

  1. Was braucht das Modell wirklich?
  2. Was ist redundant?
  3. Was kann strukturiert verdichtet werden?
  4. Was muss aus Qualitätsgründen unverändert bleiben?
  5. Wie messen wir Tokens, Ratio und Latenz pro Call?

Headroom ist eine Antwort auf genau diese Fragen.

Nicht als magische Optimierung. Als Engineering-Schicht.

Das eigentliche Mentalmodell#

Context-Kompression ist kein Prompt-Trick.

Sie ist Infrastruktur.

Wenn du Agenten baust, ist der Context nicht nur Text. Er ist dein Runtime-State.

Und Runtime-State muss verwaltet werden: sortiert, priorisiert, gemessen, komprimiert und geschützt.

Headroom macht diese Schicht sichtbar.

Nicht jeder Token ist gleich wertvoll. Gute AI-Infrastruktur behandelt ihn auch nicht so.

AI Engineering, wöchentlich.

Praktisches AI Engineering direkt in dein Postfach.