Skip to content

fix: ensure prompt cache is invalidated whenever KV cache is cleared - #542

Open
thunderbug1 wants to merge 1 commit into
ROCm:mainfrom
thunderbug1:fix/prompt-cache-invalidation
Open

fix: ensure prompt cache is invalidated whenever KV cache is cleared#542
thunderbug1 wants to merge 1 commit into
ROCm:mainfrom
thunderbug1:fix/prompt-cache-invalidation

Conversation

@thunderbug1

@thunderbug1 thunderbug1 commented May 6, 2026

Copy link
Copy Markdown

Summary

Fixes #486

The prompt prefix cache in /v1/chat/completions was broken in multiple ways, preventing multi-turn conversations from reusing the cached KV state.

  • Non-streaming path unconditionally called clear_context() and prompt_cache.reset(), making prefix caching impossible for non-streaming requests
  • Checksum mismatchupdate_checksum() included tool messages while can_use_cache() skipped them, causing permanent cache misses when tools were present
  • Stale cache hits after errors — error paths cleared the KV cache but didn't invalidate the prompt cache, so the next request would only insert the last message into an empty context
  • Stale cache hits from other handlers/api/chat, /api/generate, /v1/completions all clear the KV cache without invalidating the prompt cache

Changes

  • Remove unconditional clear_context() and prompt_cache.reset() from the non-streaming path in handle_openai_chat_completion
  • Fix update_checksum() to skip tool messages consistently with can_use_cache()
  • Introduce reset_context() helper on RestHandler that couples clear_context() with prompt_cache.reset()
  • Replace all bare clear_context() calls across all handlers with reset_context(), except the two cache-miss paths where the cache is immediately re-initialized

Test plan

  • Start flm serve with a model
  • Send a multi-turn conversation via /v1/chat/completions and verify "Use cached prompt!" appears in logs for subsequent turns
  • Verify prefill chunk count drops on cache hits (only the new message is prefilled)
  • Test with tools present in the conversation
  • Test both streaming and non-streaming requests
  • Test that interleaved requests to /api/chat or /api/generate don't cause stale cache hits on the next /v1/chat/completions request

…OCm#486)

The prompt prefix cache in /v1/chat/completions was broken in several ways:

1. Non-streaming path unconditionally cleared context and reset cache,
   making prefix caching impossible for non-streaming requests.

2. update_checksum() included tool messages in its checksum calculation
   while can_use_cache() skipped them, causing permanent cache misses
   whenever tools were present in the conversation.

3. Error paths (max length, exceptions) in handle_openai_chat_completion
   cleared the KV cache via clear_context() but did not call
   prompt_cache.reset(), so the next request would stale cache-hit
   against an empty KV cache and only insert the last message.

4. Other handlers (/api/chat, /api/generate, /v1/completions) all call
   clear_context() on every request but never invalidated the prompt
   cache, causing the same stale-hit problem for any interleaved requests.

Fix all cases by introducing a reset_context() helper on RestHandler
that couples clear_context() with prompt_cache.reset(), ensuring the
prompt cache can never outlive the KV state it refers to. The only
bare clear_context() calls that remain are the two cache-miss paths
in handle_openai_chat_completion where the cache is immediately
re-initialized with update_checksum().
@twflm

twflm commented May 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #486

The prompt prefix cache in /v1/chat/completions was broken in multiple ways, preventing multi-turn conversations from reusing the cached KV state.

  • Non-streaming path unconditionally called clear_context() and prompt_cache.reset(), making prefix caching impossible for non-streaming requests
  • Checksum mismatchupdate_checksum() included tool messages while can_use_cache() skipped them, causing permanent cache misses when tools were present
  • Stale cache hits after errors — error paths cleared the KV cache but didn't invalidate the prompt cache, so the next request would only insert the last message into an empty context
  • Stale cache hits from other handlers/api/chat, /api/generate, /v1/completions all clear the KV cache without invalidating the prompt cache

Changes

  • Remove unconditional clear_context() and prompt_cache.reset() from the non-streaming path in handle_openai_chat_completion
  • Fix update_checksum() to skip tool messages consistently with can_use_cache()
  • Introduce reset_context() helper on RestHandler that couples clear_context() with prompt_cache.reset()
  • Replace all bare clear_context() calls across all handlers with reset_context(), except the two cache-miss paths where the cache is immediately re-initialized

Test plan

  • Start flm serve with a model
  • Send a multi-turn conversation via /v1/chat/completions and verify "Use cached prompt!" appears in logs for subsequent turns
  • Verify prefill chunk count drops on cache hits (only the new message is prefilled)
  • Test with tools present in the conversation
  • Test both streaming and non-streaming requests
  • Test that interleaved requests to /api/chat or /api/generate don't cause stale cache hits on the next /v1/chat/completions request

Thank you! Currently, prefix cache is not activated for non-stream mode. Any specific app in your mind?

@twflm
twflm requested a review from ZaneNi May 7, 2026 10:26
@thunderbug1

Copy link
Copy Markdown
Author

I was playing around with using claude code with flm and found some issues with kv caching. The main issue in the end was actually that claude code changes the system prompt with every message but I fixed the other issues on the way.

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.

KV cache in server mode?

2 participants