Skip to content

fix: record and check model identity on serialized KV caches - #2302

Open
jeojdi1 wants to merge 1 commit into
MemTensor:mainfrom
jeojdi1:fix/kv-cache-carries-no-model-identity
Open

fix: record and check model identity on serialized KV caches#2302
jeojdi1 wants to merge 1 commit into
MemTensor:mainfrom
jeojdi1:fix/kv-cache-carries-no-model-identity

Conversation

@jeojdi1

@jeojdi1 jeojdi1 commented Aug 28, 2026

Copy link
Copy Markdown

Description

A KV cache is the internal activation state of one specific set of weights — it is not portable data. KVCacheMemory.dump() currently writes only {"kv_cache_memories": ...}, and load() restores it unconditionally. There is nothing recording which model produced a cache and nothing checking it on the way back in.

The consequence is silent: a cache dumped under one model and loaded under another is accepted with no error, and the model simply produces different tokens. On a close fine-tune pair I measured a next-token KL shift of 0.08–0.92 with the top-1 token flipping on 2 of 5 probes. A distant architecture does raise, but only as an opaque RuntimeError about tensor sizes, which does not tell the user what actually went wrong.

This PR:

  • records model_identity in the dumped payload (model_name_or_path, best-effort from the configured extractor LLM);
  • checks it on load() and warns on mismatch, naming both models and saying what to do about it.

It is a warning rather than an exception on purpose: caches dumped before this field existed carry no identity, and refusing to load them would break every existing store. _model_identity() returns None when the LLM config exposes no name, so a dump never fails because identity could not be determined, and a None on either side skips the check.

Related Issue (Required): #2300

Note on overlap: issue #2203 (closed) and PR #2204 cover pickle.load in this same load() path as an unsafe-deserialization sink (CWE-502). This change is orthogonal — it adds a payload field and a check, and does not touch how the payload is deserialized — but it does edit adjacent lines, so it may need a trivial rebase depending on merge order.

Type of change

  • Bug fix (non-breaking change which fixes an issue)

How Has This Been Tested?

  • Unit Test

Three tests added:

  • test_dump_records_model_identity — the field is written.
  • test_load_warns_on_model_mismatch — dump under org/model-a, load under org/model-b, assert the warning names the original model. Fails on the current code, which emits nothing.
  • test_load_is_quiet_when_model_matches — no warning on the matching case, so this is not a new source of noise.

Checklist

A note on the target branch

CONTRIBUTING.md says to open PRs against dev, but no dev branch exists — only main and dev-v2.0.28dev-v2.0.32. This is against main (185ebdb, "Dev v2.0.32"). Happy to retarget.

A KV cache is the internal activation state of one specific set of weights, not
portable data. `dump()` writes only `{"kv_cache_memories": ...}` and `load()`
restores it unconditionally, so nothing records which model produced a cache and
nothing checks it on the way back in.

A cache dumped under one model and loaded under another is therefore accepted
with no error, and the model simply produces different tokens. On a close
fine-tune pair this shifted the next-token distribution by KL 0.08-0.92 with the
top-1 token flipping on 2 of 5 probes. A distant architecture does raise, but
only as an opaque RuntimeError about tensor sizes.

Records `model_identity` on dump and warns on mismatch at load, naming both
models. A warning rather than an exception on purpose: caches written before this
field existed carry no identity, and refusing them would break every existing
store. Identity is best-effort, so a dump never fails because it could not be
determined, and a missing value on either side skips the check.

Orthogonal to MemTensor#2203 / MemTensor#2204, which cover `pickle.load` in this same path as an
unsafe-deserialization sink; this adds a payload field and a check without
changing how the payload is deserialized.
@Memtensor-AI Memtensor-AI added area:memory 记忆存储、检索、更新、召回逻辑 status:in-progress Someone or AI is working on it | 人工或 AI 正在处理 labels Aug 28, 2026
@Memtensor-AI

Copy link
Copy Markdown
Collaborator

🤖 Open Code Review

Target: PR #2302
Task: b6472f335cd88b41
Base: main
Head: fix/kv-cache-carries-no-model-identity

🔍 OpenCodeReview found 2 issue(s) in this PR.

⚠️ 1 warning(s) occurred during review.


1. tests/memories/activation/test_kv.py (L100-L103)

import pickle is placed inside the test function body. All other imports in this file are at module level. Move it to the top of the file alongside the other standard-library imports for consistency and to make the dependency visible at a glance.

💡 Suggested Change

Before:

    import pickle

    with open(tmp_path / kv_memory.config.memory_filename, "rb") as f:
        data = pickle.load(f)

After:

import logging
import pickle

from unittest.mock import MagicMock
...

2. tests/memories/activation/test_kv.py (L64-L68)

DynamicCache does not expose a .layers attribute in any released version of transformers; it uses .key_cache / .value_cache. The hasattr(merged, 'layers') branch is therefore dead code — it will never be entered — and could silently stop testing the right thing if a future transformers version ever adds an unrelated attribute called layers. Remove the dead branch and keep only the key_cache / value_cache assertions, or replace with len(merged) == 1 (the __len__ method is stable across versions and returns the number of cached layers).

💡 Suggested Change

Before:

    if hasattr(merged, "layers"):
        assert len(merged.layers) == 1
    else:
        assert len(merged.key_cache) == 1
        assert len(merged.value_cache) == 1

After:

    assert isinstance(merged, DynamicCache)
    # Check the number of layers in merged key/value cache
    assert len(merged.key_cache) == 1
    assert len(merged.value_cache) == 1

🧹 Filtered 2 low-confidence OCR finding(s) before posting/fix-loop (existing_code_mismatch: 2).

Generated by cloud-assistant via Open Code Review.

@Memtensor-AI

Copy link
Copy Markdown
Collaborator

⚠️ Automated Test Results: ENV ISSUE

The test environment encountered an issue that requires manual attention.

Details: Test collection failed because the torch module is not installed in the test environment, preventing the test module from being imported at all. [advisory, non-gating] AI-generated tests on branch test/auto-gen-b6472f335cd88b41-20260829014814: 82/82 passed — these do NOT affect the PR verdict; review the branch manually.
Branch: fix/kv-cache-carries-no-model-identity

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

Labels

area:memory 记忆存储、检索、更新、召回逻辑 status:in-progress Someone or AI is working on it | 人工或 AI 正在处理

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants