语言模型进化史:从统计计数到自注意力的跃迁
AIAI Summary (BLUF)
这篇文章从语言模型的根本任务出发,系统讲解了从N-gram统计模型、神经网络语言模型、RNN/LSTM到Transformer架构的完整演进过程。通过具体代码示例和直观比喻,帮助读者理解自注意力机制、多头注意力等关键概念,为掌握现代大语言模型的工作原理打下扎实基础。
核心洞察
这篇文章最有意思的点是,它把语言模型从 N-gram 到 Transformer 的演进拆成了能手动算一遍的例子。尤其那个只有两句话的迷你语料库,一步步算概率,比直接甩公式友好太多。如果你一直没搞懂词嵌入和注意力机制到底在解决什么问题,这篇能帮你把线串起来。
核心结论
在仅含语料
datawhale agent learns datawhale agent works的 Bigram 模型中,句子datawhale agent learns的概率按最大似然估计计算为 0.167,即 P(datawhale)=2/6、P(agent|datawhale)=2/2、P(learns|agent)=1/2 三者的连乘结果。N-gram 模型存在数据稀疏和无法泛化语义相似的问题;词嵌入将词映射为连续向量,使语义相近的词在向量空间中靠近,文中简化二维向量演示中
king - man + woman与queen的余弦相似度为 1.0000。RNN/LSTM 必须按时间步顺序处理序列,难以大规模并行;Transformer 完全去掉循环结构,仅依赖注意力机制,从而实现了并行计算。
Transformer 的自注意力让每个词元同时承担 Q、K、V 三种角色,通过 (\frac{QK^\top}{\sqrt{d_k}}) 打分、softmax 加权后对 V 加权求和;多头注意力则将 Q/K/V 切分为 h 个子空间并行计算,使模型能同时捕捉多种关注模式。
一、语言模型与 Transformer 架构
1、从 N-gram 到 RNN
语言模型(Language Model, LM) 是自然语言处理的核心,它要做的事情很简单:计算一个词序列出现的概率。一个靠谱的语言模型能判断出哪个句子通顺、哪个句子别扭。在多智能体系统里,语言模型是智能体看懂人话、生成回复的基础。我们从最早的统计方法讲起,一路走到深度学习,这样你才能明白 Transformer 到底解决了哪些麻烦。
1)统计语言模型与 N-gram 的思想
深度学习火起来之前,统计方法统治了语言模型。核心想法是:一个句子出现的概率,等于它里面每个词出现的条件概率连乘。假设句子 S 由一组词构成,那 P(S) 可以写成链式法则的形式。
但直接算这个公式根本行不通。像“在某个词之后出现某个词”这样的条件概率,没法从语料库里可靠地估出来,因为那个词序列可能压根没出现过。
图 3.1 马尔可夫假设示意图
后来研究者引入了马尔可夫假设(Markov Assumption):不用回头看一个词的全部历史,只需要看它前面有限的 N 个词就够了。基于这个假设建立的模型就是 N-gram 模型。N 代表上下文窗口的大小。看两个最常见的例子:
- Bigram(N=2):假设一个词只跟它前面的一个词有关。链式法则里的复杂条件概率就简化成了容易计算的形式。
- Trigram(N=3):类似,只看前面的两个词。
这些概率可以用**最大似然估计(MLE)**在大型语料库中算出来。名字听着吓人,想法很朴素:最可能的情况就是数据里出现次数最多的那种。比如在 Bigram 模型里,要估计在词 A 后面出现词 B 的概率,就是数数:
用 A 后面跟着 B 的次数,除以 A 出现的总次数。
我们来手动算一遍。假设语料库只有两句话:datawhale agent learns 和 datawhale agent works。用 Bigram 模型估计句子 datawhale agent learns 的概率。
第一步:计算第一个词的概率datawhale 出现了 2 次,总词数 6,所以 P(datawhale) = 2/6。
第二步:计算 P(agent | datawhale)datawhale agent 出现了 2 次,datawhale 出现了 2 次,所以概率是 2/2 = 1。
第三步:计算 P(learns | agent)agent learns 出现了 1 次,agent 出现了 2 次,所以概率是 1/2 = 0.5。
最后连乘
P(句子) ≈ 0.333 × 1.000 × 0.5 = 0.167。
下面是 Python 代码,跟上面的手算过程一一对应:
import collections
corpus = "datawhale agent learns datawhale agent works"
tokens = corpus.split()
total_tokens = len(tokens)
# 第一步:P(datawhale)
count_datawhale = tokens.count('datawhale')
p_datawhale = count_datawhale / total_tokens
print(f"第一步: P(datawhale) = {count_datawhale}/{total_tokens} = {p_datawhale:.3f}")
# 准备 bigram 计数
bigrams = zip(tokens, tokens[1:])
bigram_counts = collections.Counter(bigrams)
# 第二步:P(agent|datawhale)
count_datawhale_agent = bigram_counts[('datawhale', 'agent')]
p_agent_given_datawhale = count_datawhale_agent / count_datawhale
print(f"第二步: P(agent|datawhale) = {count_datawhale_agent}/{count_datawhale} = {p_agent_given_datawhale:.3f}")
# 第三步:P(learns|agent)
count_agent_learns = bigram_counts[('agent', 'learns')]
count_agent = tokens.count('agent')
p_learns_given_agent = count_agent_learns / count_agent
print(f"第三步: P(learns|agent) = {count_agent_learns}/{count_agent} = {p_learns_given_agent:.3f}")
# 最后:连乘
p_sentence = p_datawhale * p_agent_given_datawhale * p_learns_given_agent
print(f"最后: P('datawhale agent learns') ≈ {p_datawhale:.3f} * {p_agent_given_datawhale:.3f} * {p_learns_given_agent:.3f} = {p_sentence:.3f}")
输出:
第一步: P(datawhale) = 2/6 = 0.333
第二步: P(agent|datawhale) = 2/2 = 1.000
第三步: P(learns|agent) = 1/2 = 0.500
最后: P('datawhale agent learns') ≈ 0.333 * 1.000 * 0.500 = 0.167
N-gram 简单,但有两个硬伤:
- 数据稀疏:某个词序列要是没在语料库里出现过,概率直接算成 0。平滑技术能缓解,但治不了本。
- 泛化能力差:模型不懂词和词之间的语义相似。举个例子,就算语料里有一堆
agent learns,模型也想不到robot learns可能成立。要是robot这个词或者robot learns这个组合没见过,概率就是零。模型完全不知道agent和robot意思接近。
2)神经网络语言模型与词嵌入
N-gram 的病根在于把词当成孤立的离散符号。研究者就想:能不能用连续向量来表示词?2003 年 Bengio 等人提出了前馈神经网络语言模型,这是这个方向的开山之作。
做法分两步:
- 建一个语义空间:搞一个高维连续向量空间,把词汇表里每个词都映射成空间里的一个点。这个点就是词嵌入(Word Embedding)。语义相近的词,向量位置也近。比如
agent和robot的向量会挨着,agent和apple会离很远。 - 学一个从上下文到下一个词的映射:用神经网络拟合一个函数,输入是前 N 个词的向量,输出是词汇表里每个词出现在当前上下文之后的概率。
图 3.2 神经网络语言模型架构示意图
词嵌入是在训练过程中自动学出来的。模型为了把“预测下一个词”这个任务做好,会不停地调整每个词的向量位置,最后这些向量就带上了丰富的语义信息。词变成向量之后,就能用数学工具量关系了。最常用的是余弦相似度(Cosine Similarity),算两个向量夹角的余弦值。
这个公式的判断标准很直接:
- 方向完全一样,夹角 0°,余弦值 1,完全相关。
- 方向正交,夹角 90°,余弦值 0,毫无关系。
- 方向完全相反,夹角 180°,余弦值 -1,完全负相关。
词向量不光能抓“同义词”这种简单关系,还能搞出更复杂的类比关系。有个著名例子:vector('King') - vector('Man') + vector('Woman') 这个运算结果,在向量空间里离 vector('Queen') 非常近。相当于从“国王”出发,去掉“男性”的方向,加上“女性”的方向,就到了“女王”的位置。这说明词嵌入真的学到了“性别”“皇室”这种抽象概念。
代码里用简化过的二维向量演示一下:
import numpy as np
embeddings = {
"king": np.array([0.9, 0.8]),
"queen": np.array([0.9, 0.2]),
"man": np.array([0.7, 0.9]),
"woman": np.array([0.7, 0.3])
}
def cosine_similarity(vec1, vec2):
dot_product = np.dot(vec1, vec2)
norm_product = np.linalg.norm(vec1) * np.linalg.norm(vec2)
return dot_product / norm_product
result_vec = embeddings["king"] - embeddings["man"] + embeddings["woman"]
sim = cosine_similarity(result_vec, embeddings["queen"])
print(f"king - man + woman 的结果向量: {result_vec}")
print(f"该结果与 'queen' 的相似度: {sim:.4f}")
输出:
king - man + woman 的结果向量: [0.9 0.2]
该结果与 'queen' 的相似度: 1.0000
神经网络语言模型用词嵌入解决了泛化问题,但它还是被固定窗口卡着:只能看前 N-1 个词,更早的信息直接扔掉。这跟人说话的方式不太一样。后面循环神经网络的出现,就是为了打破这个限制。
3)循环神经网络(RNN)与长短时记忆网络(LSTM)
RNN 的思路很直白:给网络加“记忆”。它引入了一个**隐藏状态(hidden state)**向量,相当于短期记忆。每处理一个词,网络会读当前输入,再结合上一刻的记忆,生成新的记忆传给下一刻。信息就这样沿着序列往后传。
图 3.3 RNN 结构示意图
但标准 RNN 有个严重的毛病:长期依赖问题。训练时靠反向传播调整权重,序列多长网络就多深。序列一长,梯度在往回传的时候一路连乘,要么快速变成零(梯度消失),要么变得巨大(梯度爆炸)。梯度消失意味着模型学不到早期信息对后期输出的影响,长距离依赖就抓不住。
长短时记忆网络(LSTM) 就是冲着这个问题去的。LSTM 是种特殊 RNN,核心创新是加了细胞状态(Cell State)和一套门控机制(Gating Mechanism)。细胞状态像一条独立的信息通路,跟隐藏状态分开走,让信息在时间步之间传得更顺畅。门控机制是几个小型神经网络,学着决定让哪些信息通过,从而控制细胞状态里信息的增删。一共三道门:
- 遗忘门(Forget Gate):决定从上一时刻的细胞状态里扔掉什么。
- 输入门(Input Gate):决定当前输入里的哪些新信息写进细胞状态。
- 输出门(Output Gate):决定根据当前细胞状态,输出什么到隐藏状态。
2、Transformer 架构解析
RNN 和 LSTM 用循环结构处理序列,确实能捕捉长距离依赖。但循环计算有个绕不开的瓶颈:必须按顺序处理。第 t 个时间步要等第 t-1 个时间步算完才行。这样没法大规模并行,处理长序列效率极低,模型规模和训练速度都被卡死了。
Transformer 在 2017 年由谷歌团队提出,彻底扔掉了循环结构,完全靠**注意力(Attention)**机制捕捉序列内部的依赖,实现了真正的并行计算。
1)Encoder-Decoder 整体结构
最初的 Transformer 是给机器翻译设计的端到端模型。宏观上它沿用了一个经典结构:编码器-解码器(Encoder-Decoder)。
图 3.4 Transformer 整体架构图
把这个结构理解成一个分工明确的团队:
- 编码器(Encoder):负责“理解”整个输入句子。它读完所有输入词元,给每个词元生成一个包含上下文信息的向量表示。
- 解码器(Decoder):负责“生成”目标句子。它会参考自己已经生成的前文,再“咨询”编码器的理解结果,生成下一个词。
要真正理解 Transformer,最好的办法是自己动手实现。下面我们用“自顶向下”的方法:先把 Transformer 完整的代码框架搭出来,定义好所有需要的类和函数,然后像拼图一样一个个填上具体实现。
import torch
import torch.nn as nn
import math
# 占位符模块,将在后续小节中实现
class PositionalEncoding(nn.Module):
"""位置编码模块"""
def forward(self, x):
pass
class MultiHeadAttention(nn.Module):
"""多头注意力机制模块"""
def forward(self, query, key, value, mask):
pass
class PositionWiseFeedForward(nn.Module):
"""位置前馈网络模块"""
def forward(self, x):
pass
# 编码器核心层
class EncoderLayer(nn.Module):
def __init__(self, d_model, num_heads, d_ff, dropout):
super(EncoderLayer, self).__init__()
self.self_attn = MultiHeadAttention() # 待实现
self.feed_forward = PositionWiseFeedForward() # 待实现
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, x, mask):
# 残差连接与层归一化将在后面的小节中解释
# 1. 多头自注意力
attn_output = self.self_attn(x, x, x, mask)
x = self.norm1(x + self.dropout(attn_output))
# 2. 前馈网络
ff_output = self.feed_forward(x)
x = self.norm2(x + self.dropout(ff_output))
return x
# 解码器核心层
class DecoderLayer(nn.Module):
def __init__(self, d_model, num_heads, d_ff, dropout):
super(DecoderLayer, self).__init__()
self.self_attn = MultiHeadAttention() # 待实现
self.cross_attn = MultiHeadAttention() # 待实现
self.feed_forward = PositionWiseFeedForward() # 待实现
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.norm3 = nn.LayerNorm(d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, x, encoder_output, src_mask, tgt_mask):
# 1. 掩码多头自注意力(对自己)
attn_output = self.self_attn(x, x, x, tgt_mask)
x = self.norm1(x + self.dropout(attn_output))
# 2. 交叉注意力(对编码器输出)
cross_attn_output = self.cross_attn(x, encoder_output, encoder_output, src_mask)
x = self.norm2(x + self.dropout(cross_attn_output))
# 3. 前馈网络
ff_output = self.feed_forward(x)
x = self.norm3(x + self.dropout(ff_output))
return x
框架摆在这儿,具体模块怎么实现,接下来一节一节补上。
骨架 forward 里最后两步是前馈网络和残差连接,这两个模块后面再展开,注意力机制才是这个骨架的重头戏。
2)从自注意力到多头注意力
读 "The agent learns because it is intelligent." 这句话时,你看到加粗的 it,会下意识去前面找指代对象。agent 这个词会被你多看两眼。自注意力就是给这种现象做数学建模。
处理序列里某个词的时候,自注意力会同时看句子里所有其他词,给每个词分配一个权重。权重越大,那个词跟当前词的关系越近,它的信息在当前词的新表示里占的份量就越大。
为了做到这一点,每个词元向量要同时承担三种角色:
- 查询(Query,Q):代表当前词,主动去跟别的词比对。
- 键(Key,K):代表可被查询的词的标签。
- 值(Value,V):词本身真正携带的内容。
这三个角色由原始词嵌入乘三个不同的可学习权重矩阵得到。整个计算过程像一场开卷考试。
给句子里的每个词都配好 Q、K、V 三份资料。要更新某个词的表示,就拿着它的 Q 去和所有词的 K 做点积。点积结果就是相关性得分。得分除以 (\sqrt{d_k}) 做一次缩放,防止数值太大把 softmax 推到梯度极小的区域。接着过 softmax,把分数变成加起来等于 1 的权重。最后拿这些权重去乘对应的 V,再求和。得到的向量就是这个词融合全局上下文之后的新表示。
公式写出来是这样:
[
\text{Attention}(Q,K,V)=\text{softmax}\left(\frac{QK^\top}{\sqrt{d_k}}\right)V
]
只做一次注意力计算,模型往往只学到一种关注模式。比如处理 it 时只盯主语,忽略了时态或从属关系。语言里的关系是叠加的,所以有了多头注意力。
多头注意力的做法不复杂。把 Q、K、V 在维度上切成 h 份,每一份独立做一次缩放点积注意力。相当于请了 h 个专家,每个专家从不同角度审视句子。最后把 h 份输出拼回去,再过一个线性层整合。
图 3.5 画的就是这个流程。多头意味着模型能同时抓住不同位置、不同子空间里的关系,表达能力一下丰富了很多。
下面这个类实现了完整的多头注意力:
class MultiHeadAttention(nn.Module):
"""
多头注意力机制模块
"""
def __init__(self, d_model, num_heads):
super(MultiHeadAttention, self).__init__()
assert d_model % num_heads == 0, "d_model 必须能被 num_heads 整除"
self.d_model = d_model
self.num_heads = num_heads
self.d_k = d_model // num_heads
# 定义 Q, K, V 和输出的线性变换层
self.W_q = nn.Linear(d_model, d_model)
self.W_k = nn.Linear(d_model, d_model)
self.W_v = nn.Linear(d_model, d_model)
self.W_o = nn.Linear(d_model, d_model)
def scaled_dot_product_attention(self, Q, K, V, mask=None):
# 1. 计算注意力得分 (QK^T)
attn_scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)
# 2. 应用掩码 (如果提供)
if mask is not None:
# 将掩码中为 0 的位置设置为一个非常小的负数,这样 softmax 后会接近 0
attn_scores = attn_scores.masked_fill(mask == 0, -1e9)
# 3. 计算注意力权重 (Softmax)
attn_probs = torch.softmax(attn_scores, dim=-1)
# 4. 加权求和 (权重 * V)
output = torch.matmul(attn_probs, V)
return output
def split_heads(self, x):
# 将输入 x 的形状从 (batch_size, seq_length, d_model)
# 变换为 (batch_size, num_heads, seq_length, d_k)
batch_size, seq_length, d_model = x.size()
return x.view(batch_size, seq_length, self.num_heads, self.d_k).transpose(1, 2)
def combine_heads(self, x):
# 将输入 x 的形状从 (batch_size, num_heads, seq_length, d_k)
# 变回 (batch_size, seq_length, d_model)
batch_size, num_heads, seq_length, d_k = x.size()
return x.transpose(1, 2).contiguous().view(batch_size, seq_length, self.d_model)
def forward(self, Q, K, V, mask=None):
# 1. 对 Q, K, V 进行线性变换
Q = self.split_heads(self.W_q(Q))
K = self.split_heads(self.W_k(K))
V = self.split_heads(self.W_v(V))
# 2. 计算缩放点积注意力
attn_output = self.scaled_dot_product_attention(Q, K, V, mask)
# 3. 合并多头输出并进行最终的线性变换
output = self.W_o(self.combine_heads(attn_output))
return output
3)前馈神经网络
每个 Encoder 和 Decoder 层里,多头注意力子层后面都跟着一个逐位置前馈网络。自注意力负责从整个序列里聚合信息,前馈网络负责在这些聚合结果上做更高阶的特征提取。
逐位置的意思是,同一个前馈网络依次处理序列里的每个词元。seq_len 有多长,它就跑多少趟,但所有位置共享同一组权重。每个位置被独立加工,参数量又不会随序列长度增长。
结构很简单。两个线性层夹一个 ReLU 激活。第一层把 d_model 维扩到 d_ff,通常 d_ff 是 d_model 的四倍。第二层再映射回 d_model。这种先扩大再压缩的瓶颈结构,让模型有更大空间去组合特征。
PyTorch 实现:
class PositionWiseFeedForward(nn.Module):
"""
位置前馈网络模块
"""
def __init__(self, d_model, d_ff, dropout=0.1):
super(PositionWiseFeedForward, self).__init__()
self.linear1 = nn.Linear(d_model, d_ff)
self.dropout = nn.Dropout(dropout)
self.linear2 = nn.Linear(d_ff, d_model)
self.relu = nn.ReLU()
def forward(self, x):
# x 形状: (batch_size, seq_len, d_model)
x = self.linear1(x)
x = self.relu(x)
x = self.dropout(x)
x = self.linear2(x)
# 最终输出形状: (batch_size, seq_len, d_model)
return x
4)残差连接与层归一化
Transformer 里每个子模块外面都包着一层 Add & Norm。
Add 是残差连接,把子模块的输入 x 直接加到输出上。反向传播时梯度能绕开子模块往前传,层数做得很深也不容易梯度消失。
Norm 是层归一化。它把单个样本的所有特征拉回均值 0、方差 1 的分布。每层输入分布稳定了,训练收敛会快很多。
公式合并起来就是:
[
\text{LayerNorm}(x + \text{Sublayer}(x))
]
5)位置编码
自注意力有一个天生的盲区:它看不到词的顺序。
"agent learns" 和 "learns agent" 这两串词,对注意力机制来说完全一样。它只关心词和词之间的关系,不关心位置。可语言里词序变了意思就全变了。
Transformer 的做法是,每个位置的词嵌入后面额外加一个位置向量。这个向量用一个固定公式直接算出,不参与训练。
原论文用的是正弦和余弦函数:
[
PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{2i/d_{model}}}\right)
]
[
PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{2i/d_{model}}}\right)
]
pos 是词在序列里的位置,从 0 开始数。i 是位置向量的维度下标,从 0 到 d_model/2。d_model 是词嵌入的维度。
偶数维度填 sin,奇数维度填 cos。每个位置拿到的位置向量都不一样,词嵌入就算相同,加完位置编码之后也会被区分开。
代码:
class PositionalEncoding(nn.Module):
"""
为输入序列的词嵌入向量添加位置编码。
"""
def __init__(self, d_model: int, dropout: float = 0.1, max_len: int = 5000):
super().__init__()
self.dropout = nn.Dropout(p=dropout)
# 创建一个足够长的位置编码矩阵
position = torch.arange(max_len).unsqueeze(1)
div_term = torch.exp(torch.arange(0, d_model, 2) * (-math.log(10000.0) / d_model))
# pe (positional encoding) 的大小为 (1, max_len, d_model)
pe = torch.zeros(1, max_len, d_model)
# 偶数维度使用 sin, 奇数维度使用 cos
pe[:, 0, 0::2] = torch.sin(position * div_term)
pe[:, 0, 1::2] = torch.cos(position * div_term)
# 将 pe 注册为 buffer,这样它就不会被视为模型参数,但会随模型移动(例如 to(device))
self.register_buffer('pe', pe)
def forward(self, x: torch.Tensor) -> torch.Tensor:
# x.size(0) 是当前输入的序列长度
# 将位置编码加到输入向量上
x = x + self.pe[:x.size(0)]
return self.dropout(x)
到这里,Transformer 的骨架和每个关键模块就完整了。我们不再继续往下实现,因为要理解的是大模型怎么从这套东西里长出来。下一节看 Decoder-Only 架构。
3、Decoder-Only 架构
前面搭起来的那套完整 Transformer 在机器翻译这类端到端任务上表现很好。但要做对话、创作、智能体大脑,其实未必需要这么复杂的结构。
Transformer 的设计是先理解再生成。编码器读完整个句子,记下全局信息,交给解码器慢慢生成。OpenAI 做 GPT 的时候换了个角度:语言的核心任务,就是预测下一个最可能出现的词。
回答问题、写故事、写代码,说到底都是在一个已有的文本序列后面不断补最合理的下一个词。顺着这个思路,GPT 直接把编码器拿掉了,只留解码器。这就是 Decoder-Only 架构。
Decoder-Only 的工作方式叫自回归,听起来专业,其实就是文字接龙。
- 给模型一段起始文本,比如 "Datawhale Agent is"。
- 模型算出下一个最可能的词,比如 "a"。
- 把这个词粘回输入末尾,新输入变成 "Datawhale Agent is a"。
- 模型继续预测下一个词,比如 "powerful"。
- 循环这个过程,直到生成完整句子或碰到停止条件。
模型一遍遍看着自己写下的内容,再决定下一笔落在哪。
那它靠什么保证预测第 t 个词的时候,不去偷看后面的答案?
答案在掩码自注意力。注意力分数矩阵算完之后,softmax 之前,把当前位置之后的位置全部替换成极大的负数。softmax 算到这些位置时概率归零。模型在位置 t 只能访问到位置 t 及之前的信息,后面的内容在数学上被拦住了。
就是这一步,保证了自回归的公平性。
Decoder-Only 能统治今天的大模型时代,理由有三。
训练目标统一。预测下一个词这个目标,让模型可以在海量无标注文本上直接预训练。
结构简单。组件少了,规模化扩展容易。GPT-4、Llama 这些动辄千亿万亿参数的大模型,都长在一套简洁的 Decoder-Only 骨架里。
天然适合生成。自回归过程和文本生成、对话、代码补全都是同一套模式,这也是它成为智能体基础架构的原因。
二、与大语言模型交互
1、提示工程
大语言模型像一个能力很强的脑子,提示就是跟它说话的语言。提示工程研究的是怎么把提示设计到位,让模型输出你想要的东西。做智能体时尤其重要,提示写得好,智能体之间协作分工会顺很多。
(1)模型采样参数
调大模型的时候经常碰到 Temperature 这类参数。它们改的是模型对概率分布的采样策略。模型原本的分布由 softmax 算出来,采样参数会重新调整或截断这个分布,进而改变下一个 token 是什么。
Temperature 是控制随机性和确定性的关键参数。它给 softmax 引入一个温度系数 T:
[
\text{softmax}\left(\frac{z_i}{T}\right)
]
T 变小,分布变陡,高概率词被放大,输出更保守,重复率会高一些。T 变大,分布变平,低概率词也有机会出场,输出更多样,但可能不连贯。
- 温度低于 0.3:输出偏精准、确定。适合事实问答、数据计算、代码生成、法律条文、技术文档这类容不得乱来的场景。
- 温度在 0.3 到 0.7 之间:输出平衡、自然。适合客服对话、邮件撰写、产品文案、日常聊天。
- 温度高于 0.7:输出更发散。适合诗歌创作、科幻故事构思、广告语头脑风暴这些要创意的活。
Top-k 做的是截断候选集。把所有 token 按概率从高到低排序,只保留前 k 个,再对这 k 个的概率重新归一化,从里面采样。
Top-k 只管数量,不管分布长什么样。k=1 时等于每次选概率最高的 token,就是贪心采样。
Top-p 不太一样。它从概率最高的 token 开始累加,直到累积概率超过阈值 p。这些被累加进来的 token 组成核集合,再归一化采样。
Top-p 的候选集大小是动态的。分布集中时核集合小,分布散的时候核集合自动变大,对长尾分布更稳。
三个参数同时设置时是分层生效。温度先调整原始分布的陡峭程度,Top-k 再截出前 k 个候选,Top-p 接着从中选累积概率达标的最小集合。但平时 Top-k 和 Top-p 二选一就够,两个都设,最终候选集取的是两者的交集。
温度设成 0,Top-k 和 Top-p 就没意义了。模型每次只会挑概率最高的那个 Token 当输出,其他选项全被跳过。反过来,Top-k 设成 1,温度和 Top-p 也成了摆设。因为能通过筛选的 Token 只剩一个,下一个预测结果必然是它。
2)零样本、单样本与少样本提示
给模型的示例(Exemplar)数量不同,提示可以分成三种。拿情感分类任务来说,就是让模型判断一段文字是正面、负面还是中性,三种方式放到一起看会很清楚。
零样本提示(Zero-shot Prompting)
不给示例,直接把指令甩给模型。它靠的是在海量数据上预训练出来的泛化能力,模型能接得住这样的裸题。
文本:Datawhale的AI Agent课程非常棒!
情感:正面
单样本提示(One-shot Prompting)
给一个完整的示例,任务格式和期望的输出风格就都展示出来了。
先放一个“文本-情感”对当示范,再抛新问题:
文本:这家餐厅的服务太慢了。
情感:负面
文本:Datawhale的AI Agent课程非常棒!
情感:
模型会照着示例的样子,在末尾补上“正面”。
少样本提示(Few-shot Prompting)
多给几个示例,模型对任务边界和细节的理解会更深,输出也更稳定。
文本:这家餐厅的服务太慢了。
情感:负面
文本:这部电影的情节很平淡。
情感:中性
文本:Datawhale的AI Agent课程非常棒!
情感:
看了一圈例子,最后一句被归为“正面”没什么悬念。
3)指令调优的影响
早期的 GPT 模型,比如 GPT-3,本质是个文本补全器。顺着上文接下文,它能写得很溜,可你要它照指令办事,它就不太听话。
指令调优(Instruction Tuning)就是用大量“指令-回答”对去微调预训练模型,让它学会理解并执行人的要求。现在大家用的 ChatGPT、DeepSeek、Qwen,通通是各自模型家族里做过指令调优的版本。
给一个文本补全模型下翻译任务,你得先把示例格式拉满:
这是一段将英文翻译成中文的程序。
英文:Hello
中文:你好
英文:How are you?
中文:
换成指令调优过的模型,一句话就够了:
请将下面的英文翻译成中文:How are you?
4)基础提示技巧
角色扮演(Role-playing)
给模型安一个身份,它的用词、语气和知识范围都会往这个身份靠。想要什么风格的回答,就配什么角色。
# 案例
你现在是一位资深的Python编程专家。请解释一下Python中的GIL(全局解释器锁)是什么,要让一个初学者也能听懂。
上下文示例(In-context Example)
和少样本提示一个思路。在提示里摆几个输入输出例子,模型自然照着格式来。遇到复杂格式或特定风格的输出,这一招特别能打。
# 案例
我需要你从产品评论中提取产品名称和用户情感。请严格按照下面的JSON格式输出。
评论:这款“星尘”笔记本电脑的屏幕显示效果惊人,但我不太喜欢它的键盘手感。
输出:{"product_name": "星尘笔记本电脑", "sentiment": "混合"}
评论:我刚买的“声动”耳机音质很棒,续航也超出了我的预期!
输出:
5)思维链
碰到逻辑推理、计算这类要多步完成的问题,直接让模型给结果容易翻车。思维链(Chain-of-Thought,CoT)的做法,是在提示里加一句引导语,比如“请逐步思考”,英文里常叫“Let’s think step by step”。
一个篮球队在一个赛季的80场比赛中赢了60%。在接下来的赛季中,他们打了15场比赛,赢了12场。两个赛季的总胜率是多少?
请一步一步地思考并解答。
>>>(模型可能会输出)
好的,我们来一步步计算。
第一步:计算第一个赛季赢得的比赛数。80场 * 60% = 48场。
第二步:计算两个赛季的总比赛数和总胜利数。
总比赛数 = 80 + 15 = 95场。
总胜利数 = 48 + 12 = 60场。
第三步:计算总胜率。
总胜率 = (总胜利数 / 总比赛数) * 100% = (60 / 95) * 100% ≈ 63.16%。
所以,两个赛季的总胜率约为63.16%。
推理过程一摊开,答案对不对立刻能看出来,模型哪一步算岔了也能随手揪住。
说完了提示词,再看模型入口的另一块:文本分词。
2、文本分词
计算机只认得数字。自然语言文本喂给大模型之前,得先转成它熟悉的数字格式。
文本序列转数字序列,这个过程叫分词(Tokenization)。分词器(Tokenizer)定义了一套切分规则,把原始文本切成最小的单元,也就是词元(Token)。
1)为何需要分词
早期做法很直接:按空格和标点把句子切成单词。问题在于词表会爆炸。语言的词汇量太大了,每个词都占一个条目,词表根本收不住。更麻烦的是,没见过的词,比如 DatawhaleAgent,模型只能傻眼。
改成按字符切,词表小多了,英文字母、数字、标点加起来没多少,也不会碰上生词问题。但单个字符基本不携带语义,模型要花更多力气把字符拼装成意思,学习效率太差。
子词分词(Subword Tokenization)是现在的主流,在词表大小和语义表达之间取了平衡。常见词,像 agent,整个保留为词元。生僻词,比如 Tokenization,拆成 Token 和 ization 这种有含义的片段。词表不会膨胀得太离谱,模型也能靠组合子词理解新词。
2)字节对编码算法解析
字节对编码(Byte-Pair Encoding,BPE)是子词分词里最常用的算法,GPT 系列用的就是它。核心思路是一个贪心的合并过程:
- 初始化。词表先放语料中出现过的所有基本字符。
- 迭代合并。统计语料里相邻词元对的出现频率,把最高频的那对合并成一个新词元,加入词表。
- 重复。一直合并到词表大小达到预设阈值。
假设迷你语料库是 {"hug": 1, "pug": 1, "pun": 1, "bun": 1},目标词表大小是 10。BPE 的训练过程见表 3.1。
表 3.1 BPE 算法合并过程示例

训练结束,词表到了 10,分词规则定形。这时遇到一个没见过的词,bug。分词器先查整个 bug,不在词表里;再查 bu,也没有;最后查到 b 和 ug 都在,于是切成 ['b', 'ug']。
下面这段代码模拟了上面的过程:
import re, collections
def get_stats(vocab):
"""统计词元对频率"""
pairs = collections.defaultdict(int)
for word, freq in vocab.items():
symbols = word.split()
for i in range(len(symbols)-1):
pairs[symbols[i], symbols[i+1]] += freq
return pairs
def merge_vocab(pair, v_in):
"""合并词元对"""
v_out = {}
bigram = re.escape(' '.join(pair))
p = re.compile(r'(?<!\S)' + bigram + r'(?!\S)')
for word in v_in:
w_out = p.sub(''.join(pair), word)
v_out[w_out] = v_in[word]
return v_out
vocab = {'h u g </w>': 1, 'p u g </w>': 1, 'p u n </w>': 1, 'b u n </w>': 1}
num_merges = 4
for i in range(num_merges):
pairs = get_stats(vocab)
if not pairs:
break
best = max(pairs, key=pairs.get)
vocab = merge_vocab(best, vocab)
print(f"第{i+1}次合并: {best} -> {''.join(best)}")
print(f"新词表(部分): {list(vocab.keys())}")
print("-" * 20)
输出:
第1次合并: ('u', 'g') -> ug
新词表(部分): ['h ug </w>', 'p ug </w>', 'p u n </w>', 'b u n </w>']
--------------------
第2次合并: ('ug', '</w>') -> ug</w>
新词表(部分): ['h ug</w>', 'p ug</w>', 'p u n </w>', 'b u n </w>']
--------------------
第3次合并: ('u', 'n') -> un
新词表(部分): ['h ug</w>', 'p ug</w>', 'p un </w>', 'b un </w>']
--------------------
第4次合并: ('un', '</w>') -> un</w>
新词表(部分): ['h ug</w>', 'p ug</w>', 'p un</w>', 'b un</w>']
--------------------
BPE 之后的优化算法基本都在它上面改。Google 的 WordPiece 和 SentencePiece 是影响力最大的两个分支。
WordPiece 被 BERT 使用。它和 BPE 很像,但合并标准不是最高频,而是“让语料库的语言模型概率提升最大”。优先合并那些读起来最顺的词元对。
SentencePiece 是 Google 开源的预处理工具,Llama 系列用的就是它。它的特点是直接拿空格当普通字符,通常用下划线 _ 表示。分词和解码完全可逆,还不绑定特定语言。中文这种不用空格分隔的文本,它也能照常处理。
3)分词器对开发者的意义
分词的细节不需要背下来,但作为智能体的开发者,有些影响绕不开。它直接关系到性能、成本和稳定性。
模型的上下文窗口(8K、128K 之类的数字)按 Token 数量算,不是按字符数或单词数。同一段话,换成中文或英文,Token 数能差出一截;不同分词器处理同一段话,结果也不一样。精确管理输入长度,别让智能体的记忆超出上下文限制,是长时记忆设计的基础。
计费也一样。市面上的模型 API 基本按 Token 计费,你的文本会被切成多少 Token,直接决定运行成本。
还有些奇怪的行为,根源就在分词。模型算 2 + 2 很轻松,换成 2+2(没有空格)就出错,因为它可能被分词器当成一个独立但不常见的词元。首字母大小写也能改变切分结果,同一个词可能因为写法不同变成两套 Token。写提示词、解析模型输出的时候,这些细节不注意,智能体就容易出幺蛾子。
原理讲完,动手跑个真实的模型。
3、调用开源大语言模型
前面我们用 API 接上了大模型,跑起来很快,也省事。但有些场景得走另一条路:数据敏感、要离线运行、或者想把成本控制得更细,模型得部署在本地。
Hugging Face Transformers 正好干这个。它提供一套标准接口,能加载数万个预训练模型,下面就用它实践一把。
选择模型要考虑多数人的电脑配置。这次用的是 Qwen/Qwen1.5-0.5B-Chat,阿里巴巴达摩院开源的对话模型,大概 5 亿参数。体积小,性能不差,入门和本地部署都合适。
装好依赖先:
pip install transformers torch
transformers 里常用两个类:AutoModelForCausalLM 负责自动加载模型权重,AutoTokenizer 负责加载匹配的分词器。第一次运行下面的代码会从 Hugging Face Hub 下载模型文件,耗时看网速。
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
model_id = "Qwen/Qwen1.5-0.5B-Chat"
device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"Using device: {device}")
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id).to(device)
print("模型和分词器加载完成!")
Qwen1.5-Chat 有自己规定的聊天模板。构造对话后,要用 tokenizer 先格式化,再转成模型认识的数字 ID(Token ID):
messages = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "你好,请介绍你自己。"}
]
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
model_inputs = tokenizer([text], return_tensors="pt").to(device)
print("编码后的输入文本:")
print(model_inputs)
输出是一串 Tensor,包含 input_ids 和 attention_mask:
{'input_ids': tensor([[151644, 8948, 198, 2610, 525, 264, 10950, 17847, 13,151645, 198, 151644, 872, 198, 108386, 37945, 100157, 107828,1773, 151645, 198, 151644, 77091, 198]], device='cuda:0'), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]], device='cuda:0')}
调 generate() 就能生成回答了。模型输出的照样是一串 Token ID,最后用 decode() 把它翻译回文字:
generated_ids = model.generate(
model_inputs.input_ids,
max_new_tokens=512
)
generated_ids = [
output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
]
response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
print("\n模型的回答:")
print(response)
运行结果:
我叫通义千问,是由阿里云研发的预训练语言模型,可以回答问题、创作文字,还能表达观点、撰写代码。我主要的功能是在多个领域提供帮助,包括但不限于:语言理解、文本生成、机器翻译、问答系统等。有什么我可以帮到你的吗?
2)零样本、单样本与少样本提示
给模型几个参考示例再提问,输出质量往往比直接抛一个问题好不少。零样本就是不给示例,靠模型自己的预训练知识硬答。单样本给一个示范,少样本再多给几个。
别小看这几个示例的差别。某些任务上,三五个精心挑选的例子带来的提升,甚至比换个大一号的模型还明显。所以调提示词的时候,别只盯着措辞,先找几个高质量示例放进去,见效更快。
当你把上一节的代码完整跑完,本地电脑上会出现一段模型自己生成的Qwen介绍。恭喜,一个开源大语言模型已经在你自己的机器上跑起来了。
4、模型的选择
上一节跑通的是个小型开源模型,下一步自然要面对那个很实际的问题:市面上的模型那么多,做智能体到底该选谁?
选模型不能只看参数大小。真正要做的是在性能、成本、速度和部署方式之间找到适合自己的平衡。下面先讲选型时要考虑的几个因素,再盘点当前主流的闭源和开源模型。
大模型领域迭代速度很快,今天的主流几个月后可能就被替代。文中的具体型号和性能数据只代表当前阶段,重点看选型思路,别当成长期答案。
1)模型选型的关键考量
性能永远是第一项。不同模型擅长的方向差别很大。逻辑推理和代码生成强的模型,创意写作不一定行。公开榜单像LMSys Chatbot Arena可以帮你快速了解综合水平,但跑分和真实场景之间还是有差距。
成本要区分两类。闭源模型按token计费,单价低但量大。开源模型没有接口费,但GPU、内存和运维都是实打实的开销。
延迟直接关系到体验。客服、游戏NPC这些实时场景,慢一拍的感受很明显。轻量级模型和针对性优化过的模型,速度表现更好。
上下文窗口决定模型一次能处理多少内容。长文档分析、代码库阅读、多轮对话记忆,这些任务没有128K以上的窗口很难撑起来。
部署方式影响数据隐私。用接口最省事,但数据要过第三方服务器。本地部署折腾,换来的是自主性和对数据的掌控。
生态和工具链是隐形效率项。热门模型的教程、社区方案、LangChain这类框架支持都更完善,遇到问题能找到答案。冷门模型资源稀少,踩坑全靠自己。
微调能力在业务数据特殊的场景里是硬指标。能不能用自有数据做定制化训练,直接决定模型在你手上的实用性。开源模型通常更灵活。
安全性和伦理问题越来越实际。偏见、有害输出、幻觉,对面向公众的应用来说都是选型阶段该纳入评估的风险。
这些维度经常互相冲突。性能和成本,隐私和便利,很少能同时拉满。最终哪个优先,取决于智能体具体的应用场景。
2)闭源模型概览
闭源模型通常站在技术最前沿,也提供稳定的接口服务,想快速上手的话是最省事的选择。
OpenAI GPT系列:GPT-3把大模型带进了公共视野,ChatGPT通过RLHF让模型输出更贴近人的预期,GPT-4打开多模态,GPT-5开始把文本、音频、图像的输入输出混在一起做。实时语音对话的响应速度和自然度,这代提升很明显。
Google Gemini系列:Gemini从出生就是原生多模态,文本、代码、图像、视频统一处理,上下文窗口也一直压着别人一头。Ultra、Pro、Nano分别对应最复杂任务、常规任务和边缘设备。2.5系列里Pro的推理继续增强,Flash把速度和成本控制得很好。
Anthropic Claude系列:安全是这个品牌最深的标签。Claude在长文档、减少有害输出、遵循指令这几块尤其稳,企业客户认可度高。Claude 3的Opus、Sonnet、Haiku分别对应性能天花板、均衡款和快跑款。Claude 4 Opus在复杂推理和代码生成上又往前走了一步。
国内主流闭源模型:文心一言、腾讯混元、华为盘古、讯飞星火、月之暗面,这些模型的中文能力是这个阵营里最突出的优势。
3)开源模型概览
开源模型的价值在透明和可控:本地部署、自由微调、完整掌控,这些是闭源接口给不了的权利。代价是技术门槛和运维成本得自己承担。
Meta Llama系列:Llama基本是开源模型里绕不开的地基。Llama 4是Meta第一次换用MoE架构,这种混合专家设计每次只激活任务相关的部分,计算效率高不少。Scout支持一千万token上下文,长文档和移动端是它的目标场景。Maverick主打多模态,编码、复杂推理和多语言都不弱。Behemoth是旗舰型号,STEM基准测试超过了多个竞品。
Mistral AI系列:法国团队,擅长用更小的模型达到接近大模型的水平。Mistral Medium 3.1在代码、STEM推理、跨领域问答上提升明显,基准跑赢过Claude Sonnet 3.7和Llama 4 Maverick。它也支持图文混合输入,还内置了语调适配层,公司拿来做品牌化输出很方便。
国内开源力量:阿里的通义千问和清华智谱的ChatGLM是领头羊,中文能力强,社区也很活跃。
闭源和开源的边界在实际项目里没那么非此即彼。用API起步,后期把敏感业务迁到本地开源模型,这种混合节奏很常见。选型的关键还是想清楚自己的约束条件。
三、大语言模型的缩放法则与局限性
大模型这几年的进步,背后有一条可以被量化的规律在支撑,就是缩放法则(Scaling Laws)。它解释了为什么模型越大越聪明,同时也提醒我们数据和算力要跟着一起涨。理解它的另一面,就是看清模型有哪些根治不掉的毛病。
1、缩放法则
缩放法则的核心发现是:模型性能和参数量、训练数据量、计算量之间存在稳定的幂律关系。在对数坐标下,模型loss随这三个因素的增加而稳定下降,画出来几乎是一条直线。意味着只要按比例增加三者的规模,性能会平滑提升,不会遇到明显的瓶颈。
早期研究更强调加参数量。DeepMind 2022年的Chinchilla研究把方向修正了一下:给定计算预算,参数量和训练数据之间有一个最优配比。模型不必搞得太大,但数据要喂得足够多。Chinchilla是700亿参数,用了四倍于GPT-3的数据量,最后性能反超。那个“参数越大越好”的说法,基本到此为止。后来的Llama系列也明显延续了这套思路。
缩放法则最吸引人的副产品是能力涌现。模型规模跨过某个阈值后,一些此前完全不行的能力会突然冒出来。链式思考、指令遵循、多步推理、代码生成,基本都是在百亿千亿参数这个量级附近才出现的。
对智能体开发者的启示很直接:复杂决策和规划是吃模型规模的任务。模型太小,这些能力真的不具备,提示词再精细也换不出来。
2、模型幻觉
模型幻觉说的是模型一本正经地编造信息。生成的内容可能和事实矛盾,可能和输入冲突,也可能只是无中生有。常见的有三类:事实性幻觉,生成内容与真实世界对不上;忠实性幻觉,摘要和翻译时偏离了原文;内在幻觉,生成内容直接否定输入信息。
幻觉出现的原因有几个。训练数据本身就有错误,模型无从分辨。自回归生成的每个token都是概率预测,模型内部没有事实核查这一步。推理链条一断,后续就会顺着错误继续补全。旅游规划智能体推荐一个不存在的景点,或者订一张航班号不存在的机票,就是这么来的。
除了幻觉,知识时效和偏见也挡不住。训练数据截止之后的事,模型就是不知道。数据里的偏见和刻板印象,模型学得很快,输出时还会放大。
缓解幻觉的手段已经有三条成熟路线。
数据上用高质量清洗、事实性知识注入、RLHF来减少源头错误。模型层探索新架构和不确定性表达,让模型在没把握的时候认怂,别硬编。推理侧目前最有效的是检索增强生成(RAG):生成之前先从外部知识库检索材料,把检索结果放回上下文中再作答。多步推理加自检、调用外部工具做实时查询或精确计算,都能把幻觉压到一个更低的频率。
幻觉没法彻底根除,但RAG和工具调用这一套组合拳,已经在实际产品里证明了效果。对大多数应用场景来说,可控即可用。
四、本章小结
这一章从Transformer讲到大模型生态,再到幻觉治理,信息量不小。不过这些内容不是孤立的知识点,它们都是后续构建智能体时的地基。
模型演进与核心架构:从N-gram到RNN、LSTM,再到Transformer,架构更新主要解决过去模型的长距离依赖和并行效率问题。自注意力机制是Transformer的灵魂,也是当前几乎所有大模型的共同基础。
与模型的交互方式:提示工程是引导模型行为的主要手段,零样本、单样本、少样本是基础。分词决定了模型眼里的输入长什么样。上一节本地运行开源模型的练习,则是把这些概念真正落到了一次实操里。
模型生态与选型:闭源模型开箱即用,前沿能力跟上;开源模型透明可定制,代价是要自己维护。选型就是在各种约束条件里做权衡,排行榜第一未必是你的最佳答案。
法则与局限:缩放法则说明性能提升有规律,参数和数据要按比例增长,能力涌现则提示了规模门槛。幻觉、知识过时、偏见是共性问题,RAG、外部工具和推理验证是目前主要的应对手段。
这些基础也直接连着智能体设计。怎么用提示词引导规划决策,怎么选底座模型,怎么在工作流里加防幻觉的验证机制,答案都在这里。
理论部分到这儿收尾。下一章开始进入智能体经典范式的构建,真正动起手来。
顶尖师资,深耕AI大模型前沿技术
课是谁讲的,这点比课程大纲重要得多。这门课请的是真正在一线做项目的实战派,不是念PPT的理论党。他们踩过的坑,总结成经验直接给你,省掉你自己撞墙的时间。
一对一学习规划,职业生涯指导
报名之后会有老师单独找你聊,根据你现在的技术底子、想去的方向,帮你规划学习路线。不是扔给你一套录播课就完事,是有人管你的。
真实商业项目实训
练手用的项目不是玩具,是真实商业项目。学习标准就是商业交付标准,你做的东西要能上线跑。做完的项目可以写进简历,背调也支持。这一条对转行的人特别友好,简历上有真东西可写,面试官问起来也不虚。
大厂绿色直通车,冲击行业高薪岗位
表现好的学员,有直接进大厂面试的通道。身边不少朋友就是靠这个跳槽成功的,薪资涨幅比自己海投简历强多了。
文中涉及到的完整版大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】
常见问题(FAQ)
N-gram模型有哪些缺点?
N-gram模型有两个硬伤:一是数据稀疏,未出现过的词序列概率会被算作0;二是泛化能力差,无法利用词语间的语义相似性,例如不知道'agent'和'robot'意思接近。
词嵌入在语言模型中有什么作用?
词嵌入将词语映射为高维连续向量,使语义相近的词在向量空间中距离更近,能通过余弦相似度量化关系,甚至支持向量运算,如'国王-男人+女人≈女王',从而让模型理解词语的语义联系。
语言模型的核心任务是什么?
语言模型的核心任务是计算一个词序列出现的概率,以此判断句子是否通顺。它是自然语言处理的基础,为文本生成、机器翻译等任务提供依据。
版权与免责声明:本文仅用于信息分享与交流,不构成任何形式的法律、投资、医疗或其他专业建议,也不构成对任何结果的承诺或保证。
文中提及的商标、品牌、Logo、产品名称及相关图片/素材,其权利归各自合法权利人所有。本站内容可能基于公开资料整理,亦可能使用 AI 辅助生成或润色;我们尽力确保准确与合规,但不保证完整性、时效性与适用性,请读者自行甄别并以官方信息为准。
若本文内容或素材涉嫌侵权、隐私不当或存在错误,请相关权利人/当事人联系本站,我们将及时核实并采取删除、修正或下架等处理措施。也请勿在评论或联系信息中提交身份证号、手机号、住址等个人敏感信息。



