为什么龙虾 OpenClaw 费 token?
大家好,我是煎鱼。
最近几个月看到不少人在聊 OpenClaw 和爱马仕,有一个问题反复出现:为什么它这么费 token?

很多时候不是因为你“问了一句很贵”,而是因为它每次触发,都不是单纯把用户消息发给模型,而是跑了一个完整的 agent runtime。
具体我们今天这篇文章展开来看看。
成本结构与普通聊天不同
普通聊天产品,最直观的成本是输入和输出。OpenClaw 不是这个路子。
它每轮运行前都要先拼 system prompt、挂工具、补工作区上下文、接会话历史,必要时再带上工具结果、附件、压缩摘要。
后台 heartbeat 也是同一套流程,只是触发者不是你。
所以你看到的是一句提问,模型实际收到的更像是:
用户问题+ system prompt+ bootstrap files+ skills metadata+ tool list+ tool schemas+ conversation history+ tool results= 真正送进模型的输入
system prompt 的上下文成本
OpenClaw 的 system prompt 不是一两句人格设定。
从运行路径看,src/agents/pi-embedded-runner/run/attempt.ts 每次都会重新 resolve 当前 run 需要的 skillsPrompt、bootstrap context、工具集合,再走 buildAttemptSystemPrompt(...) 拼成最终 prompt。
最容易被忽略的是工作区 bootstrap 文件注入。默认情况下,像 AGENTS.md、SOUL.md、TOOLS.md、IDENTITY.md、USER.md、HEARTBEAT.md、BOOTSTRAP.md、MEMORY.md 这些内容,都会进入 prompt 组装流程。
源码里的真实默认值,resolver 写得很明确:
agents:defaults:contextInjection:"continuation-skip"bootstrapMaxChars:12000bootstrapTotalMaxChars:60000
这里有两个点:
-
contextInjection不是彻底懒加载,continuation-skip只是安全续写时少注一点。 -
bootstrapMaxChars和bootstrapTotalMaxChars是“截断后仍然进 prompt 的量”,不是说超过就不算。项目说明文档越长,默认上下文就越重。
SKills 上下文开销
很多人会误会,以为 OpenClaw 会把所有 SKILL.md 全文都塞给模型。
当前实现不是,是默认进 system prompt 的是技能目录元数据:技能名、描述、位置,先整理成一个 <available_skills> 清单,让模型知道有哪些技能可读。
真要用某个技能,再去调用 read 打开对应的 SKILL.md。
<available_skills><skill><name>...</name><description>...</description><location>...</location></skill></available_skills>
但这不等于它没成本。OpenClaw 对技能 prompt 也专门做了预算控制,默认 maxSkillsPromptChars 是 18000。
技能会费 token,但主要费在技能目录,不是每个技能正文都默认注入。
工具 schema 的隐藏成本
工具对上下文有两层消耗。第一层是工具列表、工具描述。第二层更重:发给模型的 JSON schema。
这部分平时不显眼,但源码算得很老实。/context detail 那条链路里,会把每个工具的参数 schema 做 JSON.stringify(parameters).length,再累计出总字符数。
官方文档也明说了:Tool schemas (JSON) 算上下文,只是不按普通文本展示。
有时候你明明只问了一句,账单看起来却不像只问了一句,问题往往就出在这里。真想查,先跑 /context detail,很多时候大头根本不在聊天记录里。
会话历史与工具结果的累积成本
只要你还在同一个 session 里聊,历史消息就会一直累。
工具调用和工具结果也会进 transcript,后面的每一轮都得重新背这些东西。
OpenClaw 也知道这里容易炸,所以专门加了几道保险,比如:
agents:defaults:contextLimits:toolResultMaxChars:16000contextPruning:mode:"cache-ttl"ttl:"1h"
这里的 toolResultMaxChars 默认是 16000。
不是说工具输出超过就没了,而是 live path 上会做截断,避免一条超长命令输出把下一轮 prompt 顶爆。
contextPruning.mode = "cache-ttl" 也很关键,它缓存的是内存里的上下文,不是磁盘上的 transcript。
heartbeat 的后台消耗
这个点很多人会漏。它确实存在,而且不是“象征性消耗”,而是实打实的模型调用成本。
OpenClaw 的 heartbeat 不是传统意义上那个轻量 ping。它跑的是完整 agent turn。
官方文档写得很直白:heartbeat runs full agent turns,间隔越短,token 消耗越高。
如果 heartbeat 直接复用主会话,它通常会带上:
-
当前 system prompt。 -
必要的 bootstrap 文件。 -
当前会话上下文。 -
很多情况下,还有主会话历史。
所以它消耗的不是“监控 token”,而是真正的输入输出 token。有人会觉得奇怪:我明明没发消息,为什么 /status、/usage 里的数字还在涨?因为后台 agent 还在按计划跑。
这一块官方也给了两个很关键的降耗开关:
agents:defaults:heartbeat:every:"55m"lightContext:trueisolatedSession:true
lightContext: true 的意思是,heartbeat 尽量走轻量上下文,只保留必要的 HEARTBEAT.md。isolatedSession: true 更狠,直接让 heartbeat 用隔离 session 跑,不复用整段主会话历史。官方文档里给了很直接的量级对比:这样做可以把单次 heartbeat 从大约 ~100K token 级别,压到 ~2-5K。
所以“定时探活是不是费 token”,答案就是:费,而且很可能是后台最容易被忽略的一笔持续成本。
compaction 与 heartbeat 的成本取舍
很多人一看到 /compact、cache、heartbeat,就会把它们自动翻译成“省钱按钮”。这就想多了。
compaction 的逻辑是:先花一次摘要成本,把太长的历史压一压,换后面的上下文窗口继续能跑。
配置里像 reserveTokensFloor、keepRecentTokens,就是在控制什么时候开始压、最近原文保留多少。
heartbeat 也一样,它能帮你保连续性、保缓存热度、保后台任务不断线,但这部分成本不会自己消失。
总结
看到这里,OpenClaw 为什么费 token,已经比较清楚了。
不是单点问题,而是几层东西叠在一起:每轮都要重建自己的 system prompt,技能目录和工具 schema 本身就占上下文,会话历史和工具结果会持续累积。
后台 heartbeat 还会继续烧,compaction 和缓存只能挪成本、打折,不能把成本抹掉。
很多时候,贵的不是单一的模型价格,而是龙虾带了多少东西在跑。
关注和加煎鱼微信,
一手消息和知识,拉你进技术交流群👇


你好,我是煎鱼,出版过 Go 畅销书《Go 语言编程之旅》,再到获得 GOP(Go 领域最有观点专家)荣誉,点击蓝字查看我的出书之路。
日常分享高质量文章,输出 Go 面试、工作经验、架构设计,加微信拉读者交流群,和大家交流!
原创不易 点赞支持
夜雨聆风