<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>推理优化 on Chico's Tech Blog</title><link>https://realtime-ai.chat/tags/%E6%8E%A8%E7%90%86%E4%BC%98%E5%8C%96/</link><description>Recent content in 推理优化 on Chico's Tech Blog</description><image><title>Chico's Tech Blog</title><url>https://github.com/chicogong.png</url><link>https://github.com/chicogong.png</link></image><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Thu, 07 May 2026 11:00:00 +0800</lastBuildDate><atom:link href="https://realtime-ai.chat/tags/%E6%8E%A8%E7%90%86%E4%BC%98%E5%8C%96/index.xml" rel="self" type="application/rss+xml"/><item><title>MoE 为什么成了大模型标配</title><link>https://realtime-ai.chat/posts/moe-architecture/</link><pubDate>Thu, 07 May 2026 11:00:00 +0800</pubDate><guid>https://realtime-ai.chat/posts/moe-architecture/</guid><description>DeepSeek V3 一共 6710 亿参数,推理时每个 token 只用 370 亿。这篇讲清 MoE 怎么做到「参数量大但推理便宜」,以及它换来的工程代价。</description><content:encoded><![CDATA[<p>DeepSeek V3 一共有 6710 亿参数。但你每问它一句话,真正参与计算的只有 370 亿——剩下的 95% 在显存里待命,一个 token 都不碰。</p>
<p>这听起来像偷工减料,其实是过去三年大模型架构最重要的一次转向。到 2026 年,你叫得出名字的开源旗舰里,几乎没有一个还是&quot;老老实实每个参数都算&quot;的稠密模型:DeepSeek V4-Pro(1.6 万亿总参 / 490 亿激活)、Qwen 3.5(3970 亿 / 170 亿)、Llama 4 Maverick(4000 亿 / 170 亿)、Kimi K2(1 万亿 / 约 320 亿)、Mistral Large 3(6750 亿 / 410 亿)。这个架构叫 Mixture-of-Experts,混合专家。</p>
<p>它解决的是一个很具体的矛盾:模型想变聪明,最直接的办法是堆参数;但参数一多,推理就慢、就贵。MoE 的本质,是<strong>把&quot;模型有多少知识&quot;和&quot;算一次要花多少钱&quot;这两件事拆开</strong>。这篇讲清楚它怎么做到的,以及它换来了什么样的工程代价。</p>
<h2 id="先讲清楚稠密模型贵在哪">先讲清楚:稠密模型贵在哪</h2>
<p>传统的大模型——也就是 GPT-3、早期 Llama 那种&quot;稠密&quot;(dense)模型——有一个朴素的规则:<strong>每个 token 经过每一层时,所有参数都要参与计算</strong>。</p>
<p>一个 700 亿参数的稠密模型,处理一个 token 就要做大约 700 亿次乘加。处理一句 100 字的话,乘以 100。参数翻倍到 1400 亿,这个账单也跟着翻倍。算力、显存带宽、电费,全是线性涨上去的。</p>
<p>问题是,模型里真的每个参数对每个 token 都有用吗?</p>
<p>直觉上不是。你问它&quot;今天北京天气&quot;,和你让它&quot;写一段 Rust 的并发代码&quot;,用到的知识完全不同。稠密模型的浪费就在这:不管你问什么,它都把&quot;写代码的脑区&quot;和&quot;聊天气的脑区&quot;全部点亮算一遍。</p>
<p>MoE 想做的事很朴素——<strong>该用哪块脑子,就只用哪块</strong>。</p>
<h2 id="用一个类比把它讲透">用一个类比把它讲透</h2>
<p>把稠密模型想象成一家公司,每来一个问题,全公司 200 个人都得开会、都得发言,然后把意见汇总。问题再小也这么干。开会效率极低,但好处是没人会漏掉。</p>
<p>MoE 是另一种公司。同样养着 200 个员工(这叫<strong>专家</strong>,expert),但每来一个问题,门口坐着一个<strong>调度员</strong>(这叫<strong>路由器</strong>,router 或 gating network),它扫一眼问题,只挑最对口的 8 个人进会议室,其余 192 人继续待岗。</p>
<p>关键点来了:</p>
<ul>
<li><strong>这家公司&quot;知识总量&quot;还是 200 人份的</strong>——养着这么多专业各异的人,什么问题都有人能接。</li>
<li><strong>但&quot;开一次会的成本&quot;只有 8 人份</strong>——大部分人这次根本没参与。</li>
</ul>
<p>这就是 MoE 那句听起来矛盾的话——&ldquo;参数量大,但推理便宜&rdquo;——的全部秘密。<strong>总参数</strong>(200 人)决定模型的知识容量;<strong>激活参数</strong>(8 人)决定你每跑一次推理的算力账单。MoE 把这两个数字解耦了。</p>
<p>DeepSeek V3 就是个标准样本:总参 6710 亿,但每个 token 只激活 370 亿。它每个 token 的计算量,大约相当于一个 370 亿的稠密模型,但它肚子里装的知识,是 6710 亿那个量级的。官方的说法是,它每 token 的有效计算成本,大致是同等总参稠密模型的二十分之一。</p>
<h2 id="路由器整个架构的开关">路由器:整个架构的开关</h2>
<p>MoE 里最精巧、也最容易出问题的零件,是路由器。</p>
<p>它的工作具体发生在模型的每一个 MoE 层里。一个 token 进来,路由器算一个打分,给当前层的每个专家打个分,然后选出得分最高的几个(术语叫 top-K,DeepSeek V3 是 top-8),只把这个 token 送进这几个专家。专家各自算完,按打分加权汇总,再往下一层走。下一层又是一次全新的挑选。</p>
<pre class="mermaid">flowchart TD
  T[输入 token] --> R{路由器<br/>给每个专家打分}
  R -->|得分 0.41| E1[专家 1 ✓]
  R -->|得分 0.27| E2[专家 2 ✓]
  R -->|得分 0.02| E3[专家 3 跳过]
  R -->|得分 0.18| E4[专家 4 ✓]
  R -->|得分 0.01| E5[专家 ... 跳过]
  E1 --> M[加权汇总]
  E2 --> M
  E4 --> M
  M --> O[进入下一层]
  style E3 fill:#eee,stroke:#bbb,color:#999
  style E5 fill:#eee,stroke:#bbb,color:#999
  style R fill:#fde7c2,stroke:#e8b23c
