先看出事的那一刻
2026 年 7 月 26 日,AI 导师第一次接上第三方的兼容模型。按最初的设计,护栏是"每次会话最多花 0.1 美元":SDK 每次调用之后都会报告用了多少 token、折合多少钱,超过就停。
测试用的是最简单的一句话:"回复一个字:好。"默认配置下,这一个字的回复被报成了两万一千多个输入 token、0.1085 美元,第一句话就超了预算。收窄配置之后再测两次,同样的配置、同样的问题,输入 token 一次报 1884,一次报 28。
这节课要回答的是:接上 AI 接口之后,怎么知道花了多少钱?接口自己报的用量能不能信?护栏应该建在哪里?
装备几个词
为什么要懂
AI 替你做了
SDK 每次调用都会报告 token 数和折算的费用,AI 很自然地拿它来做预算控制,代码也最好写。
留给你的
判断这些数字可不可信、是按谁的价格算的,并把护栏建在一个你自己数得清的地方。
不懂的代价
护栏建在不可信的数字上:可能第一句话就误触发,也可能该拦的时候没拦住,而且错的方向还不固定。
一个字,为什么是两万个 token
模型每次读到的,不只是你的那句话。默认配置下,系统提示词、所有可用工具的说明、之前的对话,都会一起发过去,全部算作输入 token。"回复一个字"这句话本身只有几个 token,陪它一起发过去的说明书却有两万多。
收窄工具之后,同一个问题只剩一千多个输入 token。代码里的注释据此写着"收窄工具是省 token 的关键(14 倍)":只是这个 14 倍,用的恰恰是那组不稳定的上报数字。
上报的数字,为什么不能直接当护栏
三个原因:
- 费用是 SDK 自己估的。它按自己的价格表换算成美元,并不知道第三方模型的真实价格。
- 兼容端点报的 token 数不稳定。同一套配置、同一句话,一次 1884,一次 28。
- 当时的测量本身也有漏洞。测试脚本只看了输入和输出两个字段,漏掉了缓存相关的计数;"不可信"这个结论里,也掺进了一部分自己的混淆。
于是护栏换成了一个自己数得清的东西:条数。每回答一次,在自己的数据库里记一行;每人每天 80 条、每分钟 6 条,超过就拒绝(第 14 课)。SDK 的预算上限还留着,但调高到 0.5 美元,只作为异常时的兜底。
还差一步:对账
条数只能告诉你"用了多少次",不能告诉你"花了多少钱"。真正的钱,要看模型平台后台的账单。
这个项目一直没有拿账单来对过账,而且想对也对不了:计数表只记了"谁、什么时候",没有记 token,也没有记费用;SDK 每次返回的用量被直接丢掉;计数记录只保留 7 天,想和一个月的账单对,当月的记录早就被清掉了。
一个可靠的成本护栏,至少要有三层:
| 层 | 做什么 | 以什么为准 |
|---|---|---|
| 拦 | 请求进来时,按条数和全站预算卡住 | 自己的数据库 |
| 记 | 每次调用之后,记下上报的 token 和费用 | 接口上报,只作参考 |
| 对 | 每月和平台账单核对一次,校准估算 | 平台账单 |
深潜证据也会丢+
那几组测量数字(两万一千多、1884、28),当时写进了架构文档。后来的一次文档重写,把这一节整个删掉了,没有存档;代码注释里还在引用"架构 §8.2",可这一节已经不存在了。
几个月后再想知道"当初为什么不信上报的用量",就只能去翻聊天记录。重要的测量结果和决定,要放在不会被顺手删掉的地方:单独的决策记录,或者提交说明里。
找茬
下面是 AI 导师里和成本有关的真实代码与注释(节选)。站长想要的是:知道每个月实际花了多少钱,护栏在花钱之前就能拦住。找出让成本看不清、对不上,或者依然依赖不可信数字的地方。
这段 JS / SQL 里埋了 5 处问题。点击你觉得有问题的行,至少找出 3 处再揭晓。
·第 3 行中危
说是“只作观测”,其实什么也没记
注释说上报的用量"只作观测",可下一行发出的"完成"事件里没有它,也没有写进任何地方。观测的数据,一条都没留下来。
该问的话:每次调用上报的 token 和费用,记在哪里了?
·第 7 行中危
计数表只记了“谁、什么时候”
表里只有用户和时间,没有 token、模型、费用,也没有这次调用是成功还是失败。拿它只能数次数,算不出钱。用户被删除时,他的用量记录还会一起被删掉。
该问的话:这张表能回答“这个月一共花了多少钱”吗?
·第 8 行低危
只留 7 天,对不了月账单
7 天够算每日上限,却不够和按月结算的账单核对:到月底想对账时,前三周的记录已经被清掉了。而且清理只在服务启动时跑一次,注释里的"定期"并不准确。
该问的话:想和上个月的账单对一对,自己手里还有上个月的记录吗?
·第 11 行低危
“14 倍”用的是不可信的数字
这个 14 倍,来自那组前后差几十倍的上报数据,而且测量时的配置和线上也不一样。它可以当作方向,不能当作结论。
该问的话:这个数字是怎么测出来的?和线上的配置一样吗?
·第 14 行低危
兜底仍然依赖不可信的估算
这个预算上限,判断依据还是 SDK 自己估的美元数。从 0.1 调到 0.5,只是让它不再误触发,并没有让它变得可靠。
该问的话:这个兜底上限,是按什么数字来判断的?它靠得住吗?
查看代码与答案(5 处问题)
1 // server/tutor/service.mjs(收到结果时,节选)
2 if (m.type === "result") {
3 // 端点的 usage/cost 不可信,只作观测不作决策(架构 §8.2)
4 yield { type: "done", usedToday: quota.usedToday, limit: quota.limit, durationMs: m.duration_ms ?? null, tools: … };
5
6 // server/db.mjs(计数表与清理,节选)
7 CREATE TABLE IF NOT EXISTS usage_log ( id BIGSERIAL PRIMARY KEY, user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, at TIMESTAMPTZ NOT NULL DEFAULT now() );
8 /** 定期清理,避免 usage_log 无限增长(只保留 7 天,够算日配额) */
9
10 // server/tutor/service.mjs(注释,节选)
11 /** 只声明真正会用到的内置工具。收窄 tools 是省 token 的关键(14 倍,架构 §8.1) */
12
13 // server/config.mjs(护栏配置,节选)
14 budgetUsdFallback: 0.5, // maxBudgetUsd:仅作异常兜底,非日常成本控制- 第 3 行 · 中危 · 说是“只作观测”,其实什么也没记:注释说上报的用量"只作观测",可下一行发出的"完成"事件里没有它,也没有写进任何地方。观测的数据,一条都没留下来。 该问的话:每次调用上报的 token 和费用,记在哪里了?
- 第 7 行 · 中危 · 计数表只记了“谁、什么时候”:表里只有用户和时间,没有 token、模型、费用,也没有这次调用是成功还是失败。拿它只能数次数,算不出钱。用户被删除时,他的用量记录还会一起被删掉。 该问的话:这张表能回答“这个月一共花了多少钱”吗?
- 第 8 行 · 低危 · 只留 7 天,对不了月账单:7 天够算每日上限,却不够和按月结算的账单核对:到月底想对账时,前三周的记录已经被清掉了。而且清理只在服务启动时跑一次,注释里的"定期"并不准确。 该问的话:想和上个月的账单对一对,自己手里还有上个月的记录吗?
- 第 11 行 · 低危 · “14 倍”用的是不可信的数字:这个 14 倍,来自那组前后差几十倍的上报数据,而且测量时的配置和线上也不一样。它可以当作方向,不能当作结论。 该问的话:这个数字是怎么测出来的?和线上的配置一样吗?
- 第 14 行 · 低危 · 兜底仍然依赖不可信的估算:这个预算上限,判断依据还是 SDK 自己估的美元数。从 0.1 调到 0.5,只是让它不再误触发,并没有让它变得可靠。 该问的话:这个兜底上限,是按什么数字来判断的?它靠得住吗?
快测
1. SDK 报告一次调用花了 0.1 美元,模型平台账单上的价格却低得多。以谁为准?
你可能是这么想的:SDK 的费用是按它自己的价格表估的,并不知道第三方模型的真实价格;兼容端点报的 token 数,本身也不稳定。
对了。钱是平台收的,以它的账单为准。
你可能是这么想的:条数只能告诉你用了多少次,不能告诉你花了多少钱:一条长回答和一条短回答算一样。
估算用来参考,账单用来定论。
查看选项与答案
- A. 以 SDK 的报告为准,费用是按实际用量算出来的——SDK 的费用是按它自己的价格表估的,并不知道第三方模型的真实价格;兼容端点报的 token 数,本身也不稳定。
- B. 以模型平台后台的账单为准,SDK 的估算只当作参考(正确)——钱是平台收的,以它的账单为准。
- C. 以自己数据库里的调用条数,乘上估算的单价为准——条数只能告诉你用了多少次,不能告诉你花了多少钱:一条长回答和一条短回答算一样。
估算用来参考,账单用来定论。
2. 为什么一句“回复一个字”,会用掉两万多个输入 token?
对了。默认配置下,系统提示词、所有可用工具的说明都会一起发过去,全部算作输入 token。收窄工具之后,同一个问题只剩一千多个输入 token。
你可能是这么想的:“回复一个字”这句话本身只有几个 token,再多几倍也差不出两万多;多出来的是陪它一起发过去的说明书。
你可能是这么想的:这是会话里的第一句话,还没有对话历史。两万多个 token 来自陪它一起发过去的系统提示词和工具说明。
计费看的是模型读到的全部内容。
查看选项与答案
- A. 系统提示词和工具说明也算输入,每次都一起发出(正确)——默认配置下,系统提示词、所有可用工具的说明都会一起发过去,全部算作输入 token。收窄工具之后,同一个问题只剩一千多个输入 token。
- B. 中文按字节拆成 token,同样的话比英文多出很多倍——“回复一个字”这句话本身只有几个 token,再多几倍也差不出两万多;多出来的是陪它一起发过去的说明书。
- C. 对话历史一路累积,前面每一轮都被重新算了一遍输入——这是会话里的第一句话,还没有对话历史。两万多个 token 来自陪它一起发过去的系统提示词和工具说明。
计费看的是模型读到的全部内容。
3. 付费 AI 功能的护栏,最可靠的做法是?
你可能是这么想的:提醒是事后的:它到的时候,钱已经花出去了,也说不清是谁花的。可以当补充,不能当护栏。
对了。拦截靠自己数得清的东西,钱以账单为准。
你可能是这么想的:上限调高,只是不再误触发,护栏依然建在不可信的数字上:可能在不该停的时候停,也可能在该停的时候不停。
拦、记、对,三层各管一段。
查看选项与答案
- A. 在模型平台后台设一个预算提醒,花到额度就通知自己——提醒是事后的:它到的时候,钱已经花出去了,也说不清是谁花的。可以当补充,不能当护栏。
- B. 在自己的数据库里按请求条数拦截,再定期和平台账单对账(正确)——拦截靠自己数得清的东西,钱以账单为准。
- C. 读取 SDK 上报的美元费用做预算,上限调高一点防误触发——上限调高,只是不再误触发,护栏依然建在不可信的数字上:可能在不该停的时候停,也可能在该停的时候不停。
拦、记、对,三层各管一段。
判断时刻
你发现兼容端点上报的 token 数前后差几十倍,按它做的“每次会话 0.1 美元”预算,第一句话就触发了。AI 给了三个方案。
你会选哪一个?
考察:调参数
误触发没了,但护栏依然建在不可信的数字上:可能在不该停的时候停,也可能在该停的时候不停。这次也把它调到了 0.5,只是同时把它降级成了异常兜底。
考察:数自己数得清的东西
条数不会乱跳,护栏稳定、可预期。代价是条数不等于钱:一条长回答和一条短回答算一样。这次最后选的就是这条。
考察:对账
最完整:条数负责拦,记录负责查,账单负责定。多出来的只是一张记录表和每月一次核对,而这个项目恰恰一直没有做这一步。
护栏要建在你自己数得清的东西上,钱要以平台账单为准。接口上报的用量,只配当参考。
三个选项各自的代价
- A. 把预算上限调高到 0.5 美元,继续用上报的数字——考察调参数:误触发没了,但护栏依然建在不可信的数字上:可能在不该停的时候停,也可能在该停的时候不停。这次也把它调到了 0.5,只是同时把它降级成了异常兜底。
- B. 改成在自己的数据库里数条数:每人每天、每分钟各一个上限——考察数自己数得清的东西:条数不会乱跳,护栏稳定、可预期。代价是条数不等于钱:一条长回答和一条短回答算一样。这次最后选的就是这条。
- C. 在上一个方案的基础上,每次调用记下上报的用量,每月和平台账单对一次——考察对账:最完整:条数负责拦,记录负责查,账单负责定。多出来的只是一张记录表和每月一次核对,而这个项目恰恰一直没有做这一步。
护栏要建在你自己数得清的东西上,钱要以平台账单为准。接口上报的用量,只配当参考。
带走
下次让 AI 做这件事时,问它
- 这个 AI 功能每次调用大约用掉多少输入和输出 token?其中系统提示词和工具说明占多少?
- 接口上报的用量和费用,是按谁的价格算的?和平台账单对过吗?
- 护栏是按什么计数的?计数记在哪里、保留多久?
- 每次调用的用量有没有记下来?能不能每月和平台账单对一次?
自己验证
- 同一个请求连发几次,比较上报的 token 数稳不稳定。
- 到模型平台的后台,把一天的账单金额和自己数据库里的调用次数放在一起看。
- 看一眼计数表的结构:除了“谁、什么时候”,还记了什么?
护栏数自己数得清的东西,钱以账单为准;上报的用量,只配当参考。
