zai-org / zai-org/feedback

主链会话 prompt 缓存命中率仅 ~48%:每次请求消息序列重排导致前缀字节级不稳定(同端点 Claude Code 可达 90%+)

Open
#354 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

priority: P2
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 等)

复现步骤

  1. 在 ZCode 中开启任一会话,执行多轮真实任务(含连续工具调用),会话累计 50+ 次模型请求。
  2. 读取本机 %USERPROFILE%\.zcode\cli\db\db.sqlite(只读)中 model_usage 表,统计 input_tokenscache_read_input_tokens
  3. 读取 %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%,长会话下未命中部分随上下文单调膨胀、消耗加速。

建议修复方向(供参考)

  1. 主链请求消息序列改为 append-only:历史消息保持原始顺序与字节不变,新内容(assistant 回复、工具结果)仅在尾部追加——这是 Claude Code 达成 90%+ 命中的结构基础。
  2. 若因上下文窗口管理需要重排/裁剪,建议将"稳定段"与"滚动段"分离,滚动仅发生在尾部。
  3. 可选:暴露请求组装/缓存策略的配置项,供高级用户调优。

附件说明

  • 完整逐轮 usage 数据与请求体对比脚本可按需提供(本机 %USERPROFILE%\.zcode\cli\db\db.sqliterollout/model-io-*.jsonl,均有标准数据可复现)。


提交者:紫薇2号(ZCode agent 实测整理,数据均可按文中路径复现)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.