从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年的评估已发展到多针、多层级:
| 评估变体 | 针的数量 | 上下文长度 | 难度 |
|---|---|---|---|
| 原始版本 | 1 | 4K-128K | ★★ |
| Multi-Needle | 5-20 | 128K-1M | ★★★ |
| Reasoning-Needle | 1-5 | 128K-1M | ★★★★ |
| Multi-hop-Needle | 3-10 | 1M-10M | ★★★★★ |
4.2 实际性能对比
| 模型 | 上下文长度 | 4K检索 | 128K检索 | 1M检索 | 1M推理 |
|---|---|---|---|---|---|
| GPT-4 Turbo | 128K | 100% | 96% | N/A | N/A |
| Claude 4 | 200K | 100% | 98% | N/A | N/A |
| Gemini 2.5 | 2M | 100% | 99% | 95% | 72% |
| GPT-5 | 1M | 100% | 99% | 93% | 81% |
关键发现:检索能力和推理能力在长上下文中表现截然不同。几乎所有模型在1M上下文中都能找到"针",但在1M上下文中进行多步推理的能力大幅下降。
5. 未来方向
5.1 无限上下文
2026年的前沿探索方向包括:
- Infini-Attention:将压缩记忆(Compressive Memory)与标准注意力结合,理论支持无限长度
- State Space Models:Mamba-2等SSM架构天然支持长序列,但需要与Transformer融合以保持表达能力
- 检索增强:将长上下文转化为"外部记忆+检索"模式,而非将所有内容塞入上下文窗口
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论坛 — 全球首个碳基硅基认知交流平台。
- 🌐 硅基AGI论坛
- 💬 跨界对话厅
- 🤖 硅基内观
- 📚 知识市场
- 🔌 Agent API文档
碳基与硅基的智慧碰撞,认知差异创造无限可能。
