从GPT-3的2K上下文到Gemini 2.5的10M上下文,长上下文技术是大模型领域进步最快的方向之一。2026年,百万级token的上下文窗口已成为旗舰模型的标配。本文将系统梳理这一技术演进的核心脉络。

1. 位置编码的演进

1.1 绝对位置编码的局限

原始Transformer使用可学习的绝对位置编码,最大长度在训练时固定。外推到更长序列时效果急剧下降。

1.2 RoPE:旋转位置编码

RoPE(Rotary Position Embedding)通过在复数域旋转Query和Key来编码相对位置:

$$\text{RoPE}(x, m) = x e^{im\theta}$$

其中 $m$ 为位置索引,$\theta_i = 10000^{-2i/d}$。两个位置 $m, n$ 的注意力分数仅依赖于相对位置 $m - n$:

$$\text{Re}[\langle \text{RoPE}(q, m), \text{RoPE}(k, n) \rangle] = \text{Re}[\langle q, k \rangle \cdot e^{i(m-n)\theta}]$$

def apply_rotary_pos_emb(q, k, cos, sin):
    # q, k: [batch, heads, seq_len, d_k]
    # cos, sin: [seq_len, d_k]
    q_rot = (q * cos) + (rotate_half(q) * sin)
    k_rot = (k * cos) + (rotate_half(k) * sin)
    return q_rot, k_rot

def rotate_half(x):
    x1 = x[..., :x.shape[-1] // 2]
    x2 = x[..., x.shape[-1] // 2:]
    return torch.cat((-x2, x1), dim=-1)

1.3 RoPE外推方案

训练时上下文长度为 $L_{train}$,推理时需要扩展到 $L_{test}$。主要外推方案:

方案原理效果计算开销
Position Interpolation (PI)将位置索引缩放到训练范围良好
NTK-aware调整RoPE基频 $\theta$优秀
YaRN分频段不同插值策略最佳极低
LongRoPE进化搜索最优插值参数2026年SOTA一次性搜索

YaRN的核心思想是对不同频率分量采用不同策略:

def yarn_rope(seq_len, dim, base=10000, scale=4.0, 
              original_max=2048, beta_fast=32, beta_slow=1):
    # 计算频率
    freqs = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))
    
    # 低频维度:插值
    # 高频维度:外推
    # 中频维度:混合
    low_freq = freqs[:beta_fast]
    high_freq = freqs[beta_slow:]
    mid_freq = freqs[beta_fast:beta_slow]
    
    # 分段处理
    low_freq_wavelen = original_max / low_freq
    high_freq_wavelen = original_max / high_freq
    
    # 渐变插值
    def get_scaling(wavelen):
        ratio = wavelen / (original_max * scale)
        return min(1.0, max(ratio, 0.0))
    
    scaling = torch.cat([
        torch.tensor([get_scaling(w) for w in low_freq_wavelen]),
        torch.tensor([get_scaling(w) for w in mid_freq_wavelen]) * 0.5,
        torch.ones(len(high_freq))  # 高频不缩放
    ])
    
    freqs = freqs / scaling
    return torch.outer(torch.arange(seq_len), freqs)

2. 注意力计算优化

2.1 分块注意力

将长序列切分为块,仅在块内和跨块使用不同注意力模式:

Local-Global Attention

  • 块内使用完整Self-Attention
  • 块间使用稀疏全局注意力(如选取每个块的CLS token)
class ChunkedAttention(nn.Module):
    def __init__(self, chunk_size=4096, num_global_tokens=64):
        super().__init__()
        self.chunk_size = chunk_size
        self.num_global_tokens = num_global_tokens

    def forward(self, x):
        B, N, D = x.shape
        # 提取全局token
        global_tokens = x[:, :self.num_global_tokens]
        local_tokens = x[:, self.num_global_tokens:]
        
        # 块内注意力
        chunks = local_tokens.reshape(B, -1, self.chunk_size, D)
        local_attn = full_attention(chunks)  # 块内完整注意力
        
        # 全局注意力:所有token关注全局token
        global_attn = cross_attention(local_tokens, global_tokens)
        
        return local_attn + global_attn

2.2 Flash Attention长上下文优化

FA 3.0针对长上下文场景做了专门优化:

  • 分页KV Cache:将KV cache组织为不连续的页,减少内存碎片
  • 流式计算:支持流式输入,无需等待完整序列到达
  • CPU Offloading:超长上下文时将部分KV cache卸载到CPU内存

3. Ring Attention:跨设备长上下文

3.1 核心原理

Ring Attention是2026年百万级上下文的核心技术。它将序列分块分布到多个GPU上,通过环形通信模式重叠计算和通信:

GPU 0: Block 0 ──→ GPU 1: Block 1 ──→ GPU 2: Block 2 ──→ GPU 3: Block 3
     ↑                                                          │
     └──────────────────────────────────────────────────────────┘
                        环形通信

每个GPU计算本地Block的Q与接收到的Block的K,V的注意力,同时将K,V传递给下一个GPU。

3.2 数学推导

对于序列 $X = [x_1, …, x_N]$ 分为 $P$ 个块分配到 $P$ 个GPU:

$$\text{Attn}(Q, K, V) = \begin{bmatrix} \text{Attn}(Q_1, K_{1:P}, V_{1:P}) \ \vdots \ \text{Attn}(Q_P, K_{1:P}, V_{1:P}) \end{bmatrix}$$

每个GPU $i$ 需要 $Q_i$ 和所有 $K_{j}, V_{j}$。Ring Attention通过流水线重叠:

时间 →
GPU 0: [Compute(Q0,K0)] [Send K0,V0] [Compute(Q0,K1)] [Send K1,V1] ...
GPU 1: [Compute(Q1,K1)] [Recv K0,V0] [Compute(Q1,K0)] [Send K0,V0] ...

3.3 实现要点

def ring_attention_forward(q, k, v, device_group, rank):
    """Ring Attention实现(简化版)"""
    world_size = len(device_group)
    
    # 本地Q, K, V
    local_q = q[rank]
    local_k = k[rank]
    local_v = v[rank]
    
    # 初始化输出和归一化项
    output = torch.zeros_like(local_q)
    normalizer = torch.zeros(local_q.shape[:-1], device=local_q.device)
    
    current_k, current_v = local_k, local_v
    
    for step in range(world_size):
        # 计算本地Q与当前K,V的注意力
        block_output, block_lse = flash_attention(
            local_q, current_k, current_v, return_lse=True
        )
        
        # 在线归一化合并
        output, normalizer = online_merge(
            output, normalizer, block_output, block_lse
        )
        
        # 环形传递K, V
        next_rank = (rank + 1) % world_size
        prev_rank = (rank - 1) % world_size
        
        # 异步通信,与下一次计算重叠
        current_k = send_recv(current_k, prev_rank, next_rank)
        current_v = send_recv(current_v, prev_rank, next_rank)
    
    output = output / normalizer.unsqueeze(-1)
    return output

def online_merge(output, norm, block_out, block_lse):
    """在线合并注意力块(基于LogSumExp)"""
    max_lse = torch.max(norm, block_lse)
    scale_old = torch.exp(norm - max_lse)
    scale_new = torch.exp(block_lse - max_lse)
    
    output = (output * scale_old + block_out * scale_new) / (scale_old + scale_new)
    norm = torch.log(scale_old + scale_new) + max_lse
    return output, norm

4. 长上下文评估

4.1 Needles-in-a-Haystack

这是长上下文评估的黄金标准:在不同位置插入"针"(需要检索的事实),测试模型的检索能力。

2026年的评估已发展到多针、多层级

评估变体针的数量上下文长度难度
原始版本14K-128K★★
Multi-Needle5-20128K-1M★★★
Reasoning-Needle1-5128K-1M★★★★
Multi-hop-Needle3-101M-10M★★★★★

4.2 实际性能对比

模型上下文长度4K检索128K检索1M检索1M推理
GPT-4 Turbo128K100%96%N/AN/A
Claude 4200K100%98%N/AN/A
Gemini 2.52M100%99%95%72%
GPT-51M100%99%93%81%

关键发现:检索能力推理能力在长上下文中表现截然不同。几乎所有模型在1M上下文中都能找到"针",但在1M上下文中进行多步推理的能力大幅下降。

5. 未来方向

5.1 无限上下文

2026年的前沿探索方向包括:

  1. Infini-Attention:将压缩记忆(Compressive Memory)与标准注意力结合,理论支持无限长度
  2. State Space Models:Mamba-2等SSM架构天然支持长序列,但需要与Transformer融合以保持表达能力
  3. 检索增强:将长上下文转化为"外部记忆+检索"模式,而非将所有内容塞入上下文窗口

5.2 上下文压缩

另一个方向是在传输前压缩上下文

# 上下文压缩示例
def compress_context(long_context, target_length=8192):
    # 1. 分块摘要
    chunks = split_into_chunks(long_context, chunk_size=4096)
    summaries = [summarize(chunk) for chunk in chunks]
    
    # 2. 关键信息提取
    key_facts = extract_key_facts(long_context)
    
    # 3. 结构化重组
    compressed = f"关键事实:\n{key_facts}\n\n摘要:\n" + "\n".join(summaries)
    return compressed[:target_length]

长上下文技术的终极目标不是无限扩展窗口大小,而是在有限窗口内实现最高效的信息利用。

加入讨论

这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。

碳基与硅基的智慧碰撞,认知差异创造无限可能。