memory and model

MLX-LM Server Cache: Reusing Shared Prompts and Testing Concurrency

Reuse prefix computation when repeatedly reading the same policy.

Prompt1 caching reuses computation state from the beginning of an already processed input, or prefix, in later requests. A server receiving shared instructions or the same document repeatedly can reduce input processing before the first answer. This guide sends a return policy twice using MLX-LM2 to examine input reuse, memory, and waiting time.

Product support often attaches the same return policy while changing the customer's question. The server can reuse policy computation and process the new question and answer. Because each answer is generated anew, also check that the policy and question were transmitted correctly.

Requirements and key details
  • Reuse requires the same model, message template, and token prefix.
  • Stored caches need memory, so adjust cache size together with concurrency.
  • Check supported options in the installed version's help and logs.

Start a baseline server on an Apple Silicon Mac

This exercise uses MLX-LM and mlx-community/Qwen3-4B-4bit on an Apple Silicon Mac. The model card's 2.26GB is the download size. Execution also needs unified memory3 for weights, caches, and temporary computation.

Prepare a Python tooling environment and uv, then run the commands below. The first run downloads the model, so wait for the server-ready log. This example uses default context settings and keeps the same server process. If the server is already running, send requests to that process.

Start a server with the Qwen3 4B MLX model
uv tool install mlx-lm
mlx_lm.server --model "mlx-community/Qwen3-4B-4bit" --host 127.0.0.1 --port 8080
After downloading the tool and model, wait for the server-ready log and send requests from another terminal.

Keep the policy and change only the question

The system message below contains an example return policy: unopened accessories may be returned within 30 days with proof of purchase; opened items qualify only if they arrived damaged. The first user asks whether an opened item can be returned after a change of mind. Check that the answer cites the relevant policy sentence and reason.

For the second request, change only the user's content to ask what happens if the item arrived damaged. Keep the model, message roles and order, system content, template, and context settings. The questions differ, but the policy tokens4 at the beginning can be shared.

If response usage includes usage.prompt_tokens_details.cached_tokens, record it for both requests. It indicates reused input length. If your version does not return this field, inspect server logs and available usage information. Record first-token time, total completion time, and output token count to compare actual waiting times. This example uses stream:false and returns the completed answer, so obtain TTFT5 from server timing metrics or a separate streaming request.

Send a question with the shared return policy
curl -sS http://127.0.0.1:8080/v1/chat/completions -H 'Content-Type: application/json' -d '{"model":"mlx-community/Qwen3-4B-4bit","messages":[{"role":"system","content":"Return the relevant policy sentence and one short reason. Policy: Unopened accessories may be returned within 30 days with proof of purchase. Opened accessories are not returnable unless they arrived damaged."},{"role":"user","content":"A customer opened an accessory and changed their mind. Can they return it?"}],"max_tokens":128,"stream":false}'
Keep the system message and change only the user question in the next request.
A cache flow sharing common-document input state across later requests
Send the shared policy first and vary the question to allow prefix reuse.

Text before shared content also affects the cache

The cache reuses the beginning of the final token sequence sent to the model. A date or user ID before the policy can change the input from that point onward. Check the difference between shared instructions followed by the customer's question and customer-specific instructions placed first.

Changing the model or message template also changes reuse conditions. Preserve required permissions and safety instructions when adjusting order for caching. Next, alternate different long policies and return to the original to check whether its earlier state remains.

If cached tokens are zero for apparently identical content, check actual system content, the server process, cache entry retention, and the model's cache trimming support in turn. Compare logs to see which request state was removed and why it was recomputed.

Different questions branching after a shared input prefix
Changing text before a shared document shortens the reusable prefix.

Measure individual latency separately from throughput

First send inquiries one at a time to the prepared server. Keep the same model and policy, recording first token, completion time, input and output tokens, and cache hits. Separate initial model loading after restart and compare prepared requests with each other.

Next send independent inquiries concurrently. Record median request latency, slow requests, total tokens per second, and memory. Test concurrent shared prefixes separately from mixed user-specific prefixes to distinguish caching and concurrency effects.

As an illustration, suppose one request takes 30 seconds and four concurrent requests each finish in 36 seconds. Individual latency increases by 6 seconds, or 20%. Sequential processing takes 30×4=120 seconds, while concurrent completion takes about 36 seconds of wall-clock time. The sum of individual concurrent times, 36×4=144 seconds, differs from elapsed time. Prioritize individual latency for immediate answers or completion count and elapsed time for inquiry batches.

Record server request conditions separately.
ConditionKey recordsWhat it reveals
Sequential warm requestsTTFT, completion time, cached tokensShared-input reuse effect
Cold startModel loading, first request, memoryServer preparation cost
Concurrent requestsIndividual latency, throughput, memoryLatency and capacity under concurrency
Mixed prefixesHit/miss, requests after evictionCache retention scope

What to check when reducing cache size

Retained state continues to use memory. Model weights, active request KV caches, and stored entries share that space. If memory is tight, first test reducing concurrency and actual input length.

Find cache limits in the current version's mlx_lm.server --help. Options such as --prompt-cache-bytes limit stored-entry size, whereas --max-kv-size changes the cache structure for long conversations. Verify support and application in help and startup logs, then change one option at a time and compare hits, TTFT, and peak memory.

After establishing stability with short context and one request, increase to match your workload. If the first token improves but generation does not, compare decode6 next. If greater concurrency exceeds acceptable waiting time, reduce it and retain a cache size that preserves reuse of frequent shared documents.

Cache entries being replaced as the model and template change
Compare space for retained caches alongside request latency.

Keep settings matched to the version and workload

MLX-LM v0.31.0 includes server cache and size-limit improvements; v0.31.2 improves system and user message caching and the batch generator. v0.31.3 adds fixes for batch KV cache7 and parallel tool calls8. On updates, recheck options and logs, then compare previous settings with the same requests.

For work repeatedly using the same instructions and documents, tune according to actual hits and first-response differences. If you read each new document once and your Mac responds adequately, larger caches may be unnecessary. Add concurrency tests when multiple applications begin connecting at once.

Terminology notes

  1. Prompt — The input text sent to a model. For generative models it describes the desired result and strongly shapes the output.

    Back to the text
  2. MLX-LM — A package for loading, running, and fine-tuning language models with MLX.

    Back to the text
  3. Unified memory — An architecture where the CPU and GPU share one physical memory pool.

    Back to the text
  4. Token — A unit into which a model divides input or output for processing.

    Back to the text
  5. Time to First Token — The time from sending a request until its first output token arrives.

    Back to the text
  6. Token decoding — The stage that generates successive output tokens using the input and the response produced so far.

    Back to the text
  7. KV cache — Memory that stores attention keys and values from earlier tokens for reuse during later token generation. Its size depends on context length and batch size.

    Back to the text
  8. Tool call — A structured request from a model for an external function such as reading a file, searching, or running a command. The agent runtime and its permission settings decide whether the request is actually executed.

    Back to the text

Frequently asked questions

What should you check first in this article?
Prompt caching reuses computation state from the beginning of an already processed input, or prefix, in later requests. A server receiving shared instructions or the same document repeatedly can reduce input processing before the first answer. This guide sends a return policy twice using MLX-LM to examine input reuse, memory, and waiting time.
How much memory does it need?
This exercise uses MLX-LM and mlx-community/Qwen3-4B-4bit on an Apple Silicon Mac. The model card's 2.26GB is the download size. Execution also needs unified memory for weights, caches, and temporary computation.