Skip to content

Commit 01ced97

Browse files
committed
LLama: Optimize KV cache management for multi-round conversations
- Implements prefix-matching logic to truncate stale "ghost" tokens in C++ KV cache - Prevents attention misalignment and context poisoning during multi-turn interactions - Reduces memory overhead by reusing matched prefixes efficiently Signed-off-by: JamePeng <jame_peng@sina.com>
1 parent e4861df commit 01ced97

2 files changed

Lines changed: 14 additions & 30 deletions

File tree

llama_cpp/llama.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,14 +1077,28 @@ def adapter(token_data_array: llama_cpp.llama_token_data_array):
10771077
longest_prefix = self.longest_token_prefix(self._input_ids, tokens[:-1])
10781078
if longest_prefix > 0:
10791079
reset = False
1080+
1081+
# Physically erase trailing "ghost" tokens from the C++ KV cache
1082+
# to prevent attention misalignment in multi-round chats.
1083+
if longest_prefix < self.n_tokens:
1084+
if self.verbose:
1085+
print(f"Llama.generate: Truncating KV cache size from {self.n_tokens} to {longest_prefix}", file=sys.stderr)
1086+
self._ctx.memory_seq_rm(0, longest_prefix, -1)
1087+
1088+
# Adjust the tokens array and cursor to reuse the matched cache
10801089
tokens = tokens[longest_prefix:]
10811090
self.n_tokens = longest_prefix
1091+
10821092
if self.verbose:
10831093
print(
10841094
f"Llama.generate: {longest_prefix} prefix-match hit, "
10851095
f"remaining {len(tokens)} prompt tokens to eval",
10861096
file=sys.stderr,
10871097
)
1098+
else:
1099+
# No prefix matched. Completely clear the KV cache to prevent context poisoning.
1100+
self.n_tokens = 0
1101+
self._ctx.memory_clear(True)
10881102

10891103
# Reset the model state
10901104
if reset:

llama_cpp/llama_chat_format.py

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3817,9 +3817,6 @@ def __call__(self, **kwargs):
38173817
kwargs['stop'] = [self.MINICPMV_EOS_TOKEN, self.MINICPMV_PAD_TOKEN]
38183818

38193819
llama = kwargs['llama']
3820-
llama.reset()
3821-
llama._ctx.memory_clear(True)
3822-
llama.n_tokens = 0
38233820

38243821
if hasattr(llama, 'input_ids'):
38253822
llama.input_ids.fill(0)
@@ -3950,11 +3947,6 @@ def __call__(self, **kwargs):
39503947

39513948
llama = kwargs['llama']
39523949

3953-
# Clear state for multiple runs
3954-
llama.reset()
3955-
llama._ctx.memory_clear(True)
3956-
llama.n_tokens = 0
3957-
39583950
if hasattr(llama, 'input_ids'):
39593951
llama.input_ids.fill(0)
39603952

@@ -4053,9 +4045,6 @@ def __call__(self, **kwargs):
40534045
kwargs['stop'] = [self.GLM46V_EOS_TOKEN, "<|user|>", "<|observation|>", "<|code_middle|>"] # Stop token patch
40544046

40554047
llama = kwargs['llama']
4056-
llama.reset()
4057-
llama._ctx.memory_clear(True)
4058-
llama.n_tokens = 0
40594048

40604049
if hasattr(llama, 'input_ids'):
40614050
llama.input_ids.fill(0)
@@ -4140,9 +4129,6 @@ def __call__(self, **kwargs):
41404129
kwargs['stop'] = [self.GRANITE_EOS_TOKEN]
41414130

41424131
llama = kwargs['llama']
4143-
llama.reset()
4144-
llama._ctx.memory_clear(True)
4145-
llama.n_tokens = 0
41464132

41474133
if hasattr(llama, 'input_ids'):
41484134
llama.input_ids.fill(0)
@@ -4205,9 +4191,6 @@ def __init__(self, image_min_tokens: int = -1, image_max_tokens: int = -1, **kwa
42054191
def __call__(self, **kwargs):
42064192

42074193
llama = kwargs['llama']
4208-
llama.reset()
4209-
llama._ctx.memory_clear(True)
4210-
llama.n_tokens = 0
42114194

42124195
if hasattr(llama, 'input_ids'):
42134196
llama.input_ids.fill(0)
@@ -4325,9 +4308,6 @@ def __call__(self, **kwargs):
43254308
kwargs['stop'] = [self.PADDLEOCR_EOS_TOKEN]
43264309

43274310
llama = kwargs['llama']
4328-
llama.reset()
4329-
llama._ctx.memory_clear(True)
4330-
llama.n_tokens = 0
43314311

43324312
if hasattr(llama, 'input_ids'):
43334313
llama.input_ids.fill(0)
@@ -4381,11 +4361,6 @@ class Qwen25VLChatHandler(Llava15ChatHandler):
43814361
def __call__(self, **kwargs):
43824362
llama = kwargs['llama']
43834363

4384-
# Clear state for multiple runs
4385-
llama.reset()
4386-
llama._ctx.memory_clear(True)
4387-
llama.n_tokens = 0
4388-
43894364
if hasattr(llama, 'input_ids'):
43904365
llama.input_ids.fill(0)
43914366

@@ -4525,11 +4500,6 @@ def __call__(self, **kwargs):
45254500

45264501
llama = kwargs['llama']
45274502

4528-
# Clear state for multiple runs
4529-
llama.reset()
4530-
llama._ctx.memory_clear(True)
4531-
llama.n_tokens = 0
4532-
45334503
if hasattr(llama, 'input_ids'):
45344504
llama.input_ids.fill(0)
45354505

0 commit comments

Comments
 (0)