</pre><p>这里有几个反常识的点,值得单独说:</p>
<p><strong>专家不是&quot;按学科分工&quot;的。</strong> 你不会找到一个&quot;数学专家&quot;或者一个&quot;法语专家&quot;。训练完之后去看,专家学到的分工往往很碎、很说不清——可能某个专家专门处理标点和换行,某个专门管代码缩进。分工是训练里自己涌现出来的,人没法预先指派。</p>
<p><strong>路由是逐层、逐 token 的。</strong> 不是一句话进来挑一次专家就定了。一个 token 在 60 层里,可能经过 60 组完全不同的专家组合。所以&quot;激活了哪些专家&quot;是个非常动态的东西。</p>
<p><strong>2026 年的主流是&quot;细粒度专家 + 共享专家&quot;。</strong> DeepSeek 带火的这套设计有两个改动。一是<strong>把专家切小切多</strong>——与其养 8 个大专家,不如养 256 个小专家,每次激活 8 个。专家越细,组合越多,分工越能专精。二是留一两个<strong>共享专家</strong>(shared expert)常驻,不参与路由,每个 token 都过——专门负责&quot;标点、语法、常识&quot;这类谁都要用的通用能力,这样路由的那些专家就能腾出来专攻各自的细分领域。</p>
<h2 id="激活参数-vs-总参数一张表说清楚">激活参数 vs 总参数:一张表说清楚</h2>
<p>这两个数字,是 2026 年看模型参数表时唯一真正要分清的事。它们决定了完全不同的东西:</p>
<table>
  <thead>
      <tr>
          <th>维度</th>
          <th>总参数</th>
          <th>激活参数</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>它代表</td>
          <td>模型的知识容量</td>
          <td>单 token 的计算量</td>
      </tr>
      <tr>
          <td>决定</td>
          <td><strong>显存</strong>够不够装得下</td>
          <td><strong>推理速度</strong> / 单次成本</td>
      </tr>
      <tr>
          <td>DeepSeek V3</td>
          <td>6710 亿</td>
          <td>370 亿</td>
      </tr>
      <tr>
          <td>Qwen 3.5</td>
          <td>3970 亿</td>
          <td>170 亿</td>
      </tr>
      <tr>
          <td>Llama 4 Maverick</td>
          <td>4000 亿</td>
          <td>170 亿</td>
      </tr>
      <tr>
          <td>Kimi K2</td>
          <td>1 万亿</td>
          <td>约 320 亿</td>
      </tr>
  </tbody>
