完整学习LLM(三):为什么大模型是在预测下一个Token
完整学习LLM(三):为什么大模型是在预测下一个Token
好家伙,
上一篇我们聊了一个最基础的问题:
大模型到底是什么?
当时我给了一个比较朴素的理解:
普通程序按规则执行.
大模型按上下文生成.
但这里还有一个问题没有展开:
大模型到底是怎么生成的?
它为什么能从一个问题开始,慢慢写出一整段回答?
它是不是先在脑子里想好整篇文章,然后一次性吐出来?
不是.
更准确地说:
大模型是在不断预测下一个 token.
这句话很关键.
因为后面很多问题都和它有关:
为什么模型会一个字一个字输出?
为什么同一个问题每次回答不一样?
为什么上下文会影响答案?
为什么 temperature 会影响发散程度?
为什么模型有时候会顺着错误方向越说越偏?
所以这篇就只讲一件事:
预测下一个 token 到底是什么意思?
0.背景:它不是一次性写完整篇答案
我们平时看大模型回答问题,经常会看到文字一点点冒出来.
比如我问:
RAG 是什么?
它可能这样输出:
RAG
RAG 是
RAG 是一种
RAG 是一种让
RAG 是一种让大模型
RAG 是一种让大模型先检索资料
...
从使用体验上看,像是它正在打字.
但从模型工作方式上看,更像是:
先看已有内容
算一下下一个 token 最可能是什么
选一个 token 输出
把这个 token 拼回上下文
再继续算下一个
也就是说,它不是一次性生成完整答案.
它是一轮一轮接出来的.
这个过程有点像我们写文章时不断续句子.
比如我写:
今天我们来学习
接下来可能接:
大模型
RAG
Token
Docker
Python
不同词都可能接得上.
但哪个更合适,取决于前面的上下文.
1.先理解什么是"下一个"
先不急着讲 token.
我们先拿中文句子做一个直觉例子.
比如现在有一句话:
我今天想喝一杯
下一个词可能是什么?
咖啡
奶茶
水
可乐
如果前面再加一点上下文:
我今天写代码写到很晚,有点困,想喝一杯
那下一个词更可能是:
咖啡
如果上下文换成:
天气太热了,我刚运动完,想喝一杯
那下一个词可能更偏向:
水
冰饮料
这就是上下文的作用.
同样是:
想喝一杯
前面给的信息不同,后面最合理的续写就不一样.
大模型也是类似.
只不过它不是在几个中文词里选.
它是在一大堆 token 里计算概率.
2.Token先粗略理解成文本碎片
Token 后面会单独写一篇.
这篇先简单理解:
Token 是模型处理文本时使用的基本单位.
它可能是一个字.
可能是一个词.
也可能是一个词的一部分.
比如英文里:
learning
可能会被拆成一个 token,也可能被拆成几个 token.
中文里也不是一定一个汉字一个 token.
先不用纠结细节.
这里最重要的是:
模型不是直接处理整篇文章.
它看到的是一串 token.
比如一句话可以粗略想象成:
["我", "想", "学习", "大模型"]
模型要做的事情是:
根据前面的 token,
预测下一个 token.
3.预测下一个token是怎么形成答案的
假设用户问:
大模型是什么?
模型不会直接拿出一个完整答案.
它会先根据这个问题,预测第一个回答 token.
比如可能是:
大
然后上下文变成:
用户: 大模型是什么?
模型: 大
接着它再预测下一个 token.
可能是:
模型
上下文继续变成:
用户: 大模型是什么?
模型: 大模型
然后再预测:
是
继续:
用户: 大模型是什么?
模型: 大模型是
就这样一步一步接下去.
最后你看到的是一整段回答.
但这段回答本质上是很多次预测拼出来的.
可以写成一个简单流程:
上下文
-> 模型计算
-> 得到下一个 token 的概率
-> 选出一个 token
-> 拼回上下文
-> 继续下一轮

