# CED：输入 8B、输出 16B

> 因果编码器-解码器把 40 层拆成前后两半，解码器的全局 KV 直接从编码器最后一层投影出来，输入 token 大多只走前 20 层，预填充的计算差不多减半。

- 作者：David（道雾轩）
- 专栏：DeepSeek V4.1 Flash 深度解析（https://daiw.org/manual/deepseek-v4-flash.md）
- 最后更新：2026-09-19
- 原文：https://daiw.org/manual/deepseek-v4-flash/ced
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

Agent 干活的节奏是：想一步，调一次工具，把工具结果追加进上下文，再想下一步。每一次调用，都是一次新的预填充请求；只要前缀缓存没命中，就得把这段输入完整算一遍。V4.1 报告把这称为“预填充瓶颈”，给出的解法是 **CED（Causal Encoder-Decoder，因果编码器-解码器）**[1]。

## 先看它的来源：YOCO

报告写明 CED 受 YOCO 启发 [1]。YOCO（You Only Cache Once，2024）是一种“解码器-解码器”结构：下半部分叫 self-decoder，负责生成一份全局 KV 缓存；上半部分叫 cross-decoder，通过交叉注意力复用这份缓存。整个模型对外仍像普通的 decoder-only Transformer 一样逐 token 生成，但 KV 只缓存一次，而且**预填充可以提前退出**：处理输入时只要跑完下半部分，就已经拿到了上半部分需要的全部缓存 [3]。

CED 继承了这个思路，又做了几处结构调整，报告的说法是既提高了 KV 缓存的总体容量，也加深了 KV 生成的计算深度 [1]。

## CED 怎么切

V4.1-Flash 的 40 层被分成两半 [1][4]：

- **第 0–19 层是因果编码器**，**第 20–39 层是解码器**（层号从 0 数）。
- **全局注意力**：解码器各层的全局 KV 不从自己的隐藏状态算，而是从**编码器最后一层的输出**直接投影出来，每层用自己的投影矩阵。和 [CSA2](https://daiw.org/manual/deepseek-v4-flash/csa2) 结合后，只有解码器的第一层（第 20 层）真正做这次投影，后面各层复用它。
- **滑动窗口注意力**：所有层照旧逐层计算，每层用自己的隐藏状态生成最近 128 个 token 的局部 KV。

<Callout type="info">
  “编码器-解码器”这个名字容易让人想到 T5：先把整段输入双向读一遍，再交给解码器。**CED 不是这样**。它的编码器也是因果的，每个位置只看前文；整个模型是 40 层因果 Transformer，对外仍然逐 token 地生成文本 [1]。“编码器”和“解码器”说的只是层的分工：前一半负责产出全局缓存，后一半负责消费它。
</Callout>

## 预填充为什么能减半

关键在于：一个输入 token 要为后续生成留下的东西，是它在各层的 KV。普通 decoder-only 模型里，每一层的 KV 都来自这一层自己的隐藏状态，所以每个输入 token 必须走完全部层。CED 把解码器的全局 KV 改成从编码器输出投影，于是：

| | 普通 decoder-only | **CED** |
| --- | --- | --- |
| 输入 token 要走的层 | 全部 40 层 | 编码器 20 层；只有最后 128 个 token 还要走一遍解码器 |
| 解码时每个新 token | 40 层 | 40 层 |
| 每 token 激活参数 | —— | 预填充 8B，解码 16B |

为什么最后 128 个 token 还要走解码器？因为解码器的滑动窗口 KV 来自解码器自己的隐藏状态，生成开头几步要用。严格算的话，解码器每一层的窗口状态又依赖上一层更早的位置，精确重建要多处理“窗口长度 × 20 层”个 token；V4.1 改为只重放最后 128 个 token，把滑动窗口截断在这一段里，得到的是近似状态。报告称这对回答质量的影响可以忽略，并在后训练时模拟了同样的重放，让模型提前适应 [1]。这个技巧叫**解码器 SWA 有界重放**，[后面专门有一章](https://daiw.org/manual/deepseek-v4-flash/swa-bounded-replay)。

报告给出的账是：序列长度远大于窗口时，预填充的计算量从“全部层 × 序列长度”降到“一半层 × 序列长度”再加一个与序列长度无关的小项，**差不多减半** [1]。

## 8B 和 16B 从哪来

V4.1-Flash 每一层都是 MoE 层，每 token 激活 1 个共享专家和 6 个路由专家 [1]。预填充时输入 token 基本只走编码器的 20 层，解码时新 token 走全部 40 层，于是官方给出“预填充 8B、解码 16B”。

按 `config.json` 粗算一下（本专栏估算）：每个专家约 3,539 万参数，每层激活 7 个约 2.5 亿，20 层约 5B、40 层约 10B；再加上注意力、嵌入与输出层这些稠密部分，和官方的 8B / 16B 是同一个量级 [4]。

官方公告把这称为“输入和输出不对称”，并说“成本显著低于已知的同尺寸模型”[2]。后半句是厂商自述，属于**官方口径**。

## 代价与未知

- **解码器看全局，只能通过编码器最后一层。** 解码器各层拿到的长程信息，全部是编码器最后一层输出的投影；解码器自己对历史 token 更深的表示，后续 token 只能在 128 个 token 的窗口里看到。报告的结论是 CED 在“性能与基线相当”的前提下减掉近一半预填充计算 [1]，但**没有公开单独衡量 CED 影响的消融数字**。
- **有界重放是近似。** 报告在局限性一节承认，SWA 有界重放的近似状态重建“仍可能在未测试的边界情形下导致能力下降”，并把“缓存恢复边界处的 SWA 状态重建”列为后续重点压测的方向 [1]。
- **收益取决于负载形态。** 输入越长、缓存越常不命中，CED 省得越多；如果是输入很短、输出很长的任务，16B 的解码开销并没有变小。

下一章讲另一半：解码器复用编码器的缓存之后，全局 KV 本身怎么再省。👉 [CSA2：跨层共享的压缩稀疏注意力](https://daiw.org/manual/deepseek-v4-flash/csa2)

## 参考文献

- [1] DeepSeek-AI. “DeepSeek-V4.1-Flash: Pushing the Limits of KV Cache Compression.” 2026-09. [arXiv:2609.19969](https://arxiv.org/abs/2609.19969) —— 第 2.1 节（40 层因果 Transformer 的划分）、第 2.2 节（CED 的定义、式 1 与复杂度分析）、第 2.3.1 节（CED 与 CSA2 的结合）、第 3.2.2 节（解码器 SWA 有界重放）、第 6 节（局限性）。
- [2] DeepSeek. “DeepSeek-V4.1-Flash 发布.” 2026-09-10. [api-docs.deepseek.com/zh-cn/news/news260910](https://api-docs.deepseek.com/zh-cn/news/news260910) —— “输入和输出不对称”“成本显著低于已知的同尺寸模型”的原话。
- [3] Sun et al. “You Only Cache Once: Decoder-Decoder Architectures for Language Models.” 2024-05. [arXiv:2405.05254](https://arxiv.org/abs/2405.05254) —— self-decoder / cross-decoder 结构与预填充提前退出。
- [4] Hugging Face：[deepseek-ai/DeepSeek-V4.1-Flash 的 config.json](https://huggingface.co/deepseek-ai/DeepSeek-V4.1-Flash/blob/main/config.json) —— 层数、隐藏维度、专家数与专家中间维度。