</table>
<p>看这张表,你能立刻得到一条很实用的判断:一个标成 &ldquo;397B-A17B&rdquo; 的模型,<strong>前面那个数(397B)是你买显存时要看的,后面那个数(17B)是你估推理速度时要看的</strong>。两者别搞混——这是 MoE 部署里最常见的认知错误。</p>
<p>它带来的实际效果是反直觉的:Qwen3.5 那个 35B-A3B 的 MoE 版本,占的显存远比 9B 的稠密版大(光权重就 21GB 对 5.8GB),但在同一张卡上,它的吞吐和首 token 延迟反而更好。<strong>显存占得多,但跑得快</strong>——因为速度只跟那 3B 激活参数有关。</p>
<h2 id="天下没有白吃的午餐moe-的工程代价">天下没有白吃的午餐:MoE 的工程代价</h2>
<p>讲到这你可能觉得 MoE 是纯赚的——同样的算力,能装下大得多的模型。但它把成本从&quot;算力&quot;转移到了别的地方,而且这些地方往往更难搞。</p>
<p><strong>第一笔账:显存。</strong> 推理时虽然只算 8 个专家,但你不知道下一个 token 会路由到哪 8 个,所以<strong>全部 256 个专家的权重都得待在显存里</strong>。MoE 省的是算力,不是显存。Kimi K2 这种 1 万亿参数的模型,FP16 精度下光权重就要 2TB 量级的显存,只能靠多卡集群伺候。&ldquo;激活参数小&quot;绝不意味着&quot;能在小显卡上跑&rdquo;。</p>
<p><strong>第二笔账:负载均衡。</strong> 路由器是学出来的,它会&quot;偏心&quot;。如果不管,训练到后面会出现&quot;马太效应&quot;——几个专家因为早期表现好,被路由器越选越多,练得越来越强;另一批专家几乎没 token 光顾,等于白养。极端情况下,你那个 256 专家的模型,实际只有几十个在干活,知识容量大打折扣。</p>
<p>早期的解法是加一个<strong>辅助损失</strong>(auxiliary loss),硬性惩罚&quot;分配不均&quot;,逼路由器雨露均沾。但这个惩罚项会和&quot;把 token 送给最对的专家&quot;这个主目标打架,损害模型质量。DeepSeek V3 改用了一个<strong>无辅助损失</strong>的方案:给每个专家的路由打分加一个可调的偏置项,某个专家最近太忙就把它的偏置调低、太闲就调高——只动路由、不进损失函数。这个细节,正是 DeepSeek 那一代模型训练能又稳又便宜的关键之一。</p>
<p><strong>第三笔账:部署复杂度。</strong> 专家太多,一张 GPU 装不下,得<strong>专家并行</strong>(expert parallelism)——把 256 个专家摊到几十张卡上。这下问题来了:一个 token 路由到的 8 个专家,可能散在 8 张不同的卡上,token 得先被发过去、算完再收回来。这种跨卡通信(all-to-all)是 MoE 推理的头号瓶颈,而且负载是<strong>动态</strong>的——这一批 token 可能全挤向某几张卡,那几张卡就成了堵点。稠密模型完全没有这套烦恼。</p>
<p>所以 MoE 不是&quot;免费午餐&quot;,而是一笔<strong>用工程复杂度换计算效率的交易</strong>。它假设你有能力搞定多卡集群、搞定专家并行、搞定负载均衡。对个人开发者和小团队,在本地跑一个大 MoE,门槛其实比同等&quot;能力档位&quot;的稠密模型更高——因为卡在显存上。</p>
<h2 id="为什么-2026-年几乎全是-moe">为什么 2026 年几乎全是 MoE</h2>
<p>把上面的账合起来算,结论就很清楚了。</p>
<p>到 2026 年,纯靠堆稠密参数这条路已经走到头:再大的稠密模型,推理成本高到没法规模化服务。而模型厂商面对的需求又是确定的——既要在榜单上有竞争力(要知识容量、要总参数),又要能用可接受的成本服务上亿用户(要推理便宜、要激活参数小)。</p>
<p>MoE 是目前唯一能同时满足这两头的架构。它让厂商可以理直气壮地把总参数推到万亿级,同时把激活参数压在二三十亿到五十亿这个&quot;服务得起&quot;的区间。DeepSeek、Qwen、Llama、Kimi、Mistral——这些团队各自独立地收敛到同一个设计,不是跟风,是因为约束条件相同,最优解也就相同。</p>
<p>但要泼一点冷水:MoE 不是没有代价的银弹。它把模型能力做大了,却把工程门槛也抬高了——显存、通信、负载均衡,每一样都需要专门的基础设施。<strong>它真正改变的,不是&quot;模型能多强&quot;,而是&quot;多强的模型能被服务得起&quot;。</strong> 对 2026 年要做规模化部署的团队来说,这恰恰是最重要的那个问题。</p>
<hr>
<p>参考来源:</p>
<ul>
<li><a href="https://arxiv.org/html/2412.19437v1">DeepSeek-V3 Technical Report (arXiv)</a></li>
<li><a href="https://arxiv.org/pdf/2401.06066">DeepSeekMoE: Towards Ultimate Expert Specialization (arXiv)</a></li>
<li><a href="https://www.spheron.network/blog/moe-inference-optimization-gpu-cloud/">MoE Model Inference on GPU Cloud: Expert Parallelism, Memory, and Cost (2026) — Spheron</a></li>
<li><a href="https://qubittool.com/blog/llm-landscape-may-2026-deepseek-qwen-llama-comparison">LLM Landscape May 2026: DeepSeek V4 vs Qwen 3.5 vs Llama 4 — QubitTool</a></li>
<li><a href="https://huggingface.co/blog/NormalUhr/moe-balance">A Review on Load Balancing Strategy in MoE LLMs — Hugging Face</a></li>
</ul>
]]></content:encoded></item><item><title>Prompt Caching 实战:把推理成本和延迟砍下来</title><link>https://realtime-ai.chat/posts/prompt-caching/</link><pubDate>Tue, 05 May 2026 11:00:00 +0800</pubDate><guid>https://realtime-ai.chat/posts/prompt-caching/</guid><description>同一段 system prompt 反复 prefill 是在烧钱。这篇讲清 prompt caching 怎么命中、缓存断点放哪、Anthropic/OpenAI/Gemini/DeepSeek 各家计费与 TTL 差异,以及对延迟的影响。</description><content:encoded><![CDATA[<p>先说一个很多团队没算过的账。</p>
<p>假设你的 Agent 有一段 4000 token 的 system prompt:角色设定、工具说明、几个 few-shot 例子,雷打不动。用户每轮真正输入的,可能就 30 个字。一天 10 万次请求,这 4000 token × 10 万,就是 4 亿个 token 反复进入模型做同一件事——把固定前缀重新算一遍。</p>
<p>这部分计算,90% 是白烧的。因为前缀一模一样,模型每次算出来的中间结果(KV cache)也一模一样。<strong>Prompt caching 就是把这份中间结果存下来,下次直接复用。</strong> 它不改你的代码逻辑,不动模型质量,却能把输入侧成本砍掉一大半,顺带把首 token 延迟压下去。</p>
<p>2026 年,它依然是被严重低估的省钱手段。不是因为难,恰恰是因为太简单——简单到大家以为&quot;开了就行&quot;,结果断点放错位置,缓存全程没命中,白付一笔写入费还不自知。</p>
<h2 id="它到底缓存了什么">它到底缓存了什么</h2>
<p>要用对,先得知道模型推理分两个阶段。</p>
<p><strong>Prefill(预填充)</strong>:把你的整段 prompt 一次性喂进模型,逐 token 算出每一层的 KV(key/value)向量。这一步是并行的、算力密集的,prompt 越长越慢。</p>
<p><strong>Decode(解码)</strong>:基于 prefill 的结果,一个一个吐出回答 token。</p>
<p>Prompt caching 缓存的,就是 prefill 阶段算出来的那份 KV。注意:它缓存的是<strong>前缀</strong>,不是&quot;整个 prompt&quot;。模型从第一个 token 开始,一段一段比对——只要某个位置往前的内容和缓存里的完全一致,这段就能复用;一旦遇到第一个不一样的 token,从那里往后全部得重算。</p>
<pre class="mermaid">flowchart LR
  A["请求 prompt"] --> B{"逐 token 比对前缀"}
  B -->|"前缀命中"| C["复用 KV<br/>(便宜 + 快)"]
  B -->|"遇到第一个差异"| D["从这里往后重新 prefill"]
  C --> D
  D --> E["Decode 出 token"]
</pre><p>这张图就是 prompt caching 的全部精髓。所有的&quot;怎么用对&quot;,归结成一句话:<strong>让不变的东西待在前面,让变化的东西待在后面。</strong></p>
<h2 id="为什么前缀的顺序决定一切">为什么前缀的顺序决定一切</h2>
<p>各家请求体的拼接顺序是固定的:<strong>tools(工具定义)→ system(系统提示)→ messages(对话历史)</strong>。模型按这个顺序拼成一条长 prefix,再从头比对。</p>
<p>这意味着排在越前面的内容,越&quot;值钱&quot;——它一旦变化,后面所有东西的缓存全部作废。所以一个合格的可缓存 prompt,结构应该长这样,从稳定到易变排列:</p>
<table>
  <thead>
      <tr>
          <th>位置</th>
          <th>放什么</th>
          <th>变化频率</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>最前</td>
          <td>工具定义、函数 schema</td>
          <td>几乎不变</td>
      </tr>
      <tr>
          <td>靠前</td>
          <td>system prompt、角色设定、few-shot 例子</td>
          <td>发版才变</td>
      </tr>
      <tr>
          <td>中间</td>
          <td>知识库片段、长文档、检索结果</td>
          <td>按会话变</td>
      </tr>
      <tr>
          <td>最后</td>
          <td>当前用户输入、本轮变量</td>
          <td>每次都变</td>
      </tr>
  </tbody>
</table>
<p>最常见的翻车,是把&quot;变化的东西塞进了前面&quot;。比如有人喜欢在 system prompt 顶部写一句 <code>当前时间:2026-05-05 11:23:07</code>。看着无害,实际是灾难——这个时间戳每秒都不一样,等于把整条 prefix 的第一个字就改了,<strong>后面 4000 token 的缓存全程一次都命中不了</strong>。同类的坑还有:user ID、请求 UUID、A/B 实验分组标记、随机打乱的 few-shot 顺序。</p>
<p>如果你确实需要给模型当前时间,把它放到对话消息的<strong>最后</strong>,跟用户输入待在一起。前面那一大坨稳定前缀,该缓存照样缓存。</p>
<h2 id="缓存断点放哪自动-vs-手动">缓存断点放哪:自动 vs 手动</h2>
<p>这里是各家最大的分歧,也是最容易用错的地方。</p>
<p><strong>自动派(OpenAI、Google 隐式缓存、DeepSeek)</strong>:你什么都不用做。系统自动识别请求之间的公共前缀,命中了就给你折扣。OpenAI 对超过 1024 token 的 prompt 自动启用;DeepSeek 是后端自动复用磁盘上的前缀缓存;Gemini 2.5 及以后的模型默认开启隐式缓存。</p>
<p>自动派的好处是零成本接入,坏处是<strong>没有保证</strong>。命中是&quot;尽力而为&quot;的——Google 自己也写明,隐式缓存只在系统判定命中时才给折扣,你无法强制。</p>
<p><strong>手动派(Anthropic,以及 Gemini 的显式缓存)</strong>:你得自己在 prompt 里打一个 <code>cache_control</code> 标记,告诉模型&quot;缓存到这里为止&quot;。这个标记叫<strong>缓存断点(cache breakpoint)</strong>。Anthropic 一个请求最多打 4 个断点。</p>
<p>手动派麻烦一点,但换来确定性:你明确知道哪一段被缓存了。</p>
<p>手动派最经典的错误,是<strong>把断点打在了会变的块上</strong>。比如这样的结构——一大段静态知识库,后面跟一个&quot;包含时间戳 + 用户输入&quot;的块,然后断点打在最后这个块上。结果时间戳每次都变,这个块的 hash 每次都不同,缓存永远写入、永远读不到。</p>
<p>正确做法:<strong>断点打在「最后一个跨请求不变」的块的末尾</strong>,而不是打在变化的块上。把静态前缀和动态后缀切开,断点卡在它们的交界处。</p>
<pre class="mermaid">flowchart TB
  subgraph 错误["错误:断点在变化块上"]
    A1["静态知识库 8000 token"] --> A2["时间戳 + 用户输入 ⟵ 断点"]
  end
  subgraph 正确["正确:断点在静态前缀末尾"]
    B1["静态知识库 8000 token ⟵ 断点"] --> B2["时间戳 + 用户输入"]
  end
</pre><p>还有一个多轮对话特有的坑:对话越滚越长,你的断点可能被挤到&quot;上一次写入位置&quot;20 多个块之外,超出回溯窗口,于是又一次踩空。多轮场景里,务必随着对话增长<strong>滚动更新断点位置</strong>,让它始终贴着最新的稳定边界。</p>
<h2 id="四家的计费和-ttl差得不小">四家的计费和 TTL,差得不小</h2>
<p>省多少、贵多少、能存多久——各家规则不一样,接之前一定要看清。</p>
<table>
  <thead>
      <tr>
          <th>厂商</th>
          <th>缓存写入</th>
          <th>缓存读取</th>
          <th>TTL</th>
          <th>模式</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Anthropic</td>
          <td>1.25×(5 分钟)/ 2.0×(1 小时)输入价</td>
          <td>0.1× 输入价</td>
          <td>5 分钟默认,可选 1 小时</td>
          <td>手动断点</td>
      </tr>
      <tr>
          <td>OpenAI</td>
          <td>不额外收费</td>
          <td>视模型 0.1×~0.5× 输入价</td>
          <td>几分钟,空闲淘汰</td>
          <td>自动</td>
      </tr>
      <tr>
          <td>Google Gemini</td>
          <td>隐式无写入费;显式按标准输入价计</td>
          <td>约 0.1× 输入价(2.5+ 省 90%)</td>
          <td>隐式自动;显式按 TTL 计存储费</td>
          <td>隐式自动 / 显式手动</td>
      </tr>
      <tr>
          <td>DeepSeek</td>
          <td>不额外收费</td>
          <td>约 0.1× 输入价(cache hit 价)</td>
          <td>后端管理,存储免费</td>
          <td>自动(磁盘)</td>
      </tr>
  </tbody>
</table>
<p>几个要点单独拎出来说。</p>
<p><strong>Anthropic 是唯一对&quot;写入&quot;收钱的。</strong> 写一次缓存比正常输入贵 25%(5 分钟档)。这意味着如果你的 prompt 写进去之后根本没被复用就过期了,你是<strong>净亏</strong>的——多付了 25%,一分钱折扣没拿到。所以 Anthropic 的缓存只对&quot;高频复用同一前缀&quot;的场景划算。读取确实便宜,只要 1/10 输入价。</p>
<p><strong>TTL 是个隐形雷区。</strong> Anthropic 默认 TTL 在 2026 年初从 1 小时悄悄变回了 5 分钟,不少团队因此缓存创建成本涨了 20%~30% 还没察觉。5 分钟意味着:如果你的请求间隔超过 5 分钟,缓存早凉了,每次都是冷启动重新写入。好消息是 TTL 的时钟会在每次命中时<strong>重置</strong>——只要请求够密,缓存能一直续命。需要长间隔复用的,Anthropic 可以花 2 倍写入价买 1 小时 TTL。</p>
<p><strong>OpenAI 和 DeepSeek 对开发者最省心</strong>:不收写入费,自动命中,几乎是&quot;白送的折扣&quot;。DeepSeek 2026 年 4 月把 cache hit 价格再砍到发布价的 1/10,V4-Flash 上缓存命中把输入成本从 $0.14 压到 $0.0028 每百万 token——98% 的降幅。</p>
<p><strong>省钱幅度的体感</strong>:输入侧能省 50%~90%。具体看你的 prompt 里&quot;固定前缀占比&quot;有多高——前缀越长、变量越短,省得越狠。一个 8000 token 知识库 + 50 token 提问的 RAG 应用,几乎是为 prompt caching 量身定做的。</p>
<h2 id="别忘了它还能压延迟">别忘了它还能压延迟</h2>
<p>省钱是它最出名的好处,但对实时类应用,<strong>降延迟才是关键收益</strong>。</p>
<p>命中缓存时,prefill 这一步被整段跳过。前面说过,prefill 是算力密集的,prompt 越长越慢。跳过它,首 token 延迟(TTFT)的下降立竿见影——DeepSeek 给过一个数据:128K 的长 prompt 高度命中缓存时,首 token 延迟从 13 秒压到 500 毫秒。</p>
<p>这对语音 Agent、实时对话这种&quot;首 token 延迟就是及格线&quot;的场景,意义比省钱大得多。一个挂着长 system prompt 和工具定义的语音助手,把这部分缓存住,等于每一轮对话都省掉了几千 token 的 prefill 时间。如果你正在为 TTFT 抠毫秒,prompt caching 应该排在优化清单的前列。</p>
<p>不过有个前提:<strong>省下来的延迟,得真的有缓存可命中</strong>。冷启动那一次(第一次写入)不但不快,Anthropic 那边还更慢更贵。所以 prompt caching 优化的是&quot;稳态延迟&quot;,不是&quot;首次延迟&quot;。</p>
<h2 id="一份排查清单为什么我没命中">一份排查清单:为什么我没命中</h2>
<p>如果你接了 prompt caching,但账单没怎么降,大概率是踩了下面某一条。按顺序自查:</p>
<ol>
<li>
<p><strong>前缀里有变量。</strong> 时间戳、UUID、user ID、随机数——但凡有一个混进了 system prompt 或工具定义,整条缓存作废。把它们全部赶到 messages 末尾。</p>
</li>
<li>
<p><strong>断点打错位置(手动派)。</strong> 断点要打在&quot;最后一个不变块&quot;的末尾,不是打在变化块上。切开静态与动态的交界。</p>
</li>
<li>
<p><strong>请求间隔超了 TTL。</strong> Anthropic 默认才 5 分钟。低频请求(比如定时任务、长间隔轮询)很可能每次都冷启动。要么提高请求密度,要么买长 TTL。</p>
</li>
<li>
<p><strong>prompt 太短没够门槛。</strong> OpenAI 要超过 1024 token 才会自动缓存。短 prompt 本来也省不了多少,不用纠结。</p>
</li>
<li>
<p><strong>工具定义或 system prompt 偷偷变了。</strong> 多人协作时,有人调了一下工具描述、改了个标点,排在最前面的 tools 段一变,后面全塌。把可缓存前缀<strong>当成发布制品来管理</strong>,别让它随手改。</p>
</li>
<li>
<p><strong>few-shot 例子顺序不固定。</strong> 有些代码每次随机打乱 few-shot 顺序&quot;增加多样性&quot;——这会让前缀每次都不同。要缓存,就固定顺序。</p>
</li>
</ol>
<h2 id="落地建议">落地建议</h2>
<p>不用一上来就上复杂方案。三步走:</p>
<p><strong>第一步,把 prompt 重新排版。</strong> 不管你用哪家,先按&quot;工具 → system → 知识库 → 用户输入&quot;从稳到变重排一遍,把所有变量揪到最后。光这一步,自动派(OpenAI / DeepSeek / Gemini)就能开始命中了,一行代码没动。</p>
<p><strong>第二步,手动派打好断点。</strong> 用 Anthropic,就在静态前缀末尾打 <code>cache_control</code>;多轮对话记得滚动更新断点。</p>
<p><strong>第三步,盯住命中率。</strong> 各家 API 响应里都会返回 cache 相关字段(命中 token 数、写入 token 数)。把&quot;缓存读取 token / 总输入 token&quot;做成一个监控指标。它要是长期偏低,回到上面那份清单逐条查。</p>
<p>最后提醒一句取舍:prompt caching 不是&quot;开了就一定赚&quot;。对 Anthropic 这种收写入费的厂商,低频、前缀短、变量多的场景,反而可能亏。先搞清楚自己的流量形态——<strong>高频复用同一份长前缀,才是它的主场</strong>。判断对了,这是你能拿到的、性价比最高的一次优化:不掉质量,不改逻辑,省一半成本,还顺手降了延迟。</p>
<hr>
<p>参考资料:</p>
<ul>
<li><a href="https://platform.claude.com/docs/en/build-with-claude/prompt-caching">Prompt caching - Claude API Docs</a></li>
<li><a href="https://github.com/anthropics/claude-code/issues/46829">Cache TTL silently regressed from 1h to 5m · Issue #46829</a></li>
<li><a href="https://openai.com/index/api-prompt-caching/">Prompt Caching in the API | OpenAI</a></li>
<li><a href="https://developers.openai.com/api/docs/guides/prompt-caching">Prompt caching | OpenAI API</a></li>
<li><a href="https://docs.cloud.google.com/gemini-enterprise-agent-platform/models/context-cache/context-cache-overview">Context caching overview | Google Cloud</a></li>
<li><a href="https://developers.googleblog.com/gemini-2-5-models-now-support-implicit-caching/">Gemini 2.5 Models now support implicit caching - Google Developers Blog</a></li>
<li><a href="https://api-docs.deepseek.com/news/news0802">DeepSeek API introduces Context Caching on Disk</a></li>
</ul>
]]></content:encoded></item><item><title>模型蒸馏:把大模型的能力搬进小模型</title><link>https://realtime-ai.chat/posts/model-distillation/</link><pubDate>Fri, 01 May 2026 11:00:00 +0800</pubDate><guid>https://realtime-ai.chat/posts/model-distillation/</guid><description>蒸馏不是模型压缩的玄学,而是用大模型当老师教小模型。这篇讲清楚蒸馏到底搬走了什么、和微调的关系、能搬多少、做不到什么,以及一套能落地的实践流程和常见坑。</description><content:encoded><![CDATA[<p>2025 年初,DeepSeek 放出一组叫 R1-Distill 的模型,其中那个 7B 版本在 AIME 2024 数学竞赛题上拿到了 55.5% 的 pass@1。</p>
<p>这个数字有意思的地方在于:它比 QwQ-32B-Preview 还高。一个 7B 的小模型,在硬核推理题上,打过了一个参数量是它四倍多的模型。</p>
<p>更反常识的是后面这句——DeepSeek 自己说的:<strong>直接拿强化学习去训练那个 7B 小模型,效果还不如蒸馏</strong>。小模型自己练,练不出这种推理能力;但你拿一个 671B 的大模型当老师,把它的思考过程喂给小模型学,小模型就学会了。</p>
<p>这就是蒸馏。它不是模型压缩里的某种玄学技巧,而是 2026 年几乎每家做小模型的团队都在用的标准动作。这篇把它讲清楚:蒸馏到底搬走了什么,和微调是什么关系,能搬多少,做不到什么,以及一套能落地的流程。</p>
<h2 id="为什么要蒸馏质量和成本之间那道墙">为什么要蒸馏:质量和成本之间那道墙</h2>
<p>先说动机。</p>
<p>大模型好用,但贵。一个 400B 参数的旗舰模型,推理延迟高、单次调用成本高、显存吃得狠,你不可能把它塞进每一台手机、每一个边缘设备、每一条高并发的客服管道。可小模型呢?便宜、快、能本地跑,但你直接拿一个 7B 模型出来用,它在复杂任务上的回答质量,和旗舰模型差着一大截。</p>
<p>这就是那道墙:<strong>质量在大模型这边,成本和延迟在小模型那边</strong>,你想两个都要。</p>
<p>传统的过墙办法有两种。一种是直接训练一个小模型——但小模型受参数量限制,见的数据再多,某些能力(尤其是多步推理)就是练不出来,这是容量天花板。另一种是把大模型剪枝、量化——这能省一点,但省不了数量级,而且剪过头质量就崩。</p>
<p>蒸馏是第三条路,也是目前性价比最高的一条:<strong>不让小模型自己悟,而是让大模型手把手教它</strong>。Meta 拿 Llama 4 Behemoth 去训 Llama 4 的 Scout 和 Maverick,Google 用 Gemini 去带 Gemma 2 和 Gemma 3,DeepSeek 用 R1 蒸出 1.5B 到 70B 一整个系列——2026 年你能叫得出名字的小模型,背后基本都站着一个大模型老师。</p>
<p>道理很朴素:让一个聪明人把题做一遍、把思路讲给你听,比你自己对着标准答案死磕,学得快得多。</p>
<h2 id="蒸馏到底在传递什么">蒸馏到底在传递什么</h2>
<p>很多人对蒸馏的第一印象是&quot;用大模型造点数据,拿去训小模型&quot;。这个理解对了一半,但漏掉了最关键的东西。</p>
<p>蒸馏的精髓在于<strong>软标签(soft label)</strong>。</p>
<p>举个例子。你问模型&quot;这句话情感是正面还是负面&quot;,一个普通的训练样本只会告诉小模型一个<strong>硬标签</strong>:正面。但大模型老师给出的不是一个字,而是一整个概率分布——比如&quot;正面 0.82、负面 0.11、中性 0.07&quot;。</p>
<p>这个分布里藏着硬标签给不了的信息:老师不光告诉你答案是什么,还告诉你<strong>它有多确定、它觉得别的选项有多接近</strong>。这种&quot;模型对各种可能性的相对判断&quot;,业内叫<strong>暗知识(dark knowledge)</strong>。小模型学的不只是结论,是老师那套打分的体感。</p>
<p>技术上,这通常通过让学生去拟合老师的 logits(输出层的原始分数)来实现,用 KL 散度当损失函数,衡量学生分布和老师分布差了多远。这条路线效果最好,但有个前提:你得能拿到老师的 logits——也就是老师得是个&quot;白盒&quot;。</p>
<pre class="mermaid">flowchart TB
  T[教师大模型] -->|完整概率分布<br/>soft label| K[KL 散度损失]
  T -->|生成的答案 + 思维链<br/>hard label| C[交叉熵损失]
  K --> S[学生小模型]
  C --> S
  S -->|采样自己的回答| V[教师/验证器打分]
  V -->|纠正学生的错误| S
  style T fill:#fde7c2,stroke:#e8b23c
  style S fill:#cfe8d8,stroke:#4ca877
