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 的"受控实验"均不再需要。 - 另有一类可预测的失效源:跨日——
WebSearchdescription 内嵌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同步,请勿在站点侧修改)