Gisting: Compress Prompts for Faster, Cheaper LLM Agents

Peter Bubenik · Shopify ML · · Source
Image for Gisting: Compressing LLM Agent context to ↑ throughput and ↓ cost (2026) - Shopify

After studying this material, you should be able to:

  1. Explain what gisting is and why it matters for LLM inference
  2. Describe how gist tokens are trained using knowledge distillation
  3. Distinguish between gisting and prefix caching and explain why both are needed
  4. Identify the key optimizations that make gisting work effectively
  5. Evaluate the real-world performance gains gisting provides

Step-by-Step Teaching

Step 1: The Problem — Why Long Prompts Are Expensive

Before understanding gisting, you need to understand what it solves.

The Core Issue

When you deploy an LLM agent, you typically give it a system prompt — a set of instructions that defines its behavior. For example:

"You are a GraphQL agent. You help users query data.
Follow these rules: [rule 1]... [rule 2]... [rule 3]...
Here are example queries: [example 1]... [example 2]..."

This can easily reach thousands of tokens.

Why That Hurts

Every token in your prompt has a direct cost:

ProblemExplanation
Slower inferenceMore tokens = more computation per request
Higher costYou pay per token in most APIs
More GPUs neededTo serve the same traffic volume
Larger KV cacheEvery generated token must read the entire cached sequence

Concrete example from Shopify: Their GraphQL agent had a ~6,000 token system prompt. At 350 requests per minute, this created measurable latency and required more GPUs than necessary.

Key Insight

The system prompt is identical across every request. You are paying the same token cost thousands of times per minute for the same information.


Step 2: What Is Gisting?

The Core Idea

Gisting compresses a long prompt into a small set of special tokens called gist tokens, which carry the same behavioral information as the full prompt — but at a fraction of the token count.

BEFORE gisting:
[6,000 token system prompt] + [user message] → Model

AFTER gisting:
[1,500 gist tokens] + [user message] → Model

Same model behavior. 4× fewer tokens.

What Is a Gist Token?

A gist token is:

  • A new special token added to the model's vocabulary
  • Represented by a learned embedding vector (a list of numbers)
  • Trained to encode the meaning of multiple original prompt tokens

Think of it like a zip file for meaning — the compressed version unpacks to the same information when the model processes it.

The Compression Ratio

At 4:1 compression, one gist token replaces four original prompt tokens:

Original:  [tok1][tok2][tok3][tok4] → [gist_1]
Original:  [tok5][tok6][tok7][tok8] → [gist_2]
...and so on

6,000 tokens → 1,500 gist tokens


Step 3: How Gist Tokens Are Trained — Knowledge Distillation

This is the most technically important part. The gist embeddings are not hand-crafted — they are learned through a process called knowledge distillation.

What Is Knowledge Distillation?

Knowledge distillation is a technique where a student model learns to mimic a teacher model. Here, both teacher and student are the same model — the difference is what they see as input.

The Training Process

Training runs two forward passes on each example:

Pass 1: Teacher Pass

Input:  [Full natural-language system prompt] + [conversation]
Output: Teacher logits (probability distribution over next tokens)

The model sees the real, full prompt and produces predictions. These predictions are the ground truth we want to replicate.

Pass 2: Student Pass

Input:  [Gist tokens] + [conversation]
Output: Student logits (probability distribution over next tokens)

The model sees only the compressed gist tokens and produces its own predictions.

The Training Signal

We measure the difference between teacher and student predictions using KL divergence — a mathematical measure of how different two probability distributions are:

Loss = KL_divergence(teacher_logits, student_logits)

We then update only the gist embeddings (not the model weights) to minimize this loss. Over many training steps, the gist embeddings learn to make the model behave as if it saw the full prompt.

Important: The model weights are frozen. Only the gist token embeddings are trained. This is efficient and preserves the model's existing capabilities.

Visual Summary

Teacher: [Full Prompt] → [Same LLM] → Teacher Logits ─┐
                                                        ├→ KL Loss → Update Gist Embeddings
Student: [Gist Tokens] → [Same LLM] → Student Logits ─┘

Step 4: Deploying a Gisted Model

Once training is complete, deployment is straightforward:

What Changes at Deployment

  1. Gist embeddings are written directly into the model's embedding matrix
  2. Gist tokens are registered as special tokens in the tokenizer
  3. At inference time, the system prompt string is replaced with gist tokens

What Does NOT Change

  • No custom attention masks
  • No extra encoder
  • No special serving infrastructure
  • The model loads and runs like any other model

Key principle: The entire cost of compression is paid once, at training time. Inference is standard.

Inference Flow

Before: Request → [6,000 token prompt + user message] → GPU → Response
After:  Request → [1,500 gist tokens + user message]  → GPU → Response

Step 5: Why Prefix Caching Alone Isn't Enough

You might wonder: "Can't we just cache the system prompt so we don't recompute it?" This is called prefix caching, and it's a good optimization — but it doesn't fully solve the problem.

How Prefix Caching Works

Modern serving engines store KV (key-value) tensors for previously seen sequences. If the system prompt was seen before, its KV tensors are fetched from cache instead of recomputed.

