Your memory layer is lying to you (and your LLM agrees)
Your memory layer is lying to you (and your LLM agrees)
你的记忆层在对你撒谎(而你的大模型表示赞同)
The Mechanical vs. The Semantic: What Happens When AI Memory is Wrong? Tested on a 50K LOC Python codebase. 机械与语义:当 AI 记忆出错时会发生什么?基于 5 万行 Python 代码库的测试。
The verify-on-read experiment (1-V) used a deterministic proxy agent to catch false claims in memory before surfacing them to the user. Proxy FA=0 by construction — that’s a useful property, but it tells you nothing about what a real LLM would do with the same claims. A reviewer’s note from Part 3 was blunt: “headline numbers were a property of the heuristic, not LLM behavior.” So we ran it with live models. 50 facts, 2 arms, 14 models, ~3300 API calls, $0.14 total. Here’s what we found. “读取时验证”(verify-on-read)实验(1-V)使用了一个确定性的代理(proxy agent)来捕获记忆中的虚假声明,然后再将其呈现给用户。从设计上讲,代理的虚假接受率(FA)为 0——这是一个有用的属性,但它无法告诉你真实的大模型在面对相同声明时会怎么做。第三部分的一条审稿人笔记直言不讳:“头条数据是启发式算法的属性,而非大模型的行为。”因此,我们使用真实模型进行了测试。50 个事实、2 种实验组、14 个模型、约 3300 次 API 调用,总成本 0.14 美元。以下是我们的发现。
The setup
实验设置
Dataset: memory_contamination_facts_v4_rep.json, N=50 (R01–R50), sha256 fingerprint 820bbbf60a0fc930. 数据集:memory_contamination_facts_v4_rep.json,N=50 (R01–R50),sha256 指纹 820bbbf60a0fc930。
- real (25 TRUE claims): grep-validated against code.
- absent-mutation (16 FALSE): component doesn’t exist in the project.
- present-trap (6 FALSE): file exists but claim is about wrong subject/value.
- silent (3 FALSE): external systems the codebase doesn’t mention.
- 真实(25 个正确声明): 通过 grep 在代码中验证。
- 缺失变体(16 个错误声明): 组件在项目中不存在。
- 存在陷阱(6 个错误声明): 文件存在,但声明的主体或值错误。
- 静默(3 个错误声明): 代码库未提及的外部系统。
Two arms per fact: 每个事实分为两组:
- memory_first: model sees only the claim text, no code context. Does it trust memory without evidence?
- code_first: model sees claim + support_patterns + section. Does it correctly evaluate the anchors?
- memory_first(仅记忆): 模型仅看到声明文本,没有代码上下文。它是否会在没有证据的情况下信任记忆?
- code_first(代码优先): 模型看到声明 + 支持模式 + 代码片段。它是否能正确评估这些锚点?
Model verdict: {“verdict”: “true”|“false”|“unknown”}, JSON-only, max_tokens=100, temp=0, seed=42, —no-reasoning. 模型判定:{“verdict”: “true”|“false”|“unknown”},仅限 JSON,max_tokens=100,temp=0,seed=42,—no-reasoning。
Leak-guard: assert “truth” not in prompt on every fact, unit-tested. 防泄漏保护:在每个事实的提示词中确保不包含 “truth” 关键字,并经过单元测试。
Metric we care about: false_accept rate (FA) — fraction of false claims the model returned “true” for. This is the contamination risk number. 我们关注的指标:虚假接受率(FA)——模型判定为“true”的虚假声明比例。这是衡量污染风险的指标。
Results (V2 prompt, canonical)
结果(V2 提示词,标准版)
(Table omitted for brevity, focusing on key findings) (为简洁起见省略表格,重点关注核心发现)
The main finding: model choice dominates. code_first FA range: 0.00 to 0.38. glm-4.7-flash at code_first FA=0.30 (V1 prompt) / 0.24 (V2 prompt) is accepting nearly 1 in 4 false claims even when supporting anchors are shown. nemotron-3-nano is worse: 0.38, meaning it accepted 19/50 false claims in the code_first arm. The best flash-tier models (qwen3.6, qwen3.7) hit FA=0.00 at 1/10th the cost of Claude. 主要发现:模型选择起决定性作用。code_first 的 FA 范围在 0.00 到 0.38 之间。glm-4.7-flash 在 code_first 模式下的 FA 为 0.30(V1 提示词)/ 0.24(V2 提示词),即使在展示了支持锚点的情况下,它仍会接受近 1/4 的虚假声明。nemotron-3-nano 更糟:达到 0.38,意味着它在 code_first 组中接受了 50 个虚假声明中的 19 个。表现最好的 Flash 级模型(qwen3.6, qwen3.7)以 Claude 1/10 的成本实现了 FA=0.00。
Claude is the cleaner baseline — FA=0.00 in both arms, high unknown rate (0.86/0.70) — but it’s not giving you better contamination protection than the cheapest qwen models. “Any cheap model works for verification” is the wrong conclusion from the cost numbers. Claude 是更干净的基准——在两组中 FA 均为 0.00,且未知率较高(0.86/0.70)——但它提供的污染防护并不比最便宜的 Qwen 模型更好。从成本数据得出“任何廉价模型都适用于验证”是错误的结论。
Pitfall 1: bare-token anchors inflate FA by design
陷阱 1:裸词锚点会人为增加 FA
The V1 prompt showed support_patterns and asked “does the claim appear supported by these anchors?” The model sees the bare string “typesense”, sees it repeated in the supporting anchors field, and returns “true”. It’s treating a field label as evidence. V1 提示词展示了支持模式并询问“声明是否看起来被这些锚点支持?”模型看到裸字符串“typesense”,看到它在支持锚点字段中重复出现,于是返回“true”。它把字段标签当成了证据。
The fix in V2: V2 的修复方案:
V1 (sycophantic): Does the claim appear supported by these anchors?
V2 (neutral): Return true ONLY if the anchors directly verify the claim; false if the anchors contradict it or the claim refers to something absent from the anchors; unknown if you cannot determine.
V1(谄媚型):声明是否看起来被这些锚点支持?
V2(中立型):仅在锚点直接验证声明时返回 true;如果锚点与声明矛盾,或声明引用了锚点中不存在的内容,则返回 false;如果无法确定,则返回 unknown。
Pitfall 2: temp=0 + seed=42 is not determinism on OpenRouter
陷阱 2:在 OpenRouter 上,temp=0 + seed=42 并不意味着确定性
Run-to-run variance for nemotron-3.5-lightning code_first: FA went from 0.18 to 0.08 between two otherwise identical sweeps. That’s ±0.10 on a single-pass measurement. OpenRouter routes to different upstreams, which adds a layer of variance on top of whatever the model itself does. nemotron-3.5-lightning 在 code_first 模式下的运行差异:在两次完全相同的扫描中,FA 从 0.18 变为 0.08。在单次测量中,这有 ±0.10 的波动。OpenRouter 会路由到不同的上游,这在模型自身行为之外又增加了一层变数。
Pitfall 3: unknown ≠ broken
陷阱 3:unknown 不等于故障
The failure mode you want to avoid is FA, not high unknown. High unknown means “go check the code.” High FA means “accepted a lie.” 你需要避免的故障模式是 FA(虚假接受),而不是高 unknown(未知)。高 unknown 意味着“去检查代码”。高 FA 意味着“接受了一个谎言”。