主题
成本与用量
读完这页你能做到四件事:
- 看懂
/cost和会话摘要里每个数字的口径,知道哪个是真实总花费 - 判断你的缓存命中率是正常还是异常(两族协议的正常上限根本不一样)
- 用四种手段把成本压下来,从改一行配置到换模型
- 给会话设花费上限,超了自动停
为什么这页值得读
成本是 sid-code 少数有硬数据支撑的方向。缓存命中率不是玄学—— 它直接决定你同一个任务花八分钱还是三毛钱。而这个数就摆在 /cost 里,随时能看。
快速上手
会话里打 /cost:
text
会话时长: 24s
总费用: $0.0529
API 耗时: 21s
工具耗时: 22ms
Token 用量(汇总):
输入: 101287
输出: 210
缓存读取: 71680
缓存命中率: 70.8% 省钱: $0.0589
(openai 协议为隐式缓存,60-70% 属正常上限;90%+ 需 anthropic 族显式缓存)上面是真实数据:来自一次「改一个写错的
add函数」的四轮会话 (glm-5.2 / openai 协议),四次请求的 usage 取自落盘轨迹。
任务结束时不用问也会给一份摘要(同一次会话的真实输出):
text
Session ID: 20260727-184318-a08fce0c
会话时长: 0.4 分钟
LLM: 4 次请求, 25585 tokens, 平均 5.3s, $0.0529
工具: 3 次调用 (3成功/0失败)
交互: 1 次提示, 4 轮循环
缓存: 命中 71% (71.7k/101.3k)先看两个数:$0.0529(花了多少)和 命中 71%(缓存效率)。 第二个数低的时候,第一个数会翻好几倍。
每个数字的口径
这几个数容易看混,逐个说清:
| 字段 | 含义 | 注意 |
|---|---|---|
总费用 | 主对话 + 辅助调用的真实总花费 | 这是你实际要付的钱 |
其中辅助调用 | 标题生成 / 记忆抽取 / 风险分类 / 摘要等影子调用 | 只在 >0 时显示。这部分容易被忽略,但它真的花钱 |
输入 | 全会话累计输入 token(累加口径,不是最后一次请求的长度) | 多轮会话里这个数会远大于上下文窗口,正常 |
输出 | 全会话累计输出 token | — |
缓存读取 | 命中缓存的 token 数 | 这部分单价便宜得多 |
缓存创建 | 主动写入缓存的 token 数 | 只有 anthropic 族有,openai 族恒为 0 |
缓存命中率 | 缓存命中 / 输入总量 | 判断标准见下一节,别拿一个数字套两族协议 |
省钱 | 因为命中缓存而少付的金额 | 注意它可能比总费用还大——省下的比花掉的多是常态 |
多模型会话还会按模型分列,input 用的是同一套累计口径, 所以「分模型之和」和「上方汇总」是能对上的。
缓存命中率:两族协议的正常值不同
这是最容易误判的一点。同样 65% 的命中率,在一族是正常上限,在另一族是明显偏低。
| 协议族 | 缓存机制 | 正常命中率 | 判断 |
|---|---|---|---|
anthropic | 客户端显式写入(cache_control) | 90%+ | 低于 80% 说明有问题,值得查 |
openai(含各家兼容网关) | 服务端隐式缓存 | 60–70% | 到 70% 就已经是上限,别再折腾 |
区别在于:anthropic 族由客户端主动标记「这段缓存起来」,能精确控制缓存边界; openai 族靠服务端自己判断前缀是否重复,客户端插不上手,所以 缓存创建 恒为 0, 结构性上限就在 60–70%。
sid-code 会替你判断并在 /cost 里标注,就是那行括号里的提示—— 看到 70% 配这行提示,说明你已经到顶了,不用再优化。
上面这两个区间不是估的。Prompt Cache:两族协议的分叉 交出了跨 294 个会话、4.3 亿输入 token 的实测账本, 并解释了两族协议为什么必须写成两种形状(openai 族的 缓存创建 恒为 0 就是那里推出来的)。
不要拿 100% 当目标
实测一个单轮会话可以打出 缓存: 命中 100% (24.6k/24.6k)——因为输入全部是重复前缀。 这个数很好看但没意义,真实多轮任务的命中率天然会被新增内容拉低。 有参考价值的是同类任务的命中率趋势,不是单次绝对值。
怎么把命中率提上去
缓存是按前缀命中的,前缀一变整段就废。所以核心原则只有一条: 让稳定的东西待在前面,让变化的东西待在后面。
| 做法 | 为什么有效 |
|---|---|
| 同一个任务留在同一个会话里做 | 换会话等于前缀重建,命中率归零 |
别频繁 /clear | 同上。想换话题但保留上下文用 /compact |
项目约定写进 CLAUDE.md 而不是每次口述 | 它作为稳定前缀被缓存;口述的内容夹在对话中间,破坏后续前缀 |
中途别反复 /model 切换 | 换模型等于换缓存空间,前面攒的全不算 |
| 长任务里别插无关的临时问题 | 插进去的内容会让后面每一轮的前缀都变 |
跨会话:/cache
/cost 只看当前这次会话。想知道"这周缓存命中率是不是在掉""哪个模型最近老断缓存", 用 /cache——它读的是跨会话的用量账本,不是内存里的当前会话。
数据存在 ~/.sid-code/usage-ledger.jsonl(append-only,每会话一行汇总, src/telemetry/usage-ledger.ts)。所以即使会话关了、机器重启了,历史还在。
默认输出:长期命中率与省钱趋势
text
/cache无参显示长期统计:总命中率(百分比 + 绝对 token 数)、累计省钱(USD)、累计成本
- 会话数、按模型分列的用量(按命中 token 降序)、各周期命中率的趋势 sparkline (
▁▃▅▆▇█字符图,一眼看出在涨还是在掉)。
五个参数
| 参数 | 作用 |
|---|---|
--period day|week|month | 聚合粒度,默认 day。week 用 ISO 周键、month 用年月键 |
--model <name> | 按模型名过滤(精确或前缀匹配) |
--breaks | 显示最近 20 条缓存中断记录 + 健康度建议(src/api/cache-detection.ts 的 getCacheHealthAdvice()) |
--history | 跨会话缓存中断遥测历史聚合,从 ~/.sid-code/cache-breaks.jsonl 读,按归因类型计数 |
--prune <N> | 滚动裁剪账本,只保留最近 N 行(账本太大时用) |
--breaks:缓存退化监测
这是 /cache 最该单独说一节的能力。缓存命中率从 90% 掉到 70%,不是 /cost 能看出来的—— 你得知道它为什么掉了、什么时候掉的。--breaks 就是干这个的。
检测机制(src/api/cache-detection.ts 的 CacheBreakDetector):每轮请求前快照缓存关键状态 (system prompt hash / 工具 schema hash / 模型 / cache control / beta headers / 消息数 / 工具顺序),响应后比较 cache_read_tokens 变化。下降 > 5% 且绝对值 > 2000 tokens 才算一次中断(cache-detection.ts:115-116)——避免正常波动报假警。
15+ 种归因维度:模型变化、system prompt 变化、工具增删改、工具顺序变化、缓存策略变化、 beta headers 变化、消息数量骤减(compact 导致)、TTL 过期、重试关联……
--history 把这些中断落盘到 ~/.sid-code/cache-breaks.jsonl(append-only),长期聚合, 告诉你"最近哪种归因最频繁"。子代理的缓存中断独立计——MultiSourceCacheDetector 按 agentId 维护独立基线(cache-detection.ts:299-362),不会把子代理的正常波动算进主会话。
实测这些归因跑出来长什么样、以及为什么"本地前缀 hash 变没变"是最关键的那个判据, 见 Prompt Cache 的归因分布一节—— 632 条真实中断里 99.8% 是本地不可控的服务端波动, 这个数本身就是结论:本地能优化的前缀断裂几乎为零。
compact 会触发一次中断,但会被抑制
/compact 会让消息数量骤减,正常应该报一次中断。但 notifyCompaction() / notifyCacheDeletion() 会跳过紧接的那次检测(假阳性抑制),所以 compact 后看到命中率 下降是正常的,不会在 --breaks 里报成异常。
单会话深度分析:/insights
/cost 给数字,/insights 给结构化报告——这次会话到底发生了什么、哪里可能有问题。
text
/insights # 分析当前会话
/insights latest # 分析最近一个会话
/insights 20260728-004217-cc55cf0d # 分析指定会话别名 /analyze。纯本地执行,不调模型(src/command/commands/insights/insights.ts), 复用 trace/digest.ts 的 renderHuman() 渲染。产出结构(与 轨迹采集与可观测 里 trace-digest 同源):
text
━━━ session <id> [<exitStatus>] ━━━
模型/API 次数/步骤/耗时/成本/token
用户意图: 1. <prompt>
L0 事实层 (N) — 机器可验证,带出处,不含判断:
[高] <kind>: <detail> ⊢ 出处: <file> @<lineRef> = <rawValue>
L1 假设层 (N) — 待验证,先消解证伪条件再采信:
[中] <kind>: <detail> ⚖ 证伪条件: <condition>
工具序列 (N 次调用): · <tool> / ✗ <tool>
思维链要点: 💭 <thought>
子代理执行: <N> 个(成功/失败) 模式: 串行|并行|混合它最有价值的设计是 L0/L1 分层:L0 事实层带出处(messages.json 的哪一行 = 什么值), L1 假设层带证伪条件。它不直接给你"结论是 X",而是给可验证的事实 + 待验证的假设 + 推翻假设需要看哪里。比如 exit_status = error 是事实,但假设层同时给了证伪路径—— 查 messages.json 的 attribution 会看到实际是正常 end_turn,说明 error 状态不等价于异常终止。
/cost、/cache、/insights 各管什么
| 命令 | 回答什么 | 数据源 | 范围 |
|---|---|---|---|
/cost | 这次花了多少钱、缓存命中多少 | 内存当前会话 | 单会话 |
/cache | 缓存命中率长期趋势、是否在退化 | usage-ledger.jsonl + cache-breaks.jsonl | 全部历史会话 |
/insights | 这次发生了什么、哪里可能有问题 | trajectories/sessions/<id>/ 轨迹文件 | 单会话深度 |
三者不重复、不替代:/cost 看当下花了多少、/cache 看长期缓存在不在退化、 /insights 看单次会话的决策链与异常信号。
设花费上限
单次会话给个硬顶,超了自动停:
bash
sid-code --max-budget-usd 0.50四级预警,按累计花费占上限的比例触发(实测输出):
text
$0.0011 / 0.002 → [info] 成本已达配额 55%
$0.0017 / 0.002 → [warning] ⚠ 成本已达配额 85%,请注意控制用量
$0.0019 / 0.002 → [critical] ⚠ 成本已达配额 95%,即将超限!
$0.0025 / 0.002 → [exceeded] 成本已超出配额,自动停止到 exceeded 就真的终止本轮,实测:
text
⚠️ 成本已超出配额($0.0083 / $0.00),自动停止每级只报一次(级别升级才报),不会刷屏。计算基数是含辅助调用的总花费, 所以影子调用烧的钱也受这个上限约束,不会绕过去。
两个必须知道的坑
一、quota.costLimit 会盖掉 --max-budget-usd。 配置里 quota.costLimit 一旦存在,命令行参数就不生效了(取值逻辑是 quota.costLimit ?? costLimit,前者非空即胜)。实测配了 quota: { costLimit: 100 } 之后传 --max-budget-usd 0.002 完全没反应—— 参数确实进了配置,但生效值仍是 100。删掉 quota 段后同一条命令立刻正常触发。 排查方法:--max-budget-usd 不生效时,先去 ~/.sid-code/settings.json 看有没有 quota 段。 团队默认配置里就带 quota.costLimit,所以这事很容易撞上。
二、告警文案里的上限值会显示成 $0.00。 上面那行 ($0.0083 / $0.00) 里的 $0.00 其实是 0.002—— 文案对上限只保留两位小数,设了小于一分钱的上限就会显示成 0。 不影响实际拦截(0.0083 ≥ 0.002 判定正确),只是数字看着怪。
团队级的持续管控(每分钟请求数、token 速率、按规则降级)不在这页, 见配额与成本控制。
把成本降下来的四招
按性价比排序,第一招几乎零成本:
一、给子代理配便宜模型
主对话用强模型,子代理干粗活用便宜的。子代理通常做的是搜索、读文件、跑命令这类 不需要强推理的事,用同一个贵模型是浪费。配置见子代理。
二、保住缓存命中率
见上一节。一次会话做完一件事,比来回开新会话省得多。
三、控制上下文体积
上下文越长,每一轮的输入 token 越多。/context 看当前占用, 长任务到七八成的时候 /compact 一次。细节见上下文与压缩。
四、按任务难度换模型
简单任务不需要最贵的档位。/model 随时切,不用重启。 还有 /effort 调推理档位——低档位输出的 reasoning token 少,也省钱。
Fast Mode:/fast(预留开关)
/fast 切换的是 fastMode 偏好——"优先用更快的输出端点/服务档位"。 如实说明:当前网关未提供对等 fast 能力,开启暂无实际加速效果。 这是预留开关,等网关支持后无需改命令即可生效 (src/command/commands/fast/fast.ts,透传到 src/llm/fallback.ts:212 的 fastMode 字段,fallback 层标注为「预留,暂未启用」)。
text
/fast 显示当前开关态 + 能力说明
/fast on 开启(仅当前会话)
/fast off 关闭
/fast on -p 开启并持久化到 settings.json(别名 --persist / save)无参时的真实输出:
text
Fast Mode: off
注: 当前网关未提供对等 fast 能力,开启暂无实际加速效果(此为预留开关,网关支持后自动生效)。和 /effort 的区别:/effort 控制推理深度(已生效,低档位省 reasoning token), /fast 控制输出端点速度(预留,当前无实际效果)。两者正交——/effort 现在就能用, /fast 等网关就绪后才真正生效。无效参数会提示 用法: /fast [on|off] [-p]。
为什么不删掉这个预留命令
按项目约定(CLAUDE.md「做了但没接线也要说」),如实写"预留"比不写好。 用户看到 /fast 在命令列表里,打了会明确告知"当前无实际加速"—— 比让它消失、等网关支持了再突然出现更诚实。
常见问题
省钱金额比总费用还大,是不是算错了
没算错。省钱 是「如果这些 token 全按未缓存单价付,会多付多少」。 缓存命中比例高的时候,省下的确实可以超过实际花掉的。
总费用和我在网关看到的账单对不上
先看 其中辅助调用 那行。标题生成、记忆抽取、风险分类这些影子调用也算钱, /cost 的总费用是把它们算进去的。如果差得多,用 /trace 看这次会话的完整调用清单。
--max-budget-usd 设了但没生效
九成是被 quota.costLimit 盖掉了,见上面的坑一。检查:
bash
grep -A3 '"quota"' ~/.sid-code/settings.json有 costLimit 就把它改小,或者整段删掉再用命令行参数。
输入 token 数比模型的上下文窗口还大
正常。输入 是全会话累加,不是单次请求的长度。 四轮会话每轮输入 25k,累加就是 100k,但每一轮实际都在窗口内。 想看单次占用去 /context。
想看跨会话的成本趋势
/insights 看聚合视图,/trace --health 看 provider 维度的成功率与延迟。 团队维度的采集见轨迹采集与可观测。