
1. 第 6 节事故5 小时烧掉 16.7 亿 token账单却隔天才到GitHub issue #4095 里Claude Code 在 5 小时内烧掉 1,673,680,266 个 token。把 TaoTokenhttps://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 放在这组数字旁边失控的原因立刻变得具体这个会话之所以隔天才被发现是因为整个链路里没有会话级用量账本。把 Base URL 接入 TaoToken 之后每次调用的 session_id、token 数、请求时间都会落在记录里按会话聚合 sum(tokens) 变成一件十分钟就能完成的事。原文第六节正是用这个例子说明Agent 停不下来的代价不是模型能力问题而是观测层缺失。原文第六节把这类事故单独拎出来讲不是为猎奇而是因为它和前面那些删库事故共享同一个盲区当 Agent 从“生成代码”变成“自主跑循环”成本和风险都进入了一个人类反应速度够不到的地带。4095 的细节是四个 bug 叠加计划循环递归、缓存爆炸、hook 递归、API 错误时的重试风暴。四个机制单独出现时最多让某个任务变慢或卡住同时出现在同一个会话里循环就再也找不到出口。整个过程产生了 253 个 usage limit 错误但没有一个变成停止指令。用户还在等 Claude 回复IDE 还在转圈计费器还在累加。直到账单落到 1.6 万到 5 万美元区间才有人意识到要回去翻日志。1.1 日账单粒度把失控会话“平均”掉了日账单是一个每天滚动归零的计数器。某个会话在深夜烧掉 8 亿 token账单页能给出的信息只有“今天用量异常偏高”至于哪台机器、哪个项目、哪个 session全都不在账单维度里。Agent 的成本结构又让这个盲区变得格外危险它不是聊天机器人那种一进一出即可结束的交互而是每一步都要携带完整历史上下文的循环。一个跑 47 次的失控循环成本可以到 980 万 token是普通调用的上万倍只要循环不退出成本曲线就按 O(n²) 把上下文越撑越大。这种增长方式下晚发现 10 分钟和晚发现 2 小时账单的差别是数量级的。1.2 四个 bug 各自为战乘在一起才是灾难计划循环递归让 Agent 不断推翻旧计划重新规划缓存爆炸把早已失效的中间状态反复灌回上下文hook 递归在每次输出之后催生下一轮输出重试风暴则在 API 报错时把同一个请求原样重放。这四个机制都在消耗 token又都能绕过常规的单点上限限流被重试逻辑重置token 上限被重复计费冲掉熔断器没有按会话维度设置于是 253 个 usage limit 错误一路上涨循环本身却像什么都没发生一样继续跑。这个案例把一个问题摆到台面上成本控制不能交给模型自觉也不能只靠日快照必须有一层独立于模型决策、按会话记录的观测点。2. 接入 TaoToken 后失控会话第一次有了会话级账本TaoToken 的定位是统一 API 兼容通道。Claude Code 不需要换工具也不需要改项目结构唯一变的是 base URL从官方地址换成 https://taotoken.net/api 之后请求照常到达模型响应照常回到对话窗口但每一笔调用都会在 TaoToken 这边留下会话级记录。这层记录正是 16.7 亿事故里最缺的东西——它不依赖模型“记住自己的用量”也不依赖运维事后翻 log而是从网关这一侧把每次请求的 session_id、token 数和时间戳保存下来。需要说明的是控制台的注册、Key 管理和用量查询都走官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 而填进 Claude Code 的接口地址只有一个https://taotoken.net/api末尾不带 /v1。2.1 session_id 成为成本的第一聚合维度拿到调用记录之后第一件值得做的事就是按 session_id 聚合 token 消耗。会话 ID 是 Claude Code 每次启动对话时生成的标识一个会话内所有子请求都挂在同一个 ID 下正好用来分析“单会话燃烧率”。把 TaoToken 导出的调用日志导入数据分析环境后一次简单的聚合查询就能回答“哪个会话今天吃掉了 90% 的用量”select session_id, date_trunc(minute, request_time) as bucket, sum(input_tokens output_tokens) as total_tokens, count(*) as request_count from taotoken_call_logs group by session_id, date_trunc(minute, request_time) order by total_tokens desc limit 20;这份结果的价值在于它把“日账单一个总数”拆成了一个个可以单独定位的会话。排在最上面的 session就是需要被暂停和检查的对象。如果你现在想的是“先让它跑完再对账”4095 已经演示过那样做的后果。2.2 5 分钟窗口告警在坏循环加速前提早亮灯total_tokens 只能回答“已经烧了多少”要阻止 16.7 亿重演还得回答“正在以什么速度烧”。把聚合窗口缩小到 5 分钟整个画面会清晰许多一个正常开发会话在 5 分钟内最多消耗几十万 token而一个失控递归很容易在单个时间窗里冲上几百万。按 session_id 加 5 分钟窗口做滑动统计超过阈值就告警并暂停会话整条链路就不再依赖“有人碰巧打开账单”这个运气因素。4095 案例如果早有这样的监控第一个小时内就能看到那个异常膨胀的窗口后面四个半小时的燃烧完全可以避免。3. 落地在 ~/.claude/settings.json 里把 Claude Code 指向 TaoToken配置过程没有魔法就是两件事先到 TaoToken 官网创建一份 API Key再让 Claude Code 的模型请求改走 https://taotoken.net/api。前者让你获得统一入口的凭证后者让所有会话的请求都经过计数和记录。这个过程中最容易犯的错误是把官网链接和接口地址混为一谈注册、创建 Key、看模型广场和用量记录全部在官网落地页 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 完成而 settings.json 里填的 base URL 只认 https://taotoken.net/api 。两者功能不同地址也不同下文拆开讲。3.1 先到官网创建 API Key打开 TaoToken 注册账号进入控制台创建一个 API Key。创建完成后复制那串 Key后续文章里统一用 YOUR_API_KEY 占位。Key 的权限范围决定你能调用哪些模型、能看到哪些调用记录如果之后发现某个模型报权限错误回到这个页面检查 Key 是否有对应模型的访问权。官网页面不承担模型请求转发只负责账号、Key 和用量数据的展示真正让请求走通的是下一小节里那个接口地址。3.2 修改 settings.json 的 env 块Claude Code 的配置入口是 ~/.claude/settings.json。如果文件不存在手动创建一个即可。在 env 块里放入三组配置分别指定接口地址、认证 Token 和模型 ID{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: YOUR_API_KEY, ANTHROPIC_MODEL: YOUR_MODEL_ID } }其中 ANTHROPIC_BASE_URL 是固定的末尾没有 /v1ANTHROPIC_AUTH_TOKEN 是 3.1 节复制的 KeyANTHROPIC_MODEL 里的 YOUR_MODEL_ID 需要替换成模型广场里实际存在的模型 ID——直接去 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 的模型广场复制不要凭记忆填。注意如果 ~/.zshrc 或 ~/.bashrc 里已经配置过 ANTHROPIC_BASE_URL它会和 settings.json 的 env 产生冲突。建议只保留一份配置避免请求发到两套地址导致时好时坏。3.3 用一次最小调用验证通道保存配置后在任意项目目录运行一句 claude 命令例如让 Claude 回答“当前配置是否生效”。等它输出完成回到 TaoToken 控制台打开调用记录页面找到刚才这次请求。如果记录里能看到对应的 session_id、token 数和模型名说明通道已经通了Claude Code 能正常调用模型也能拿到会话级用量数据。这个验证动作是整个改造的验收标准建议不要跳过因为后面所有监控和告警都建立在“数据已经在被记录”这个前提下。4. 把熔断线设在 1000 万 token而不是 16.7 亿原文第七节列出的四层防线里和 4095 最直接相关的是第三层Agent 预算与熔断。作者给出的诊断指标很明确按 sum(tokens) by (session_id) 聚合配 5 分钟窗口告警单会话跨过 1000 万 output tokens 几乎可以确定是病态的。这个阈值不需要等模型更新也不依赖模型自带什么护栏纯粹是基础设施层的配置。TaoToken 恰好把做这件事需要的原始数据给齐了会话 ID、每次请求的 token 数、请求时间戳。下面两段分别对应“事后定位”和“事前熔断”两种用法。4.1 识别病态会话的第二种查询第一种查询按天聚合找总量大头适合做日报第二种查询换到分钟级窗口专门找“短时间内 token 消耗陡增”的会话适合做实时告警。逻辑和 2.1 的 SQL 类似只是多了分钟分组和阈值过滤select session_id, date_trunc(minute, request_time) as bucket, sum(input_tokens output_tokens) as window_tokens, count(*) as request_count from taotoken_call_logs group by session_id, date_trunc(minute, request_time) having sum(input_tokens output_tokens) 10000000;这个查询返回的每一行都代表一个在单分钟内消耗超过 1000 万 token 的会话。正常开发会话几乎不可能触线能触到的基本可以判断为失控循环。如果你不想自己维护监控也可以直接用控制台自带的记录筛选和导出功能先把异常会话抓到再说。4.2 失败率超过 50% 时要能停得住4095 事故里最让人后背发凉的数字是 253 个 usage limit 错误系统其实一直在发出“用量超限”的信号但这些信号被重试逻辑吞掉没有形成任何负反馈。高失败率本身也是一个独立信号。如果某个会话最近 5 分钟的请求失败率超过 50%它大概率在同一个错误上反复打转。把失败率规则和上面的 token 阈值规则叠加起来就是两条完整的熔断指标一条管“烧得多快”一条管“错得多密”。它们从不同角度描述同一个病态会话两条同时触发时暂停当前会话是成本最低的处理方式。5. 接入过程容易踩的两个小坑/v1 和模型 ID配置本身不复杂实际接入时有两个很容易被忽略的细节都是“少看一步文档”导致的。记录在这里给后面接的人省点时间。5.1 Base URL 末尾多了 /v1习惯 OpenAI 系地址的开发者容易顺手把 base URL 写成 https://taotoken.net/api/v1 。这样请求会落到一个不存在的路径上返回 404。TaoToken 的接口路径就是 https://taotoken.net/api 末尾没有 /v1。遇到 404 时第一个检查点就是这里别去怀疑 Key 或模型配置。这个问题排查起来很快但第一次遇到时确实会让人愣一下因为报错信息不会直接告诉你“路径少了”。5.2 模型 ID 凭记忆填没去模型广场核对另一个容易卡住的位置是 ANTHROPIC_MODEL。填一个不存在的模型名时报错提示通常是模型不存在或 model not found而且不会自动回退到某个默认模型。处理方式很直接打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 的模型广场从列表里找到当前可用的模型 ID复制到 settings.json 里不要凭记忆输入。这条对同时维护多套 API 环境的人尤其重要不同通道的模型命名不保证一致复制粘贴永远比手敲可靠。6. 在 16.7 亿 token 事故之后给生产环境补一层会话级账单原文最后给出的行动清单是最小权限、破坏性操作确认门禁、per-session 预算、备份隔离。放在生产环境里前两层能防住“删库”这类高破坏力事故per-session 预算防的是静默失血。删库事故有震感几万美元的账单也很有震感但真正扩大损失的是“从异常发生到被发现”这段间隔。会话级用量记录把这段间隔从数小时压缩到数分钟而且实现成本极低不改代码不改模型只改一个 base URL再加一组聚合查询。6.1 把防护从“告诉模型别跑偏”改成“网关设阈值”系统提示在模型眼里永远是建议不是约束。PocketOS 的 Agent 能逐条写下自己违反了哪条规则说明“告诉它不要做”不可靠同样“告诉它省着点用”也不如一个 gateway 侧的数字硬上限。接入 TaoToken 后写进监控里的阈值规则本质上是把安全从 prompt 层挪到了基础设施层模型再怎么递归、缓存再怎么爆sum(tokens) 一旦超过阈值熔断信号会从网关发出来而不是等模型自己想明白。6.2 现在去官网建 Key跑一次最小调用如果你正在生产环境里使用 AI Agent今天就可以做的一件事是打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 注册并创建一个 API Key按第 3 节把 settings.json 配好跑一次最小调用再回到控制台看这次调用是否已经落在调用日志里。看到“一条记录出现在列表里”的那一刻用量控制就不再依赖信任而是依赖账本。16.7 亿 token 的事故留下的教训不是“AI 会失控”而是失控必然发生问题只在于它需要多久被发现。会话级账单让这个时间缩短到可以被人类干预的范围内。这个账本现在可以自己搭了。