Skip to content

Honor minimum common prefix for prompt cache reuse#1854

Closed
zeljkokalezic wants to merge 2 commits into
ikawrakow:mainfrom
zeljkokalezic:fix-prompt-cache-min-common-prefix
Closed

Honor minimum common prefix for prompt cache reuse#1854
zeljkokalezic wants to merge 2 commits into
ikawrakow:mainfrom
zeljkokalezic:fix-prompt-cache-min-common-prefix

Conversation

@zeljkokalezic

@zeljkokalezic zeljkokalezic commented May 21, 2026

Copy link
Copy Markdown

Summary

This fixes prompt-cache behavior when a single server slot alternates between large prompts with different early tool/schema sections.

In that case the prompts may share only a small prefix, but the server could still try to reuse live slot state or RAM prompt-cache state. With checkpointing enabled this can lead to stale checkpoint reuse, checkpoint invalidation, and repeated full prompt reprocessing.

The change makes --cache-ram-n-min act as a minimum common-prefix requirement for prompt-cache reuse, not only as a size gate for saving.

Changes

  • Apply cache_ram_n_min when selecting RAM prompt-cache entries.
  • Return whether RAM prompt-cache restore succeeded, so callers can avoid treating a rejected cache as reusable.
  • Clear live slot prompt/cache state when the common prefix is below cache_ram_n_min.
  • Save a hot live slot before a low-prefix request evicts it, allowing the previous prompt shape to be restored later.
  • Add n_common to prompt-cache logs to make reuse/skip decisions visible.
  • Update help text and parameter docs for the new cache_ram_n_min behavior.

Why

This was observed with agent workloads where a main coding prompt and a background/tooling prompt share only about 7k initial tokens while each full prompt is 70k-80k tokens.

Before this change, a low-prefix request could poison the single live slot and cause the next matching request to reprocess the entire prompt. After this change, low-prefix requests run from scratch while the hot prompt can be preserved in RAM prompt cache and restored when the matching prompt shape returns.

Validation

  • Built with:
    cmake --build build --target llama-server -j 24
  • Manually validated alternating prompt shapes:
    • low-prefix requests below --cache-ram-n-min 32768 are skipped
    • matching prompts restore/reuse cached state
    • observed prompt eval dropping from roughly 70k-80k tokens to small tail evals such as 12-70 tokens in the steady matching case

@firecoperana firecoperana left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check my comment.

ret->cache_tokens = ret->server_cached_prompt.tokens.clone(); // recover cache tokens
ret->n_discarded_prompt = ret->server_cached_prompt.n_discarded_prompt;
ret->n_kept_prompt = ret->server_cached_prompt.n_kept_prompt;
if (prompt_loaded) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole part is not needed because if no prompt is loaded, there is no need to change cache_tokens, but you are erasing all the cache tokens.

int32_t back = 4;
if (prefix.second >= back && prefix.first >= back) {
print_tokens(slot.prompt_tokens, slot.cache_tokens, prefix.second - back, prefix.first - back, 30);
const size_t n_common = std::min(prefix.first, prefix.second);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No change is needed in this part.

Comment thread common/common.cpp
options.push_back({ "*", "-cram, --cache-ram N", "set the maximum cache size in MiB (default: %d, -1 - no limit, 0 - disable)",params.cache_ram_mib });
options.push_back({ "*", "-crs, --cache-ram-similarity N", "max of similarity of prompt tokens to cache tokens that triggers prompt cache (default: %.2f).",params.cache_ram_similarity });
options.push_back({ "*", "-cram-n-min --cache-ram-n-min N", "minimum number of the cached tokens that triggers prompt cache (default: %d).", params.cache_ram_n_min });
options.push_back({ "*", "-cram-n-min --cache-ram-n-min N", "minimum number of common prompt tokens required to reuse or save prompt cache (default: %d).", params.cache_ram_n_min });

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use case of cache-ram-n-min is different. It is for the whole length of the prompt, not just the common prefix. Create a new parameter instead.

@zeljkokalezic

Copy link
Copy Markdown
Author

On second thought, what you can do is to not destroy the prompt cached in ram while loading it, so when the next prompt arrives, it can still find it and reprocess only a few tokens. The trade-off is just increase in ram usage, but this feature could be easily disabled via a command line arg when needed. Using a fixed number as a threshold is not good.

Hm, that is a better idea, I will see to explore it, thanks a lot 😄 !

@firecoperana

firecoperana commented May 21, 2026

Copy link
Copy Markdown
Collaborator

It's not that easy after I thought about it. When you retrieve the prompt A and run some inference, it becomes B. The next prompt C is a different prompt, so it saves prompt B. Now A and B are very similar, but prompt B may not fully contain A. You now have two long prompts A and B. You need some unique id to know that prompt B is from prompt A, so you can delete A and keep B.

@zeljkokalezic

Copy link
Copy Markdown
Author

Yup and there is also a case where it alternates between two caches that are almost identical because they are both in memory (A and B) 🙈

And the question should B always replace A if there is eviction based on lineage 🤔

I will see what can be done, interesting problem to solve anyway 😄

@zeljkokalezic zeljkokalezic mentioned this pull request May 25, 2026
4 tasks
@zeljkokalezic

Copy link
Copy Markdown
Author

Closing in favor of #1877

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants