文章

有关LLM的token花费

有关LLM的token花费

当前计费方式的不合理

众所周知transformer输出单个token的计算量基本上正比于上文token数。即单个token的时间复杂度为$O(n)$($n$为上文token数)。所以严格来说,当输入token数为$m$、输出token数为$n$时,应当是:

\[\sum_{i=1}^{n}\left({m+i}\right)=mn+\frac{n\left(n+1\right)}{2}\approx{mn+\frac{n^2}{2}}\]

但当前的计费方式却是$am+bn$,其中$a$、$b$分别为输入token数和输出token数的单价。

这将引出一个问题,大模型计算量与价格并不成正比,在此前我认为虽然二者不成正比,但一般情况下应该大体正相关,因此若想节省花费就在尝试减少token数。但事实上,二者有可能大相径庭。

工具调用产生的高花费

考虑输入token数为$m$、输出token数为$n$、工具调用次数为$k$的情况。不妨假设:

  • 工具调用在输出中均匀分布,即每次工具调用输出$n/k$个token。
  • 工具不返回任何内容,即工具调用不返回任何内容给大模型,不产生额外的token数。

那么显然,总计算量与$k$无关,仍为:

\[\sum_{i=1}^{n}\left({m+i}\right)=mn+\frac{n\left(n+1\right)}{2}\approx{mn+\frac{n^2}{2}}\]

但考虑花费,第一次输入token为$m$,输出为$n/k$。第二次输入为$m+n/k$,输出为$n/k$。以此类推。

总输出token数为$n$。
总的输入token数为

\[\sum_{i=1}^{k}\left[m+\left(i-1\right)\frac{n}{k}\right]=\frac{\left(2m+n-n/k\right)k}{2}=km+\frac{\left({k}-1\right)n}{2}\]

更细致的考虑,现在许多厂商对缓存和非缓存的token数分别计费,那么,缓存的token数为:

\[\sum_{i=2}^{k}\left[m+\left(i-1\right)\frac{n}{k}\right]=\left(k-1\right)m+\frac{\left({k}-1\right)n}{2}\]

未缓存的token数为$m$。

你或许发现了问题,工具调用并不产生额外的计算量,但按当前计费方式,输入token数将大大增加。 以deepseek-v3.2的定价为例,缓存输入0.2/M、未缓存输入2/M、输出3/M。假设输入上文的token数为10000token,总输出token为2000token。在无工具调用时,价格为$10000\times{2}+2000\times{3}=26000$。若出现了10次工具调用(这在agent工作时并不多),价格将变为:

  • 未缓存输入$10000\times{2}=20000$
  • 缓存输入${0.2}\times\left[{\left(10-1\right)}\times{10000}+\frac{\left(10-1\right)\times{2000}}{2}\right]=19800$
  • 输出$2000\times{3}=6000$

总价格为$20000+19800+6000=45800$。

可以看到未缓存输入和输出与工具调用次数无关,但工具调用会额外产生$\left(k-1\right)m+\frac{\left({k}-1\right)n}{2}$的缓存输入token。仍是deepseek-v3.2,对于许多无缓存优惠的提供商,在上述场景额外花费将从$19800$增加到$198000$。此时总花费当达到无工具总花费调用的$862\%$!。若工具调用20次,额外花费将从$19800$增加到$41800$,达到无工具总花费调用的$261\%$,若是没有缓存优惠将达到$1708\%$!

小结

综上分析,一次多token的调用因为工具调用等原因拆分成多次短调用,在总计算量不变的情况下,总花费将大大增加,甚至在连续几十次的工具调用中,总花费将增加数十甚至百倍。

优化

让模型输出更多东西会使得总计算量增加,同时带来的是响应速度的下降。但在很大程度上,让模型输出更多东西但避免多次调用工具,是值得的。

例如,我们有一个agent来编辑代码,现在我们有两种方案:

  1. 每次调用工具修改局部代码
  2. 一次性输出全部新代码

方案1是增量的,每次仅需修改少量代码,而后者则需要将未修改的代码也一并输出一次。听起来前者会优于后者,但事实上,如果代码中包含多处修改,多次工具调用的总花费将远远超过一次性输出全部新代码。也就是说,多次工具调用带来的输入token多次计算,花费将远远超过浪费的输出token。即使修改的代码仅占总代码的很小一部分,但让大模型输出更多代码,反倒减少了token用量。

这仅为一个例子,简而言之,为了减少工具调用或其他请求的次数,适当浪费大模型的输出是值得的。

另外,现在许多大模型都开始做交叉思考,这使得工具调用愈发频繁,或许这是大模型厂商增加利润的阴谋…

本文由作者按照 CC BY-NC 4.0 进行授权, 未经许可不得转载。