</pre><p>如果老师是个只给你返回文字的 API(黑盒),你拿不到 logits,那就退而求其次:让老师<strong>大量生成完整的答案和推理过程</strong>,再拿这些文本当训练数据去教小模型。DeepSeek 蒸馏 R1 用的就是这条路——他们用 R1 生成了 80 万条样本,然后纯靠监督微调(SFT)把这些样本喂给 Qwen 和 Llama,连强化学习都没加。这条路拿不到暗知识,但胜在简单、不挑老师、谁的 API 都能蒸。</p>
<h2 id="蒸馏和微调到底什么关系">蒸馏和微调,到底什么关系</h2>
<p>这是最容易绕晕的一个点,我直接给结论:<strong>蒸馏和微调不是对立的,蒸馏的落地往往就是一次微调,只是数据来源不同</strong>。</p>
<p>把它们放一起看:</p>
<table>
  <thead>
      <tr>
          <th>维度</th>
          <th>普通微调</th>
          <th>蒸馏</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>数据从哪来</td>
          <td>人工标注 / 真实业务数据</td>
          <td>大模型老师生成</td>
      </tr>
      <tr>
          <td>学的是什么</td>
          <td>硬标签:正确答案</td>
          <td>软标签 + 答案 + 推理过程</td>
      </tr>
      <tr>
          <td>想解决的问题</td>
          <td>让模型适配某个特定任务</td>
          <td>把大模型的通用能力搬进小模型</td>
      </tr>
      <tr>
          <td>训练动作</td>
          <td>SFT / LoRA</td>
          <td>通常也是 SFT / LoRA,或加 KL 损失</td>
      </tr>
  </tbody>