First request:  Compute KV tensors for system prompt → Store in cache
Second request: Fetch KV tensors from cache → Skip recomputation ✓

The Limitation: Decode Cost

Prefix caching eliminates recomputation but not memory reads.

Every time the model generates a new token, that token must attend over every key in the sequence — cached or not. This means:

For each generated token:
  Read entire KV cache from memory (including cached system prompt)
  
Memory read size grows linearly with sequence length

This is called being memory-bandwidth-bound — the bottleneck is how fast you can read data from memory, not how fast you can compute.

How Gisting Helps Beyond Prefix Caching

OptimizationEliminates RecomputationReduces Memory Reads
Prefix Caching✅ Yes❌ No
Gisting✅ Yes (fewer tokens to compute)✅ Yes (smaller KV cache)
Both Together✅ Yes✅ Yes (maximum benefit)

Shopify uses both in production. The optimizations compound — they don't cancel each other out.


Step 6: Key Training Optimizations

Shopify used an autoresearch loop (automated hyperparameter tuning) to discover these critical optimizations:

Optimization 1: Smart Initialization

Bad approach: Initialize gist embeddings with random noise Good approach: Initialize each gist embedding with the mean of the corresponding chunk of the original prompt

Prompt chunk 1: [tok1, tok2, tok3, tok4]
Gist token 1 initialized = mean_embedding([tok1, tok2, tok3, tok4])

Prompt chunk 2: [tok5, tok6, tok7, tok8]
Gist token 2 initialized = mean_embedding([tok5, tok6, tok7, tok8])

Result: Initial loss reduced by a factor of 7×. The embeddings start close to the right answer instead of from scratch.

Optimization 2: Finding the Right Compression Ratio

Not all compression ratios work equally well. Too aggressive = quality loss. The team tested multiple ratios and found 4:1 was optimal for their domain complexity.

Different domains may have different optimal ratios. A simple prompt might compress more; a complex technical prompt might compress less.

Optimization 3: Data Quantity and Diversity

The training dataset needs to be:

  • Large — enough examples to generalize
  • Diverse — covering the range of real user interactions

This closed the remaining quality gap after the other optimizations.

Optimization 4: Loss Normalization

Wrong: Average loss per response token → caused hallucinations Right: Average loss over the entire batch → preserved signal from long responses, produced stable embeddings

Optimization 5: Speed Improvements

  • Precompute teacher logits once and store them (don't recompute every epoch)
  • Pre-tokenize data before training begins

Result: Training time cut from 30 hours to 6 hours


Step 7: Real-World Results

Load Test Results at 350 Requests Per Minute

MetricFull PromptGistedImprovement
Median TTFT438ms354ms↓ 19%
Median E2E Latency6.8s4.2s↓ 38%
Throughput20.2 QPS23.4 QPS↑ 16%
GPUs RequiredBaseline−14%Fewer GPUs

Why the Gap Grows With Load

At higher concurrency, batches get larger. Larger batches mean more KV cache reads per step. Since gisting reduces KV cache size, the benefit compounds as load increases.


Step 8: Gisting and Continual Learning

Gisting integrates cleanly into ongoing model improvement:

The Continual Learning Loop

1. Train gist embeddings via distillation
2. Deploy gisted model
3. Collect new data from production
4. Post-train using gist tokens as prefix
5. Update BOTH model weights AND gist embeddings on new data
6. No need to re-distill from scratch

Benefit: You can continuously improve the model without paying the full distillation cost each time. The gist embeddings evolve alongside the model weights.


Concept Summary

GISTING IN ONE DIAGRAM:

Training Time (paid once):
  Full Prompt (6,000 tokens)
       ↓ Knowledge Distillation
  Gist Embeddings (1,500 tokens)
       ↓ Written into model
  Updated Model

Inference Time (paid every request):
  [1,500 gist tokens] + [user message]
       ↓
  Same model, same behavior
       ↓
  Response
  
  Result: 4× fewer tokens, same quality

Quick Self-Check Questions

  1. What is a gist token and how does it differ from a regular token?

    A gist token is a special token with a learned embedding that encodes the meaning of multiple original prompt tokens. Unlike regular tokens whose embeddings are fixed during pretraining, gist embeddings are specifically trained to compress prompt information.

  2. Why are model weights frozen during gist training?

    To preserve the model's existing capabilities. Only the gist embeddings need to learn — the model already knows how to process information; we just need to teach it what the new tokens mean.

  3. Why doesn't prefix caching eliminate the need for gisting?

    Prefix caching eliminates recomputation but not memory reads. Every generated token still reads the full KV cache, and that read scales with sequence length. Gisting reduces the sequence length itself.

  4. What would happen if you used too aggressive a compression ratio?

    Prediction quality would degrade — the gist tokens wouldn't have enough capacity to encode all the information in the original prompt.

  5. Why does the performance gap between gisted and non-gisted models grow at higher request concurrency?

    Larger batches require more KV cache reads per step. Since gisting reduces KV cache size, the memory bandwidth savings become more significant as batch sizes grow.

More to study