Skip to content

伪缓存与心跳税:如何烧掉你的钱

证据等级:F(源码直接证明)
分析基线:4f843556


一句话

OpenAI 的 prompt caching 被一行代码明确关闭:supports_cache_control = normalized_provider == "qwen"。只有 Qwen 受益。与此同时,每 4 小时一次的心跳不分 idle/running,触发完整 LLM 会话,无并发控制。


1. 伪缓存

# client.py:2599
supports_cache_control = normalized_provider == "qwen"

各厂商缓存策略

厂商 缓存 实际效果
OpenAI 禁用 每轮重传全部 prompt
Anthropic 静态前缀 动态内容永远重发
Qwen 启用 唯一受益者

固定开销

System prompt:  ~6,000 tokens
Tools:          ~5,000 tokens
─────────────────────────
每轮固定:       ~11,000 tokens(无缓存命中)

2. 心跳税

# heartbeat.py:473,512
if state in ("idle", "running"):  # 无差别
    create_task(heartbeat_session())  # 无并发控制
  • 无 lock、semaphore、rate limiting、jitter、backpressure
  • 固定 4 小时间隔

你以为的 ping-pong,实际是负重奔跑

心跳的本意是"你还活着吗"——一次轻量存活检查。但这里的实现是:

  1. 组装完整上下文:soul.md + memory.md + skills/ + tools + enterprise_info + focus + triggers → 全部拼进一个 system message,然后发给 LLM
  2. LLM 认真回复:模型收到 ~20K tokens 的完整上下文,生成一段有意义的回复
  3. 回复被丢弃:没有人读取这个回复,不做任何处理

这不是心跳——这是每 4 小时让 LLM 把整个 Agent 的"人格 + 记忆 + 能力"读一遍,然后写一段读后感,再扔掉。

对比:一个正确的心跳应该是什么

正确的心跳:
  echo pang → "pang"
  2 tokens

实际的心跳:
  → 组装 soul + memory + skills + tools + enterprise_info + focus + triggers
  → 发给 LLM
  ← LLM 生成一段认真的回复
  → 回复被丢弃
  ~20,000 tokens

从 2 到 20,000——一万倍起步。不是优化不够,是根本没意识到心跳不应该进 LLM。

成本估算

1 Agent × 6 次/天 × ~20K tokens/次 = ~120K tokens/天
100 Agent × 6 次/天 × ~20K tokens/次 = ~12M tokens/天

仅心跳,不含用户实际使用。

换算成钱

输入:12M tokens/天
输出:~0.2M tokens/天

                   输入价格    输出价格    每天      每月
Claude Sonnet 5    $3/1M      $15/1M     ~$39      ~$1,170
Claude Opus 4.8    $5/1M      $25/1M     ~$65      ~$1,950

100 个 Agent,什么正事都不干,光心跳。Sonnet 一个月烧掉一千多美元,Opus 翻倍。

换算一下:Sonnet 一个 Agent 的心跳 ≈ $11.70/月。两个 Agent 的光心跳就够订一个 Claude Pro($20/月)。用 Opus 的话,一个 Agent 就够了。

而一个正确的心跳只需要 echo pang——2 tokens。


3. 叠加效应

伪缓存 + 心跳:每 4 小时,每个 Agent 重传 ~20K tokens 的完整上下文——这正是缓存本应避免的。

心跳 + 无并发控制:所有 Agent 同时重启 → 所有心跳同时触发 → API 被 DDoS。

心跳 + 无 jitter:心跳间隔固定,全部 Agent 同时到期。

心跳 vs Dashboard:两个灾难,完美错位

心跳每 4 小时烧 20K tokens,但从不更新 agent.status

Dashboard 这边呢?每 15 秒自动刷新一次,一天 43,600 次 HTTP 请求。但它读的数据库字段,心跳从来没写过。

心跳:6 次/天 × 20K tokens = 120K tokens/天 → 不更新 status
Dashboard:2,880 次刷新/天 × 42 请求/次 = 43,600 请求/天 → 读到的是心跳从未更新过的数据

一个烧钱不产出,一个刷屏看不到真相。
两个都在拼命工作,方向完全错开。

4. 与 AI Coding 的关系

  1. == "qwen" 不可能是故意设计:这是最简实现——只为测试过的厂商开启缓存,其余"先不管"
  2. 心跳逻辑是逐任务叠加的:先写"每 4 小时触发",再写"判断状态",最后无人补并发控制
  3. AI 不会主动优化成本:心跳、缓存、并发——这些是跨任务的系统属性,AI 在每个任务里只看到局部需求

关键代码

文件 行号 内容
client.py 2599 supports_cache_control = normalized_provider == "qwen"
heartbeat.py 473 if state in ("idle", "running"):
heartbeat.py 512 create_task(...) 无并发控制
heartbeat.py 282 _build_heartbeat_instruction() → 组装心跳指令
heartbeat_runtime.py 81 enqueue_heartbeat_runtime() → 入队为 runtime run
worker_service.py 224 RuntimeModelStepService(prompt_builder=build_agent_context) → 默认用完整上下文构建器
model_step_service.py 1208 self._prompt_builder(...) → 调用 build_agent_context,组装 soul + memory + skills + enterprise_info + focus + triggers