Claude-thermos:自动保活 Claude 会话
开源工具自动维持 Claude 对话活跃,避免超时断连和上下文丢失。
开源工具自动维持 Claude 对话活跃,避免超时断连和上下文丢失。
别再为重建 Claude Code 缓存付费了。当主 Agent 等待 subagent 超过 5 分钟时,它的 prompt cache 会悄然过期。到下一轮交互时,系统不会以低廉的价格读取缓存,而是按写入费率重新编码你的整个对话。在包含大量 subagent 的长会话中,这笔开销约占账单的 20%。claude-thermos 会持续为缓存保温,让你再也不用缴纳这笔额外的“缓存税”。
你仍然可以像平常一样运行 Claude Code,只需通过 uvx 使用 claude-thermos:
uvx claude-thermos # instead of: claude
uvx claude-thermos -p "fix the bug" # any claude args pass straight through
需要 Python 3.11+,并且 claude CLI 已位于你的 PATH 中。
就这么简单。保温操作会自动在后台运行。如果想在不修改命令的情况下禁用某一次运行的保温功能,请设置 CLAUDE_THERMOS_DISABLE=1。
默认情况下,claude-thermos 会启动在 PATH 中找到的 claude。你可以通过 --bin 或 CLAUDE_THERMOS_BIN 环境变量指定另一个二进制文件。仅提供名称时,会在 PATH 中查找(因此 --bin claude-nightly 可以正常工作);提供完整路径时,则会直接使用该路径。这对于项目内置的构建版本,或者为不同账号导出不同 CLAUDE_CONFIG_DIR 的 wrapper 非常实用。
claude-thermos --bin /path/to/bin/claude -p "fix the bug"
# or
export CLAUDE_THERMOS_BIN=/path/to/bin/claude
claude-thermos -p "fix the bug"
该 flag 必须放在所有透传给 claude 的参数之前。
默认命令只会为它所启动的 claude 进程进行缓存保温。那些自行启动 claude 的客户端——例如会拉起自身内置二进制文件的 VSCode/Claude Code 扩展——不会经过它,其他终端同样也不会。
claude-thermos serve 会在一个固定的 loopback 端口上,将保温 proxy 作为独立 daemon 运行。让任意客户端指向它,所有客户端就能共享同一个保温器:
claude-thermos serve --port 8787 # run the daemon (Ctrl-C / SIGTERM to stop)
# then, for any client:
export ANTHROPIC_BASE_URL=http://127.0.0.1:8787
claude -p "fix the bug" # terminal — warmed by the daemon
对于 VSCode 扩展,请确保它的进程继承了这个环境变量。在 macOS 上,可以在启动应用之前执行 launchctl setenv ANTHROPIC_BASE_URL http://127.0.0.1:8787;也可以在启动编辑器的 shell 中导出该变量。该扩展支持 ANTHROPIC_BASE_URL,因此它的流量会通过 daemon 转发;在 subagent 运行期间,主 Agent 的缓存也能保持温热。
daemon 会像 launcher 一样观察流量,并且已经能够同时追踪多个会话,因此一台机器上的所有客户端都可以共用一个 daemon。它会清理空闲时间超过 --session-ttl 的会话(默认值为 3600s),因此可以无限期运行。
调优方面,serve 支持默认命令所具有的 --idle/--interval/--max-cycles/--subagent-window flag,此外还包括:
需要注意:--upstream 必须指向真实 API,绝不能指向 daemon 自己的 loopback 地址,否则 proxy 会把请求转发给自己。serve 会拒绝 loopback upstream,因此即便你已全局导出 ANTHROPIC_BASE_URL,启动 daemon 时仍应显式指定 --upstream https://api.anthropic.com。
Claude Code 的 prompt cache 采用 5 分钟的 TTL。只要缓存一直有效,每轮交互的完整对话历史都会从缓存中提供,费用为输入价格的 0.1x,而不需要按全价重新发送。
如果同一个 prefix 上的两次请求间隔超过 5 分钟,缓存就会过期。造成这种间隔的首要原因,并不是你思考了太久,而是主 Agent 被一个运行时间超过 5 分钟的 subagent 阻塞。subagent 使用不同的 system prompt 和工具集,因此它的请求拥有不同的 cache prefix,永远不会刷新主 Agent 的缓存。subagent 工作时,主 Agent 缓存中的历史记录始终得不到访问,只会不断老化;超过 5 分钟后,它就消失了。subagent 返回时,主 Agent 会带着逐字节完全相同、仅在末尾追加内容的历史记录恢复运行,却发现缓存已经丢失,于是不得不按 1.25x 的写入费率进行完整的重新编码。
此时历史记录已经非常庞大,因此重新编码的成本很高:单次缓存失效可能会重新写入 200K 至 500K token。根据大约 185 个本地会话的测量结果,这类缓存重建约占总账单的 22%,而这笔钱只是用来重新编码片刻之前还存在于缓存中的内容。
claude-thermos 会在一个小型本地 reverse proxy 后面启动 Claude Code(它会将 ANTHROPIC_BASE_URL 指向 loopback 端口;所有流量最终仍会发送至真正的 Anthropic API)。
proxy 会观察 /v1/messages 流量,并将其归入不同的 session 和 lineage。一个 lineage 代表一个 cache prefix,以 model + tool set + system text 作为 key。第一个携带工具的 lineage 是主 Agent,其余则是 subagent。
当主 lineage 进入空闲状态,同时某个 subagent 正在运行时,主 prefix 就面临过期风险。
它会以短于 5 分钟 TTL 的间隔,将主 Agent 最近一次真实请求重放为保温请求:使用完全相同、可缓存的 prefix,但将 max_tokens: 1,并禁用 streaming。生成的单个 token 会被丢弃;真正的目的是执行 prefill,从而读取并刷新完整的缓存 prefix。保温请求会直接发送至 API,绝不会经过 proxy,因此不会干扰真实流量。
当 subagent 完成任务时,主 Agent 的缓存仍然是热的。它只需支付低廉的读取费用,而不是完整重写费用。
每次保温都需要支付一次缓存读取费用(0.1x);而它避免的每次重写,原本需要针对大得多的 prefix 支付写入费用(1.25x),因此这笔交换对你非常有利。
每个 session 都会写入:
~/.claude-thermos/logs/<session_id>/
├── events.jsonl # append-only structured event stream
└── summary.json # rollup totals, written when the session ends
events.jsonl 会记录每次请求和响应的 token usage,以及每一个保温决策(warm_fired、warm_result、cap_reached、resume_detected 等)。summary.json 则是汇总文件,通常你主要查看的就是它:
三个成本数字均以基础 input token 为单位,也就是已经根据对应 cache multiplier 加权后的 token 数量。要将 net_savings 换算成美元,只需将其乘以所用 model 的单个 input token 价格:
dollars saved ≈ net_savings × (input token price)
例如,当输入价格为每 1M token 3 美元时,net_savings 为 1_200_000,就意味着该 session 大约节省了 1_200_000 × $3 / 1_000_000 = $3.60。