洛小山 13小时前
你每月烧掉的 Token 费用,至少 20% 都是冤枉钱
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_keji1.html

 

Hi,早上好。

我是洛小山,和你聊聊 AI 应用的降本增效。

Ps. 本文涉及技术细节,适合 AI 应用产研阅读。

在 AI 产品从 Demo 走向商业化的过程中,每一位产品负责人都会经历大模型成本焦虑。

不知道你有没有这种感受?

我们总想为用户提供更好的 AI 服务,但在商业化层面,是和用户在对赌。

因为产品用得越好,用户用得越多,利润反而越薄。

看到消费账单的时候,不知道会不会窒息…

这么高额的 Token 费用,想优化提示词,但不知道还有哪些地方还能抠一点。

这篇文章是我对大模型成本管理的方法论,全是干货,欢迎看到最后。

这个方法论主要回答四个问题。

语法层:提示词里能压缩多少成本?

语义层:上下文有哪些优化空间?

架构层:KV Cache 藏着哪些坑?

输出层:输出长度有哪些优化点?

01|语法层:要面向机器写提示词

很多产品早期为了调试方便,或者单纯让自己看着舒服,亦或者我们找了 AI 帮忙,生成提示词。

AI 习惯用 ###、** 加粗重点,用 JSON 来展示数据结构。

虽然这样的形式对人类很友好。

但在大模型的计费逻辑里,这些都是词法税。

这么说你可能没啥感觉,我给你举个例子。

为了搞清楚这笔税有多重,我做了个 Token 可视化分析工具。

网址:yusuan.ai/analyzer

也可以后台发送【预算】,获得网站与功能说明。

我把一小段提示词丢进去分析,结果是这样的…

我们付给模型厂商的每一分钱,买的应该是智能服务。

至于那些空格、回车、用来加粗的星号…

这些东西能省则省吧。就不应该花这些钱,对吧。

我下面这个提示词,是精简的 Lyra 提示词(翻译版)

光是加粗用的 ** 符号,就吃掉了 8.5% 的 Token。

吓人吗?这还只是加粗。

算上列表、标题等符号、以及 JSON 格式化带来的缩进换行…

这份提示词13% 都是格式性的提示词。

最终,我们的 Prompt 里可能有 10%-20% 都是这种装饰性的 Token。

你看,如果是千万级调用量下,每个月 20% 的预算,就这么花在让产品经理看起来容易一点上了。

所以这是我的第一个经验:

Prompt 是写给机器的指令,最终版本不需要美观,** 等格式只需用在需要强调的地方。

毕竟机器关注的是逻辑,而不是排版。

但除了砍装饰,结构化数据也得清理。

我总结了三条经验:

1、复杂对象用 YAML 或者 TOON,别用 JSON

很多人习惯在 Prompt 里直接贴 JSON 格式的配置。

问题是 JSON 的信噪比太低,因为每个 Key 都要双引号包裹,每层嵌套都要花括号闭合。

而这些符号往往都是独立计费的。

你可以考虑换成 YAML,或者 TOON 试试。

官网地址:yaml.org

YAML 用缩进代替闭合符号,用冒号代替"引号+冒号",不仅更符合自然语言阅读习惯,Token 消耗通常能省 10%-15%以上,多的能到 40%。

2、扁平列表用 CSV ,别用 JSON 数组

这是 RAG 场景的重灾区。

假设你从数据库捞了 50 条用户记录喂给模型,用 JSON 是这样的:

[

{"id":1,"name":"Alice","role":"Admin"},

{"id":2,"name":"Bob","role":"User"},

...

]

发现问题没?

id、name、role 这些字段名重复写了 50 遍!

这里就建议考虑换成带表头的格式:

id name role

1 Alice Admin

2 Bob User

一下子把重复的键名全干掉了。

长列表场景能砍 30%-60% 的 Token,而且同样的 Context 窗口能放更多的数据。

TOON(Token-Oriented Object Notation)语法是专门为这个场景设计的格式,感兴趣可以搜一下。

https://github.com/toon-format/toon

不过我还是更推荐使用 YAML + CSV 的原因,是因为 TOON 作为新定义出来的格式,LLM 不一定支持得很好。

3、后台输出强制用压缩 JSON

上面是基于输入的优化,但输出端的 Token 比输入端更贵,而且直接影响接口返回效率。

如果你是面向用户的流式输出,为了首字速度,格式宽松点可以接受。

但纯后台任务(提取标签、情感分析、数据清洗),其实是不需要任何排版的。

我的做法是在 System Prompt 里显式约束:输出必须是 Minified JSON,就是{"id":1,"status":"ok"}这种,不换行不缩进。

因为机器读数据不需要美观,只需要合法。

显示添加这样的约束之后,在批量处理的任务下面,能显著降低生成的耗时。

好,最后总结一下。

除了通过去掉排版用的 markdown 符号以外,不同的场景建议选择合适的数据结构,以尽量节省 Token 开销。

02|语义层:优化召回效率

格式层的问题解决之后,我们再深入到上下文场景。

RAG 和长文档场景里,我见过最常见的工程错误:把上下文窗口当垃圾桶。

一堆 Few-Shot 案例、还有检索出来的 n 篇文档等等,全怼到上下文里,让模型自己辨识。

确实能用,但不该这样用。

因为这样做有两个问题:

第一,贵而且慢。

Transformer 的自注意力机制,计算复杂度是 O(N²)。

说人话就是:你的提示词长度翻倍,那么计算量翻四倍。

提示词越长,模型预处理的阶段耗时越久,首个 Token 延迟就越高。

当用户还没看到第一个字,耐心可能已经消磨没了。

第二,效果可能更差。

有效信息被废话淹没后,会产生中段迷失效应。

说白了就是:模型对 Prompt 中间部分的注意力最弱。

你可以把大模型的注意力想象成一个人在读长文章。

开头会认真看,因为要搞清楚「这是在讲什么」;结尾也会留意,因为知道「快结束了,该出结论了」。

但中间那一大坨?眼睛扫过去,脑子没过去。

大模型也是一样的。

Prompt 塞得越长,中间塞的信息越容易被「注意力稀释」。

你精心挑选的参考资料,如果不幸落在中段,模型可能根本没认真看。

所以,上下文不是越多越好。

关键信息要么放开头要么放结尾。

中间的位置,留给「丢了也不心疼」的内容。

参考 Claude 之前的研究,模型对 Prompt 中间部分的注意力最弱。

内容塞得越多,反而越抓不住重点。

有兴趣的可以看看这篇关于上下文腐烂的博客。

https://research.trychroma.com/context-rot

对此,我的解法是双重蒸馏。

策略一:动态 Few-Shot,别硬编码

拿 Text-to-SQL 举例。

之前看到一个朋友写 SQL 的脚本,为了覆盖他们各种业务场景,很多人会在 Prompt 里写死 20 个 SQL 案例,加起来 4,000 多 Token。

然后每次用户提问,模型都要先复习一遍这 4,000 字,既烧 Token 又慢。

要不我们换个思路:

1. 把 20 个案例存进向量数据库

2. 用户问"上个月销售额"时,提前用语义检索,只捞 Top-3 个财务相关的案例

3. 最终 Prompt 从 4,000 Token 砍到 500

实测效果:Token 成本降 87.5%,响应速度快 3 倍以上。

而且因为去掉了无关案例的干扰,SQL 生成准确率反而更高了。

策略二:长文档先压缩再喂

金融研报、会议纪要这类文档,充满正确的废话:免责声明、重复的背景介绍、口语化的垫话。

直接喂给 AI,等于花大成本请博士生帮你读垃圾邮件。

建议考虑在 RAG 检索后、送去推理之前,插一层 LLMLingua-2 中间件。

这东西并不是简单粗暴地砍词。

它用 BERT 的双向注意力机制,能同时看到上下文的前后,精准识别核心语义(实体、数据、关键动词),把冗余的噪音剔掉。

这个中间件能把文档压缩 5-20 倍。

原本需要 1 秒的预填充,压完后 50 毫秒搞定。

对高并发场景来说,吞吐量直接上一个量级。

因为高密度的提示词才能换来高质量的注意力。

别让用户在等待里流失。

03|架构层:KV Cache 的注意事项

在商业化产品的降本增效中,KV Cache 是我认为最被低估的技术点之一。

先说什么是 KV Cache。

我之前的推文提到过,大模型的本质是「Token 推 Token」的过程:它不关心你问的是什么问题,只关心前文是什么。点击这里查看原文

这意味着:如果两次对话的前缀相同,模型其实在重复计算同样的内容。

KV Cache 就是用来解决这个问题的。

我们可以把已经计算过的中间结果存下来,下次遇到相同前缀时直接复用。

本质上就是用更廉价的存储空间,换相对昂贵的实时计算。这就是「空间换时间」。

举个例子,

当你问大模型「2 + 4 = ?」,它算出 6。

如果你再问「3 + 4 = ?」,前缀变了,模型只能从头再算一遍。

但如果你问的是「2 + 4 + 1 = ?」

前缀「2 + 4」没变,模型就能直接从 6 开始,算出 7。

这就是 KV Cache 的核心机制:前缀匹配。

只要前缀不变,缓存就能命中。

命中缓存和没命中,最高能节省 90% 的成本。

比如下图是 DeepSeek 的报价。

现在 DeepSeek、Qwen、智谱等主流模型都支持这个能力,以至于这是我在挑选大模型 API 时必看的一项。

虽然听起来诱人,但里面有几个隐形的坑,不说你可能不知道。

1、如果你用 Tool 参数,那别动态切换工具

有些产品为了极致省钱,会根据用户意图动态挂载 AI 调用的工具:问天气就挂 WeatherTool,闲聊就不挂任何工具。

看起来很美好,节省 Token 美滋滋。

但实际上,这是大坑。

原因在于大模型后端的模板逻辑。

我以 Qwen 3 的提示词模板为例。

你看…

只要你在请求里带了 tools 参数,

AI 服务器后台会在 System Prompt 后面插入一段工具说明…

如果你的提示词没有 System Prompt,模板会自动帮你加一个System Prompt…

然后再插入工具说明。

这不就坑大了吗…

一旦工具状态变了(比如从有到无,或从 A 工具换成 B 工具),Prompt 的头部前缀就变了。

模型会认为这是一段全新的对话,之前缓存的 Token 瞬间灰飞烟灭…

所以我推荐的操作是:尽可能 System Prompt 保持不变 + 不用 Tools 字段。

或者宁可浪费点 Token ,把全量工具定义一直挂着,也要保住知识库的缓存命中。

因为 System Prompt 的稳定性比省那点 Token 重要得多。

2、谨慎管理滑动窗口,尽量采用归纳形式

大模型的上下文长度有限,多轮对话场景下,历史消息很容易撑爆窗口。

很多产品的做法是「滑动窗口」,就是只保留最近 10 轮对话,旧的直接丢掉。

这是偷懒,而且会出问题。

比如用户上传了一份 2 万字的合同,然后开始和 AI 逐段讨论、修改。

如果窗口只保留最近几轮,AI 会丢失对整份文档的理解,改到第三段时已经忘了第一段的上下文。

因为滑动窗口的本质是队列,先进先出。

用户前几个会话交代的重要背景(比如「我对花生过敏」),后面可能就因为窗口移动被切掉了。

结果就是间歇性失忆…

用户会觉得「这 AI 根本没在听我说话」。

我更推荐的做法是「固定左侧,压缩后文」。

左侧固定:System Prompt 和关键背景信息始终保留,不参与滑动。右侧压缩:当 Token 接近阈值(比如 8k)时,不要直接丢弃旧对话,而是把它们压缩成几百字的摘要,追加到左侧固定区。

这样做的好处是:长期记忆有「索引」(压缩摘要),短期记忆有「高清」(完整对话)。

这样才能在质量和成本之间找到更合理的平衡点。

04|输出长度有哪些优化点?

不过,前文里我们老盯着 Prompt 做优化,但说实话,真正费钱费时间的是输出。

为什么?

因为大模型的输入和输出,处理方式完全不同。

输入是并行的,一次性读完;输出是串行的,一个 Token 一个 Token 往外输出。

