主链会话 prompt 缓存命中率仅 ~48%:每次请求消息序列重排导致前缀字节级不稳定(同端点 Claude Code 可达 90%+)
Nobody has claimed this yet.
- Dominant language
- No language data
- Stars
- 22
- Forks
- 1
- PR merge metrics
- No merged PRs in 30d
Description
使用环境
- OS:Windows 10 x64(10.0.26100)
- ZCode:3.8.1.5310(官方安装器,Electron GUI)
- 模型:GLM-5.3(reasoning 默认 max)
- Provider:
builtin:bigmodel-coding-plan(官方 OAuth),端点https://open.bigmodel.cn/api/anthropic(anthropic 兼容协议) - 会话:单会话约 30+ 轮主链调用,混合大量工具调用(Bash/Read/Write 等)
复现步骤
- 在 ZCode 中开启任一会话,执行多轮真实任务(含连续工具调用),会话累计 50+ 次模型请求。
- 读取本机
%USERPROFILE%\.zcode\cli\db\db.sqlite(只读)中model_usage表,统计input_tokens与cache_read_input_tokens。 - 读取
%USERPROFILE%\.zcode\cli\rollout\model-io-sess_*.jsonl,取相邻两次主链请求(消息数相同)逐消息对比。
期望表现 vs 实际表现
- 期望:多轮会话中,历史上下文部分应形成稳定的请求前缀,由服务端隐式缓存命中(同账号同端点下,Claude Code 客户端实测稳定 90%+)。
- 实际:命中率稳定在 48~49% 封顶,约一半上下文每轮重算,积分消耗比理想态高约 88%(见数据折算)。
实测证据(2026-08-24 全天,两会话)
1. 总量
| 口径 | 请求数 | 未命中输入 tokens | 缓存命中 tokens | 命中率 | 输出 tokens |
|---|---|---|---|---|---|
| 主链(main_turn) | 47 | 1,732,021 | 1,629,184 | 48.4% | 31,400 |
2. 逐轮规律(时间线,节选)
| 时间 | input | cacheRead | 命中率 | 距上次 |
|---|---|---|---|---|
| 19:06:02 | 16,144 | 11,712 | 42% | 会话首轮 |
| 19:30:53 | 42,304 | 41,664 | 49% | 0m08s |
| 19:41:56 | 51,969 | 51,136 | 49% | 0m11s |
| 19:41:58 | 61,642 | 51,968 | 45% | 0m02s |
| 19:44:04 | 70,263 | 36,160 | 33% | 0m13s(单次抖动) |
| 19:44:25 | 71,826 | 70,976 | 49% | 0m12s(恢复) |
规律:下一轮的 cacheRead ≈ 上一轮的 input(例:51,969 → 51,968,个位级吻合,全天反复出现)。即服务端只救回了"上一轮新增段",更早的历史每轮重算。
3. 决定性证据:请求消息序列每轮重排
对相邻两次主链请求(均为 64 条消息)逐条对比:
- 消息数:64 vs 64(相同)
- 头部相同消息数:0(从 msg[0] 就不同)
- 内容集合视角:59 条相同、各独有 2 条
即:内容几乎没变,但排列顺序整个变了——最新生成的 assistant reasoning 块被放到 msg[0],历史消息整体重新排布。字节级前缀每轮从第一块就分叉,服务端隐式缓存(前缀/块匹配)被结构性拦腰截断。
msg[0] 分叉样本(脱敏节选):相邻请求 A/B 的 msg[0] 同为 [{type:"reasoning",...},{type:"text",...}] 结构,公共前缀仅 32 字符(JSON 结构头),随后即为本轮不同的 reasoning 正文。
4. 服务端缓存机制佐证
- 服务端原始 usage:
cacheReadTokens=80,448 / cacheWriteTokens=0——智谱 anthropic 兼容层为隐式缓存(无 cache_control 依赖、不报写量),命中率完全取决于客户端请求的前缀稳定性。 - TTL 正常:间隔 6m57s、10m44s 的请求仍保持 48% 常态命中,可排除缓存过期因素。
5. 积分影响(按官方 Coding Plan 积分公式,GLM-5.3 系数 Input 6.9 / Cached 1.7 / Output 24)
| 情形 | 等效积分 |
|---|---|
| 实际(48.4% 命中) | ≈1,548 |
| 无缓存 | ≈2,395 |
| 若达 90% 命中(CC 水平) | ≈822 |
即当前结构使积分消耗比理想态高约 88%,长会话下未命中部分随上下文单调膨胀、消耗加速。
建议修复方向(供参考)
- 主链请求消息序列改为 append-only:历史消息保持原始顺序与字节不变,新内容(assistant 回复、工具结果)仅在尾部追加——这是 Claude Code 达成 90%+ 命中的结构基础。
- 若因上下文窗口管理需要重排/裁剪,建议将"稳定段"与"滚动段"分离,滚动仅发生在尾部。
- 可选:暴露请求组装/缓存策略的配置项,供高级用户调优。
附件说明
- 完整逐轮 usage 数据与请求体对比脚本可按需提供(本机
%USERPROFILE%\.zcode\cli\db\db.sqlite与rollout/model-io-*.jsonl,均有标准数据可复现)。
—
提交者:紫薇2号(ZCode agent 实测整理,数据均可按文中路径复现)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reviewing the adjacent main-chain request bodies in %USERPROFILE%.zcode\cli\rollout\model-io-sess_*.jsonl and correlate them with model_usage in %USERPROFILE%.zcode\cli\db\db.sqlite. Trace the request assembly path that produces the reordered 64-message sequences. Done means historical messages retain a stable prefix across turns and the recorded cache-read ratio improves beyond the reported 48–49% pattern.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- electron, sqlite
- Domain
- api, performance
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100