30  Kimi 系列训推实战

2025 年 7 月,月之暗面(Moonshot AI)开源了 Kimi K2——一个 1 万亿参数的 MoE 模型。这不是又一个”刷榜模型”:它用全新的 MuonClip 优化器在 1T 参数规模上实现了零训练不稳定,用 15.5T tokens 的数据把 Agent 能力推到了开源模型的前沿。更关键的是,K2 的架构直接复用了 DeepSeek-V3 的 MLA + MoE 范式,并在其之上做出了实质性的工程突破。如果说 DeepSeek-V3 证明了”便宜也能训好”,Kimi K2 则证明了”规模可以再上一个台阶”。

30.1 章节导入

30.1.1 从 Moonshot V1 到 K3:一条清晰的演进路线

Kimi 的母公司月之暗面成立于 2023 年,创始人杨植麟是 Transformer-XL 和 XLNet 的核心作者。公司的技术演进路线非常清晰:

timeline
    title Kimi 模型演进路线
    2023 Q3 : Moonshot V1 : Dense 模型 : 8K/32K/128K 上下文
    2025 Q3 : Kimi K2 : 1T MoE 开源 : MLA + MuonClip : 128K 上下文
    2025-09 : Kimi K2.5 : 多模态开源 SoTA : 视觉+文本 : 256K 上下文
    2025-10 : Kimi K2.6 : 通用模型 : 思考/非思考模式 : 256K 上下文
    2025-10 : Kimi K2.7 Code : 专用编码 : 高速模式 : 256K 上下文
    2025-11 : Kimi K3 : 旗舰模型 : 2.8T 参数 : 1M 上下文 : 原生视觉 : 编程 Agent 优化

这条路线体现了几个关键战略选择:

  1. 从 Dense 到 MoE:V1 是传统稠密模型,K2 开始全面转向 MoE 架构
  2. 从闭源到开源:K2 是首个大规模开源的 Kimi 模型
  3. 从通用到专用:K2.7 Code 专注编程,K3 专注编程 Agent 场景
  4. 上下文持续扩展:8K → 128K → 256K → 1M

30.1.2 核心技术定位

Kimi K2 的技术定位可以用三个关键词概括:

  • MoE(Mixture-of-Experts):1T 总参数,32B 激活参数,384 个专家
  • MLA(Multi-head Latent Attention):复用 DeepSeek-V3 的 Attention 机制,大幅压缩 KV Cache
  • MuonClip 优化器:Muon 优化器的改进版本,在 1T 参数规模上实现了零训练不稳定

30.1.3 与 DeepSeek-V3 的关系

K2 的架构并非从零设计,而是直接复用了 DeepSeek-V3 的 DeepSeekV3CausalLM 架构(model_type 设为 "kimi_k2")。这意味着:

  • Attention 层完全相同:都使用 MLA 机制
  • MoE 结构相似但有差异:K2 有 384 个专家(V3 为 256 个),激活 8 个(V3 为 8 个)
  • 词表更大:K2 使用 160K 词表(V3 为 129K)
  • 优化器不同:K2 用 MuonClip,V3 用 AdamW

graph LR
    subgraph "DeepSeek-V3"
        D1["MLA Attention"] --> D2["MoE: 256 experts<br/>8 activated + 1 shared"]
        D2 --> D3["AdamW"]
        D3 --> D4["FP8 Training"]
    end
    
    subgraph "Kimi K2"
        K1["MLA Attention<br/>(same)"] --> K2["MoE: 384 experts<br/>8 activated + 1 shared"]
        K2 --> K3["MuonClip<br/>(new!)"]
        K3 --> K4["Block-FP8 Weights"]
    end
    
    D1 -.->|"架构复用"| K1

Note

为什么复用 DeepSeek-V3 架构? 这不是”偷懒”,而是工程智慧的体现。MLA + 细粒度 MoE 的范式已经由 DeepSeek-V3 验证了有效性。K2 团队把精力集中在了真正需要突破的地方——优化器和训练稳定性——而不是重复造轮子。这也是开源生态的价值:优秀的设计会被复用和改进。

30.2 Kimi K2 架构深度解析

30.2.1 整体架构概览

先看 K2 的完整架构参数:

参数 Kimi K2 DeepSeek-V3 对比
总参数 1T 671B K2 大 49%
激活参数 32B 37B K2 更精简
层数 61 61 相同
Dense 层数 1 1 相同
Attention Hidden Dim 7168 7168 相同
MoE Hidden Dim (per expert) 2048 2048 相同
Attention Heads 64 64 相同
专家总数 384 256 K2 多 50%
每 Token 激活专家 8 8 相同
共享专家 1 1 相同
词表大小 160K 129K K2 大 24%
上下文长度 128K 128K 相同
Attention 机制 MLA MLA 相同
优化器 MuonClip AdamW 关键差异
训练数据 15.5T tokens 14.8T tokens K2 多 5%

一个有趣的事实:K2 的总参数比 V3 大 49%,但激活参数反而少 5B(32B vs 37B)。这意味着 K2 的”参数效率”更高——用更少的计算获得更大的模型容量。

30.2.2 MoE 架构设计

30.2.2.1 384 个专家的路由策略

K2 的 MoE 层包含 384 个专家,每个 token 选择 8 个激活,外加 1 个始终激活的共享专家:

graph TD
    subgraph "Kimi K2 MoE Layer"
        A["Input Hidden State<br/>dim=7168"] --> B["Router / Gate"]
        B --> C["Top-8 Selection<br/>从 384 个专家中选 8 个"]
        B --> D["Shared Expert<br/>(always active)"]
        
        C --> E1["Expert 1<br/>dim: 7168→2048→7168"]
        C --> E2["Expert 2<br/>dim: 7168→2048→7168"]
        C --> E3["..."]
        C --> E8["Expert 8<br/>dim: 7168→2048→7168"]
        
        E1 --> F["Weighted Sum<br/>(gate scores)"]
        E2 --> F
        E8 --> F
        D --> F
        
        F --> G["Output Hidden State<br/>dim=7168"]
    end

每个专家是一个两层 MLP(使用 SwiGLU 激活函数):

import torch
import torch.nn as nn
import torch.nn.functional as F

class Expert(nn.Module):
    """Kimi K2 中的单个 MoE 专家"""
    def __init__(self, hidden_dim=7168, expert_dim=2048):
        super().__init__()
        self.w1 = nn.Linear(hidden_dim, expert_dim, bias=False)  # gate
        self.w2 = nn.Linear(expert_dim, hidden_dim, bias=False)  # down
        self.w3 = nn.Linear(hidden_dim, expert_dim, bias=False)  # up
    
    def forward(self, x):
        # SwiGLU: (x @ w1) * SiLU(x @ w3) @ w2
        return self.w2(F.silu(self.w1(x)) * self.w3(x))

class MoERouter(nn.Module):
    """Top-K 路由器"""
    def __init__(self, hidden_dim=7168, num_experts=384, top_k=8):
        super().__init__()
        self.gate = nn.Linear(hidden_dim, num_experts, bias=False)
        self.top_k = top_k
    
    def forward(self, x):
        # x: [batch * seq_len, hidden_dim]
        logits = self.gate(x)                              # [N, 384]
        scores = F.softmax(logits, dim=-1)                 # [N, 384]
        
        # Top-K 选择
        topk_scores, topk_indices = torch.topk(scores, self.top_k, dim=-1)
        # 重归一化
        topk_scores = topk_scores / topk_scores.sum(dim=-1, keepdim=True)
        
        return topk_indices, topk_scores

30.2.2.2 与 DeepSeek-V3 的 MoE 对比

两者的核心差异在于”粒度”策略:

graph LR
    subgraph "DeepSeek-V3 MoE"
        D_R["256 experts"] --> D_S["8 selected per token"]
        D_S --> D_A["~37B activated params"]
    end
    
    subgraph "Kimi K2 MoE"
        K_R["384 experts"] --> K_S["8 selected per token"]
        K_S --> K_A["~32B activated params"]
    end

K2 的策略是”更多专家、更精细选择”——384 个专家提供了更大的模型容量(1T vs 671B),但每个 token 只激活 8 个,因此激活参数反而更少。这意味着:

  • 推理速度更快:32B 激活 < 37B 激活
  • 模型容量更大:1T > 671B
  • 专家利用率更低:每次只用到 384 个中的 8 个(2.1%)

30.2.2.3 负载均衡

384 个专家的负载均衡是一个更大的挑战。K2 在训练时使用了辅助损失(auxiliary loss)来确保所有专家被均匀使用:

def load_balancing_loss(affinities, expert_indices, num_experts=384, top_k=8):
    """
    affinities: [N, num_experts] - router 的 softmax 输出
    expert_indices: [N, top_k] - 被选中的专家索引
    """
    N = affinities.shape[0]
    
    # 每个专家被选中的概率
    expert_mask = F.one_hot(expert_indices, num_experts).float()  # [N, top_k, num_experts]
    expert_freq = expert_mask.sum(dim=1).mean(dim=0)              # [num_experts]
    
    # 每个专家的平均 affinity
    expert_prob = affinities.mean(dim=0)                          # [num_experts]
    
    # 负载均衡损失
    loss = num_experts * (expert_freq * expert_prob).sum()
    return loss

30.2.3 MLA Attention

K2 完全复用了 DeepSeek-V3 的 MLA(Multi-head Latent Attention)机制。我们在第 27 章已经详细讲解过 MLA,这里只做简要回顾和 K2 特有的参数分析。

30.2.3.1 MLA 核心思想

graph TD
    subgraph "标准 MHA"
        A1["Hidden State<br/>dim=7168"] --> B1["W_Q → Q (64 heads)<br/>W_K → K (64 heads)<br/>W_V → V (64 heads)"]
        B1 --> C1["缓存 K, V<br/>per token: 2×61×64×128"]
    end
    
    subgraph "MLA (Kimi K2)"
        A2["Hidden State<br/>dim=7168"] --> B2["W_DKV → c_KV<br/>(低秩, dim ≪ 7168)"]
        B2 --> C2["只缓存 c_KV!<br/>per token: 61 × latent_dim"]
        C2 --> D2["推理时: c_KV → K, V"]
        D2 --> E2["Attention 计算"]
    end

30.2.3.2 K2 的 KV Cache 计算

对于 K2(61 层,64 头,head_dim=128):

标准 MHA:
  KV Cache per token = 2 × 61 × 64 × 128 = 1,001,472 elements
  ≈ 1.9 MB (FP16)

MLA (假设 latent_dim = 512):
  KV Cache per token = 61 × 512 = 31,232 elements
  ≈ 0.06 MB (FP16)

压缩比: ~32x !

这意味着在 128K 上下文下,K2 的 KV Cache 仅需约 7.9 GB(FP16),而非标准 MHA 的约 250 GB。这使得在有限的 GPU 内存上运行 128K 上下文成为可能。

Tip

MLA 的工程价值:对于 1T 参数的模型,如果没有 MLA,128K 上下文的 KV Cache 会消耗数百 GB 内存——即使有 16 张 H200 也难以容纳。MLA 是让 K2 在合理硬件上运行的关键技术。

30.2.4 MuonClip 优化器

MuonClip 是 K2 最核心的技术创新之一。它让 Muon 优化器首次在 1T 参数规模上稳定运行。

30.2.4.1 Muon 优化器原理

Muon(MomentUm + Orthogonalization)是一种结合动量和正交化的优化器。核心思想是对梯度矩阵进行正交化后再更新:

import torch

def muon_update(grad, momentum_buffer, beta=0.95, lr=0.02):
    """
    Muon 优化器的单步更新
    
    grad: [m, n] 梯度矩阵
    momentum_buffer: 动量缓存
    beta: 动量系数
    lr: 学习率
    """
    # 1. 动量更新
    momentum_buffer.mul_(beta).add_(grad, alpha=1 - beta)
    
    # 2. 对动量进行 Newton-Schulz 正交化
    #    这将矩阵的奇异值推向 1
    momentum_orth = newton_schulz_orthogonalize(momentum_buffer)
    
    # 3. 用正交化后的矩阵更新参数
    return -lr * momentum_orth

def newton_schulz_orthogonalize(G, steps=5):
    """
    Newton-Schulz 迭代近似正交化
    计算 G @ (G^T @ G)^{-1/2}
    """
    a, b, c = (3.4445, -4.7750, 2.0315)
    X = G.bfloat16()
    if G.shape[0] > G.shape[1]:
        X = X.T  # 保证宽矩阵形式
    
    for _ in range(steps):
        A = X @ X.T
        B = b * A + c * (A @ A)
        X = a * X + B @ X
    
    return X

30.2.4.2 为什么 Muon 比 AdamW 更好?

Muon 的优势来自一个数学性质:正交化后的梯度矩阵的所有奇异值都为 1

优化器 更新方向 步长分配 问题
AdamW 梯度 / √(二阶矩) 自适应(按元素) 大矩阵可能出现”维度坍缩”
Muon 正交化(梯度) 均匀(按奇异值) 大规模训练时不稳定
MuonClip 正交化(梯度) + Clip 均匀 + 有界 稳定!

AdamW 的问题在于它按元素处理梯度,忽略了矩阵的整体结构。Muon 通过矩阵级别的正交化,确保了更新方向在所有维度上均匀分配。但原始 Muon 在超大规模下会出现训练不稳定——这正是 MuonClip 要解决的。

30.2.4.3 Clip 技术:解决大规模不稳定性

当 Muon 扩展到 1T 参数时,会出现以下问题:

  1. 梯度范数爆炸:部分层的梯度范数可能突然变得极大
  2. 正交化数值不稳定:Newton-Schulz 迭代在极端梯度值下可能不收敛
  3. 训练发散:上述问题叠加后导致 loss 突然飙升

MuonClip 的解决方案是对梯度范数进行裁剪(Clip),在正交化之前确保梯度矩阵的范数在一个合理范围内:

def muonclip_update(grad, momentum_buffer, beta=0.95, lr=0.02, 
                    max_norm=1.0, min_norm=0.1):
    """
    MuonClip: 带范数裁剪的 Muon 优化器
    """
    # 1. 计算梯度矩阵的 Frobenius 范数
    grad_norm = torch.norm(grad, p='fro')
    
    # 2. 范数裁剪(核心创新)
    if grad_norm > max_norm:
        grad = grad * (max_norm / grad_norm)
    elif grad_norm < min_norm:
        grad = grad * (min_norm / grad_norm)
    
    # 3. 动量更新
    momentum_buffer.mul_(beta).add_(grad, alpha=1 - beta)
    
    # 4. Newton-Schulz 正交化
    momentum_orth = newton_schulz_orthogonalize(momentum_buffer)
    
    # 5. 参数更新
    return -lr * momentum_orth
Important

MuonClip 的意义不仅在于 K2。它证明了一个关键工程事实:Muon 类优化器可以扩展到 1T+ 参数。这意味着未来的超大模型不必再依赖 AdamW——Muon 族的优化器可能成为新的默认选择,带来更快的收敛和更好的最终质量。

30.3 训练系统

30.3.1 大规模预训练

30.3.1.1 训练规模

K2 的预训练规模是空前的:

维度 数值 对比 DeepSeek-V3
训练数据 15.5T tokens 14.8T tokens
模型参数 1T 671B
优化器 MuonClip AdamW
精度 FP8 训练 FP8 训练
训练稳定性 零不稳定 零不稳定

15.5T tokens 是什么概念?假设平均一个 token 对应 4 个字节,那训练数据量约为 62 TB 的纯文本。这已经超过了整个英文维基百科(约 25 GB)的 2400 倍。

30.3.1.2 Block-FP8 权重存储

K2 采用了 Block-FP8 格式存储权重,这是对标准 FP8 的重要改进:

graph TD
    subgraph "标准 FP8"
        A1["权重矩阵 (FP32/BF16)"] --> B1["逐元素量化为 FP8<br/>(E4M3 或 E5M2)"]
        B1 --> C1["每个元素 1 字节"]
    end
    
    subgraph "Block-FP8"
        A2["权重矩阵 (FP32/BF16)"] --> B2["分块<br/>(e.g., 32×32 blocks)"]
        B2 --> C2["每块计算独立的 scale"]
        C2 --> D2["块内元素量化为 FP8"]
        D2 --> E2["每块: 32×32 FP8 + 1 FP32 scale"]
    end

Block-FP8 的优势在于每个块有独立的缩放因子,因此对于分布不均匀的权重矩阵,精度损失远小于全局量化的 FP8。

import torch

def block_fp8_quantize(weight, block_size=32):
    """
    Block-FP8 量化
    
    weight: [out_features, in_features]
    block_size: 块大小
    """
    out_features, in_features = weight.shape
    
    # 计算需要多少块
    num_blocks_out = (out_features + block_size - 1) // block_size
    num_blocks_in = (in_features + block_size - 1) // block_size
    
    quantized_blocks = []
    scales = []
    
    for i in range(num_blocks_out):
        for j in range(num_blocks_in):
            # 提取块
            block = weight[
                i * block_size : (i + 1) * block_size,
                j * block_size : (j + 1) * block_size
            ]
            
            # 计算块的缩放因子
            scale = block.abs().max() / 448.0  # FP8 E4M3 最大值 ≈ 448
            
            # 量化
            quantized_block = (block / scale).to(torch.float8_e4m3fn)
            
            quantized_blocks.append(quantized_block)
            scales.append(scale)
    
    return quantized_blocks, scales

30.3.1.3 训练稳定性保障

1T 参数训练的最大风险是”跑了一半炸了”。K2 声称实现了”零训练不稳定”(zero training instability),这在开源模型中极为罕见。稳定性的保障来自多个层面:

graph TD
    subgraph "K2 训练稳定性保障"
        S1["MuonClip 优化器<br/>梯度范数裁剪"] 
        S2["FP8 训练<br/>Block-wise 量化"]
        S3["冗余检查点<br/>频繁保存"]
        S4["实时监控<br/>梯度/激活/loss 异常检测"]
        
        S1 --> R["零训练不稳定"]
        S2 --> R
        S3 --> R
        S4 --> R
    end

30.3.2 后训练(Post-training)

K2 提供了两个版本:K2-Base(基座模型)和 K2-Instruct(指令模型)。从 Base 到 Instruct 的训练流程包括:

graph LR
    A["K2-Base<br/>(15.5T tokens 预训练)"] --> B["SFT<br/>监督微调"]
    B --> C["Agent 能力训练<br/>工具调用 + 推理"]
    C --> D["RLHF / DPO<br/>人类偏好对齐"]
    D --> E["K2-Instruct<br/>(开源版本)"]

30.3.2.1 Agent 能力训练

K2-Instruct 的训练重点之一是 Agent 能力——即自主使用工具、推理和解决问题的能力。这解释了 K2 在 Agent 基准上的强劲表现:

Benchmark Kimi K2 Instruct GPT-4.1 Claude 3.7 DeepSeek-V3
SWE-bench Verified 65.8% 54.6% 70.3% 38.8%
LiveCodeBench v6 53.7% 44.2% 56.2% 46.9%
MMLU 89.5 90.2 89.2 88.5
MATH-500 97.4 95.6 96.2 95.8
GPQA-Diamond 75.1 72.0 68.2 71.1

K2 在 SWE-bench 上大幅领先 GPT-4.1(65.8% vs 54.6%),这直接归功于训练数据中大量包含了真实的软件工程任务。

30.3.2.2 Tool Use 优化

K2 的工具调用能力通过专门的训练数据强化。训练流程包括:

  1. 工具描述理解:学会阅读 API 文档并生成正确的调用格式
  2. 多轮工具调用:在对话中多次调用不同工具
  3. 错误恢复:工具调用失败后能自动修正并重试
  4. 结果整合:将多个工具的返回结果整合成连贯的回答

30.4 推理部署实战

K2 的推理部署是本章的重头戏。1T 参数的模型部署绝非易事,但得益于 MoE 架构(32B 激活)和 MLA(极小 KV Cache),实际部署比看起来可行得多。

30.4.1 硬件需求

首先看硬件门槛:

部署方式 最小 GPU 数量 GPU 类型 总显存 备注
vLLM TP 16 H200 (141GB) 2,256 GB 最小部署单元
vLLM TP 16 H20 (96GB) 1,536 GB 国内常见方案
SGLang TP 16 (2 nodes) H200/H20 2,256 GB 多节点
KTransformers 1+ CPU+GPU 混合 灵活 成本最低
Warning

1T 参数的显存需求:即使使用 FP8(每参数 1 字节),模型权重本身就需要约 1 TB 显存。加上 KV Cache、激活值和框架开销,实际需求在 1.2-1.5 TB 之间。这就是为什么最小部署单元需要 16 张 H200(共 2,256 GB)。

30.4.2 vLLM 部署

vLLM 是部署 K2 最直接的方案,需要 v0.10.0rc1 或更高版本。

30.4.2.1 方案一:张量并行(TP ≤ 16)

最简单的部署方式——单节点 16 GPU 张量并行:

# 设置模型路径
export MODEL_PATH="moonshotai/Kimi-K2-Instruct"
# 或本地路径
# export MODEL_PATH="/data/models/Kimi-K2-Instruct"

# 单节点 16 GPU 张量并行
vllm serve $MODEL_PATH \
  --port 8000 \
  --served-model-name kimi-k2 \
  --trust-remote-code \
  --tensor-parallel-size 16 \
  --enable-auto-tool-choice \
  --tool-call-parser kimi_k2 \
  --max-model-len 131072 \
  --gpu-memory-utilization 0.90 \
  --enable-prefix-caching

关键参数说明:

参数 说明
--tensor-parallel-size 16 16 路张量并行
--trust-remote-code - K2 需要自定义代码
--enable-auto-tool-choice - 启用工具调用自动选择
--tool-call-parser kimi_k2 使用 K2 专用工具调用解析器
--max-model-len 131072 128K 上下文
--gpu-memory-utilization 0.90 GPU 显存利用率
--enable-prefix-caching - 前缀缓存加速

30.4.2.2 方案二:数据并行 + 专家并行(DP + EP)

对于需要更高吞吐量的生产环境,数据并行 + 专家并行是更好的选择:

# ============================================================
# Kimi K2: 数据并行 + 专家并行部署(双节点)
# ============================================================

export MODEL_PATH="moonshotai/Kimi-K2-Instruct"
export MASTER_IP="192.168.1.100"  # 主节点 IP
export PORT=29500                  # 通信端口

# ---- Node 0 (GPU 0-7) ----
vllm serve $MODEL_PATH \
  --port 8000 \
  --served-model-name kimi-k2 \
  --trust-remote-code \
  --data-parallel-size 16 \
  --data-parallel-size-local 8 \
  --data-parallel-address $MASTER_IP \
  --data-parallel-rpc-port $PORT \
  --enable-expert-parallel \
  --max-num-batched-tokens 8192 \
  --max-num-seqs 256 \
  --gpu-memory-utilization 0.85 \
  --enable-auto-tool-choice \
  --tool-call-parser kimi_k2

# ---- Node 1 (GPU 0-7) ----
# 在另一台机器上执行(修改 node-rank)
# vllm serve $MODEL_PATH \
#   --port 8000 \
#   --served-model-name kimi-k2 \
#   --trust-remote-code \
#   --data-parallel-size 16 \
#   --data-parallel-size-local 8 \
#   --data-parallel-address $MASTER_IP \
#   --data-parallel-rpc-port $PORT \
#   --enable-expert-parallel \
#   --max-num-batched-tokens 8192 \
#   --max-num-seqs 256 \
#   --gpu-memory-utilization 0.85 \
#   --enable-auto-tool-choice \
#   --tool-call-parser kimi_k2

TP vs DP+EP 的对比:

graph TD
    subgraph "张量并行 (TP=16)"
        TP1["请求"] --> TP2["GPU 0..15<br/>每个 token 都经过<br/>所有 16 个 GPU"]
    end
    
    subgraph "数据并行 + 专家并行 (DP=16, EP)"
        DP1["请求 Batch"] --> DP2["分发到 16 个 DP rank"]
        DP2 --> DP3["每个 rank 独立处理<br/>不同的请求"]
        DP3 --> DP4["MoE 层: 专家<br/>分布在不同 GPU"]
    end

维度 TP=16 DP=16 + EP
延迟 低(单请求并行) 略高
吞吐 中等 (请求级并行)
GPU 通信 高(每层都需 AllReduce) 低(仅 MoE 层通信)
适用场景 低延迟、单请求 高吞吐、生产环境

30.4.2.3 Python 客户端调用

部署完成后,使用 OpenAI 兼容 API 调用:

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8000/v1",
    api_key="dummy"  # vLLM 默认不校验
)

# 基础对话
response = client.chat.completions.create(
    model="kimi-k2",
    messages=[
        {"role": "user", "content": "解释一下 MuonClip 优化器的原理"}
    ],
    max_tokens=2048,
    temperature=0.7
)
print(response.choices[0].message.content)

# 工具调用
response = client.chat.completions.create(
    model="kimi-k2",
    messages=[
        {"role": "user", "content": "北京今天天气怎么样?"}
    ],
    tools=[{
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "获取指定城市的天气",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "城市名称"
                    }
                },
                "required": ["city"]
            }
        }
    }],
    max_tokens=512
)

# 解析工具调用
choice = response.choices[0]
if choice.finish_reason == "tool_calls":
    for tool_call in choice.message.tool_calls:
        print(f"调用工具: {tool_call.function.name}")
        print(f"参数: {tool_call.function.arguments}")

30.4.3 SGLang 部署

SGLang 是另一个支持 K2 的高性能推理框架。相比 vLLM,SGLang 在大规模生产部署方面有一些独特优势,特别是 PD 分离架构。

30.4.3.1 方案一:张量并行(多节点)

# ============================================================
# Kimi K2: SGLang 张量并行部署(双节点)
# ============================================================

export MODEL_PATH="moonshotai/Kimi-K2-Instruct"
export MASTER_IP="192.168.1.100"

# ---- Node 0 ----
python -m sglang.launch_server \
  --model-path $MODEL_PATH \
  --tp 16 \
  --dist-init-addr $MASTER_IP:50000 \
  --nnodes 2 \
  --node-rank 0 \
  --trust-remote-code \
  --tool-call-parser kimi_k2 \
  --port 8000

# ---- Node 1 ----
# python -m sglang.launch_server \
#   --model-path $MODEL_PATH \
#   --tp 16 \
#   --dist-init-addr $MASTER_IP:50000 \
#   --nnodes 2 \
#   --node-rank 1 \
#   --trust-remote-code \
#   --tool-call-parser kimi_k2 \
#   --port 8000

30.4.3.2 方案二:PD 分离大规模部署

PD 分离(Prefill-Decode Disaggregation)是 SGLang 的杀手级特性,特别适合 K2 这种大规模 MoE 模型的生产部署。

核心思想是将 Prefill(首 token 生成)和 Decode(后续 token 生成)分离到不同的 GPU 集群:

graph LR
    subgraph "Prefill 集群 (4 节点)"
        P1["32 TP + 32 DP<br/>enable-dp-attention<br/>DeepEP MoE All-to-All"]
    end
    
    subgraph "PD Load Balancer"
        LB["KV Cache 传输<br/>请求路由"]
    end
    
    subgraph "Decode 集群 (12 节点)"
        D1["96 TP + 96 DP<br/>low_latency 模式<br/>连续批处理"]
    end
    
    P1 -->|"KV Cache"| LB
    LB --> D1

4P12D H200 架构详解

集群 节点数 GPU 并行策略 优化模式
Prefill 4 32×H200 TP=32, DP=32 DeepEP MoE All-to-All
Decode 12 96×H200 TP=96, DP=96 low_latency

为什么 Prefill 和 Decode 要分离?

特性 Prefill Decode
计算密度 高(矩阵-矩阵乘) 低(矩阵-向量乘)
Batch 友好度 差(需要 continuous batching)
GPU 利用率 低(memory-bound)
最优配置 大 batch,高 TP 小 batch,低延迟

PD 分离让每个阶段使用最优的配置,避免了在同一个集群上做取舍。

# ============================================================
# Kimi K2: SGLang PD 分离部署(示例配置)
# ============================================================

# ---- Prefill 节点 (4 节点) ----
python -m sglang.launch_server \
  --model-path $MODEL_PATH \
  --tp 32 \
  --dist-init-addr $MASTER_IP:50000 \
  --nnodes 4 \
  --node-rank $NODE_RANK \
  --trust-remote-code \
  --enable-dp-attention \
  --enable-deep-ep-moe \
  --schedule-conservativeness 0.5 \
  --port 8000

# ---- Decode 节点 (12 节点) ----
python -m sglang.launch_server \
  --model-path $MODEL_PATH \
  --tp 96 \
  --dist-init-addr $DECODE_MASTER_IP:50001 \
  --nnodes 12 \
  --node-rank $NODE_RANK \
  --trust-remote-code \
  --low-latency \
  --schedule-conservativeness 0.3 \
  --port 8000
Tip

PD 分离的适用场景:这种架构专为超大规模生产环境设计(16 节点 = 128 GPU)。如果你只需要在单节点上跑 K2,使用 vLLM 的 TP 方案更简单。PD 分离的优势在于高 QPS 场景——当并发请求量达到数百甚至数千时,它比 TP 方案的吞吐量高出数倍。

30.4.4 KTransformers 部署(CPU + GPU 混合)

KTransformers 是一种创新的部署方案,它将模型的计算分散到 CPU 和 GPU 上——MoE 专家存储在 CPU 内存(DDR)中,Attention 和激活的专家在 GPU 上计算。这使得在有限的 GPU 资源下运行 1T 参数模型成为可能。

graph TD
    subgraph "KTransformers 架构"
        A["Input Token"] --> B{"Layer Type"}
        B -->|"Attention (MLA)"| C["GPU<br/>快速计算"]
        B -->|"MoE Expert"| D{"专家选择"}
        D -->|"激活的 8 个专家"| E["GPU<br/>加载并计算"]
        D -->|"未激活的 376 个专家"| F["CPU DDR<br/>存储(不计算)"]
        C --> G["Output"]
        E --> G
    end

# ============================================================
# Kimi K2: KTransformers 部署
# ============================================================

# 安装 KTransformers
pip install ktransformers

# 下载 GGUF 格式的 K2 模型权重
# huggingface-cli download moonshotai/Kimi-K2-Instruct-GGUF \
#   --local-dir /data/models/Kimi-K2-GGUF

# 启动服务
python ktransformers/server/main.py \
  --model_path /data/models/Kimi-K2-Instruct \
  --gguf_path /data/models/Kimi-K2-GGUF \
  --cache_lens 30000 \
  --port 8000

关键参数:

参数 说明 推荐值
--cache_lens KV Cache 长度 30000(根据内存调整)
--model_path 原始模型路径(HF 格式) -
--gguf_path GGUF 量化权重路径 -

30.4.4.1 AMX 优化

对于使用 Intel Xeon 处理器的服务器,KTransformers 支持 AMX(Advanced Matrix Extensions)指令集加速 CPU 端的矩阵运算:

# 检查 CPU 是否支持 AMX
lscpu | grep amx

# 如果支持,KTransformers 会自动启用 AMX 优化
# MoE 专家的 FP8 矩阵乘法通过 AMX 加速
硬件配置 推理速度 (tok/s) 适用场景
1×H100 + 512GB DDR5 + AMX ~15-20 开发测试
2×H100 + 1TB DDR5 + AMX ~25-35 小规模服务
8×H100 + 2TB DDR5 ~50-80 中等规模
Note

KTransformers 的核心价值:它让没有 16 张 H200 的团队也能运行 K2。代价是推理速度较慢(CPU 内存带宽是瓶颈),但对于开发、测试或低 QPS 场景来说已经足够。配合 AMX 优化,性能可以接受。

30.4.5 TensorRT-LLM 部署

TensorRT-LLM 是 NVIDIA 官方的高性能推理框架,支持 K2 的多节点推理和专家并行。

# ============================================================
# Kimi K2: TensorRT-LLM 部署
# ============================================================

# 需要 TensorRT-LLM v1.0.0-rc2 或更高版本
pip install tensorrt-llm>=1.0.0rc2

# Step 1: 转换模型权重为 TensorRT 引擎
python convert_checkpoint.py \
  --model_dir /data/models/Kimi-K2-Instruct \
  --output_dir /data/models/K2-engine \
  --dtype fp8 \
  --world_size 16 \
  --tp_size 16 \
  --moe_tp_size 16

# Step 2: 多节点启动推理服务
# Node 0
mpirun -np 16 \
  --hostfile hostfile \
  python run_engine.py \
  --engine_dir /data/models/K2-engine \
  --port 8000

hostfile 示例:

# hostfile
node01 slots=8
node02 slots=8

TensorRT-LLM 支持 EP(专家并行)模式,将 384 个专家分布到不同 GPU 上:

# 使用专家并行
python convert_checkpoint.py \
  --model_dir /data/models/Kimi-K2-Instruct \
  --output_dir /data/models/K2-engine-ep \
  --dtype fp8 \
  --world_size 16 \
  --tp_size 8 \
  --moe_tp_size 2 \
  --moe_ep_size 8

30.4.6 部署方案对比

方案 最小 GPU 吞吐 延迟 易用性 适用场景
vLLM TP 16×H200 ★★★ ★★★★★ ★★★★★ 快速验证、低延迟
vLLM DP+EP 16×H200 ★★★★★ ★★★ ★★★★ 生产环境
SGLang TP 16×H200 ★★★ ★★★★ ★★★★ 多节点部署
SGLang PD 128×H200 ★★★★★ ★★★★★ ★★ 超大规模生产
KTransformers 1×GPU + CPU ★★ ★★★ 开发测试、低成本
TensorRT-LLM 16×H200 ★★★★ ★★★★ ★★★ NVIDIA 生态深度优化

30.5 Agent 能力与工具调用

30.5.1 Tool Calling 最佳实践

K2 是为 Agent 场景特别优化的模型。它的工具调用能力不需要额外的 prompt 工程——只需配置正确的 tool-call-parser

30.5.1.1 工具调用流程

sequenceDiagram
    participant U as 用户
    participant M as Kimi K2
    participant T as 工具/API

    U->>M: "帮我查一下北京的天气"
    M->>M: 分析意图,匹配可用工具
    M->>T: 调用 get_weather(city="北京")
    T-->>M: {"temp": 32, "condition": "晴"}
    M->>M: 整合工具返回结果
    M-->>U: "北京今天 32°C,晴天。"

30.5.1.2 多工具编排示例

from openai import OpenAI
import json

client = OpenAI(base_url="http://localhost:8000/v1", api_key="dummy")

# 定义多个工具
tools = [
    {
        "type": "function",
        "function": {
            "name": "search_docs",
            "description": "搜索技术文档",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {"type": "string", "description": "搜索关键词"},
                    "source": {"type": "string", "enum": ["github", "arxiv", "web"]}
                },
                "required": ["query"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "write_file",
            "description": "写入文件",
            "parameters": {
                "type": "object",
                "properties": {
                    "path": {"type": "string", "description": "文件路径"},
                    "content": {"type": "string", "description": "文件内容"}
                },
                "required": ["path", "content"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "run_command",
            "description": "执行 shell 命令",
            "parameters": {
                "type": "object",
                "properties": {
                    "command": {"type": "string", "description": "要执行的命令"}
                },
                "required": ["command"]
            }
        }
    }
]

# 模拟工具执行
def execute_tool(name, args):
    if name == "search_docs":
        return f"找到 3 篇关于 '{args.get('query')}' 的文档..."
    elif name == "write_file":
        return f"已写入文件: {args.get('path')}"
    elif name == "run_command":
        return f"命令输出: success"
    return "unknown tool"

# 多轮工具调用
messages = [
    {"role": "system", "content": "你是一个编程助手,可以搜索文档、写文件和执行命令。"},
    {"role": "user", "content": "帮我搜索 MuonClip 优化器的资料,然后整理成一个笔记文件。"}
]

print("=== Kimi K2 Agent 多工具调用演示 ===\n")

for step in range(5):  # 最多 5 轮工具调用
    response = client.chat.completions.create(
        model="kimi-k2",
        messages=messages,
        tools=tools,
        max_tokens=1024
    )
    
    msg = response.choices[0].message
    
    if response.choices[0].finish_reason == "tool_calls":
        # 模型要调用工具
        messages.append(msg.model_dump())
        for tool_call in msg.tool_calls:
            func_name = tool_call.function.name
            func_args = json.loads(tool_call.function.arguments)
            print(f"[Step {step+1}] 调用: {func_name}({func_args})")
            
            result = execute_tool(func_name, func_args)
            print(f"[Step {step+1}] 结果: {result}")
            
            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": result
            })
    else:
        # 模型给出最终回答
        print(f"\n[最终回答]\n{msg.content}")
        break

30.5.2 SWE-bench 实战

SWE-bench Verified 是评估模型自主解决真实 GitHub Issue 能力的基准。K2 在这个基准上取得了 65.8%(单次尝试)的成绩,远超 GPT-4.1(54.6%)。

30.5.2.1 SWE-bench 评测流程

graph TD
    A["GitHub Issue"] --> B["K2 分析问题"]
    B --> C["定位相关代码文件"]
    C --> D["生成修复补丁"]
    D --> E{"测试通过?"}
    E -->|"是"| F["✅ 解决"]
    E -->|"否"| G["分析测试失败"]
    G --> D

30.5.2.2 65.8% → 71.6%:多次尝试策略

K2 在多次尝试(best-of-N)下可以达到 71.6%:

# SWE-bench 多次尝试策略

def solve_issue_with_retry(issue, repo_path, max_attempts=5):
    """
    使用 Kimi K2 解决 GitHub Issue
    多次尝试策略可提升成功率从 65.8% 到 71.6%
    """
    attempts = []
    
    for attempt in range(max_attempts):
        # 生成候选修复
        patch = k2_generate_patch(
            issue=issue,
            repo_path=repo_path,
            previous_failures=attempts,  # 让模型看到之前的失败
            temperature=0.7 + attempt * 0.1  # 逐步增加随机性
        )
        
        # 运行测试
        test_result = run_tests(repo_path, patch)
        
        if test_result.passed:
            return patch, attempt + 1
        
        attempts.append({
            "patch": patch,
            "failure": test_result.failure_info
        })
    
    return None, max_attempts  # 所有尝试均失败

30.5.2.3 Agentic Coding 最佳实践

基于 K2 的 Agent 能力,以下是构建 Agentic Coding 系统的最佳实践:

  1. 提供充分的上下文:K2 能处理 128K 上下文,把完整的项目结构、相关文件和错误日志都给它
  2. 使用工具链:让 K2 通过工具调用访问文件系统、运行命令、搜索代码
  3. 多轮迭代:不要期望一次性解决复杂问题——让模型看到测试结果并迭代
  4. 温度策略:首次尝试用低温度(0.2-0.4)保证确定性,重试时逐步提高
# Agentic Coding 系统示例
class K2CodingAgent:
    def __init__(self, vllm_url, repo_path):
        self.client = OpenAI(base_url=f"{vllm_url}/v1", api_key="dummy")
        self.repo_path = repo_path
        
        self.tools = [
            {"type": "function", "function": {
                "name": "read_file",
                "description": "读取项目中的文件",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "path": {"type": "string"}
                    },
                    "required": ["path"]
                }
            }},
            {"type": "function", "function": {
                "name": "list_files",
                "description": "列出目录中的文件",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "path": {"type": "string", "default": "."}
                    }
                }
            }},
            {"type": "function", "function": {
                "name": "run_tests",
                "description": "运行项目测试",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "pattern": {"type": "string", "description": "测试文件模式"}
                    }
                }
            }}
        ]
    
    def solve_issue(self, issue_description):
        """自动解决 GitHub Issue"""
        messages = [
            {"role": "system", "content": f"""你是一个资深软件工程师。
项目路径: {self.repo_path}
请分析以下 Issue 并生成修复补丁。

Issue:
{issue_description}

请按以下步骤操作:
1. 阅读相关代码
2. 理解问题根因
3. 生成修复补丁
4. 运行测试验证"""},
            {"role": "user", "content": "请开始修复。"}
        ]
        
        for _ in range(20):  # 最多 20 轮工具调用
            response = self.client.chat.completions.create(
                model="kimi-k2",
                messages=messages,
                tools=self.tools,
                max_tokens=2048
            )
            msg = response.choices[0].message
            
            if response.choices[0].finish_reason != "tool_calls":
                return msg.content  # 返回最终修复说明
            
            messages.append(msg.model_dump())
            for tc in msg.tool_calls or []:
                result = self._execute(tc.function.name, 
                                       json.loads(tc.function.arguments))
                messages.append({"role": "tool", "tool_call_id": tc.id, "content": result})
        
        return "超出最大迭代次数"

30.6 Kimi 模型演进路线

K2 只是 Kimi 系列的一个起点。自 K2 开源以来,月之暗面快速迭代了多个版本:

30.6.1 各版本详解

graph LR
    K2["Kimi K2<br/>2025-07<br/>1T MoE, 128K"]
    K25["Kimi K2.5<br/>多模态 SoTA<br/>视觉+文本, 256K"]
    K26["Kimi K2.6<br/>通用模型<br/>思考/非思考, 256K"]
    K27["Kimi K2.7 Code<br/>专用编码<br/>高速模式, 256K"]
    K3["Kimi K3<br/>旗舰模型<br/>2.8T, 1M 上下文"]
    
    K2 --> K25 --> K26 --> K27 --> K3