每多输出一个字,用户就多等十几毫秒,后台并发能力就降一分。

然后现在的模型都有个毛病:话痨。

好的,作为一个 AI 助手,我很高兴为您解答…

希望这段代码对您有帮助,如果有任何问题请随时…

这些是 RLHF 训练出来的「礼貌废话」,工程上叫 Yapping(唠叨)。

这真得治。

对于这个约束,也有三类合适的操作,分别是提示词层面,代码层面和工程化层面。

指令层:写明确的负向约束

这个其实不是什么新技巧,很多产品经理都知道要求大模型直接给结果,或者尽量简洁回答。

但如果你的提示词里是:别写「请简洁回答」。

那是有问题的。

因为「简洁」对模型来说太抽象了,它不知道你要多简洁。

建议直接写「不要寒暄、不要总结、不要客套,直接输出结果」。

说白了就是告诉它:别整那些有的没的,直接上结果。

实测下来,Agentic 场景能砍掉 30% 的废话。

代码层:润色用 Diff,别重写整段

这是文字润色场景里最大的成本坑。

比如,用户说「把这句话改通顺一点」,模型直接把整篇 2,000 字的文章从头输出一遍。

或者约束一点之后,只生成这一个段落。

但不管怎么样,这些 Token 都是哗哗地烧。

换个思路,让模型只输出修改的部分,用 Diff 格式标出「原文→改后」,或者直接让 AI 返回正则表达式,程序拿到正则表达式之后再替换。

只动那两三个词,1 秒搞定。

成本差几十倍,用户体验还更好。

速度快,而且用户能直接看到改了哪里,不用自己去对比。

工程层:用停止逻辑强制截断

这招比在 Prompt 里写约束稳定得多,但同时也有一些风险。

你在 Prompt 里写「请只输出 3 项」,模型听不听是玄学。

它可能输出 3 项,也可能输出 5 项再加一段总结。

但停止序列是物理截断,和模型无关。

比如你让模型输出列表前 3 项,可以把「4.」设成停止序列。模型刚想往下写第 4 项,API 直接把生成流掐了。

然后不进历史上下文…

简单,粗暴,但好用。

同样的思路可以用在很多场景:

只要第一个答案?把换行符 n 设成停止序列生成 JSON 到结尾就停?把「}」设成停止序列防止模型自问自答?把「用户:」或「Human:」设成停止序列

省 Token,省时间,还不用担心模型乱讲。

有效控制输出,就是控制成本和用户体验。

终|算力时代的极简主义

如果做完这几层优化,你基本上已经跑赢 90% 的粗放型 AI 产品了。

回顾一下,我们聊了 YAML 格式、压缩算法、KV Cache、停止序列…

看起来都是在省钱、抠成本。

但往深了想,省 Token 这件事,本质上是在提高信息密度。

过滤掉格式噪音、文档废话、重复计算之后,喂给模型的都是干货。

密度越高,注意力机制越不容易分散,幻觉也越少。

说白了,高信噪比 = 高智能。

还有个副产品:快。

Token 少了,首字出得快,端到端延迟短。

C 端产品里,这直接决定用户愿不愿意继续用。

下次审工程化方案时,可以用一个标准卡一卡:

这里的每一个 Token,都在为最终结果贡献价值吗?

如果不是,考虑把它干掉。

把算力留给真正的思考。

这,才是 AI 时代的精益计算的美学。

你们团队在 Token 成本优化上还踩过什么坑?

欢迎评论区聊聊,我会挑有价值的问题单独写一篇。

关于我

我是洛小山,一个在 AI 浪潮中不断思考和实践的大厂产品总监。

我不追热点,只分享那些能真正改变我们工作模式的观察和工具。

如果你也在做 AI 产品,欢迎关注我,我们一起进化。

宙世代

宙世代

ZAKER旗下Web3.0元宇宙平台

一起剪

一起剪

ZAKER旗下免费视频剪辑工具

相关标签

ai 语法 窒息 阅读 翻译
相关文章
评论
没有更多评论了
取消

登录后才可以发布评论哦

打开小程序可以发布评论哦

12 我来说两句…
打开 ZAKER 参与讨论