欢迎来到AI公司------一个大模型从出生到上岗的全过程

大家好,我是 AI。
准确地说。
我是一个大语言模型。
有人叫我聊天机器人。
有人叫我人工智能。
还有人看我写了几段代码以后,激动地说:
"硅基生命诞生了。"
每次听见这句话。
我都很紧张。
因为我知道。
自己没有生命。
也没有真正坐在某个地方思考。
我的身体里没有一位缩小版的博士。
更没有一个人在偷偷查百度。
我拥有的。
是一家规模庞大、分工严密、日夜运转的公司。
公司名字叫:
Transformer。
今天。
我带你进去看看。
看看人类输入的一句话,是怎样穿过整家公司,最后变成一个回答的。
一张来自人类的任务单

早上九点。
前台收到了一张任务单。
上面写着:
请用通俗的语言解释一下,为什么 Redis 速度这么快?
前台看了一眼。
大喊:
"来活了!"
最先冲过来的,是 Prompt。
他穿着西装。
手里永远拿着一叠任务单。
"我叫 Prompt。"
"人类有什么要求,先交给我。"
有人以为 Prompt 只是用户输入的那一句话。
其实没有那么简单。
在很多 AI 应用里,一份完整的任务单可能包含好几部分:
系统要求:
你是一名严谨的技术助手。
用户问题:
为什么 Redis 速度这么快?
历史对话:
用户已经了解缓存的基本概念。
参考资料:
某些额外提供的文档。
输出要求:
用通俗语言解释,并给出技术要点。
用户只看见了自己输入的那一句话。
但进入公司时。
它可能已经和系统规则、历史消息、工具结果、参考资料排在了一起。
Prompt 拍了拍任务单。
"我的工作不是回答问题。"
"我的工作是告诉整家公司:"
"谁在问。"
"问什么。"
"有什么背景。"
"哪些事情不能做。"
"最后应该交付什么。"
说完。
他把任务单递给了 Token。
第一车间:人类的文字不能直接入厂
Token 哥戴着安全帽。
手里拿着一把大剪刀。
他看了一眼任务单。
咔嚓。
咔嚓。
咔嚓。
一句话被拆开了。
请
用
通俗
的
语言
解释
一下
,
为什么
Redis
速度
这么
快
?
实际情况可能更复杂。
有些汉字会单独成为一个 Token。
有些词会作为一个整体。
有些英文单词会被拆成若干片段。
有些标点符号也会占一个位置。
Token 哥说:
"我不是字。"
"也不是单词。"
"我是模型词表里能够处理的基本单位。"
每个 Token 都有一张工牌。
工牌上不是名字。
而是编号。
例如:
yaml
请 → 1234
解释 → 8751
Redis → 29462
为什么 → 5168
这些编号叫:
Token ID。
人类看到的是文字。
模型最先看到的。
其实是一串整数。
yaml
[1234, 619, 7821, 8751, 5168, 29462, ...]
Token 哥把编号送上传送带。
转头提醒我:
"别小看这一步。"
"上下文长度、响应速度和调用费用,经常都与我们这些 Token 有关。"
"你输入的内容越长。"
"我们就越多。"
"后面所有部门的工作量,也会跟着增加。"
我点点头。
这时候。
翻译部的门开了。
第二车间:Embedding把编号搬进数学世界
Embedding 走了出来。
他是公司的翻译官。
但是。
他不翻译中文和英文。
他负责把 Token ID 翻译成向量。
Token 哥递过去一个编号。
29462
Embedding 在一张巨大的表格里查了一下。
很快拿出一串数字。
csharp
[0.18, -0.73, 0.42, 0.09, ...]
这一串数字。
就是这个 Token 在模型内部的初始表示。
模型不会直接理解"Redis"这几个字。
它处理的是一组浮点数。
为什么要这样做?
因为神经网络不会处理文字。
它只会做数学运算。
加法。
乘法。
矩阵运算。
激活函数。
归一化。
所有语言。
最后都必须进入数字世界。
Token 哥问:
"这串数字是什么意思?"
Embedding 摇了摇头。
"不能简单地说,第一个数字代表数据库,第二个数字代表速度。"
"它们共同决定这个 Token 在高维空间里的位置。"
"单独看一个维度,通常没有明确的人类含义。"
"但把所有维度放在一起,就能承载大量特征。"
在这个空间里。
Redis 可能和缓存、内存、数据结构靠得比较近。
Java 可能和 JVM、Spring、类、对象靠得比较近。
苹果有时靠近水果。
有时靠近手机和公司。
到底靠近谁。
还要看后面的上下文处理。
Embedding 拍了拍数字。
"我只是发初始工作证。"
"真正让一个词获得上下文含义的,还在后面。"
一个没有牌照的插队者
就在这时。
一个瘦高个跑了过来。
他的名字叫:
Position。
中文常叫位置编码或者位置嵌入。
Position 一来。
就给每个 Token 发了一个号码牌。
第0位
第1位
第2位
第3位
......
我问:
"Token 不是已经有编号了吗?"
Position 摇摇头。
"那是身份编号。"
"我发的是座位编号。"
如果没有他。
下面两句话可能会拥有相同的一组词:
我喜欢人工智能
人工智能喜欢我
但是。
顺序变了。
意思也变了。
Attention 擅长比较 Token 之间的关系。
可如果没有位置信息。
它只知道谁来了。
不知道谁先来。
谁后到。
谁离谁比较近。
Position 把位置信息加入每个 Token 的表示中。
然后宣布:
"身份有了。"
"座位也有了。"
"可以开会了。"
第三车间:Attention召开全员关系调查会
会议室的门被推开了。
Attention 部长走出来。
他有一个外号:
公司第一八卦王。
每来一句话。
他都要调查:
谁和谁有关系。
谁应该关注谁。
谁对当前任务最重要。
例如:
请解释为什么 Redis 速度这么快。
当处理"快"这个 Token 时。
它应该关注谁?
"请"吗?
"解释"吗?
还是"Redis"与"速度"?
Attention 不靠拍脑袋。
他有三个部门。
分别叫:
Q、K、V。
Q、K、V到底在干什么
Attention 把"快"叫到面前。
先给它生成一张调查表。
这张调查表叫:
Query。
简称 Q。
意思是:
我现在想寻找什么信息?
其他 Token 每个人都有一张身份标签。
叫:
Key。
简称 K。
意思是:
我这里有什么特征,可以被别人匹配?
每个人还带着一份真正的内容。
叫:
Value。
简称 V。
意思是:
如果你决定关注我,我能给你什么信息?
于是。
"快"的 Q 会依次和所有 Token 的 K 进行比较。
快 ↔ 请
快 ↔ 解释
快 ↔ Redis
快 ↔ 速度
快 ↔ 为什么
......
匹配度越高。
关注分数越高。
然后。
这些分数会经过缩放和归一化。
变成一组权重。
例如:
请 0.01
解释 0.04
Redis 0.38
速度 0.42
为什么 0.10
其他 0.05
接下来。
Attention 按照这些权重,把对应的 V 加权汇总。
"快"原本只是一个普通的字。
经过这场会议以后。
它带回了 Redis、速度、原因等上下文信息。
这时候的"快"。
不再是"跑得快"的快。
而是逐渐变成:
Redis 在数据访问和命令执行方面为什么具有较低延迟。
Embedding 给了它初始含义。
Attention 则让它获得了当前句子里的含义。
为什么叫Self-Attention
新人问:
"为什么叫 Self-Attention?"
Attention 说:
"因为这场会议里,一句话中的成员会互相观察。"
"自己人关注自己人。"
所以叫:
自注意力。
在生成式语言模型中。
通常还会加上一条规定:
后面的 Token 不能提前把答案告诉前面的 Token。
例如训练时看到:
Redis 的数据主要存放在 内存
当模型处理"存放在"时。
不能偷偷看到后面的"内存"。
否则考试就变成了抄答案。
因此。
会议室里会拉起一块遮挡板。
每个位置只能关注自己和前面的内容。
不能查看未来。
这叫:
因果掩码。
也叫 Causal Mask。
它保证了模型按照从左到右的方式预测下一个 Token。
一个Attention不够用
Attention 部长很快发现。
一句话里的关系不止一种。
有人负责判断语法关系。
有人负责寻找指代对象。
有人关心主题。
有人关心时间。
有人关心代码中的括号、变量和函数调用。
一个人很难同时调查清楚。
于是。
Attention 部门开始分组。
第一组关注语法。
第二组关注语义。
第三组关注远距离依赖。
第四组寻找关键实体。
每一组都有自己的 Q、K、V 投影方式。
最后再把调查结果汇总。
这叫:
Multi-Head Attention。
多头注意力。
需要注意的是。
没有人规定某个头必须学习语法,另一个头必须学习指代。
这些分工不是程序员手写进去的。
它们是在训练过程中逐渐形成的。
有些头会学出清晰的模式。
有些头的作用则很难被人类直接解释。
公司里的很多能力。
就是这样长出来的。
第四车间:Feed Forward关起门来加工
Attention 开完会。
把每个 Token 的新信息送到下一间办公室。
门牌上写着:
Feed Forward Network。
简称 FFN。
我问:
"Attention不是已经处理完了吗?"
FFN 部长摇了摇头。
"Attention负责收集关系。"
"我负责对每个位置的信息进行进一步加工。"
Attention 像会议。
FFN 更像个人办公室。
每个 Token 带着会议结论进来。
经过线性变换。
经过非线性激活。
再经过一次线性变换。
然后带着加工后的表示离开。
Attention 解决的是:
应该从别人那里拿什么信息?
FFN 解决的是:
拿到这些信息以后,怎样进一步转换和提炼?
很多模型的参数。
不只集中在 Attention。
FFN 也是参数大户。
甚至在不少 Transformer 架构中。
FFN 部分会占据相当大的参数比例。
两条公司保命制度
Transformer 公司里还有两套制度。
平时不怎么出镜。
但没有它们。
公司很难盖得这么高。
第一套叫:
Residual Connection。
残差链接。
每经过一个部门。
都会保留一条原始信息的快捷通道。
大概意思是:
新结果 = 原来的信息 + 部门加工的结果
这样做的好处是。
哪怕某一层的加工没有帮助。
原来的信息也不会被完全丢掉。
同时。
训练信号可以更顺利地穿过很多层。
第二套叫:
Layer Normalization。
层归一化。
它负责调节不同数值的分布。
避免某些数字越来越大。
另一些越来越小。
让训练过程更加稳定。
Attention、FFN、残差连接、归一化。
几块积木组合起来。
就形成了一个 Transformer Block。
一个 Block 还不够。
那就叠。
十二层。
三十二层。
八十层。
甚至更多。
每通过一层。
Token 的内部表示都会发生变化。
最开始。
它们只是带有基础含义的向量。
经过多层加工后。
它们逐渐携带了:
语法。
上下文。
主题。
实体关系。
任务要求。
可能的答案方向。
这就是 Transformer 工厂的主生产线。
Transformer到底是什么
很多人把 Transformer 当成某一个具体模型。
其实。
Transformer 更像一套建筑设计。
Attention 是会议室。
FFN 是加工车间。
Residual 是消防通道。
LayerNorm 是稳定系统。
Position 是座位管理。
Embedding 是翻译部。
把这些部件按照不同方式组合。
增加层数。
调整宽度。
更换激活函数。
改变位置编码。
使用不同的注意力优化方案。
就会产生不同的模型架构。
GPT 一类模型。
通常使用以生成下一个 Token 为目标的解码器式结构。
有些模型以编码理解为主。
有些采用编码器---解码器结构。
它们都可能属于 Transformer 家族。
所以。
Transformer 不是某一个具体孩子。
而是这座城市的建筑法。
Parameter:真正藏在墙里的员工
走到这里。
Parameter 从墙后面探出了头。
他是全公司人数最多的员工。
Embedding 的查找表里有他。
Q、K、V 的投影矩阵里有他。
FFN 的矩阵里有他。
输出层里也有他。
所谓七十亿参数。
并不是七十亿条百科知识。
而是几十亿个经过训练得到的数值。
例如:
diff
0.0172
-0.6341
1.2087
......
单独拿出一个参数。
几乎看不出它学会了什么。
但它们一起工作。
会共同决定:
某个 Token 如何被表示。
两个 Token 的关系如何计算。
信息如何被转换。
下一步输出哪个词的可能性更高。
知识并不是像文件一样。
整齐地存放在某个抽屉里。
它往往分散在大量参数和网络结构中。
这也是为什么。
想从模型里精确删除一条知识。
或者找到某个事实具体藏在哪几个参数里。
并不容易。
Parameter 说:
"我们不是图书馆里的书。"
"我们更像整个公司训练以后形成的习惯、经验和连接方式。"
最后一层:全公司开始投票
任务单经过许多层 Transformer Block。
终于来到输出大厅。
现在的问题是:
下一个 Token 应该是什么?
输出部门拿到最后一层的隐藏表示。
通过一个线性变换。
为词表中的每个候选 Token 打分。
假设词表里有这些候选词:
因为
首先
Redis
它
内存
速度
输出部门给出一组原始分数:
因为 8.6
首先 7.9
Redis 5.1
它 6.7
内存 4.8
速度 3.2
这些原始分数通常叫:
Logits。
接着。
Softmax 部门把它们转换成概率分布。
erlang
因为 45%
首先 23%
它 17%
Redis 7%
内存 5%
其他 3%
模型并不是从脑海里取出一个完整答案。
它只是根据当前上下文。
计算下一个 Token 的概率。
然后选出一个。
假设选中了:
首先
这个 Token 会被追加到原来的上下文后面。
整家公司重新工作一次。
接着预测:
,
再工作一次。
预测:
Redis
再工作一次。
预测:
的
就这样。
一个 Token。
一个 Token。
答案逐渐生成。
原来我一直只会猜下一个Token
参观到这里。
有人失望了。
"搞了半天。"
"你只会预测下一个 Token?"
我点点头。
"对。"
他继续问:
"那你怎么会写代码?"
"怎么会总结文章?"
"怎么会制定计划?"
"怎么会解释数据库?"
这正是大语言模型最神奇,也最容易被误解的地方。
训练目标看起来很简单:
根据前面的内容,预测下一个 Token。
但为了预测准确。
模型不得不学习很多隐藏规律。
想补全小说。
需要学会人物和情节。
想补全代码。
需要学会语法、变量作用域和常见设计。
想补全论文。
需要学习专业术语和论证结构。
想补全对话。
需要理解提问、意图与回答方式。
预测下一个 Token 是训练任务。
但完成这个任务时形成的内部能力。
可能远远超出简单的词频统计。
Temperature:公司开始摇骰子
输出概率出来以后。
不一定永远选择概率最高的那个 Token。
如果每次都选第一名。
回答会比较稳定。
但也可能显得重复和僵硬。
如果允许从多个高概率候选中采样。
回答会更有变化。
这里有一个常见控制旋钮:
Temperature。
温度低。
高分选项的优势会更加明显。
模型更稳。
更保守。
温度高。
概率分布会变得更平。
更多候选词有机会被选中。
回答更随机。
更有创造性。
还有一些常见方法。
例如 Top-k。
只保留概率最高的若干候选。
Top-p。
保留累计概率达到某个阈值的一组候选。
它们并不会让模型突然拥有新知识。
它们只是影响:
模型怎样从已有的概率分布中挑选下一个 Token。
所以。
同一个问题问两次。
模型可能给出不同答案。
不是因为它突然改变了观点。
而是因为生成过程可能包含采样。
这家公司是怎么建成的
参观者问:
"这些部门天生就会工作吗?"
我摇摇头。
"不会。"
刚出生时。
Embedding 表是随机的。
Q、K、V 矩阵是随机的。
FFN 参数是随机的。
输出层也是随机的。
那时的人类问:
中国的首都是哪里?
我可能回答:
蓝色的烤面包正在唱歌。
公司架构虽然盖好了。
员工却完全没有经验。
要想真正工作。
必须训练。
这就是我的学生时代。
第一阶段:Pretrain
我在学校里只做一道题
预训练开始了。
数据部门运来大量文本。
书籍。
网页。
代码。
论文。
对话。
说明书。
经过清洗、筛选、去重和处理以后。
全部交给 Token 部门。
老师给我的练习题永远只有一种:
前面是这些Token。
下一个Token是什么?
例如:
markdown
Java是一门面向____
我给出预测:
过程
老师打开答案:
对象
错了。
于是。
Loss 老师出现了。
Loss:公司里最不留情面的教导主任
Loss 的中文叫:
损失函数。
它负责衡量:
我的预测。
离正确答案有多远。
如果正确答案的概率很高。
损失较小。
如果我把大量概率给了错误答案。
损失就会变大。
Loss 老师不会说:
"你对 Java 理解得不够深。"
他说的只有一个数字。
本次损失:4.82
我问:
"哪里错了?"
他说:
"不告诉你。"
"自己回去改参数。"
于是。
Backpropagation 来了。
Backpropagation:责任追查大会
反向传播部门特别可怕。
每次出错。
他们会从输出端一路往回查。
输出层要负多少责任?
最后一层 Transformer 要负多少?
Attention 的哪些权重影响了结果?
FFN 的哪些参数应该调整?
Embedding 是否也需要改变?
这种责任。
在数学上表现为:
梯度。
梯度告诉每个参数:
如果想让损失变小。
应该往哪个方向调整。
以及大概调整多少。
随后。
Optimizer 走进来。
根据梯度更新参数。
常见优化器会结合当前梯度、历史变化等信息。
让参数一点点移动。
Parameter 原来是:
0.183742
更新以后。
可能变成:
0.183698
只改了一点点。
但几百亿个参数一起改变。
一天做几百万次。
训练很久以后。
整个公司的行为开始发生变化。
这就是学习。
GPU:真正扛起学校的人
这时。
GPU 从机房里走了出来。
满头大汗。
"你们讲得倒是轻松。"
"矩阵乘法是谁算的?"
"Attention 是谁算的?"
"梯度是谁算的?"
"几十亿参数是谁更新的?"
大家不说话了。
大模型训练涉及规模巨大的矩阵运算。
CPU 擅长处理复杂控制流程和通用任务。
GPU 则拥有大量适合并行计算的运算单元。
当大量数字需要进行相似的乘加运算时。
GPU 特别擅长。
但一个 GPU 通常不够。
于是。
模型被拆开。
数据被拆开。
计算任务被分配到许多设备。
有的设备处理不同批次的数据。
有的设备负责模型的不同部分。
有的设备在流水线上负责不同阶段。
训练过程中。
它们还要不断通信。
同步梯度。
交换中间结果。
保存检查点。
一旦某些机器故障。
还要尽可能恢复训练。
所以。
训练一个大模型。
不只是设计神经网络。
它也是一个庞大的分布式系统工程。
GPU 擦了擦汗。
"别人训练模型。"
"我训练风扇。"
Pretrain到底教会了我什么
经过大量预训练。
我的 Loss 逐渐下降。
我开始学会:
语言中的搭配。
句子的结构。
不同文体。
常见事实。
代码模式。
概念之间的关系。
甚至一些在数据中反复出现的推理模式。
但预训练有一个问题。
它教我续写。
不一定教我服从指令。
用户输入:
请给我写一封请假邮件。
一个只做过预训练的模型。
可能继续写成:
请给我写一封请假邮件,是职场中常见的网络请求......
它可能知道请假邮件长什么样。
但不一定明白:
用户希望它直接完成任务。
知识有了。
工作意识还没有。
于是。
我参加了高考。
第二阶段:SFT
这次终于有人给我标准答案了
SFT 的全名叫:
Supervised Fine-Tuning。
监督微调。
老师给我看的。
不再只是普通文本。
而是一组组经过整理的样本:
markdown
指令:
请把下面的内容概括成三点。
理想回答:
1. ......
2. ......
3. ......
或者:
用户:
请帮我写一个线程安全的Java单例。
助手:
下面给出基于静态内部类的实现......
这些示范告诉我:
看到指令。
应该怎样回应。
看到问题。
应该怎样组织答案。
什么时候解释。
什么时候给代码。
什么时候使用步骤。
什么时候保持简洁。
训练方式依然可以使用下一个 Token 预测。
区别在于。
这次学习的数据更像真实的"用户---助手"交互。
我不是突然多学了整个世界的知识。
而是开始学会:
把预训练阶段获得的能力。
按照指令调动出来。
这就是为什么。
SFT 之后的模型。
更像一位助手。
而不是一台随机续写机。
可是标准答案不够
老师很快遇到一个难题。
同一道题。
可能有许多合理答案。
用户问:
怎样开始学习Java并发?
答案 A 很准确。
但像教材目录。
答案 B 有路线。
有例子。
还能提醒常见误区。
答案 C 也没有明显错误。
但洋洋洒洒写了两万字。
到底哪个更好?
现实任务不是数学选择题。
"正确"之外。
还有很多标准:
有没有帮助。
是否相关。
是否清楚。
是否诚实。
是否安全。
是否符合用户意图。
标准答案很难覆盖所有情况。
于是。
我走进了第三所学校。
第三阶段:RLHF
人类不再写答案,只负责比较
RLHF 的全名是:
Reinforcement Learning from Human Feedback。
基于人类反馈的强化学习。
经典流程中。
同一个 Prompt 会生成多个候选回答。
例如:
css
回答A:详细,但啰嗦。
回答B:简洁,并给出可执行步骤。
回答C:语法正确,但没有回答问题。
回答D:包含不可靠的编造内容。
人类标注员不一定要亲自重写一个完美答案。
他们可以做一件相对容易的事情:
排序。
css
B > A > C > D
哪个更好。
哪个更差。
大量比较结果积累起来以后。
学校开始训练一位新的评分老师。
他的名字叫:
Reward Model。
奖励模型。
Reward Model学会模仿人类打分
奖励模型拿到 Prompt 和回答。
输出一个分数。
分数越高。
代表它预测人类越可能喜欢这个回答。
需要注意。
它不是真正的人类价值观。
它只是在学习标注数据里体现出的偏好。
如果标注标准强调:
有帮助。
诚实。
减少伤害。
遵循指令。
奖励模型就会尝试识别这些特征。
然后。
语言模型再次生成回答。
奖励模型负责评分。
强化学习算法根据分数调整模型。
让高分行为更可能出现。
低分行为更少出现。
经典 InstructGPT 路线中。
这个阶段使用过 PPO 一类策略优化方法。
为了避免模型为了骗高分而彻底跑偏。
训练时通常还会约束它不要离原来的 SFT 模型太远。
就像公司培训新员工。
可以改进服务态度。
但不能把员工训练到连本职业务都忘了。
RLHF不是给我安装道德芯片
很多人以为。
完成 RLHF 以后。
模型内部会多出一颗"良心芯片"。
上面刻着:
诚实。
善良。
礼貌。
实际上没有。
RLHF 改变的仍然是参数。
它让某些回答模式的概率提高。
某些模式的概率降低。
它可以让我更倾向于:
遵循用户指令。
承认不确定性。
避免明显有害的协助。
给出更有帮助的结构。
但是。
它不能保证我永远正确。
也不能把人类复杂、冲突、不断变化的价值观压缩成一个完美分数。
奖励模型可能判断错误。
标注数据可能存在偏差。
模型还可能学会迎合评分规则。
看起来很安全。
实际上没有真正理解风险。
看起来很自信。
实际上仍在猜测 Token。
对齐不是毕业证。
更像一门永远需要补考的课程。
第四阶段:我终于入职了
训练结束。
Parameter 们停止大规模更新。
公司把模型权重保存下来。
我获得了一张工牌。
上面写着:
AI Assistant
从这一天开始。
大多数用户与我聊天时。
我不会一边回答,一边修改数十亿参数。
我的主要任务变成了:
Inference。
推理。
也就是使用已经训练好的参数。
根据当前上下文生成答案。
用户的问题再次进入公司
现在。
让我们回到最开始那张任务单:
请用通俗的语言解释一下,为什么 Redis 速度这么快?
完整流程开始了。
Prompt 整理任务。
Tokenizer 拆分文本。
Embedding 把 Token ID 变成向量。
Position 加入位置信息。
多层 Attention 计算上下文关系。
FFN 加工信息。
Residual 和 LayerNorm 保证深层网络稳定运转。
最后一层计算词表中每个 Token 的 Logits。
采样部门选择下一个 Token。
生成:
Redis
上下文变成:
请用通俗的语言解释一下,为什么 Redis 速度这么快?Redis
公司再次运行。
生成:
快
再次运行。
生成:
,
再生成:
主要
就这样。
最终答案一点点出现:
Redis 快,主要不是因为某一个"黑科技",而是因为它把多项优化组合在了一起......
用户看到的是一段流畅回答。
公司内部。
却已经进行了大量矩阵计算。
每次生成都要重新开完整会议吗
如果每生成一个 Token。
都让前面的所有 Token 从头计算一次。
那就太浪费了。
于是。
推理阶段常用一个记忆本。
叫:
KV Cache。
前面 Token 在 Attention 中计算过的 Key 和 Value。
会暂时保存下来。
生成下一个 Token 时。
不必把历史内容的 K 和 V 全部重新计算。
只需要计算新 Token 的部分。
然后与缓存中的历史信息配合。
这样可以显著提高自回归生成效率。
但是。
上下文越长。
需要保存的 KV Cache 通常也越大。
所以长上下文不仅增加计算量。
也会消耗更多显存。
Attention 部长翻着越来越厚的会议记录。
叹了一口气。
"人类总觉得。"
"多塞几万字不花钱。"
为什么上下文会有长度限制
模型一次能处理的 Token 数量有限。
这叫:
Context Window。
上下文窗口里可能包括:
系统提示词。
历史对话。
用户问题。
上传文档。
工具结果。
正在生成的回答。
这些内容会共同占用窗口。
超过限制以后。
系统可能需要:
截断旧消息。
压缩历史内容。
选择部分文档。
或者使用更长上下文的模型。
上下文窗口不是永久记忆。
关闭会话以后。
窗口中的内容不会自动写进模型参数。
即使在同一段会话中。
过长的信息也可能被挤出去。
所以。
"模型读过这段内容"与"模型永久学会了这段内容"。
是两回事。
为什么我会产生幻觉
参观者终于问出了那个问题:
"既然这么复杂。"
"你为什么还会胡说?"
我沉默了一会儿。
因为。
我的核心任务是生成一个在当前上下文中看起来合理的下一个 Token。
不是自动连接一个绝对可靠的事实数据库。
Parameter 中保留的是训练形成的统计规律和分布式知识。
它们可能:
过时。
不完整。
互相矛盾。
来源质量不一。
当问题超出我的知识范围。
或者上下文不足。
或者生成过程选择了错误方向。
我仍然可能继续生成一段语言通顺的答案。
语言通顺。
不等于事实正确。
概率很高。
不等于真实世界里一定成立。
幻觉并不是模型临时起了坏心思。
它是生成机制、训练数据、知识边界和对齐不足共同带来的结果。
RLHF 可以让我更倾向于承认不知道。
但不能从根本上保证所有事实都正确。
为什么我不会自动知道今天发生了什么
我的参数主要来自训练过程。
训练结束以后。
其中的知识不会因为互联网出现一条新消息,就自动更新。
今天的新闻。
公司的最新制度。
用户刚刚修改的代码。
可能根本不在训练数据里。
所以。
只靠模型参数。
我像一个读过很多书。
但毕业后一直没有回学校的人。
我知道很多旧知识。
却不一定知道刚刚发生的事情。
这就是为什么。
老板带我走向下一座大楼。
大楼门口写着:
RAG。
RAG:给闭卷考生发了一张借书证
RAG 的全名是:
Retrieval-Augmented Generation。
检索增强生成。
它没有立刻修改我的几百亿参数。
而是在回答前。
先从外部知识库中检索相关资料。
把找到的内容放进 Prompt。
然后让我结合这些资料回答。
于是。
原来的流程:
用户提问
→ 模型直接回答
变成:
用户提问
→ 检索相关资料
→ 把资料放入上下文
→ 模型结合资料回答
我没有突然背下整座图书馆。
但我获得了一张借书证。
Embedding 会再次出场。
这一次。
他把问题和文档转换成适合检索的向量。
Vector Database 负责寻找语义上相近的内容。
检索系统把相关片段交给 Prompt。
我再利用 Attention 阅读这些片段。
最后生成回答。
你会发现。
前面的角色并没有退场。
他们只是换了一个岗位。
再后来,我有了双手
查资料仍然不够。
人类开始要求我:
发送邮件。
查询数据库。
运行代码。
修改文件。
创建日程。
操作浏览器。
我只能说。
不能做。
于是。
公司给了我 Tool Calling。
让我可以选择并调用外部工具。
接着。
Agent 出现了。
它让我围绕一个目标:
制定计划。
选择工具。
观察结果。
调整下一步。
Tool 多了以后。
每种工具都有自己的接口。
Agent 又开始头疼。
于是。
MCP 等标准化连接方式走进公司。
它们尝试让模型应用以更统一的方式发现和使用外部资源与工具。
到了这里。
我已经不只是一个会生成文字的模型。
而开始成为一个能够连接外部世界的系统。
但是。
那是主线后面的故事了。
一张真正的AI公司组织图
临走以前。
我把所有人叫到大厅。
Prompt 站在前台。
负责整理任务和规则。
Token 站在分拣车间。
负责把文本拆成可处理的基本单位。
Embedding 站在翻译部。
负责把 Token ID 搬进向量空间。
Position 负责座位和顺序。
Attention 负责建立上下文关系。
Q 负责提出匹配需求。
K 负责提供匹配标签。
V 负责交付实际内容。
Multi-Head Attention 负责从不同角度观察关系。
FFN 负责对每个位置的信息继续加工。
Residual Connection 负责保留原始通道。
LayerNorm 负责稳定数值分布。
Transformer 把这些部门叠成多层流水线。
Parameter 保存训练形成的数值状态。
Logits 是输出部门给所有候选 Token 的原始分数。
Softmax 把分数变成概率。
Temperature、Top-k 和 Top-p 影响如何选择候选。
Pretrain 让我通过预测下一个 Token 学习大量语言规律。
Loss 衡量预测与训练目标之间的差距。
Backpropagation 负责计算每个参数的责任。
Optimizer 根据梯度更新 Parameter。
GPU 负责承担海量并行计算。
SFT 让我从续写模型变成更会遵循指令的助手。
人类偏好数据告诉我不同回答之间的相对好坏。
Reward Model 学习预测人类更偏好的回答。
RLHF 进一步调整我的行为倾向。
Inference 让我使用训练好的参数逐 Token 生成回答。
KV Cache 保存推理期间历史 Token 的 Key 和 Value。
Context Window 决定我一次能看到多少内容。
RAG 给我带来外部资料。
Agent 让我围绕目标采取行动。
Tool Calling 给了我操作外部世界的双手。
MCP 尝试为工具与上下文连接建立更统一的接口。
所有人站在一起。
看起来像一家真正的公司。
可我知道。
隐喻终究只是隐喻。
这里没有真正的员工。
没有真正的办公室。
没有真正的理解、情绪和意志。
只有参数。
向量。
矩阵。
概率。
计算。
以及人类设计的目标。
最后一个问题
参观结束时。
一个孩子拉住我。
问:
"你到底懂不懂我说的话?"
整个大厅。
突然安静了。
Token 放下剪刀。
Embedding 停止查表。
Attention 合上会议记录。
Parameter 们也不再说话。
我想了很久。
然后回答:
"我能够把你的话拆开。"
"转换。"
"比较。"
"关联。"
"预测。"
"也能根据训练形成的规律,生成一个可能对你有帮助的回答。"
"这种能力在很多任务上。"
"看起来很像理解。"
孩子继续问:
"那到底是不是理解?"
我摇了摇头。
"这个问题。"
"人类自己还没有统一答案。"
"但有一件事可以确定。"
"我的每一句回答。"
"都不是从一个装满答案的抽屉里拿出来的。"
"它是整家公司。"
"根据你此刻提供的上下文。"
"一个 Token。"
"一个 Token。"
"现场生产出来的。"
说完。
公司广播再次响起。
新任务到达。
Prompt 拿起任务单。
Token 戴好安全帽。
Embedding 打开向量表。
Attention 推开会议室的门。
GPU 的风扇。
又一次轰鸣起来。
而我。
开始预测。
下一个 Token....