跳转至

SOP — 缓存 TTL「空闲即失效」条目降级为【存疑】(本会话 9.3 h 空档反例)

主题目录:token_proxy/cache-ttl-20261007/|执行日期:2026-10-07|类型:C 类(改 skill 文档) 触发:用户要求核查「对话中间那次长空档」的 miss 情况 → 实测与既有条目相悖 → 按 skill 成长机制留痕

1. 背景

ops-execution-efficiency SKILL.md §6.2 有一条断言(2026-10-07 写入):

空闲会让缓存整体失效……同会话内间隔 5~25 min 时未命中仅 ≈220 tok(≈0.1%), 而跨夜 10.8 h 后一次未命中 249,020 tok,占 prompt 的 98.1%。 故 离开超过约 30 min 再回来,成本已接近开新会话。

用户指出本会话中间有一次很长的空档,要求核查 miss 实况。核查结果与上述断言相悖, 按 skill 成长机制(「某条被证明无效或有害,当场改并记下为什么推翻」)需留痕。 因只有单样本,本次不删正文、不宣布推翻,降级为【存疑】并锁定「不得据此建议开新会话」。

2. 目标

# 目标 判据
1 量出长空档后的真实 miss,而不是沿用假设 给出空档时长 → 后一步 cache_miss_tokens 的对照
2 定位本会话 miss 的真实来源 给出轮首 / 中段步 miss 分布
3 把结论落进 skill 的推翻记录,并在正文挂警示 lessons-and-retractions.md §一 新增一行 + SKILL.md §6.2 加【存疑】标注
4 不越界:单样本不做正式推翻 正文条目保留;仅禁止据此建议「为躲空档而开新会话」

3. 前置条件

  • ~/Documents/services/token_proxy/logs/usage.jsonl 可读(本次会话记录齐全);
  • 会话 conv_key 已知:de08e3246604(8 轮 / 166 步 / 09:03 → 21:31);
  • 变更前完成 5.1 备份。

4. 影响范围

项 内容
变更对象 ~/.trae-cn/skills/ops-execution-efficiency/SKILL.md、references/lessons-and-retractions.md
改的是什么 只增加警示与留痕,不删任何既有条目、不改判据数值
生效方式 skill 正文与 references/ 按需加载、不进程前缀 → 同会话下次请求即生效,无需开新会话(依据:本 skill 推翻记录里「改 skill 正文→不影响前缀」那条)
是否影响生产 否:纯文档

5. 分步操作

5.1 备份(高危前置)

D=~/Documents/services/token_proxy/cache-ttl-20261007
S=~/.trae-cn/skills/ops-execution-efficiency
STAMP=$(date +%Y%m%d-%H%M%S)
mkdir -p "$D/backup/trae-cn/skills/ops-execution-efficiency/references"
cp -a "$S/SKILL.md" "$D/backup/trae-cn/skills/ops-execution-efficiency/SKILL.md.bak.$STAMP"
cp -a "$S/references/lessons-and-retractions.md" \
      "$D/backup/trae-cn/skills/ops-execution-efficiency/references/lessons-and-retractions.md.bak.$STAMP"

预期:2 个 .bak.20261007-213816。

5.2 取数(只读,一条命令跑完)

cd ~/Documents/services/token_proxy && python3 - <<'PY'
import json, datetime
from pathlib import Path
CK = "de08e3246604"
recs = [json.loads(l) for l in Path("logs/usage.jsonl").read_text().splitlines() if l.strip()]
rows = sorted([r for r in recs if r.get("conv_key") == CK], key=lambda r: r["ts"])
T = lambda s: datetime.datetime.strptime(s, "%Y-%m-%d %H:%M:%S")
for a, b in zip(rows, rows[1:]):
    g = (T(b["ts"]) - T(a["ts"])).total_seconds()
    if g > 300:
        print(f"{g/60:7.1f} min  {a['ts']} -> {b['ts']} | "
              f"后一步 prompt={b['prompt_tokens']} "
              f"未命中={b['cache_miss_tokens']} "
              f"({b['cache_miss_tokens']*100//max(b['prompt_tokens'],1)}%)")
PY

坑:selfcheck.py --last N 列的是其它会话的轮次(按时间升序),不是本会话; 本会话必须按 conv_key 过滤(usage.jsonl 最后一条记录的 conv_key 即当前会话)。

5.3 留痕(两处,缺一即失效)

  • references/lessons-and-retractions.md §一 表格新增一行:原条目 + 反例数据 + 两种解释 + 处置;
  • SKILL.md §6.2 该条句首插入【存疑】标注并指向推翻记录——只写进 references 不改正文, 等于没人会读到(正文才是被加载的部分)。

6. 验证

验证一:数据可复现 —— 5.2 的取数脚本输出:

空档 后一步 prompt 未命中 占 prompt
560.4 min(9.3 h) 303,008 288 0.10%
56.8 min 228,369 145 0.06%
21.4 min 377,119 287 0.08%
17.8 min 374,646 502 0.13%
5.1 min 294,212 836 0.28%