版本 发布时间 参数规模 上下文 核心特性
K2 2025-07 1T MoE(激活 32B) 128K 开源 MoE 基座 + Agent 能力
K2.5 2025-09 - 256K 多模态(视觉+文本),开源 SoTA
K2.6 2025-10 - 256K 思考/非思考双模式
K2.7 Code 2025-10 - 256K 专用编码模型,高速模式
K3 2025-11 2.8T MoE(激活 104B) 1M KDA 架构 + MXFP4 量化 + 原生视觉 + 编程 Agent 优化

30.6.2 K3 架构创新:从 MLA 到 KDA

K3 是 Kimi 系列的最新旗舰模型,2.8T 参数、104B 激活、1M 上下文。但真正让 K3 脱颖而出的不是规模——而是从底层 Attention 机制到训练范式的全面重构。K2 复用了 DeepSeek-V3 的 MLA 架构,K3 则彻底打破了这一路径依赖,用一套全新的技术栈定义了万亿参数模型的新范式。

先看 K3 的完整架构规格:

参数 与 K2 对比
总参数 2.8T 2.8× (K2: 1T)
激活参数 104B 3.25× (K2: 32B)
层数 93(含 1 层 Dense) 1.52× (K2: 61)
Attention 层组成 69 KDA + 24 Gated MLA 全新 (K2: 全 MLA)
Attention Hidden Dim 7168 相同
Attention Heads 96 1.5× (K2: 64)
Latent MoE Dim 3584 1.5× (K2: 7168 → 2048/expert)
MoE Hidden Dim (per Expert) 3072 1.5× (K2: 2048)
专家总数 896 2.33× (K2: 384)
每 Token 选择专家 16 2× (K2: 8)
共享专家 2 2× (K2: 1)
词表 160K 相同
上下文长度 1,048,576 (1M) (K2: 128K)
Attention 机制 KDA & Gated MLA 全新 (K2: MLA)
激活函数 SiTU-GLU 新设计 (K2: SwiGLU)
视觉编码器 MoonViT-V2 (401M) 新增 (K2: 无)
量化 MXFP4 权重 / MXFP8 激活 原生 QAT (K2: Block-FP8)
模态 文本 + 图像 多模态 (K2: 纯文本)

30.6.2.1 Kimi Delta Attention (KDA):取代 MLA 的新架构

K2 和 DeepSeek-V3 使用的 MLA(Multi-head Latent Attention)通过低秩压缩 KV Cache 解决了长上下文的显存瓶颈。但 MLA 在扩展到万亿参数级别时面临两个挑战:一是压缩后的 latent dimension 仍随层数线性增长,二是 prefix caching 的粒度受限于压缩表示。

K3 团队提出了 Kimi Delta Attention (KDA)——一种全新的 Attention 机制,专为超大规模模型设计:

graph TD
    subgraph "K2: MLA (全层)"
        A1["Hidden State<br/>dim=7168"] --> B1["W_DKV → 低秩压缩<br/>latent_dim ≪ 7168"]
        B1 --> C1["缓存 c_KV"]
        C1 --> D1["推理时恢复 K, V"]
        D1 --> E1["标准 Attention"]
    end

    subgraph "K3: KDA (69层) + Gated MLA (24层)"
        A2["Hidden State<br/>dim=7168"] --> B2["Delta Attention<br/>计算相邻层的增量"]
        B2 --> C2["仅缓存 Delta"]
        C2 --> D2["选择性检索 + AttnRes"]
        D2 --> E2["高效 Attention"]
    end

    B1 -.->|"K2 路径"| E1
    B2 -.->|"K3 新路径"| E2

KDA 的核心思想是增量注意力(Delta Attention):不直接计算完整的 attention matrix,而是计算相邻层之间的注意力增量。这带来三个优势:

  1. KV Cache 进一步压缩:只存储增量而非完整 KV,缓存大小几乎不随层数增长
  2. 扩展注意力范围:KDA 天然支持跨层信息检索,不受局部窗口限制
  3. Prefix Caching 友好:增量表示使得 prefix cache 的粒度更灵活
Note

KDA 对 Prefix Caching 的挑战与贡献

KDA 的增量计算方式改变了 prefix caching 的访问模式——传统的 MLA prefix cache 是按层独立存储的,而 KDA 需要跨层一致性。K3 团队为 vLLM 社区贡献了 KDA 的 prefix caching 实现,使得 KDA 的优势能真正落地到推理引擎中。

30.6.2.2 Attention Residuals (AttnRes):跨深度信息检索

与 KDA 配套的是 Attention Residuals (AttnRes) 机制。传统的残差连接是均匀地将信息从浅层传递到深层:

# 传统残差连接(K2 / DeepSeek-V3)
h = h + attention(layer_norm(h))  # 每层都加一个残差

问题在于:并非所有层的信息对所有深度都同等重要。AttnRes 让模型选择性地检索不同深度的表征,而非均匀累积:

