第 6 章 · 第 46 讲 · 16:20
很多 AI 产品的成本失控,都不是发生在模型选型那一刻,而是发生在日复一日的调用里:
单次看都是零头,乘上百万次调用就是一整块预算。
降本这件事,一半是工程决策,另一半是产品决策。分辨率给多少、任务拆几步、失败要不要重试——这些决定只有产品能做。
本集边界:不讨论怎么跟供应商谈价,也不讨论该选哪个模型。只盯一件事——同样的模型、同样的任务,为什么你的账单比别人厚。
| 层级 | 能力 | 具体表现 | 验证方式 |
|---|---|---|---|
| L1 图片计费 | 算得清图像 Token | 知道按缩放对齐后的分辨率计费 | 手算 1000×1000 与 1025×1025 的差 |
| L2 分辨率分级 | 按任务匹配分辨率 | 四类任务对应四档预算 | 能说出每档的 Token 上限与理由 |
| L3 输入主导 | 理解 Agent 计费结构 | 知道 Input 累积膨胀是平方级 | 算出 5 轮任务的总 Input |
| L4 陷阱治理 | 四陷阱各配一道闸 | 截断 / 分级 / 熔断 / 压缩 | 能给现有 Agent 补齐四项 |
| L5 语法优化 | 消除词法税 | 装饰性 Token 压到 10% 以下 | 用分析工具量一遍前后对比 |
依赖是单向的:L1 算不清图片账单,L2 的分级就没有依据;不懂 L3 的输入主导,L4 的熔断阈值就是拍脑袋定的;L5 是独立项,但见效最快、风险最低。
真正要管的数是:单次成本 × 失败率 × 调用量。0.02 元的任务,乘上失败重试,再乘上百万次调用,就是账单窒息现场。
文字 BPE 是「合并字符」,图片编码是「切割像素」。
视觉模型把图片切成固定大小的像素块,每块对应一个 Token。以通义千问 VL 为例:
图像 Token = (h̄ × w̄) / token_pixels + 2
| 变量 | 含义 | 说明 |
|---|---|---|
h̄ / w̄ | 缩放后的高与宽 | 会被强制对齐到 32(或 28)的整数倍 |
token_pixels | 每个 Token 对应的像素数 | Qwen3-VL 是 32×32 = 1,024;QVQ / Qwen2.5-VL 是 28×28 = 784 |
+2 | 固定开销 | 视觉起止标记 |
不同厂商的路线:GPT-4o 和 Gemini 用图块(Tile)机制——GPT-4o 每个 512×512 图块约 170 Token,Gemini 1.5 Pro 每个 768×768 图块约 258 Token。
类比:文字的词表大小决定压缩率,图片的像素块大小决定压缩率。32×32 比 28×28 更省。
| 输入尺寸 | 对齐后 | Token 变化 |
|---|---|---|
| 1000 × 1000 | 1000 × 1000 | 基准 |
| 1025 × 1025(只大 2.5%) | 1056 × 1056 | Token 跳 6.5% |
跨过 1024 这个 32 的整数倍边界,成本断崖式上跳——和文字「33k 全量结算」是同一个逻辑。
传 4K 图是不是比 1080p 效果更好?不一定,而且大概率不值。
| 分辨率 | 缩放后(32 对齐) | Token 数 | 相对成本 |
|---|---|---|---|
| 512 × 512 | 512 × 512 | 258 | 1x |
| 1080p (1920×1080) | 1920 × 1088 | 2,042 | 7.9x |
| 2K (2560×1440) | 2560 × 1440 | 3,602 | 14x |
| 4K (3840×2160) | 3840 × 2176 | 8,162 | 31.6x |
| 8K (7680×4320) | 触发缩放上限 | ~16,384 | 63.5x |
研究表明 VLM 的视觉 Token 冗余高达 85%。
多图场景更危险:5 张 4K 图 ≈ 40,000 Token,直接把整单从标准档踢进高价档。
| 任务类型 | Token 预算 | 对应分辨率 | 理由 |
|---|---|---|---|
| 粗粒度分类(猫还是狗) | < 300 | 512 × 512 | 不需要细节 |
| 场景理解(图里在干什么) | < 1,000 | ~1000 × 1000 | 够用 |
| OCR / 图表分析 | < 4,000 | ~2000 × 2000 | 需要识别文字 |
| 高精度检测(医疗影像) | < 16,384 | 4K+ | 按需开启 vl_high_resolution_images |
前端预压缩不只是省 Token,它同时省了上传带宽和用户等待时间——同一件事三个角色都受益,这种改动最该优先做。
普通 Chatbot 是一问一答;Agent 是「思考 → 行动 → 观察 → 再思考」的循环。
关键认知:每一轮的 Input 都包含了全部历史信息——System Prompt、工具返回、历史输出,全都要在每一轮里重新读一遍。
| 场景 | 总 Input | 总 Output | I/O Ratio | 主导方 |
|---|---|---|---|---|
| Chatbot 讲笑话 | 10 | 150 | ≈ 1:15 | 输出主导 |
| Agent 代码修复(3 轮) | 16,790 | 270 | 62:1 | 输入主导 |
为了得到 270 个字的结果,你付了 16,790 个字的「阅读费」。
任务:「帮我分析这个 Excel 表格,找出销售额最高的产品,然后生成一个图表。」——5 轮执行,累计 Input 31,460、Output 450。
注意:这只是一次成功的执行。隐形成本还有失败重试、调试、迭代。
假设任务要 N 轮完成,System Prompt 长度 S,每轮新增(输出 + 工具返回)约 Δ:
第 N 轮 Input ≈ S + Q + Δ × (N - 1)
总 Input = 所有轮次累加 → 藏着 1 + 2 + 3 + … + (N-1) 的等差数列
每轮新增 500 Token,5 轮循环的总 Input 就有 15,000+。轮次翻倍,成本接近翻两番。
| Agent 框架 | 平均 I/O Ratio | 说明 |
|---|---|---|
| 简单 RAG Agent | 10:1 ~ 20:1 | 检索 + 回答 |
| OpenHands | 20:1 ~ 50:1 | 代码修复任务 |
| AutoGPT 类 | 30:1 ~ 100:1 | 开放式任务,循环多 |
> 50:1 说明 Agent 在「空转」——先优化流程或降级任务,而不是先换更便宜的模型。
这也解释了为什么 KV Cache 对 Agent 是决定性的:既然每轮都要重读同样的前缀,能不能命中缓存,就是 5 倍的价差。
用户说「帮我查一下数据库里所有用户的订单」→ Agent 调 SQL 工具返回 10,000 条记录 ≈ 500,000 Token。
这 50 万 Token 会被塞进下一轮 Input:触发高价区、甚至撑爆上下文窗口,模型还会因信息过载而「迷失」,输出质量反而下降。
解法:给所有工具套一层截断保护(上限 2,000 Token)。
def safe_tool_call(tool_func, *args, max_tokens=2000, **kwargs):
result = tool_func(*args, **kwargs)
result_str = json.dumps(result, ensure_ascii=False)
estimated = len(result_str) * 0.5 # 粗略估算 Token
if estimated > max_tokens:
# 保留前后各一段 + 中间标记,提示模型缩小范围
truncated = result_str[:1000] + "\n...[已截断]...\n" + result_str[-500:]
return {
"status": "truncated",
"preview": truncated,
"total_records": len(result),
"message": f"返回结果过长(约{int(estimated)} Tokens),已截断。如需完整数据,请缩小查询范围。"
}
return result
为什么保留前后各一段:前一段让模型知道数据结构长什么样(字段名有哪些),后一段让它知道最新的几条是什么,中间截掉的真需要了再要一次。
Qwen-Plus 思考模式、DeepSeek-R1、o1 这类模型会生成「思考过程」——用户可能看不到,但全部按 Output 计费,而且单价还翻 4 倍。
同一个 Agent 任务开启思考模式后:可见输出不变(450 Token),思考过程 +2,000 Token,输出费用暴涨 +2,078%。
| 任务类型 | 思考模式 | 理由 |
|---|---|---|
| 简单检索 | ❌ 关闭 | 不需要深度推理 |
| 数据清洗 | ❌ 关闭 | 规则明确,不需要「想」 |
| 复杂推理 | ✅ 开启 | 值得为准确率付费 |
| 代码生成 | ⚠️ 视情况 | 简单函数关闭,复杂架构开启 |
进阶解法:用 0.6B 级的极小模型做前置分诊,先花几厘钱判断这个请求需不需要深度思考,再决定路由到哪个模式。
Agent 修 Bug:修复 A → 报错 B → 修复 B → 报错 A(回到原点)→ …… 15 轮还在转。
每轮 Input 膨胀 1,000 Token,20 轮下来成本涨 13 倍;更糟的是用户等了 5 分钟任务还没完成。
| 方案 | 第 10 轮 Input | 说明 |
|---|---|---|
| 无限膨胀(标准错误做法) | ~50,000 | 包含全部历史 |
| 滑动窗口(最近 5 轮) | ~12,000 | 丢失早期上下文 |
| 固定 + 摘要 + 最近 3 轮 | ~6,000 | 既保关键信息,又控制长度 |
原则:System Prompt 永不压缩(保缓存前缀),最近 3 轮保留完整细节,更早的历史用小模型压成一句摘要。
死循环既是成本问题,更是体验问题。解法是强制熔断,三个条件任一命中就优雅退出:
class AgentExecutor:
def __init__(self, max_rounds=10, max_tokens=50000):
...
def execute(self, task):
while not task.is_complete():
self.round_count += 1
# 熔断 1:轮次上限
if self.round_count > self.max_rounds:
return self._graceful_exit("已达到最大执行轮次")
# 熔断 2:Token 预算
if self.total_input_tokens > self.max_tokens:
return self._graceful_exit("已达到 Token 预算上限")
# 熔断 3:死循环检测(连续 3 轮输出相似度 > 90%)
if self._detect_loop():
return self._graceful_exit("检测到可能的死循环")
result = self._run_one_round(task)
self.total_input_tokens += result.input_tokens
优雅退出要带上:rounds_executed、tokens_consumed 和 partial_result——半成品也比黑洞强。用户至少知道跑到哪一步了、拿到了什么,而不是盯着一个转圈的图标。
| 控制点 | 策略 | 预期收益 |
|---|---|---|
| 工具返回值 | 截断 + 摘要,上限 2k Tokens | 防止单轮爆炸 |
| 历史管理 | 固定左侧 + 压缩旧历史 | 降低 50%+ Input |
| 循环控制 | 熔断机制(轮次 / Token / 死循环检测) | 防止无底洞 |
| 思考模式 | 按任务分级开启 | Output 成本降 4 倍 |
| 模型选择 | 简单子任务用小模型 | 降低单价 |
| 缓存利用 | 固定 System Prompt,命中 KV Cache | Input 成本降 90% |
| 红线 | 阈值建议 | 后果 | 应对 |
|---|---|---|---|
| 单轮 Input | < 32k Tokens | 跳入高价区 | 历史压缩 + 工具截断 |
| 总轮次 | < 10 轮 | 成本指数膨胀 | 熔断机制 |
| I/O Ratio | 监控 > 50:1 | Agent 在「空转」 | 优化流程或降级任务 |
成本事故有个特点:它不是某一天突然爆的,是每天多一点点。等财务月底来对账时,已经晚了三周。
很多产品早期为了调试方便(或者干脆让 AI 代写 Prompt),习惯用 ###、、JSON 展示数据。这些对人类友好的排版,在模型的计费逻辑里全是词法税**。
实测:一段精简版 Lyra 提示词,光是加粗用的 就吃掉 8.5% 的 Token;算上列表、标题符号、JSON 缩进换行,13% 都是格式性内容**。
千万级调用量下,每月 10%–20% 的预算花在「让产品经理看起来舒服一点」上。
结论:Prompt 是写给机器的指令,最终版本不需要美观。机器关注的是逻辑,而不是排版。
① 复杂对象用 YAML(或 TOON),别用 JSON
JSON 的信噪比太低:每个 Key 双引号包裹、每层嵌套花括号闭合,而这些符号往往独立计费。YAML 用缩进代替闭合符号、冒号代替「引号 + 冒号」,Token 通常省 10%–15%,多的能到 40%。
TOON 是专为省 Token 设计的新格式,但作为新格式 LLM 不一定支持得好——更稳的组合是 YAML + CSV。
② 扁平列表用 CSV,别用 JSON 数组
带表头的表格把重复键名全干掉,长列表场景砍 30%–60%,同样的上下文窗口还能塞更多数据。字段名重复 50 遍的 JSON 数组,是 RAG 场景的重灾区。
③ 后台输出强制 Minified JSON
输出端的 Token 比输入端更贵,还直接影响接口返回速度。在系统提示词里显式约束:
输出必须是 Minified JSON,不换行、不缩进、不加代码块标记。
示例:{"id":1,"status":"ok"}
机器读数据不需要美观,只需要合法。批量任务加上这条约束后,生成耗时显著下降。
自查方法:把提示词丢进词元可视化分析工具(课程推荐 yusuan.ai/analyzer),看一眼装饰性 Token 的占比。
超过 10%,就说明有一笔最容易拿的钱还没拿。改起来很轻——把星号和井号删掉、把多余换行缩进压掉,逻辑一分不动,账单立刻变脸。
约束一:分级不是越省越好。 把 OCR 任务的图压到 512 见方,成本省了,识别率垮了,返工成本更高。分级的前提是先测出每类任务的精度拐点。
约束二:截断会丢信息。 工具截断保护适合「列表型」返回;如果工具返回的是一整份必须完整的文档(如合同全文),截断会直接破坏任务。此类工具应改用「摘要 + 按需拉取」。
约束三:熔断阈值要跟任务类型挂钩。 十轮对客服问答绰绰有余,对复杂代码重构可能不够。一刀切的轮次上限会造成大量「本可以完成却被掐断」的任务。
约束四:思考模式的开关边界会漂移。 同一个任务在模型升级后可能从「需要思考」变成「不需要」。分级表要定期复测,不能一次定终身。
约束五:YAML/CSV 的可读性代价。 省 Token 的格式对人更难读。建议只在机器到机器的链路用,人需要审阅的部分保留可读格式。
约束六:新格式有兼容风险。 TOON 这类新格式省得多,但模型不一定支持得好。生产环境优先选模型训练语料里常见的格式。
约束七:红色数字来自特定厂商和时点。 token_pixels、图块大小、单价都会随模型版本变化。本集的数字用于建立直觉,落地前请以当前官方文档为准。
成本不是财务月底给的那个数字,是你在需求评审时一个个决定累加出来的。
来源:xueai.miyang.cn(小山学堂 · 洛小山)
本页内容改编自小山学堂《学 AI 产品,从入门到精通》,为二次演绎配音版。整理自作者团队内部分享《AI Token 降本增效策略分享》;官方计费规则见阿里云百炼视觉理解文档;「分辨率诅咒」学术来源见 CARES 论文。