Where-is-DSH's-token

DeepSeek Harness(DSH)没有单独的 “token 消耗文件”。token 用量分散产生于会话事件日志、LLM 流式返回、Web 搜索响应等位置,最后会以 usage 字段或派生投影的形式保存。

1. 会话主日志(权威来源)

  • 路径根:~/.dsh/sessions/
  • 单会话文件布局:
1
2
3
4
5
~/.dsh/sessions/
--<normalized-cwd>--/
<session-id>/
session.jsonl.zstd # 默认 Zstandard 压缩
# 或 session.jsonl # 当 compression: 'none'

每个会话是一个 append-only JSONL 逻辑日志,token 用量主要出现在以下事件里。

1.1 assistant/chunk —— 流式 usage chunk

每个模型请求/step 早期会产生一次 usage chunk:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"type": "assistant/chunk",
"seq": 170,
"time": 1787397701899,
"data": {
"turn": 1,
"step": 1,
"chunk": {
"type": "usage",
"usage": {
"inputTokens": 65,
"outputTokens": 154,
"cacheReadTokens": 1664,
"reasoningTokens": 61
}
}
}
}

1.2 assistant/message —— 最终权威 usage

同一个 step 结束时,assistant/message 会携带最终 usage,覆盖早期 chunk 样本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"type": "assistant/message",
"seq": 172,
"time": 1787397701899,
"data": {
"turn": 1,
"step": 1,
"message": {},
"usage": {
"inputTokens": 65,
"outputTokens": 154,
"cacheReadTokens": 1664,
"reasoningTokens": 61
}
}
}

1.3 compaction/summary —— 压缩摘要请求

上下文压缩产生的 token 用量也会写入会话日志:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"type": "compaction/summary",
"seq": 200,
"time": 1787397705000,
"data": {
"usage": {
"inputTokens": 100,
"outputTokens": 50,
"cacheReadTokens": 0,
"cacheWriteTokens": 0,
"reasoningTokens": 0
}
}
}

1.4 web/deepseek-search-llm-request —— Web 搜索请求标记

Web 搜索的 LLM 请求会先在会话日志中留下一个请求标记,此时 token 计数为 0;真实 usage 来自搜索服务的 HTTP 响应:

1
2
3
4
5
6
7
8
9
10
{
"type": "web/deepseek-search-llm-request",
"seq": 63738,
"time": 1787774182605,
"data": {
"body": {
"model": "deepseek-v4-flash"
}
}
}

2. LLM 流式返回(会话标题等额外请求)

不是所有请求都会写入会话主日志。例如 session-title 标题生成请求通过 ctx.llm.stream() 产生,token 从流式 chunk 中读取:

1
2
3
4
5
6
7
for await (const chunk of stream) {
if (chunk.type === 'usage') {
const usage = chunk.usage
// usage.inputTokens / outputTokens / cacheReadTokens / cacheWriteTokens / reasoningTokens
}
yield chunk
}

3. Web 搜索 HTTP 响应

开启 Web 搜索 token 捕获时,真实 usage 来自 DeepSeek 搜索接口的 HTTP 响应体:

1
2
3
4
5
6
7
8
{
"usage": {
"input_tokens": 8434,
"output_tokens": 801,
"cache_read_input_tokens": 640,
"cache_creation_input_tokens": 0
}
}

转换规则:

1
2
3
const cacheRead = usage.cache_read_input_tokens ?? 0
const cacheWrite = usage.cache_creation_input_tokens ?? 0
const inputTokens = Math.max(0, (usage.input_tokens ?? 0) - cacheRead - cacheWrite)

4. 派生投影缓存(聚合统计)

  • 路径:~/.dsh/storages/session_projcache.json
  • 每个 session 一行缓存,包含 tokenUsagecontextPressurecontextBreakdownbillingsessionStats 等投影。

例如 tokenUsage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"totals": {
"uncachedInputTokens": 78364,
"outputTokens": 5989,
"cacheReadTokens": 1262848,
"cacheWriteTokens": 0
},
"last": {
"turn": 1,
"step": 25,
"buckets": {
"uncachedInputTokens": 621,
"outputTokens": 262,
"cacheReadTokens": 91008,
"cacheWriteTokens": 0
}
}
}

这是派生缓存,不是权威数据;删掉后可以从会话日志重放重建。

5. 读取这些来源的入口

  • ctx.sessions.list():读取当前已加载的 live 会话及其事件。
  • ctx.sessionPersistence.list():列出所有持久化会话。
  • ctx.sessionPersistence.inspect(id):读取某个持久化会话的完整事件日志。
  • ctx.llm.stream():捕获不写入会话日志的额外请求(如 session-title)。
  • globalThis.fetch 响应拦截:捕获 Web 搜索 HTTP 响应中的 usage。

6. 读取时的注意点

  • 默认 .jsonl.zstd 是 Zstandard 帧,不能直接 cat,可用 zstd -d -c file > out.jsonl 查看。
  • 日志写入时可能启用 packChunks,会把连续同类型 delta chunk 打包成物理存储记录(如 text-chunksreasoning-chunks),读取时会还原成逻辑事件。
  • 正确做法是通过 ctx.sessionPersistence 读取,而不是手工解析压缩文件。

小结

Token 来源 位置/接口 是否权威
主对话每次模型请求 会话日志 assistant/chunkassistant/message ✅ 权威
压缩摘要请求 会话日志 compaction/summary ✅ 权威
会话标题等额外请求 ctx.llm.stream() 的 usage chunk ✅ 权威
Web 搜索请求 会话日志 web/deepseek-search-llm-request + HTTP 响应体 usage ✅ 权威
聚合后的 token 统计 ~/.dsh/storages/session_projcache.jsontokenUsage ⚠️ 派生缓存,可重建

Where-is-DSH's-token
https://potccv.com/2026/08/28/Where-is-DSH-token/
作者
Potccv
发布于
2026年8月28日
更新于
2026年8月28日
许可协议