Elea Notes.

词条 · AI · 入门

推理

训练是造模型,推理是用模型。训练一次性花钱,推理每次调用都花钱。

也称:inference、推理阶段、解码

下面从一个你大概亲眼见过的怪现象讲起:同一个模型,读得飞快,写得很慢。

这个不对称不是实现上的瑕疵,而是这类模型运行方式的直接后果。看懂它,“推理为什么贵""上下文为什么值钱""长对话为什么越聊越慢”这几个问题会同时有答案。

先看一个麻烦:它读三万字只用两秒,写三百字要十秒

把一份长文档贴进对话框,几乎立刻就开始回答。可它吐字的速度,慢得能一个个看清。

按常识这说不通。三万字的输入比三百字的输出多一百倍,怎么反而快?

再看一个配套的怪事:同一个模型,回答长度翻倍,等待时间也差不多翻倍——线性增长,很规律。但输入长度翻倍,等待时间几乎没变。输入和输出,走的好像不是同一套逻辑。

还有一个细节值得记住:等待的分布也不一样。长输入时,你等的是开头那一下;长输出时,你等的是全程。前者可以用一句”正在思考”糊过去,后者糊不过去。

这不是网络问题,也不是服务器忙。它是模型跑起来的方式本身造成的,而这个”方式”决定了你用它要付多少钱。

朴素尝试为什么都不够

先把最容易接受的几种解释试一遍。它们大多从”想得多所以慢”这个直觉出发,也都会撞墙——而撞墙的位置恰好就是答案。

猜测一:输出比输入难,模型”想”得更久。 那”想”这件事发生在哪一步?如果是全局的思考,为什么每个字的间隔那么均匀?真正在思考的程序不会用如此规整的节拍吐字。均匀的节拍说明每个字的成本是一样的,而且是重复的。

猜测二:算力不够,加显卡就好。 换更强的卡,读得更快了,写的速度改善却很有限。如果瓶颈是算力,两边应该同步变快。它们没有同步,说明卡住的不是同一个东西。

猜测三:那就一次多生成几个字,摊薄开销。 做不到。写第 5 个字要先看到第 4 个字——第 4 个字是什么,取决于模型看完前 3 个字之后的判断。这不是实现偷懒,是逐字生成这个定义本身带来的串行依赖。而读输入没有这个依赖:全部三万字一开始就都在手上,可以同时处理。

猜测四:那就把已经算过的东西缓存下来,别重算。 这个方向对,也确实是现在的做法——但它把成本从”重复计算”搬到了”存储和搬运”,而搬运正是新的瓶颈。这就是 KV Cache 那一条要单独讲的东西。

猜测五:模型太大所以慢,用小模型就行。 小模型确实每个字更快,因为要搬的权重更少——这恰好佐证了瓶颈在搬运量上。但它换掉的是答案质量,不是解开了这个结构。真正想两头都要,得让小模型和大模型配合(第四节末尾那一条)。

五个猜测挤出了两个必须分开看的性质:

  1. 输入可以并行,输出必须串行——因为下一个字依赖上一个字;
  2. 两边缺的资源不同——一边缺算力,另一边缺把数据搬进芯片的带宽。

于是”推理”这一件事,实际上是两个性质相反的阶段。

机制:预填充与解码

  你的提问(3 万字)              模型的回答(300 字)
  ┌───────────────────┐        ┌──┬──┬──┬──   ──┬──┐
  │   全部一起处理     │   →    │字│字│字│ ...  │字│
  └───────────────────┘        └──┴──┴──┴──   ──┴──┘
      预填充 prefill              解码 decode
   一次批量,吃满算力            一字一轮,每轮搬一遍权重
   瓶颈:计算                    瓶颈:显存带宽

预填充:读入你的提问。所有词之间没有先后依赖,可以塞进一次大矩阵运算,把 GPU 的算力吃满。这是芯片最擅长的形状,所以三万字也就两秒。

解码:逐字生成。每生成一个字算一轮,而每一轮都要把模型的全部权重从显存搬进计算单元过一遍——一个几百亿参数的模型,一轮就是几十上百 GB 的搬运量。搬完只为了算出一个字。

这就解释了猜测二为什么失败:解码时,计算单元大部分时间在等数据到位。加算力等于给一条堵住的路加宽车道尽头,堵点在运货那一段。 也正因为每轮的搬运量固定,每个字的耗时才那么均匀(猜测一里那个规整的节拍)。

两个阶段的比值还解释了定价:几乎所有 API 的输出 token 都比输入 token 贵好几倍,因为它们的单位成本本来就不一样。

一个数量级的对照能让这件事更实在。假设权重要搬 140 GB,显存带宽 2 TB/s,那么一轮解码的下限约是 70 微秒——每秒最多十几个字,而且这跟”这个字好不好想”完全无关。预填充那一边则是把三万个词压进一次大矩阵乘,芯片的算力峰值终于用得上,于是几万字和几百字的耗时差别没有你以为的那么大。

顺带说明一件常被误解的事:这两个阶段用的是同一份权重、同一个模型。 它们不是两个程序,只是同一个前向计算在”一次喂多少个词”上取了两个极端。喂很多个是预填充,喂一个是解码。

为什么值得知道:推理成本是商业现实

训练成本是新闻头条,推理成本是账单。训练是一次性的资本支出,推理是随使用量线性增长的运营支出——一个被调用上亿次的模型,推理总花费会远超训练那一次投入。所以绝大部分工程努力都压在同一个目标上:让解码这一步更便宜

两个阶段的分工也解释了为什么服务商愿意为”缓存你的提问”单独定价:同一段前缀重复出现时,预填充那一半可以整块跳过。这是把第三节的结构差异直接变成了账单上的一行。

由此可以直接读懂几件事:

  • KV Cache 是解码的核心优化:把每一轮算过的中间结果留下来,下一轮不重算。代价是它占显存,且随对话变长而增长——这是猜测四换来的新麻烦。
  • Agent 特别贵:它每一轮都把越来越长的记录整份重新喂进去,等于反复付预填充的钱,还叠加许多轮解码。轮次一多,账单不是线性涨。
  • “流式输出”不是优化:它只是把已经生成的字先给你看,总时长不变。感受变好了,成本一样。
  • 上下文越长,解码越慢:每一轮要参照的历史更多,搬运量随之上升。长上下文的代价主要落在这里,而不是预填充。
  • 同样字数的一次长对话,比多次短对话贵:每轮都要把整段历史重新读一遍,历史越长,这份固定开销越大。长对话越聊越慢来自这里,不是模型”累了”。
  • 批处理(batching)帮的是服务方:把多个用户的解码轮凑成一批,一次搬运的权重供所有人共用。吞吐上去了,但你一个人的回答不会变快,反而要等凑够一批——这是服务方在吞吐和延迟之间的旋钮,也是同一个模型在不同产品上手感不同的原因之一。
  • “让模型少说话”是真的省钱:输出 token 既贵又是串行瓶颈。要求简明回答,同时降低了账单和延迟,这两件事在这里是同一件事。
  • 投机解码(speculative decoding)是绕开串行的尝试:先用一个小模型快速猜几个字,再让大模型一次性批量验证。猜对就白赚几个字,猜错就丢掉重来。它没有打破猜测三里那条依赖,只是把”必须串行的验证”改成了批量形状——又回到了预填充擅长的那一边。

一句话记住:训练花一次钱,推理每次都花钱;读便宜,写贵。 你在产品里看到的所有限额、定价和”请简明回答”的默认提示,源头都在这一条。