DeepSeek Harness 会话费用少七成:auto-review 缺 sessionId 怎么补
日级费用和中转站账单一分不差,各会话费用加起来却少了约 75%——这不是费用统计算错,而是有一批调用没有归属。 这批调用是 DeepSeek Harness(DSH)的 auto-review 审查请求:每次工具调用前跑一次,真实花钱,但请求选项里没有 sessionId。费用统计按 options.sessionId 归集,拿到 undefined 就只能记进日级总计(来源)。
对账:把 DeepSeek Harness 的费用缺口算成三列
判据不是「大概少了点」,而是「缺口次数与 auto 窗口内的 tool/call 次数逐日相等」。
- 导出当天的日级调用数与费用。预期:与网关或中转站后台的扣费一致。
- 导出各会话行的调用数与费用,求和。预期:明显小于日级总计。
- 两者相减,得到缺口次数与缺口金额。预期:开启 auto 的机器上占比约七成。
- 还原每个会话的预设切换时间线,只数 auto 窗口内的
tool/call。预期:数量与缺口完全对上。 - 切回固定预设后再采样一次。预期:缺口不再扩大。
| 口径 | 报告者第一天 | 第二天 |
|---|---|---|
| 日级调用 | 623 | 860 |
| 会话行调用 | 359 | 490 |
| 缺口次数 | 264 | 370 |
| 缺口占比 | 75.6% | 75.5% |
反向验证也成立:把权限切回固定预设后连续采样,日级与会话行各增长 14,缺口恒定,说明审查停止后未归属用量立刻停止产生。
根因:DeepSeek Harness 的审查调用没传 sessionId
GenerateOptions 里定义了 sessionId,auto-review 构造审查请求时却只给了 provider、model、system、messages、temperature、signal。
- 审查入口
classifyRisk已经拿到agent,会话 id 就在手边。预期:不需要新增依赖。 - 它把请求选项冻结成一个对象,字段里没有
sessionId。预期:归属信息在上游就丢了。 - 同一处的注释写明:这段 review prompt 只走
ctx.llm.stream,从不进入 Session log。预期:日志里也搜不到。 - 费用统计在瀑布里读
options?.sessionId。预期:拿到undefined。 - 于是每次审查都变成「有账单、无归属」的调用。预期:缺口按调用次数累积。
这不是费用插件的统计错误:它的日级数字对得上账单,会话行也只统计了有归属依据的调用,两边都没算错,缺的是上游的归属信息。
路径一:给 DeepSeek Harness 审查请求补 sessionId
改动最小也最直接:把 agent.session.id 写进审查请求的选项,让路由与计费都有归属。
- 找到构造审查请求的函数,确认选项对象里没有
sessionId。预期:字段列表与讨论一致。 - 补上
sessionId: agent.session.id,不要新建依赖。预期:类型检查通过。 - 在单会话里开 auto,跑几次工具调用。预期:该会话的费用行开始增长。
- 再观察日级总计。预期:缺口不再同步扩大。
- 如果会话行没有变化,说明计费侧不认这个字段。预期:直接转路径三,别反复试。
const options = deepFreeze({
provider: snapshot.provider,
model: snapshot.model,
sessionId: agent.session.id,
system: REVIEW_POLICY,
messages: [{ role: 'user', content: [{ type: 'text', text: reviewUserText(snapshot) }] }],
temperature: 0,
signal,
})
补字段之前先想清楚记账口径:算进被审查的会话,还是单列成后台成本。两种都能对账,但报表含义不同。
路径二:扩 purpose,把 DeepSeek Harness 审查单独归类
如果产品上认为审查不应算进被审查会话的账,那就别只补 sessionId,而是给这类调用一个可区分的用途标记。
- 在用途枚举里增加审查一档并更新校验。预期:类型与运行时校验都接受新值。
- 审查请求同时带上
sessionId与新的purpose。预期:归属有了,来源也可区分。 - 费用统计按
purpose单开一类「后台审查」。预期:会话行与后台行都能对上日级总额。 - 保留旧数据兼容路径:没有
purpose的历史调用仍归入普通会话。预期:升级后历史报表不变。 - 在报表里说明这一类的统计口径。预期:读者知道它不是普通对话成本。
目前 purpose 只允许压缩与会话标题两档,扩枚举要同步改校验和文档,否则老客户端会传不进新值。
路径三:统计侧按调用来源给 DeepSeek Harness 兜底
宿主暂时改不了时,可以在费用统计侧识别「没有 sessionId 的审查形态」并单独记账,而不是让它变成无主残差。
- 在
llm/stream观察者里判断options.sessionId是否为空。预期:能筛出未归属调用。 - 结合请求特征确认它来自审查,例如固定的 system 策略与极短输出。预期:不会把普通调用误判进来。
- 把这些调用记到一个显式的「auto-review」桶。预期:日级总额仍等于各桶之和。
- 在报表里标注这是估算归类。预期:读者知道口径边界。
- 用 DSH插件 扩展报表时保留原始字段。预期:不破坏其他消费方。
这条路不改变上游行为,只是把损失变得可见。代价是桶里混了估算,不能当精确归属用。
验证与边界:DeepSeek Harness 费用对账复查
验收只看一条:日级总计必须等于各归属行之和,且缺口不再随 auto 窗口增长。
- 开 auto 跑十分钟,记录前后两次日级与会话行。预期:两者同步增长。
- 切回固定预设,再采样一次。预期:缺口保持不变。
- 核对一条纯对话会话与一条工具密集会话。预期:后者的审查费用能对上调用次数。
- 连续观察两天。预期:没有新的无主残差。
- 对比同一会话在 auto 与固定预设下的会话行增速。预期:差额能解释为审查次数。
边界有四条:计费侧是否只认 sessionId 尚未核实,补字段后要用单会话对比确认;只在 auto 预设且自动批准路径下触发;不要用「总费用除以调用数」摊派,审查请求的输入长度远高于普通对话;影响面不止费用,依赖 sessionId 的审计、限流与遥测也会漏掉这批调用。相关费用口径问题见 模型窗口、费用与配置。
常见问题
差额来自 DeepSeek Harness 的 auto-review 审查调用。它们真实计费,所以日级总计对得上;但没有携带 sessionId,费用统计无法记到任何会话行,只能留在日级残差里。
在 DeepSeek Harness 的 auto 预设下,每次工具调用前都会先跑一次审查,一次调用对应一次模型请求。还原每个会话的预设切换时间线,只统计 auto 窗口内的 tool/call,数量与缺口逐日相等。
DeepSeek Harness 的计费侧是否只认 GenerateOptions.sessionId 还没核实,所以补字段不一定能归属。若计费走 provider 层标记,补字段不会自动生效。先补上并在单会话里对比再决定。
退出 DeepSeek Harness 的 /permission auto,改用固定预设加手动确认,缺口会立刻停止扩大。已经产生的未归属费用不会回填,只能按日级总额核对。
相关术语
- sessionId
- sessionId 是 DeepSeek Harness 请求选项里的会话标识,由 agent loop 在发起请求时写入,供路由、计费与审计按会话归属。审查类后台调用如果漏传,用量就只能落到全局总计。— https://github.com/deepseek-ai/deepseek-harness/discussions/10381
- llm/stream 瀑布
- llm/stream 瀑布是 DeepSeek Harness 对模型流式请求的洋葱式拦截链,观察者可在请求前后读取选项与用量。费用统计插件正是通过它拿到 model、provider 与 sessionId。— https://github.com/deepseek-ai/deepseek-harness/discussions/10381
- purpose
- purpose 是生成选项里标记请求用途的字段,目前允许压缩与会话标题两类。它决定后台调用能否在账单或统计里与普通对话区分开。— https://github.com/deepseek-ai/deepseek-harness/discussions/10381
来源
- #10381 — auto-review 的模型调用未传 sessionId,每次审查费用无法归属到任何会话· deepseek-ai(GitHub Discussions)
- DeepSeek Harness 官方仓库· deepseek-ai(GitHub)