4.概率是什么意思
这里还有一个点:
模型不是只算一个答案.
它会算很多候选 token 的可能性.
比如前面是:
我想学习
下一个 token 可能有很多:
Python
大模型
RAG
Docker
英语
模型会给这些候选一个倾向.
可以粗略理解成:
Python: 25%
大模型: 30%
RAG: 18%
Docker: 12%
英语: 5%
其他: 10%
真实情况当然比这个复杂得多.
但直觉上可以这样看:
模型是在一堆可能的下一个 token 里做选择.
如果每次都选概率最高的 token,回答会更稳定.
如果允许一定随机性,回答就会更灵活.
这也解释了一个很常见的现象:
同一个问题,模型每次回答可能不完全一样.
因为它不是在执行一条固定规则.
它是在概率分布里生成文本.
5.为什么它能顺着上下文说下去
因为每生成一个 token,这个 token 又会变成新的上下文.
这点很重要.
比如模型一开始回答:
RAG 是一种
接下来它就会继续围绕:
RAG 是一种...
往下生成.
如果它前面写成:
RAG 是一个数据库
那后面就很可能顺着这个错误继续解释.
这就是为什么有时候模型一旦开头错了,后面会越说越像真的.
因为后面的生成会受到前面已经生成内容的影响.
它不是每一步都重新检查事实.
它更多是在当前上下文基础上继续写.
所以在项目里,我们经常需要给它更可靠的上下文:
相关文档
数据库查询结果
工具返回结果
明确的约束条件
否则它会用自己的模式去补全.
而补全不等于事实.
6.这和普通程序有什么区别
普通程序更像:
if 条件成立:
返回固定结果
大模型更像:
当前上下文是什么?
下一个 token 哪些可能性更高?
选一个.
继续.
比如普通程序:
def answer(question: str) -> str:
if question == "RAG是什么":
return "RAG是检索增强生成"
return "不知道"
它很死板.
但可控.
大模型不会只匹配固定问题.
你可以问:
RAG 是什么?
RAG 能解决什么问题?
为什么大模型要先查资料?
项目文档怎么接入大模型?
它都能根据语义生成回答.
这就是它灵活的地方.
但也因为它灵活,所以它不是天然可靠.
它需要外部系统帮它兜住事实和边界.
7.为什么Prompt会影响输出
理解了下一个 token,就能理解 prompt 为什么重要.
Prompt 本质上就是上下文的一部分.
比如你直接问:
解释一下 RAG.
模型可能给你一段百科式解释.
但如果你问:
用一个刚开始做项目知识库的人能听懂的方式解释 RAG,
不要讲太多术语,
用一个流程说明.
那模型预测下一个 token 时,上下文已经变了.
它会更倾向于生成:
更口语
更具体
更偏流程
更少术语
所以 prompt 不是魔法咒语.
它是在改变模型生成时看到的上下文.
上下文变了,后面每一步 token 的概率也会变.
最后答案自然就变了.
8.为什么模型会胡说
现在可以解释一个很常见的问题:
为什么模型会一本正经地胡说?
因为它的目标不是:
保证每句话都来自真实数据库.
而更接近:
根据当前上下文生成最像合理回答的文本.
如果上下文里没有事实依据,但问题又要求它回答,它就可能根据训练中见过的模式补出来.
比如你问:
我这个项目里的 battle_monitor 接口部署在哪个端口?
如果你没有给它项目文档,它可能会猜:
8080
为什么?
因为很多后端服务常见端口就是 8080.
这个答案很像真的.
但对你的项目不一定是真的.
所以我现在越来越觉得:
大模型负责生成.
事实来源必须交给资料、数据库和工具.
这也是 RAG、工具调用、数据库查询这些东西存在的原因.
9.这个理解对工程有什么用
如果只是知道"预测下一个 token",好像没什么用.
但放到工程里就很有用.
第一,它提醒我们不要指望模型天然知道私有事实.
因为它是在根据上下文生成,不是自动连接你的电脑.
第二,它提醒我们 prompt 要写清楚.
因为 prompt 会进入上下文,直接影响后续生成.
第三,它提醒我们控制输出格式.
如果你要 JSON,就要给清楚结构和约束.
不然它可能生成一段自然语言.
第四,它提醒我们为什么要做评测.
因为生成不是固定程序,同一个问题可能有变化.
第五,它提醒我们为什么不能把权限交给模型感觉.
权限、金额、删除操作,这些不能靠模型自己猜.
应该由确定性程序控制.
10.总结
这篇主要想记住一句话:
大模型生成答案,本质上是在不断预测下一个 token.
它的过程可以粗略理解成:
看上下文
算候选 token 概率
选一个 token
拼回上下文
继续下一轮
所以:
上下文会影响答案.
Prompt 会影响答案.
随机性会影响答案.
前面生成错了,后面可能继续错.
没有事实资料时,它可能会补全出看似合理的内容.
这不是说大模型不行.
恰恰相反,它强就强在可以根据上下文灵活生成.
但我们要知道它强在哪里,也要知道它不该单独负责什么.
最后用一句话收一下:
大模型不是一次性写完答案.
它是在上下文里一步一步续写答案.
下一篇就可以继续拆这里最核心的单位:
Token 到底是什么?
为什么一句话进入模型前要被切开?

浙公网安备 33010602011771号