</table>
<p>看出来了:<strong>微调是&quot;怎么训&quot;的问题,蒸馏是&quot;用什么数据训、为了什么目的&quot;的问题</strong>。当你拿 R1 生成的 80 万条数据去 SFT 一个 Qwen,你既在做蒸馏,也在做微调——这两件事在那一刻是同一件事。</p>
<p>实践里常见的组合拳是这样的:先蒸馏,把大模型的通用推理能力搬进小模型,得到一个&quot;底子好&quot;的基座;再拿你自己的业务数据做一次轻量微调,让它贴合具体场景。先蒸再调,各管一段,这是 2026 年成熟团队的标准配方。</p>
<h2 id="它能搬走多少又搬不走什么">它能搬走多少,又搬不走什么</h2>
<p>蒸馏不是魔法。说清楚它的边界,比吹它的效果更重要。</p>
<p><strong>搬得动的:</strong> 有明确&quot;过程&quot;和&quot;答案&quot;的能力,蒸馏搬运效率最高。数学推理、代码生成、逻辑规划、结构化抽取、指令遵循——这些任务有清晰的思维链可以模仿,有可验证的对错。DeepSeek-R1-Distill 系列在 AIME、MATH-500、代码这些榜单上的大幅领先,就是证据。一个被好好蒸过的小模型,在它擅长的窄领域里,能逼近甚至偶尔超过原始大模型在该领域的表现。</p>
<p><strong>搬不动的,有三类要心里有数:</strong></p>
<p>第一,<strong>老师不会的,学生也学不会</strong>。蒸馏是能力的转移,不是能力的创造。老师的水平就是学生的天花板,你不可能蒸出一个比老师还强的模型(在老师覆盖的能力上)。</p>
<p>第二,<strong>广度会被压缩</strong>。小模型参数量摆在那,容量有限。你蒸数学,它数学强;但如果你想让它数学、代码、多语言、长文本、创意写作样样精通,它装不下。蒸馏逼着你做取舍:<strong>想清楚这个小模型到底要干什么,然后只蒸那部分</strong>。什么都想要,结果是什么都平庸。</p>
<p>第三,<strong>泛化能力可能变弱,这是个隐蔽的代价</strong>。2026 年有研究指出一个值得警惕的现象:蒸馏(尤其是自蒸馏)会让小模型推理变快、在分布内的题上表现好,但在没见过的、需要灵活变通的题上,泛化反而退步了。原因是学生学的是老师在特定题型上的&quot;套路&quot;,套路学得越熟,越容易在新题型上水土不服。这个权衡叫&quot;更快的推理,更弱的泛化&quot;——蒸的时候要盯着分布外的测试集,别只看训练集附近的漂亮数字。</p>
<h2 id="推理蒸馏2026-年最值得关注的一支">推理蒸馏:2026 年最值得关注的一支</h2>
<p>推理模型的兴起,给蒸馏带来一个新麻烦,也催生了一个新方法。</p>
<p>麻烦在于:推理模型动不动就是几千 token 的长思维链。链条越长,<strong>误差越会一步步累积</strong>——老师在第三步走错一小步,学生照单全收,后面全错。你按传统办法,把老师生成的思维链整段喂给学生去模仿,学生学的是&quot;老师在老师自己的思路上怎么走&quot;,可一旦学生自己推到一个老师从没经过的中间状态,它就懵了,因为训练时没人教过它这种情况怎么办。</p>
<p>2026 年的解法叫<strong>在线蒸馏(on-policy distillation)</strong>,现在已经是 DeepSeek-V4、Qwen3、Gemma、Nemotron 这些前沿模型做推理后训练的标配。</p>
<p>它的思路反过来:<strong>不让学生模仿老师的轨迹,而是让学生先自己走</strong>。学生针对一道题,用自己当前的水平生成一条推理路径;然后老师(或者一个奖励模型、一个验证器)来给这条路径打分、指出哪里错了;学生再根据这个反馈修正。</p>
<p>关键区别在于:学生学的是&quot;<strong>在我自己会犯的错误状态下,该怎么爬出来</strong>&quot;,而不是&quot;老师在它的完美状态下怎么走&quot;。这就解决了前面那个状态不匹配的问题——学生纠错纠的是自己真实会遇到的坑。代价是工程更复杂:你需要一个能在线打分的老师或验证器,训练时还得不断采样,比离线蒸馏重不少。</p>
<h2 id="一套能落地的流程和几个坑">一套能落地的流程,和几个坑</h2>
<p>如果你要真的蒸一个模型出来,我建议按这个顺序走:</p>
<ol>
<li><strong>先把任务边界划死</strong>。这个小模型只干一件事还是几件事?接受多大的质量损失换多少成本?这一步想不清楚,后面全是返工。</li>
<li><strong>选老师和基座</strong>。老师选你能力范围内最强、且最好是白盒(能拿 logits)的;基座小模型选参数量匹配你部署预算的。Qwen、Llama 这些开源系列是常见选择。</li>
<li><strong>造数据</strong>。让老师在你的目标任务分布上大量生成,带上完整推理过程。数据的覆盖面决定了学生的上限——老师没生成过的题型,学生就是盲区。</li>
<li><strong>训练</strong>。黑盒老师就纯 SFT;白盒老师就加上 logits 的 KL 损失,效果更好。资源紧就 LoRA。</li>
<li><strong>评估,而且要评分布外</strong>。别只看训练集附近的指标,一定要拿没蒸过的题型测泛化,盯住前面说的&quot;泛化退化&quot;。</li>
</ol>
<p>几个反复见到的坑:</p>
<ul>
<li><strong>老师数据不验证</strong>。大模型也会生成错答案,你不筛一遍就喂给学生,学生连错误一起学。蒸推理任务时,务必用验证器或答案对照过滤掉老师做错的样本。</li>
<li><strong>盯着平均分,忽略短板</strong>。蒸完看总分涨了就交差,结果某个子能力悄悄崩了。要按子任务分别看。</li>
<li><strong>以为蒸馏能省掉数据工程</strong>。蒸馏省的是人工标注,不是数据设计。老师生成什么、覆盖哪些分布,仍然得你来设计,这活儿一点不轻。</li>
<li><strong>法律和合规边界</strong>。用某个商业 API 的输出去蒸自己的模型,可能违反对方的服务条款。蒸之前先看清楚老师那边的许可,这是工程之外、但绕不开的一道坎。</li>
</ul>
<p>最后回到开头那个 7B 模型。它能打过 32B,不是因为它聪明,是因为它有个好老师,而且有人想清楚了&quot;只让它学推理这一件事&quot;。蒸馏的价值从来不是&quot;免费得到一个强模型&quot;,而是<strong>让你能在质量和成本之间,精确地选一个你要的点</strong>——前提是你真的想清楚了要选哪个点。</p>
<hr>
<p><strong>参考资料</strong></p>
<ul>
<li><a href="https://thinkingmachines.ai/blog/on-policy-distillation/">On-Policy Distillation — Thinking Machines Lab</a></li>
<li><a href="https://arxiv.org/abs/2604.00626">A Survey of On-Policy Distillation for Large Language Models — arXiv</a></li>
<li><a href="https://bdtechtalks.com/2026/04/13/llm-self-distillation-tradeoffs/">The paradox of LLM self-distillation: Faster reasoning, weaker generalization — TechTalks</a></li>
<li><a href="https://github.com/deepseek-ai/DeepSeek-R1">DeepSeek-R1 — GitHub</a></li>
<li><a href="https://www.marktechpost.com/2026/05/11/understanding-llm-distillation-techniques/">Understanding LLM Distillation Techniques — MarkTechPost</a></li>
<li><a href="https://www.bentoml.com/blog/the-best-open-source-small-language-models">The Best Open-Source Small Language Models in 2026 — BentoML</a></li>
<li><a href="https://labelyourdata.com/articles/machine-learning/knowledge-distillation">Knowledge Distillation: Teacher-Student Loss Explained — Label Your Data</a></li>
</ul>
]]></content:encoded></item></channel></rss>