# Attention Residuals 概念示意(K3)
def attn_res_forward(self, h, depth_idx):
    """
    AttnRes: 不是简单地将当前层输出加到残差流,
    而是选择性检索之前各层的表征
    """
    # 标准 attention 计算
    attn_out = self.attention(self.layer_norm(h))

    # AttnRes: 根据深度选择性地融合历史表征
    # 浅层(0-30):更依赖局部信息,AttnRes 权重集中在前几层
    # 中层(31-60):开始检索更远层的信息
    # 深层(61-92):广泛检索全模型的信息
    if depth_idx < 30:
        # 浅层:标准残差 + 少量跨层
        h = h + attn_out
    elif depth_idx < 60:
        # 中层:选择性检索
        h = h + attn_out + self.cross_layer_gate(h, depths=[depth_idx-5, depth_idx-10])
    else:
        # 深层:广泛检索
        h = h + attn_out + self.cross_layer_gate(h, depths=[0, depth_idx//2, depth_idx-3])
    return h

AttnRes 与 KDA 的组合构成了 K3 的架构骨干——一个为万亿参数以上规模设计的注意力系统。

30.6.2.3 69 KDA + 24 Gated MLA 的混合策略

K3 没有全部使用 KDA,而是采用了 69 层 KDA + 24 层 Gated MLA 的混合架构:

graph LR
    subgraph "K3 的 93 层结构"
        L0["Layer 0<br/>Dense"] --> L1["Layer 1-23<br/>24× Gated MLA<br/>+ SiTU-GLU MoE"]
        L1 --> L2["Layer 24-92<br/>69× KDA<br/>+ AttnRes + SiTU-GLU MoE"]
    end

    style L0 fill:#e1f5fe
    style L1 fill:#fff3e0
    style L2 fill:#e8f5e9

为什么是这种混合设计?

  • 前 24 层(Gated MLA):浅层需要稳定的、全面的 attention pattern,Gated MLA 提供了经过验证的、稳定的基础表征学习
  • 后 69 层(KDA):深层需要更高效的跨层信息检索和更紧凑的 KV Cache,KDA 的优势在这里充分发挥
  • Gated MLA 的 Gate 机制:在 MLA 的基础上增加了门控,改善了注意力的选择性——模型可以学会”忽略”不相关的上下文

这种设计是工程务实主义的体现:不在所有地方都用新技术,而是在经过验证的地方保持稳定,在需要突破的地方大胆创新。

30.6.3 Stable LatentMoE:896 专家的稀疏路由

K3 的 MoE 层从 K2 的 384 专家跃升到 896 专家——这是目前开源模型中最大的专家池。但更大的专家池意味着更严峻的路由稳定性挑战。K3 用两项技术创新解决了这个问题。

30.6.3.1 896 专家 / 16 激活的路由设计

graph TD
    subgraph "K3 MoE Layer"
        A["Input Hidden State<br/>dim=7168"] --> B["Router / Gate"]
        B --> C["Top-16 Selection<br/>从 896 个专家中选 16 个"]
        B --> D["Shared Expert × 2<br/>(always active)"]

        C --> E1["Expert 1<br/>7168→3072→7168"]
        C --> E2["Expert 2<br/>7168→3072→7168"]
        C --> E3["...×16..."]
        C --> E16["Expert 16<br/>7168→3072→7168"]

        E1 --> F["加权求和"]
        E2 --> F
        E16 --> F
        D --> F

        F --> G["Output Hidden State<br/>dim=7168"]
    end

与 K2 的对比:

维度 Kimi K2 Kimi K3 提升
专家总数 384 896 2.33×
激活专家 8 16
共享专家 1 2
专家隐藏维度 2048 3072 1.5×
专家利用率 2.1% (8/384) 1.8% (16/896) 更稀疏
总参数 1T 2.8T 2.8×
激活参数 32B 104B 3.25×
扩展效率 基线 ~2.5×
Tip

扩展效率 2.5× 是什么意思?

K3 的总参数是 K2 的 2.8 倍,但激活参数只有 3.25 倍。“扩展效率”指的是:每增加 1 单位激活计算量,获得的模型容量提升。K3 用 3.25× 的计算量获得了 2.8× 的参数——接近线性扩展。这意味着 K3 的架构设计几乎没有”浪费”计算资源。

30.6.3.2 Quantile Balancing:从分位数推导路由

896 个专家的负载均衡是一个前所未有的挑战。K2 使用传统的辅助损失(auxiliary loss)方法来均衡 384 个专家的负载。但当专家数量翻倍以上时,辅助损失方法面临两个严重问题:

  1. 超参数敏感:辅助损失的权重需要精细调优,在 896 专家规模下几乎无法手动调整
  2. 启发式更新不稳定:传统的 Expert Choice 路由依赖启发式的 bias 更新,在超大规模下容易震荡

K3 提出了 Quantile Balancing——一种全新的路由均衡方法:

import torch
import torch.nn.functional as F

def quantile_balancing_route(
    router_logits,   # [N, num_experts] router 输出
    num_experts=896,
    top_k=16,
    target_quantile=0.5  # 目标分位数
):
    """
    Quantile Balancing 路由

    核心思想:从 router-score 的分位数直接推导专家分配,
    而非依赖启发式 bias 更新。
    """
    N = router_logits.shape[0]

    # Step 1: 计算 router scores
    scores = F.softmax(router_logits, dim=-1)  # [N, 896]

    # Step 2: 计算每个专家的 score 分布的分位数
    # 不用均值(容易被极端值拉偏),而用分位数
    expert_scores = scores.T  # [896, N]
    expert_quantiles = torch.quantile(
        expert_scores, target_quantile, dim=1
    )  # [896]

    # Step 3: 基于分位数计算平衡 bias
    # 目标:让所有专家的分位数 score 尽可能接近
    mean_quantile = expert_quantiles.mean()
    balance_bias = mean_quantile - expert_quantiles  # [896]
    # score 偏低的专家获得正 bias,偏高的获得负 bias

    # Step 4: 应用 bias 后做 Top-K 选择
    adjusted_scores = scores + balance_bias.unsqueeze(0)
    topk_scores, topk_indices = torch.topk(
        adjusted_scores, top_k, dim=-1
    )

    # Step 5: 重归一化
    topk_scores = topk_scores / topk_scores.sum(dim=-1, keepdim=True)

    return topk_indices, topk_scores

Quantile Balancing 的关键优势:

特性 传统辅助损失 Quantile Balancing
超参数 需要调权重(敏感) 零超参数
更新方式 启发式 bias 更新 分位数直接推导
大规模稳定性 896 专家时震荡 稳定收敛
计算开销 额外 loss 计算 轻量分位数计算
Important

Quantile Balancing 的意义超越 K3。随着 MoE 成为大模型的标配,专家数量从 256 → 384 → 896 持续增长,传统的负载均衡方法已经触及天花板。Quantile Balancing 提供了一个无需超参数调优的解决方案,这可能成为未来大规模 MoE 路由的标准方法。

30.6.4 Per-Head Muon 与 SiTU:训练稳定性新范式

将优化器扩展到 2.8T 参数面临的是比 K2(1T)严峻得多的挑战。K3 的训练稳定性由三件套保障:Per-Head MuonSiTU 激活函数Quantile Balancing

30.6.4.1 Per-Head Muon:独立优化每个注意力头

K2 的 MuonClip 是对整个梯度矩阵做正交化。但当模型扩展到 93 层、96 个注意力头时,不同 head 承担的功能差异巨大——有的 head 关注局部语法,有的 head 跟踪长距离依赖。对它们用同一套优化参数显然不合理。

Per-Head Muon 的核心改进:为每个注意力头维护独立的动量缓冲和正交化参数

import torch
import torch.nn as nn

class PerHeadMuon:
    """
    Per-Head Muon 优化器
    为每个注意力头维护独立的优化状态
    """
    def __init__(
        self,
        params,
        num_heads=96,
        lr=0.02,
        beta=0.95,
        max_norm=1.0
    ):
        self.num_heads = num_heads
        self.lr = lr
        self.beta = beta
        self.max_norm = max_norm

        # 为每个 head 创建独立的动量缓冲
        self.momentum_buffers = {}
        for name, p in params:
            if 'attention' in name and len(p.shape) >= 2:
                # 将参数按 head 数量分割
                head_dim = p.shape[0] // num_heads
                self.momentum_buffers[name] = [
                    torch.zeros_like(p[i*head_dim:(i+1)*head_dim])
                    for i in range(num_heads)
                ]
            else:
                # 非 attention 参数使用标准 Muon
                self.momentum_buffers[name] = torch.zeros_like(p)

    def step(self, params_grads):
        for (name, p), grad in params_grads:
            if name in self.momentum_buffers and isinstance(
                self.momentum_buffers[name], list
            ):
                # Per-Head 优化
                head_dim = p.shape[0] // self.num_heads
                for h in range(self.num_heads):
                    g_h = grad[h*head_dim:(h+1)*head_dim]
                    m_h = self.momentum_buffers[name][h]

                    # 范数裁剪(Clip)
                    norm = torch.norm(g_h, p='fro')
                    if norm > self.max_norm:
                        g_h = g_h * (self.max_norm / norm)

                    # 动量更新
                    m_h.mul_(self.beta).add_(g_h, alpha=1 - self.beta)

                    # Newton-Schulz 正交化
                    orth = newton_schulz(m_h)

                    # 参数更新
                    with torch.no_grad():
                        p[h*head_dim:(h+1)*head_dim].sub_(self.lr * orth)
            else:
                # 标准Muon
                buf = self.momentum_buffers[name]
                buf.mul_(self.beta).add_(grad, alpha=1 - self.beta)
                orth = newton_schulz(buf)
                with torch.no_grad():
                    p.sub_(self.lr * orth)


def newton_schulz(G, steps=5):
    """Newton-Schulz 正交化(同 K2)"""
    a, b, c = (3.4445, -4.7750, 2.0315)
    X = G.bfloat16()
    if G.shape[0] > G.shape[1]:
        X = X.T
    for _ in range(steps):
        A = X @ X.T
        B = b * A + c * (A @ A)
        X = a * X + B @ X
    return X

Per-Head Muon 的优势在于:不同 head 可以以不同的有效学习率收敛。关注局部语法的 head 可能需要更大的步长,而跟踪长距离依赖的 head 可能需要更精细的更新。这在 2.8T 规模下实现了更自适应的训练。

30.6.4.2 SiTU:新世代激活函数

K2 使用 SwiGLU 作为 MoE 专家的激活函数。K3 提出了 SiTU(Sigmoid Tanh Unit)——一种结合 Sigmoid 和 Tanh 的新型激活函数:

import torch.nn.functional as F

def situ_glufn(x, w_gate, w_up, w_down):
    """
    SiTU-GLU 激活函数(K3 MoE 专家使用)

    对比 K2 的 SwiGLU:
      SwiGLU: (x @ w_gate) * SiLU(x @ w_up) @ w_down
      SiTU-GLU: (x @ w_gate) * SiTU(x @ w_up) @ w_down

    SiTU(x) = sigmoid(x) * tanh(x)
    SiLU(x) = x * sigmoid(x)
    """
    gate = x @ w_gate
    up = x @ w_up

    # SiTU: sigmoid * tanh
    activated = torch.sigmoid(up) * torch.tanh(up)

    return (gate * activated) @ w_down

SiTU 相比 SwiGLU 的优势:

特性 SwiGLU (K2) SiTU-GLU (K3)
有界性 无界(x·σ(x)) 有界(tanh 限制在 [-1,1])
梯度饱和 可能梯度爆炸 梯度有界
激活稀疏性 中等 更高(负值区域更接近 0)
训练稳定性 良好 更好(尤其超大规模)

SiTU 的有界性是关键——在 2.8T 参数的深度网络中,无界激活容易导致中间层激活值爆炸。SiTU 从数学上保证了激活值的范围,为训练稳定性提供了基础保障。

30.6.4.3 三件套协同:2.8T 参数的稳定训练

graph TD
    subgraph "K3 训练稳定性三件套"
        A["Per-Head Muon<br/>独立优化每个 head<br/>更自适应的学习"]
        B["SiTU-GLU<br/>有界激活函数<br/>防止激活爆炸"]
        C["Quantile Balancing<br/>零超参数路由均衡<br/>896 专家稳定收敛"]

        A --> D["2.8T 参数<br/>零训练不稳定"]
        B --> D
        C --> D
    end

这三个创新分别解决不同层面的稳定性问题: - Per-Head Muon:解决优化层面的稳定性(不同 head 的梯度差异) - SiTU:解决前向传播层面的稳定性(激活值有界) - Quantile Balancing:解决路由层面的稳定性(专家负载均衡)

三者协同,使 K3 在 2.8T 参数规模上实现了与 K2 同等的训练稳定性——这是一个工程奇迹。

30.6.5 MXFP4 原生量化训练

K2 使用 Block-FP8 格式存储权重。K3 更进一步:从 SFT 阶段开始就使用 MXFP4 量化感知训练(QAT),将权重精度压缩到 4-bit——这是目前大规模模型中最激进的量化方案。

30.6.5.1 MXFP4 vs FP8 vs INT4

量化方案 权重位宽 激活精度 训练方式 硬件兼容性
Block-FP8 (K2) 8-bit FP8/BF16 后训练量化 NVIDIA
MXFP4 (K3) 4-bit MXFP8 量化感知训练 (QAT) NVIDIA + AMD
INT4 (常见) 4-bit FP16 后训练量化 有限
GGUF Q4 4-bit - 推理时量化 CPU 为主

MXFP4(Microscaling FP4)的核心思想是将权重分成小块(通常 32 个元素一组),每组共享一个缩放因子,块内元素仅用 4 bit 表示:

import torch
import struct

def mxfp4_quantize(weight, block_size=32):
    """
    MXFP4 量化

    weight: [out_features, in_features] FP16/BF16 权重
    block_size: 每组的元素数量

    MXFP4 格式:
      - 每 block_size 个元素共享 1 个 FP8 scale
      - 每个元素用 4 bit 存储(FP4: 1 sign + 2 mantissa + 1 exp)
      - 压缩比: 16/4 = 4× 相比 FP16
    """
    out_features, in_features = weight.shape
    weight_flat = weight.reshape(-1)
    num_elements = weight_flat.numel()
    num_blocks = (num_elements + block_size - 1) // block_size

    quantized = []
    scales = []

    for i in range(num_blocks):
        start = i * block_size
        end = min(start + block_size, num_elements)
        block = weight_flat[start:end]

        # 计算块的缩放因子(用 FP8 表示)
        max_val = block.abs().max()
        # FP4 E2M1 的最大值约为 6.0
        scale = (max_val / 6.0).to(torch.float8_e5m2)

        # 量化到 FP4
        # FP4 E2M1: {0, 0.5, 1, 1.5, 2, 3, 4, 6} × sign
        fp4_levels = torch.tensor(
            [0.0, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0],
            device=block.device
        )
        normalized = block / scale.to(torch.float32)
        # 找到最近的 FP4 level
        signs = torch.sign(normalized)
        abs_vals = normalized.abs()
        indices = torch.argmin(
            (abs_vals.unsqueeze(-1) - fp4_levels).abs(), dim=-1
        )
        quantized_block = signs * fp4_levels[indices]

        quantized.append(quantized_block)
        scales.append(scale)

    return (
        torch.cat(quantized).reshape(out_features, in_features),
        torch.tensor(scales)
    )

# 压缩比计算
# FP16: 16 bit/element
# MXFP4: 4 bit/element + 8 bit/32 elements (scale) = 4.25 bit/element
# 压缩比: 16 / 4.25 ≈ 3.76×
print("MXFP4 权重压缩比: ~3.76× vs FP16")
print("MXFP4 权重压缩比: ~1.88× vs FP8")
# K3: 2.8T params × 4.25 bit ≈ 1.49 TB
# vs FP8: 2.8T × 8 bit = 2.8 TB
# 节省约 48% 的权重存储!

30.6.5.2 量化感知训练(QAT)流程

K3 的 MXFP4 不是推理时的事后量化,而是从 SFT 阶段就开始的量化感知训练:

graph LR
    A["预训练<br/>BF16 精度"] --> B["SFT 阶段<br/>开始 MXFP4 QAT"]
    B --> C["RLHF/DPO<br/>MXFP4 权重 + MXFP8 激活"]
    C --> D["最终模型<br/>原生 MXFP4"]

这意味着模型在训练过程中就已经”学会”了在 4-bit 权重下表现良好——相比推理时量化(PTQ),QAT 能显著减少精度损失。

30.6.5.3 硬件兼容性:NVIDIA + AMD

MXFP4 的一个关键优势是广泛的硬件支持:

# ============================================================
# K3 MXFP4 部署:NVIDIA 和 AMD 均支持
# ============================================================

# NVIDIA 方案(vLLM)
docker run --gpus all \
  vllm/vllm-openai:kimi-k3 \
  --model moonshotai/Kimi-K3 \
  --quantization mxfp4 \
  --tensor-parallel-size 8

# AMD 方案(vLLM ROCm)
docker run --device /dev/kfd --device /dev/dri \
  vllm/vllm-openai_rocm:kimi-k3 \
  --model moonshotai/Kimi-K3 \
  --quantization mxfp4 \
  --tensor-parallel-size 8
Note

MXFP4 的战略意义:K3 的 MXFP4 QAT 不只是技术选择——它是一种”硬件民主化”策略。通过确保 AMD GPU 同等支持 K3 的量化格式,月之暗面降低了对 NVIDIA 生态的依赖。这在 GPU 供给紧张的环境下具有重要的商业价值。

30.6.6 K3 部署实战

K3 的部署比 K2 更灵活——虽然模型大了 2.8 倍,但 MXFP4 量化使得实际显存需求大幅降低,且同时支持 NVIDIA 和 AMD 硬件。

30.6.6.1 vLLM 部署(推荐)

vLLM 是部署 K3 的首选方案。K3 需要 vLLM 0.27.0 或更高版本,官方提供了专用的 Docker 镜像:

# ============================================================
# Kimi K3: vLLM 部署(TP8 方案 — 单节点 8×GB300)
# ============================================================

# 方案 1: 张量并行(TP=8),适合低延迟场景
docker run --gpus all --shm-size 16g \
  -p 8000:8000 \
  -v /data/models:/models \
  -e VLLM_USE_V2_MODEL_RUNNER=1 \
  -e VLLM_USE_RUST_FRONTEND=1 \
  vllm/vllm-openai:kimi-k3 \
  --model moonshotai/Kimi-K3 \
  --served-model-name kimi-k3 \
  --tensor-parallel-size 8 \
  --quantization mxfp4 \
  --max-model-len 1048576 \
  --enable-prefix-caching \
  --all2all-backend deepep_v2 \
  --moe-backend deep_gemm_mega_moe

# 方案 2: 专家并行 + 张量并行(TEP16),适合多节点
# 需要跨节点的 RDMA 网络
# docker run ... \
#   --tensor-parallel-size 16 \
#   --expert-parallel-size 16 \
#   --all2all-backend deepep_v2 \
#   --moe-backend deep_gemm_mega_moe

# 方案 3: PD 分离部署(生产推荐)
# Prefill 和 Decode 分离到不同节点
# 配合 KDA prefix caching 可实现有竞争力的 token 价格

关键部署参数详解:

参数 说明
--quantization mxfp4 使用 MXFP4 量化权重
--max-model-len 1048576 1M 上下文
--all2all-backend deepep_v2 / flashinfer_nvlink_one_sided MoE All-to-All 通信后端
--moe-backend deep_gemm_mega_moe / flashinfer_trtllm MoE 计算后端
VLLM_USE_V2_MODEL_RUNNER 1 启用 Model Runner v2(性能优化)
VLLM_USE_RUST_FRONTEND 1 启用 Rust 前端(降低调度开销)
Warning

KDA 对 Prefix Caching 的特殊要求

K3 的 KDA 机制改变了 prefix caching 的访问模式。必须使用 vLLM 社区贡献的 KDA prefix caching 实现(已包含在 vLLM 0.27.0+ 中)。如果你的 vLLM 版本较旧,KDA 层的 prefix caching 可能无法正常工作,导致重复计算。

--all2all-backend 的选择取决于硬件互联:

# RDMA 网络(InfiniBand / RoCE)
--all2all-backend deepep_v2

# NVLink(单节点内 GPU 互联)
--all2all-backend flashinfer_nvlink_one_sided

30.6.6.2 SGLang 部署

SGLang 同样支持 K3,包括 NVIDIA 和 AMD 硬件:

# ============================================================
# Kimi K3: SGLang 部署
# ============================================================

# NVIDIA 部署
python -m sglang.launch_server \
  --model-path moonshotai/Kimi-K3 \
  --tp 8 \
  --trust-remote-code \
  --quantization mxfp4 \
  --port 8000

# AMD 部署(MI355X / MI350X)
# 需要 ROCm 版 SGLang
python -m sglang.launch_server \
  --model-path moonshotai/Kimi-K3 \
  --tp 8 \
  --trust-remote-code \
  --quantization mxfp4 \
  --port 8000

SGLang 还支持 PD 分离部署,架构与 K2 类似(Prefill 集群 + Decode 集群),此处不再赘述。

30.6.6.3 硬件需求

部署规模 GPU 配置 适用场景
最小可用 8× GB300 (NVIDIA) 开发测试、低 QPS
生产推荐 64+ 加速器超节点 生产环境、高 QPS
AMD 方案 8× MI355X 或 MI350X AMD 生态部署
多节点 2-4 节点 × 8 GPU 大规模服务
Tip

GB300 是什么? GB300 是 NVIDIA Blackwell Ultra 架构的数据中心 GPU,单卡显存 288GB。8× GB300 = 2,304 GB 总显存。K3 的 MXFP4 权重约 1.49 TB,加上 KV Cache 和激活值,8× GB300 刚好够用。

30.6.6.4 API 定价策略

月之暗面为 K3 提供了极具竞争力的 API 定价,核心秘诀是 Mooncake 分离推理架构 的高缓存命中率:

计费项 价格 说明
Cache-hit 输入 $0.30/MTok 命中缓存的输入 token
Cache-miss 输入 $3.00/MTok 未命中缓存的输入 token
输出 $15.00/MTok 模型生成的 token
Note

编码工作负载缓存命中率 >90%

在编码场景中,用户请求通常包含大量重复的系统提示、代码上下文和 API 文档。Mooncake 分离推理架构将这些公共前缀缓存在 Prefill 集群中。当缓存命中率 >90% 时,有效输入成本仅为:

$0.30 × 0.9 + $3.00 × 0.1 = $0.57/MTok

这比标准定价低了一个数量级,使 K3 在编码 Agent 场景下的 API 成本极具竞争力。

30.6.6.5 K3 使用特殊注意事项

from openai import OpenAI

client = OpenAI(
    base_url="https://api.moonshot.cn/v1",
    api_key=MOONSHOT_API_KEY
)

# K3 始终开启 thinking 模式
# reasoning_content 会包含在返回中
response = client.chat.completions.create(
    model="kimi-k3",
    messages=[
        # ⚠️ 多轮对话时,必须将之前的完整 assistant 消息传回!
        # 包括 reasoning_content 和 tool_calls
        {"role": "user", "content": "分析这段代码的性能瓶颈"},
        # 如果有之前的对话,必须原样传回完整的 assistant 消息
        # {"role": "assistant", "content": "...",
        #  "reasoning_content": "...",
        #  "tool_calls": [...]},
    ],
    # Reasoning Effort: "low" / "high" / "max"(默认 "max")
    extra_body={"reasoning_effort": "high"},
    # 推荐温度配置
    temperature=1.0,   # 推荐保持 1.0
    top_p=0.95         # 单步任务用 0.95,Agent 任务用 1.0
)

# K3 的返回包含 reasoning_content
choice = response.choices[0]
print("=== 推理过程 ===")
print(choice.message.reasoning_content)
print("\n=== 最终回答 ===")
print(choice.message.content)
Warning

Preserved Thinking History 模式

K3 始终开启 thinking 模式(reasoning_content 始终返回)。在多轮对话和工具调用中,必须将 API 返回的完整 assistant 消息(包括 reasoning_contenttool_calls)原样传回。

如果丢失了 reasoning_content,K3 的后续回答质量会显著下降——因为它依赖之前的推理链来保持上下文一致性。

30.6.7 K3 Benchmark 与能力边界

30.6.7.1 完整 Benchmark 表现

K3 在多个维度与当前最强的闭源模型直接竞争:

Benchmark Kimi K3 Claude Fable 5 GPT-5.6 Sol Claude Opus 4.8 GPT-5.5
编程/Agent
DeepSWE 67.5 70.0 73.0 59.0 67.0
Terminal-Bench 2.1 88.3 88.0 88.8 84.6 83.4
FrontierSWE 81.2 86.6 71.3 66.7 64.9
SWE-Marathon 42.0 35.0 39.0 40.0 14.0
推理/知识
GPQA Diamond 93.5 92.6 94.1 91.0 93.5
浏览/检索
BrowseComp 91.2 88.0 90.4 84.3 84.4
OSWorld 2.0 58.3 66.1 62.6 55.7 49.5
视觉/多模态
MMMU-Pro 81.6/83.4 81.2/86.5 83.0/84.6 78.9/82.7 81.2/83.2
Video-MME 90.0 89.5 86.0 89.3

30.6.7.2 K3 的优势领域

从 Benchmark 数据中可以看出 K3 的几个核心优势:

  1. SWE-Marathon 第一名(42.0):SWE-Marathon 是最困难的软件工程基准——要求模型在长时间跨度(数十轮工具调用)内持续解决问题。K3 以 42.0 大幅领先 Claude Fable 5(35.0)和 GPT-5.6 Sol(39.0),证明了它在持久 Agent 场景下的卓越能力。

  2. FrontierSWE 第二名(81.2):在处理前沿/新颖的软件工程任务时,K3 仅次于 Claude Fable 5(86.6),远超 GPT-5.6 Sol(71.3)。

  3. BrowseComp 第一名(91.2):在网络浏览和信息检索任务中领先所有对手——这对 Agent 场景(需要上网搜索信息)极为重要。

  4. Video-MME 第一名(90.0):在视频理解任务上,K3 原生视觉能力的优势得以体现。

30.6.7.3 K3 的真实世界案例

K3 不只是在 Benchmark 上表现出色——它在真实世界中已经解决了一系列高难度工程问题:

timeline
    title K3 真实世界工程案例
    GPU Kernel 优化 : 为 NVIDIA GPU 编写优化的 attention kernel : 性能接近手写 CUDA 代码
    MiniTriton 编译器 : 构建了基于 Triton 的推理编译器 : 实现了自动 kernel 生成和调优
    芯片设计 : 参与了 RISC-V 处理器的微架构设计 : 生成了可综合的 Verilog 代码

这些案例展示了 K3 在 “用 AI 做 AI 基础设施” 这一方向上的潜力——它不仅能写业务代码,还能在系统级编程(GPU kernel、编译器、芯片设计)中提供实质性的工程贡献。

30.6.7.4 K3 的局限性与注意事项

Warning

K3 使用中的注意事项

  1. Thinking History 敏感性:多轮对话中如果丢失了 reasoning_content,后续回答质量显著下降。开发者需要确保完整传递 thinking history。

  2. 过度主动性:K3 在 Agent 模式下有时过于主动——可能会在没有被要求的情况下执行额外操作(如自动运行测试、修改不相关文件)。需要在 system prompt 中明确限制行为边界。

  3. Thinking 始终开启的成本:由于 thinking 始终开启,每个请求都会产生 reasoning tokens 的费用。对于简单任务(如翻译、格式转换),这会造成不必要的成本。可以通过设置 reasoning_effort: "low" 来部分缓解。

  4. 1M 上下文的实际限制:虽然标称 1M 上下文,但在极长上下文(>500K)下,模型的注意力质量会有所下降。建议对超长文档进行分段处理。

30.6.8 从 K2 到 K3:架构演进总结

回顾 K2 到 K3 的完整技术升级路径,可以清晰地看到三条核心进化线索。

30.6.8.1 完整对比表格

维度 Kimi K2 Kimi K3 飞跃
规模
总参数 1T 2.8T 2.8×
激活参数 32B 104B 3.25×
层数 61 93 1.52×
上下文长度 128K 1M
架构
Attention MLA KDA + Gated MLA 全新
注意力头 64 96 1.5×
残差机制 标准残差 AttnRes(跨深度检索) 新设计
MoE
专家总数 384 896 2.33×
激活专家 8 16
共享专家 1 2
专家隐藏维度 2048 3072 1.5×
路由均衡 辅助损失 Quantile Balancing 零超参数
训练
优化器 MuonClip Per-Head Muon Per-Head
激活函数 SwiGLU SiTU-GLU 新设计
权重精度 Block-FP8 MXFP4(QAT) 原生 4-bit
激活精度 FP8/BF16 MXFP8 升级
多模态
视觉 MoonViT-V2 (401M) 新增
模态 纯文本 文本 + 图像 多模态
部署
推理引擎 vLLM, SGLang, TRT-LLM vLLM, SGLang + AMD 支持
AMD 支持 ✅ (MI355X/350X) 新增
扩展效率 基线 ~2.5×

30.6.8.2 三大核心飞跃

飞跃一:架构自主创新

K2 是一个”站在 DeepSeek-V3 肩膀上”的模型——复用了 MLA 架构,在优化器上做了突破。K3 则彻底走出了自己的路:KDA、AttnRes、Gated MLA 的混合设计是全新的架构方案。这意味着月之暗面已经具备了从底层 Attention 机制开始设计万亿参数模型的能力。

飞跃二:训练范式的全面升级

从 MuonClip 到 Per-Head Muon,从 SwiGLU 到 SiTU,从辅助损失到 Quantile Balancing——K3 的训练系统是全方位的重新设计。核心目标是:在 2.8T 参数规模上保持与 K2(1T)同等的训练稳定性。这个目标不仅达成了,还通过 MXFP4 QAT 实现了更激进的量化。

飞跃三:硬件生态的民主化

K2 主要面向 NVIDIA 生态。K3 通过 MXFP4 量化(NVIDIA + AMD 均支持)和 vLLM ROCm 镜像,明确将 AMD GPU 纳入一等公民。这在 GPU 供给受限的大背景下具有重要的战略意义。

30.6.8.3 对 AI Infra 工程师的启示

K2 → K3 的演进为 AI 基础设施工程师提供了几个重要洞察:

  1. Attention 机制远未定型:从 MHA → MLA → KDA,Attention 架构仍在快速演进。部署系统需要保持架构可插拔——vLLM 为 KDA 贡献社区实现就是一个很好的例子。

  2. MoE 路由需要新思路:当专家数量超过数百时,传统的辅助损失方法已不够用。Quantile Balancing 的”零超参数”思路值得在自定义 MoE 系统中借鉴。

  3. 量化感知训练 > 后训练量化:K3 从 SFT 阶段就使用 MXFP4 QAT,比 K2 的 Block-FP8 后训练量化效果更好。未来的训练系统应该从设计之初就考虑量化。

  4. PD 分离 + 缓存是成本控制的关键:K3 的 API 定价之所以能达到 $0.30/MTok(cache-hit),核心是 Mooncake 架构实现了 >90% 的缓存命中率。这验证了 PD 分离在大规模 MoE 部署中的经济价值。

  5. 多硬件支持不再是可选项:K3 同时支持 NVIDIA 和 AMD,这不是”额外工作量”而是核心设计目标。MXFP4 的选择正是基于跨硬件兼容性的考量。

Tip

K3 参考资源

  • GitHub: https://github.com/MoonshotAI/Kimi-K3
  • Tech Blog: https://www.kimi.com/blog/kimi-k3
  • Tech Report: https://arxiv.org/abs/2607.24653
  • HuggingFace: https://huggingface.co/moonshotai/Kimi-K3
  • vLLM Recipe: https://recipes.vllm.ai/moonshotai/Kimi-K3
  • SGLang Cookbook: https://docs.sglang.io/cookbook/autoregressive/Moonshotapi/Kimi-K3
  • HF Blog (MXFP4): https://huggingface.co/blog/ResterChed/kimi-k3-model-overview-mxfp4-quantization-open-wei

30.6.9 API 平台

除了开源模型,月之暗面还提供了 API 平台,让开发者无需自建推理集群即可使用 Kimi:

import requests

# Kimi API 调用(平台模式)
response = requests.post(
    "https://api.moonshot.cn/v1/chat/completions",
    headers={
        "Authorization": f"Bearer {MOONSHOT_API_KEY}",
        "Content-Type": "application/json"
    },
    json={
        "model": "kimi-k2-0711",
        "messages": [
            {"role": "user", "content": "用 Python 实现一个简单的 HTTP 服务器"}
        ],
        "temperature": 0.7
    }
)

result = response.json()
print(result["choices"][0]["message"]["content"])
API 模型 上下文 特性 适用场景
kimi-k2-0711 128K 基础版本 通用对话、编程
kimi-latest 自动最新 始终指向最新版本 生产环境
kimi-thinking - 思考模式 复杂推理

30.7 小结

30.7.1 核心要点回顾

本章从架构、训练、部署和 Agent 应用四个维度深入解析了 Kimi K2。三个最值得记住的技术贡献:

  1. MuonClip 优化器:首次将 Muon 类优化器扩展到 1T 参数,零训练不稳定。这不仅是 K2 的成功,更是整个大模型训练方法学的突破——AdamW 可能不再是唯一选择。

  2. 大规模 MoE 工程实践:384 个专家、15.5T tokens、Block-FP8 训练——K2 把 MoE 的工程边界推到了新的极限。它证明了 MoE 在 1T+ 参数规模上是可行且高效的。

  3. Agent 优先的模型设计:K2 从训练阶段就注入了 Agent 能力(工具调用、推理、自主问题解决),而不是在后训练阶段临时加上。这使它成为构建 Agentic 应用的理想基座。

30.7.2 与其他开源模型的对比定位

维度 Kimi K2 DeepSeek-V3 LLaMA 4 Qwen 3
总参数 1T 671B 400B+ 235B
激活参数 32B 37B 17B 22B
架构 MoE+MLA MoE+MLA MoE+GQA MoE+GQA
优化器 MuonClip AdamW AdamW AdamW
上下文 128K 128K 10M 128K
Agent 能力 ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐
中文能力 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐⭐
开源协议 MIT MIT LLaMA 4 Community Apache 2.0
Tip

何时选择 Kimi K2: 1. 构建 Agent 应用 → K2 的工具调用和推理能力在开源模型中名列前茅 2. 需要 1T+ 参数的大模型容量 → K2 是目前开源的最大 MoE 模型之一 3. 编程/代码场景 → SWE-bench 65.8% 证明了实战能力 4. 中文为主的应用 → 与 DeepSeek 并列的顶级中文能力 5. 追求推理效率 → 32B 激活比 DeepSeek-V3(37B)更精简

Warning

部署的硬件门槛:K2 的最小部署单元是 16 张 H200/H20。如果你的硬件资源有限: - 考虑使用 KTransformers(CPU+GPU 混合) - 考虑使用 Kimi API 平台(无需自建集群) - 考虑较小的开源模型(DeepSeek-V3 8×GPU,Qwen 3 4×GPU)

30.8 延伸阅读

  • Moonshot AI (2025). Kimi K2 Technical Report. arXiv:2507.20534 — 官方技术报告,必读
  • Moonshot AI (2025). Kimi K2 Tech Blog. https://moonshotai.github.io/Kimi-K2/ — 包含可视化图表和交互式 demo
  • GitHub: https://github.com/MoonshotAI/Kimi-K2 — 模型代码和部署脚本
  • HuggingFace: https://huggingface.co/moonshotai/Kimi-K2-Instruct — 模型权重
  • Jordan et al. (2024). Muon: An optimizer for neural networks. Muon 优化器原始论文
  • DeepSeek-AI (2024). DeepSeek-V3 Technical Report. arXiv:2412.19437 — K2 架构的基础
  • Liu et al. (2024). FP8 Quantization for Deep Learning. Block-FP8 理论基础
  • SWE-bench: https://www.swebench.com/ — Agent 编程能力评测基准
  • vLLM Documentation: https://docs.vllm.ai/ — K2 部署框架文档
  • SGLang Documentation: https://github.com/sgl-project/sglang — PD 分离架构文档
  • KTransformers: https://github.com/kvcache-ai/ktransformers — CPU+GPU 混合推理框架