[object Object]

← back to Exo

Strip Claude headers to improve prefix cache hit rates (#1552)

423ed0f07f706b0555547a0f3512ea0402221207 · 2026-02-19 18:29:34 +0000 · rltakashige

## Motivation
Our hits are really bad at the moment (0.2%). This PR makes it 98.5% on
average.

## Changes

Also adds an example for how to run Claude using Exo.

## Why It Works
Claude sends some billing and session headers that change with each
message.

## Test Plan

### Manual Testing
Works in manual testing.

Files touched

Diff

commit 423ed0f07f706b0555547a0f3512ea0402221207
Author: rltakashige <rl.takashige@gmail.com>
Date:   Thu Feb 19 18:29:34 2026 +0000

    Strip Claude headers to improve prefix cache hit rates (#1552)
    
    ## Motivation
    Our hits are really bad at the moment (0.2%). This PR makes it 98.5% on
    average.
    
    ## Changes
    
    Also adds an example for how to run Claude using Exo.
    
    ## Why It Works
    Claude sends some billing and session headers that change with each
    message.
    
    ## Test Plan
    
    ### Manual Testing
    Works in manual testing.
---
 src/exo/master/adapters/claude.py  | 19 +++++++++++++++++++
 tmp/config_examples/claude_code.sh |  8 ++++++++
 2 files changed, 27 insertions(+)

diff --git a/src/exo/master/adapters/claude.py b/src/exo/master/adapters/claude.py
index d9d52496..d5246bbc 100644
--- a/src/exo/master/adapters/claude.py
+++ b/src/exo/master/adapters/claude.py
@@ -1,6 +1,7 @@
 """Claude Messages API adapter for converting requests/responses."""
 
 import json
+import re
 from collections.abc import AsyncGenerator
 from typing import Any
 
@@ -61,6 +62,22 @@ def _extract_tool_result_text(block: ClaudeToolResultBlock) -> str:
     return "".join(sub_block.text for sub_block in block.content)
 
 
+# Matches "x-anthropic-billing-header: ...;" (with optional trailing newline)
+# or similar telemetry headers that change every request and break KV prefix caching.
+_VOLATILE_HEADER_RE = re.compile(r"^x-anthropic-[^\n]*;\n?", re.MULTILINE)
+
+
+def _strip_volatile_headers(text: str) -> str:
+    """Remove Anthropic billing/telemetry headers from system prompt text.
+
+    Claude Code prepends headers like 'x-anthropic-billing-header: cc_version=...;
+    cc_entrypoint=...; cch=...;' that contain per-request content hashes. These
+    change every request and break KV prefix caching (the prefix diverges at ~20
+    tokens instead of matching thousands of conversation tokens).
+    """
+    return _VOLATILE_HEADER_RE.sub("", text)
+
+
 def claude_request_to_text_generation(
     request: ClaudeMessagesRequest,
 ) -> TextGenerationTaskParams:
@@ -73,6 +90,8 @@ def claude_request_to_text_generation(
             instructions = request.system
         else:
             instructions = "".join(block.text for block in request.system)
+
+        instructions = _strip_volatile_headers(instructions)
         chat_template_messages.append({"role": "system", "content": instructions})
 
     # Convert messages to input
diff --git a/tmp/config_examples/claude_code.sh b/tmp/config_examples/claude_code.sh
new file mode 100755
index 00000000..685d0a27
--- /dev/null
+++ b/tmp/config_examples/claude_code.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+# Run Claude Code against a local exo cluster! (Here, GPT OSS 120B)
+ANTHROPIC_BASE_URL="http://localhost:52415/" \
+  ANTHROPIC_AUTH_TOKEN="dummy" \
+  ANTHROPIC_MODEL="mlx-community/gpt-oss-120b-MXFP4-Q8" \
+  ANTHROPIC_SMALL_FAST_MODEL="mlx-community/gpt-oss-120b-MXFP4-Q8" \
+  CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 \
+  claude

← ed001f24 remove prefillprogress event (#1550)  ·  back to Exo  ·  feat: Mac Studio en2 RDMA port warning v2 (#1551) 94b2ce69 →