mirror of
https://github.com/open-webui/open-webui.git
synced 2026-10-24 05:44:07 +00:00
fix: context compaction not triggering with llama.cpp prompt caching
Context compaction failed to trigger for llama.cpp backends with prompt caching enabled, letting chats grow until the server rejected the request with a context overflow error. Two issues combined to cause this: 1. load_messages_from_db() dropped the usage field when reconstructing messages from the DB, so _exceeds_token_threshold() never saw any reported token counts and always fell back to rough char-based estimation. 2. The threshold check summed only input_tokens + output_tokens. llama.cpp reports cached prefix tokens separately (timings.cache_n, merged into the stored usage) and excludes them from prompt_n, so a mostly cached context of ~30k tokens was counted as only a few thousand. Keep usage on DB-loaded messages so the threshold check can use it, count cache_n towards the total, and strip usage in strip_compaction_fields() after compaction runs so the non-standard field never reaches the LLM payload. Reported and verified in https://github.com/open-webui/open-webui/discussions/24410
This commit is contained in:
parent
10724d057a
commit
9cda762af8
2 changed files with 10 additions and 4 deletions
|
|
@ -231,8 +231,13 @@ def _exceeds_token_threshold(messages: list[dict], system_prompt: str, summary:
|
|||
|
||||
for idx in range(len(messages) - 1, -1, -1):
|
||||
usage = messages[idx].get('usage') or (messages[idx].get('info') or {}).get('usage')
|
||||
if isinstance(usage, dict) and usage.get('input_tokens'):
|
||||
total = int(usage.get('input_tokens') or 0) + int(usage.get('output_tokens') or 0)
|
||||
if isinstance(usage, dict) and (usage.get('input_tokens') or usage.get('cache_n')):
|
||||
# llama.cpp reports cached prefix tokens separately (timings.cache_n), excluded from prompt_n
|
||||
total = (
|
||||
int(usage.get('input_tokens') or 0)
|
||||
+ int(usage.get('output_tokens') or 0)
|
||||
+ int(usage.get('cache_n') or 0)
|
||||
)
|
||||
return total + _estimate_messages_tokens(messages[idx + 1 :]) > threshold
|
||||
|
||||
estimated = _estimate_tokens(system_prompt) + _estimate_tokens(summary or '') + _estimate_messages_tokens(messages)
|
||||
|
|
|
|||
|
|
@ -1975,7 +1975,7 @@ async def load_messages_from_db(chat_id: str, message_id: str) -> Optional[list[
|
|||
return None
|
||||
|
||||
return [
|
||||
{k: v for k, v in msg.items() if k in ('role', 'content', 'output', 'files', 'contextSummary')}
|
||||
{k: v for k, v in msg.items() if k in ('role', 'content', 'output', 'files', 'contextSummary', 'usage')}
|
||||
for msg in db_messages
|
||||
]
|
||||
|
||||
|
|
@ -2034,6 +2034,7 @@ def strip_compaction_fields(messages: list[dict]) -> list[dict]:
|
|||
clean = dict(message)
|
||||
clean.pop('contextSummary', None)
|
||||
clean.pop('context_summary', None)
|
||||
clean.pop('usage', None)
|
||||
stripped.append(clean)
|
||||
return stripped
|
||||
|
||||
|
|
@ -2222,7 +2223,7 @@ async def process_chat_payload(request, form_data, user, metadata, model):
|
|||
{
|
||||
k: v
|
||||
for k, v in assistant_message.items()
|
||||
if k in ('role', 'content', 'output', 'files', 'contextSummary')
|
||||
if k in ('role', 'content', 'output', 'files', 'contextSummary', 'usage')
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue