概要
通过 --resume 恢复一个已有会话时,每发起一个新的 user turn,
skill_listing 和 skill_discovery(learned-gap 触发的)这两类 attachment
都会被重新生成,并经由 reorderAttachmentsForAPI 浮动到本回合最新的
user 消息位置。与此同时,T1 写盘后的 transcript 在 T2 加载时丢掉了原本
inline 在 user 消息里的对应 <system-reminder> 内容块。
结果:T2 发往 Anthropic API 的 messages 数组里,T1 那条 user 消息的
content 形态与 T1 当时实际发出去的不一致。Anthropic 端按 prefix 哈希
做命中判断,于是从该消息往后整段失效,每回合都付一遍 cache write 的钱。
影响
cache_read_input_tokens 长期只命中 Anthropic 服务端对 claude_code preset 的全局共享前缀(约 22K),命中率被压在 10%~76% 之间(轮数越多命中率越低)
- 用户每回合多付全量 prompt 的 cache write 成本
- 消息不连贯,导致模型 Agent 性能劣化
环境
- Claude Code 版本:<填你跑的版本>
- Node:<v?>
- 平台:Linux x86_64
- 模型:claude-opus-4-7
复现步骤(最小化)
- 在系统层挂一个抓 HTTPS 的代理(mitmproxy 即可),让 CLI 的请求经过它:
mitmdump -p 18080 -s capture.py # 把 api.anthropic.com 的 POST body 落盘
export HTTPS_PROXY=http://127.0.0.1:18080
export NODE_EXTRA_CA_CERTS=$HOME/.mitmproxy/mitmproxy-ca-cert.pem
起一个新会话,发一条短消息:
claude -p "你好"
用相同的 sessionId resume,再发一条:
claude --resume <sid> -p "你好"
- 此时 diff 两个抓到的 /v1/messages 请求体的 messages[] 数组,即可发现问题。
问题包demo
T1
{
"messages": [
{ "role": "user", "content": "<available-deferred-tools>...</available-deferred-tools>" },
{
"role": "user",
"content": [
{ "type": "text", "text": "<system-reminder>\nNo high-confidence active skill was auto-loaded for this request.\nA learned skill was promoted for future turns: ...\n</system-reminder>" },
{ "type": "text", "text": "<system-reminder>\nThe following skills are available for use with the Skill tool:\n...\n</system-reminder>" },
{ "type": "text", "text": "<system-reminder>\n# currentDate\nToday's date is ...\n</system-reminder>" },
{ "type": "text", "text": "你好", "cache_control": { "type": "ephemeral", "ttl": "1h" } }
]
}
]
}
T2
{
"messages": [
{ "role": "user", "content": "<available-deferred-tools>...</available-deferred-tools>" },
{
"role": "user",
"content": [
{ "type": "text", "text": "<system-reminder>\n# currentDate\n...\n</system-reminder>" },
{ "type": "text", "text": "你好" }
]
},
{ "role": "assistant", "content": [ { "type": "text", "text": "你好!..." } ] },
{
"role": "user",
"content": [
{ "type": "text", "text": "<system-reminder>\nNo high-confidence active skill was auto-loaded for this request.\nA learned skill was promoted for future turns: ...\n</system-reminder>" },
{ "type": "text", "text": "<system-reminder>\nThe following skills are available for use with the Skill tool:\n...\n</system-reminder>" },
{ "type": "text", "text": "你好", "cache_control": { "type": "ephemeral", "ttl": "1h" } }
]
}
]
}
Usage 证据
| 回合 |
tokens_in |
cache_read |
cache_create |
cache_hit |
| t1 |
6 |
22207 |
6979 |
76.1% |
| t2 |
6 |
22207 |
7008 |
76.0% |
| t3 |
6 |
22207 |
7038 |
75.9% |
概要
通过
--resume恢复一个已有会话时,每发起一个新的 user turn,skill_listing和skill_discovery(learned-gap 触发的)这两类 attachment都会被重新生成,并经由
reorderAttachmentsForAPI浮动到本回合最新的user 消息位置。与此同时,T1 写盘后的 transcript 在 T2 加载时丢掉了原本
inline 在 user 消息里的对应
<system-reminder>内容块。结果:T2 发往 Anthropic API 的 messages 数组里,T1 那条 user 消息的
content 形态与 T1 当时实际发出去的不一致。Anthropic 端按 prefix 哈希
做命中判断,于是从该消息往后整段失效,每回合都付一遍 cache write 的钱。
影响
cache_read_input_tokens长期只命中 Anthropic 服务端对claude_codepreset 的全局共享前缀(约 22K),命中率被压在 10%~76% 之间(轮数越多命中率越低)环境
复现步骤(最小化)
起一个新会话,发一条短消息:
claude -p "你好"用相同的 sessionId resume,再发一条:
claude --resume <sid> -p "你好"问题包demo
T1
T2
Usage 证据