5K

Prompt Caching via Exact Prefix Preservation

Keeps static prompt content first in a fixed order and only appends new messages, including config changes, so each request reuses the cached prefix

emerging Updated 2026-10-13 By Nikola Balic (@nibzard) Based on Michael Bolin (OpenAI Codex)
View .md Edit on GitHub
Add to Pack
or

Saved locally in this browser for now.

Cite This Pattern
APA
Nikola Balic (@nibzard) (2026). Prompt Caching via Exact Prefix Preservation. In *Awesome Agentic Patterns*. Retrieved October 14, 2026, from https://agentic-patterns.com/patterns/prompt-caching-via-exact-prefix-preservation
BibTeX
@misc{agentic_patterns_prompt-caching-via-exact-prefix-preservation,
  title = {Prompt Caching via Exact Prefix Preservation},
  author = {Nikola Balic (@nibzard)},
  year = {2026},
  howpublished = {\url{https://agentic-patterns.com/patterns/prompt-caching-via-exact-prefix-preservation}},
  note = {Awesome Agentic Patterns}
}

Use when

  • Long agent conversations with many tool calls
  • Zero Data Retention rules out server-side conversation state
  • Inference cost or latency grows as history grows

Avoid when

  • Tool list or model must change mid-conversation
  • Short single-turn requests with little repeated content

Problem

Long-running agent conversations with many tool calls can suffer from quadratic performance degradation:

  • Growing JSON payloads: Each iteration sends the entire conversation history to the API
  • Expensive re-computation: Without caching, the model re-processes the same static content repeatedly
  • ZDR constraints: Zero Data Retention (ZDR) policies prevent server-side state, ruling out previous_response_id optimization
  • Configuration changes: Mid-conversation changes (sandbox, tools, working directory) can break cache efficiency

As conversations grow, inference costs and latency increase quadratically without proper caching strategies.

Solution

Maintain prompt cache efficiency through exact prefix preservation - always append new messages rather than modifying existing ones, and carefully order messages to maximize cache hits.

Core insight: Prompt caches only work on exact prefix matches. If the first N tokens of a request match a previous request, the cached computation can be reused.

Mechanism: Caching operates at the token level, not message level. The cache checks token-by-token for prefix matches, independent of message boundaries.

Message ordering strategy:

  1. Static content first (beginning of prompt - cached across all requests):

    • System message (if server-controlled)
    • Tool definitions (must be in consistent order)
    • Developer instructions
    • User/project instructions
  2. Variable content last (end of prompt - changes per request):

    • User message
    • Assistant messages
    • Tool call results (appended iteratively)

Configuration change via insertion:

When configuration changes mid-conversation, insert a new message rather than modifying an existing one:

[Static prefix...]
<sandbox_config_v1>     // Original config message
[Conversation...]

<sandbox changed>
<sandbox_config_v2>     // NEW message inserted
[Conversation continues...]

This preserves the exact prefix of all previous messages, maintaining cache hits.

What breaks cache hits:

  • Changing the list of available tools (position-sensitive)
  • Reordering messages
  • Modifying existing message content
  • Changing the model (affects server-side system message)

Provider variations:

  • OpenAI: Caching requires an exact rendered-prefix match ("Cache reuse requires the entire rendered prefix to match"). Older models cache implicitly at model-dependent intervals; newer models also support explicit cache breakpoints (up to four cache writes per request), with cached tokens discounted up to 95% (reads at 0.1x the uncached input rate on most models)
  • Anthropic: Explicit cache_control breakpoints plus automatic caching, a 5-minute default TTL with a 1-hour TTL option, cache reads at 0.1x the base input price (0.05x on Opus 5.5/Sonnet 5.5, 0.025x on Fable 5.1/Mythos 5.1), and a per-model minimum cacheable prefix length

Stateless design for ZDR:

Avoid previous_response_id to support Zero Data Retention. Instead, rely on prompt caching for linear performance:

Without previous_response_id:
- Quadratic network traffic (send full JSON each time)
- Linear sampling cost (due to prompt caching)

With previous_response_id:
- Linear network traffic
- But violates ZDR (server must store conversation state)

Example

graph TD subgraph "Request 1" A1[System message] A2[Tools] A3[Instructions] A4[User message] end subgraph "Request 2 - Cache Hit!" B1[System message] B2[Tools] B3[Instructions] B4[User message] B5[Assistant response] B6[Tool result] end subgraph "Request 3 - Cache Hit!" C1[System message] C2[Tools] C3[Instructions] C4[User message] C5[Assistant response] C6[Tool result 1] C7[Tool result 2] end style A1 fill:#90EE90 style A2 fill:#90EE90 style A3 fill:#90EE90 style B1 fill:#90EE90 style B2 fill:#90EE90 style B3 fill:#90EE90 style C1 fill:#90EE90 style C2 fill:#90EE90 style C3 fill:#90EE90 style A4 fill:#FFB6C1 style B4 fill:#FFB6C1 style B5 fill:#FFB6C1 style B6 fill:#FFB6C1 style C4 fill:#FFB6C1 style C5 fill:#FFB6C1 style C6 fill:#FFB6C1 style C7 fill:#FFB6C1

Green = Cached (exact prefix match) | Pink = Recomputed (new tokens)

How to use it

Prompt construction checklist:

  1. Order messages by stability: Static → Variable
  2. Never modify existing messages: Always append new ones
  3. Keep tool order consistent: Enumerate tools in deterministic order
  4. Insert, don't update: For config changes, add new messages

Handling configuration changes:

Change Type What NOT to do What TO do
Sandbox/approval mode Modify permission message Insert new role=developer message
Working directory Modify environment message Insert new role=user message
Tool list Change mid-conversation Avoid if possible; breaks cache

MCP server considerations:

MCP servers can emit notifications/tools/list_changed to indicate tool list changes. Avoid honoring this mid-conversation as it breaks cache hits. Instead:

  • Delay tool refresh until conversation boundary
  • Or accept the cache miss as necessary trade-off

Compaction:

The Codex post that documents this pattern also describes a /responses/compact endpoint for auto-compaction: the client posts the conversation and receives a compaction item with opaque encrypted_content that summarizes prior turns while keeping the request stateless, and auto_compact_limit controls when compaction triggers. Compaction trades context for a cache reset — everything after the compacted summary is new tokens.

Implementation sketch:

function buildPrompt(state: ConversationState): Prompt {
  const items: PromptItem[] = [];

  // Static prefix (cached)
  items.push({ role: 'system', content: state.systemMessage });
  items.push({ type: 'tools', tools: state.tools });  // Consistent order!
  items.push({ role: 'developer', content: state.instructions });

  // Variable content (appended)
  items.push(...state.history);

  return { items };
}

function handleConfigChange(
  state: ConversationState,
  newConfig: SandboxConfig
): ConversationState {
  // DON'T: Modify existing permission message
  // DO: Insert new message
  return {
    ...state,
    history: [
      ...state.history,
      {
        role: 'developer',
        content: formatSandboxConfig(newConfig),
      },
    ],
  };
}

Trade-offs

Pros:

  • Linear sampling cost: Prompt caching makes repeated inference linear rather than quadratic
  • ZDR-compatible: Stateless design supports Zero Data Retention policies
  • No server state: Avoids previous_response_id complexity
  • Simple conceptual model: Exact prefix matching is easy to reason about

Cons:

  • Quadratic network traffic: JSON payload size still grows quadratically (only sampling is cached)
  • Cache fragility: Mid-conversation changes (tools, model) break prefix matching
  • Disciplined ordering required: All static content must come before variable content
  • Tool enumeration complexity: Must maintain consistent tool ordering
  • MCP server limitations: Dynamic tool changes can cause cache misses

References