到期之前
Bonsai 的对话栏多了一行小字,就在上下文用量的圆环旁边:缓存剩 42 分钟。
它只在 agent 停下来等你的时候出现,也就是一轮做完了,或者它问了你一个问题。剩下十分钟以内会变红,到点了就变成缓存已过期。
这篇讲讲这个数字是怎么算出来的,以及我们为什么没有去问 harness 要一个「真实的」到期时间。
为什么要在意缓存
Claude Code、Codex 这类 harness 每次调用模型,通常都会把整段对话重新发一遍:system prompt、工具定义、到目前为止的每一句话、每一次工具调用的结果。一段干了一下午的对话,发一次就是几十万个 token。
提示缓存(prompt cache)让模型服务商不必每次从头处理这些内容。前缀和上一次一样,就从缓存里读。读缓存比正常输入便宜得多,在 Anthropic 那里大约是十分之一的价格,而且快得多。
但缓存会过期。没人用它,它就被丢掉。下一句话再来,整段上下文就得从头处理一遍:更慢,也更贵。
所以当 agent 停下来等你的时候,有一个你看不见的倒计时在走。在它走完之前回一句,下一轮就接着用缓存;走完了才回,下一轮就要付全价把整段对话重新读一遍。
Bonsai 怎么算
规则很短:
- 从会话里最后一个事件的时间开始算。事件是执行端发上来的:一段回复、一次工具调用、一轮结束、一个请求。每个事件都带着执行端本机的毫秒时间戳。
- 加上一小时。
- 减去现在的时间,向上取整到分钟。
为什么是最后一个事件?缓存的寿命是从最后一次被使用开始续的,而模型的最后一次调用,就发生在 agent 吐出最后那几个事件的时候。两者的差距通常只有几秒,对一个按分钟显示的提醒来说可以忽略。
为什么是一小时?Anthropic 的 API 提供两档缓存:默认五分钟,加钱可以买一小时。我们按长的那一档算。如果你用的 harness 或服务商用的是更短的窗口,这个数字就太乐观了。我们宁愿给一个统一、好记的数字:一小时内回复。
几种情况下不显示:
- agent 正在跑。缓存在被持续使用,倒数没有意义。
- 一轮都还没结束过,也没有在等你回答的请求。
- 对话已经结束了,而且缓存也已经过期。这时候再挂一句「已过期」只是噪音,你翻看三天前的对话时不需要它。
已经结束、但还能接着聊的对话会照常倒数,因为接着聊用的是同一段上下文,缓存同样有效。
我们没有去读 harness 的缓存
你可能会想,为什么不直接问 harness:你的缓存什么时候过期?
因为它们大多不告诉你。Harness 知道自己给每次请求设了什么缓存参数,但服务商什么时候真的把缓存清掉,通常不在任何一个返回值里。不同的 harness、不同的服务商、同一家服务商的不同模型,规则都不一样。
Bonsai 对 harness 的态度一直是这样:它不认识任何一项具体设定。模型、effort、权限模式,都是执行端在握手时自己声明的,Bonsai 只负责照着画出来。缓存也一样。如果要为每一家 harness 写一份缓存规则,Bonsai 就得跟着每一家的更新改,而且总会有一家写错。
所以我们做了更简单、也更诚实的事:Bonsai 只看它确实知道的东西,也就是最后一个事件的时间。数字旁边的说明也直接说了,这是提醒,不是账单。
下一步
这是 Bonsai 关于「到你了」的第一块拼图。agent 卡住,不管是流程里预设好要停下来,还是遇到了没想到的问题,对你来说都是同一件事:有东西在等你,而且最好在一小时内回。
对话里的倒数只是让你在打开对话时看见它。我们同时在做 Bonsai 自己的通知系统,好让你不打开对话也能知道。