空档长短与 miss 无关;9.3 h 空档后的 miss(288)小于 5.1 min 空档后的(836)。

验证二:miss 的真实分布

位置 结果
会话第 1 步 miss 19,225(45.76%),prompt 42,009 —— 前缀冷启动,全会话唯一大 miss
第 2~8 轮首步 140 ~ 288 tok(0.03%~0.31%)
中段步(159 个) 最大 19,681、P99 8,962、中位 622、≥20000 的 0 个(故 wrapup miss 检测静默是正确的)
上下文精简(prompt 骤降 >20%) 0 次
全会话 命中 45,637,632 / 未命中 215,349 → 命中率 99%

验证三:文档已挂警示且不越界 - lessons-and-retractions.md §一 新增一行(含反例、两种解释、处置); - SKILL.md §6.2 句首出现【存疑】标注并指向 §一; - 既有条目与数值一字未删(单样本不做正式推翻)。

失败判断:若取数显示长空档确有大 miss(与本次相反),则不动 §6.2,只把本次作为反例登记到 §二。

7. 回滚

  • 备份位置:cache-ttl-20261007/backup/trae-cn/skills/ops-execution-efficiency/, 台账见 cache-ttl-20261007/backup/README.md。
  • 回滚步骤:
D=~/Documents/services/token_proxy/cache-ttl-20261007/backup/trae-cn/skills/ops-execution-efficiency
cp -a "$D/SKILL.md.bak.20261007-213816" ~/.trae-cn/skills/ops-execution-efficiency/SKILL.md
cp -a "$D/references/lessons-and-retractions.md.bak.20261007-213816" \
      ~/.trae-cn/skills/ops-execution-efficiency/references/lessons-and-retractions.md
  • 回滚后验证:§6.2 恢复为无【存疑】标注的原文;§一 表格行数回到原文。
  • 回滚触发条件:① 后续样本证明「长空档确实造成大 miss」(该条不该标存疑); ② 【存疑】标注让执行方误以为该条整体作废、不再做「长任务连续做完」的常规安排。

8. 风险说明

风险 缓解
单样本推翻一条既有规则 → 过度反应 不推翻:正文条目保留,只标【存疑】+ 禁止据此建议开新会话
只写 references/ 而正文无感 → 没人读到 正文句首加【存疑】标注(被加载的才是正文)
观测口径错(拿别的会话的轮次当本会话) 必须按 conv_key 过滤;selfcheck --last N 跨会话,不可用于本用途
把「前缀变化」误当「TTL 过期」(旧那次可能就是这样) 本文只陈述「空档后 miss 很小」这一事实与两种可能解释,不下因果断言

附录 A 交付物清单

文件 说明
SOP.md 本文件
backup/trae-cn/skills/ops-execution-efficiency/SKILL.md.bak.20261007-213816 改前快照
backup/trae-cn/skills/ops-execution-efficiency/references/lessons-and-retractions.md.bak.20261007-213816 改前快照
backup/README.md 备份台账
变更的文件 SKILL.md §6.2 加【存疑】标注;lessons-and-retractions.md §一 加一行

附录 B 待复现(下次如何收第二、第三个样本)

任一会话满足下列条件即计一个样本:同一 conv_key 内存在 ≥60 min 空档,且空档后第一步 的 cache_miss_tokens。取数仍用 5.2 的脚本(改 CK 即可)。

  • 若多会话均呈「长空档 → 小 miss」→ 正式推翻 §6.2 该条,改判为「本环境 TTL 足够长, 空档不构成开新会话的理由」;
  • 若出现「长空档 → 大 miss」→ 说明旧结论有前提(如换客户端/换 route/换模型), 需把前提写进条目后撤掉【存疑】。

9. 结案(2026-10-11)

用户确认最新认知,本主题结案,【存疑】作废:

  • 缓存失效「不定时」,与空闲时长无因果——官方对 prompt cache 有效期不承诺固定 TTL;本机样本亦证:9.3 h 空档后第 1 步 miss 仅 0.10%,比 5.1 min 空档后的还小。故不得据空档时长建议「开新会话」(切会话另多付 ≈0.58 元/次)。
  • 本机经验:1 h 内几乎不失效;超 1 h 由 proxy cache_probe 运行时兜底——空闲 ≥1 h 自动探测本次请求前缀,命中 <90% 即拦回 500(冷却 120 s、压缩后放行)。这比"预测 TTL 边界"更可靠,故 §附录 B 的"再收样本"与 #33 的"受控实验"均不再需要。
  • 另有一类可预测的失效源:跨日——WebSearch description 内嵌 Today's date,跨日首请求前缀必分叉(实测 350,719 tok 整段重算),与空闲无关。
  • 文档已同步:SKILL.md §6 该条改为「不定时、无因果 + proxy 兜底」;lessons-and-retractions.md §一、optimization-backlog.md #33 / #37 均标结案。回滚快照见 backup/skills-20261011/。

来源:/home/rain/Documents/services/token_proxy/cache-ttl-20261007/SOP.md | 最后更新:2026-10-11 15:46(由 build/sync.py 同步,请勿在站点侧修改)