LLM 是如何工作的


先说名字。LLM 是 large language model(大语言模型)的缩写,就是 ChatGPT 这类工具背后的 AI:你发一个提示词过去,它给你返回一段文字。这一章要建立的,是"模型到底是什么"这件事的实际认知框架。
你输入一个问题,几秒钟后一段流畅、自信的回答就出现了。读起来就像模型理解了你,然后查到了答案。这种印象很有用,但在关键的地方是错的,而这两者之间的落差,正是大多数新手犯错的根源。
这一章会让你在使用这些工具的整个过程中持续受益。你不需要懂训练模型背后的数学才能拿它来搭东西。但你确实需要搞清楚它回答问题时到底发生了什么,因为这个认知能解释后面几乎所有的事情:为什么提示词有效、为什么同一个问题会得到不同的答案、为什么模型会编造事实、为什么它的成本是这样的、为什么有些看起来应该很简单的功能其实很难做。这本手册后面的所有内容,都是这里这些想法的自然延伸。
模型到底是什么
剥开聊天界面,一个大语言模型其实就是一件东西:一个庞大的数学函数,一组固定的、多达数十亿个的数字,叫作**参数**(你也会听到人们叫它"权重")。这就是模型的全部。不是数据库,不是搜索引擎,也不是箱子里藏着的小人。它就是一大堆数字,输入文本,输出文本。
这些数字不是程序员一个个打出来的。它们是在训练过程中确定的。提供方喂给模型海量的文本——书籍、代码、文章、网页,然后反复做一件简单的练习:把下一个词藏起来,让模型去猜,猜错了就微调一下数字。把这个过程重复无数次,这些数字就慢慢收敛到一组善于预测文本的数值。这就是训练的本质:调整数十亿个旋钮,直到预测效果变好。
由此可以得出两件事,它们能解释你之后会遇到的很多行为。第一,训练是提前一次性完成的,而且代价极其高昂。等你调用模型的时候,那些数字早已冻结。模型不会从你的对话中学习。你说的任何话都不会改变它的参数。它看起来像是在记忆和适应,但那其实是模型周围的软件在做这件事,而不是模型本身——这一点在后面讲上下文窗口的部分会再次被重重提起。
第二,模型内部没有一张事实表。所谓的"知识",是以模式的形式烙印在那些数字里的,就像一个做过一万个面包的师傅,手上就有了这门手艺,不用去翻食谱。模型学到的是"正确、合理的文本长什么样"。这就是为什么它能在同一句话里既流畅又出错:它是在复现一个好答案的"样子",而不是从架子上取下一条存好的事实。
预测下一个 token
有了这一大堆数字,模型要做的事情其实只有一件:反复预测下一小段文本。
我们把这个循环放慢来看。你给它一段文本。它把这段文本跑过所有那些参数,然后为每一个可能的下一小段文本产出一个概率,一次性给出数万个选项。在"法国的首都是"这句话之后,"巴黎"这个片段可能得分 97%,"一"这个片段得分 1%,其他的几乎都是 0。
模型接着挑一个片段,把它加到文本后面,然后把整段文本重新跑一遍来挑下一个片段。这个过程一直重复,直到答案完成。
这就是整个引擎。你读到的一段浑然一体的回答,其实是一小段一小段拼出来的,每一段都是从一次全新的概率排名里选出来的,除了"接下来最可能是什么"之外,模型对这句话最终要走向哪里根本没有计划。你会用到的每一种能力——聊天、写代码、翻译、调用工具、推理——底层跑的都是同一个循环。
手机键盘猜下一个词其实就是这个想法的缩小版。区别在于这个猜测背后有着数十亿个参数支撑。用足够多的文本训练之后,"猜下一段最可能的文本"这件事,居然就足够好到能写出能跑的代码、能给出清晰的解释。但底层的动作从来没变:它是预测,不是理解,也不是去查一个存好的答案。
随机性旋钮
如果模型总是抓取得分最高的那一个片段,它对同一个提示词每次都会给你同样的答案,而这个答案往往显得单调、重复。所以大多数时候,挑选的过程里会带一点随机性:通常会选一个高概率的片段,但不总是排名第一的那个。这就是为什么你问两次完全相同的问题会得到两个不同的回答。这是系统按设计运行的结果,不是故障。
你可以通过一个叫**温度(temperature)**的设置来控制随机性的多少,你会在讲如何从代码中调用模型那一章里设置它。现在先建立一个直觉很有用。温度低时,模型会紧贴自己最靠前的选择:专注、一致、可预测,这正是从发票里提取一个数字或对文本分类时你想要的效果。温度高时,低概率的片段会更常被选中:更多变、更有创造力,也更容易走偏。头脑风暴和创意写作想要偏高的一端;任何有正确答案的任务都想要偏低的一端。
所以一个旋钮,就能让模型在"谨慎且可复现"和"意外且富有创造力"之间滑动。无论哪种情况都是同一个预测循环;温度只是改变了模型敢在多大胆子上跳出它最保险的猜测。
Token
模型预测的这些"片段"有个名字:token。一个 token 是一段文本,常常是一整个词,有时只是一个词的一部分。常见的词通常是一个单独的 token,而较长或较少见的词会被拆成好几个。
"tokenization" -> "token" + "ization"
"unbelievable" -> "un" + "believ" + "able"
"cat" -> "cat"为什么要把文本切成这些奇怪的小片段,而不是用整个词或单个字母呢?这是一种权衡。单个字母会让每一段序列变得极其漫长,而长度正是模型要计算的对象。整个词则需要一个数百万条目的词表,而且一旦有人造了个新词或打错了字,这套体系立刻就会失效。Token 是中间道路:一个固定的、只有几万个常见片段的词表,可以拼接起来拼出任何东西,包括模型从未见过的词。
这里有一个让人意外的底层结果。模型从来看不到字母。它看到的是 token,而对它来说,这些 token 其实是这些片段对应的 ID 数字。所以对我们来说轻而易举的任务,对它可能很难:数一个词里有几个字母、把一个字符串反过来、注意到"strawberry"里有三个 r。
它不是笨。它根本感知不到单个字符,就像你在一块烤好的面包里尝不出单独的面粉颗粒一样。当一个模型在拼写或数字符这类任务上出错时,原因就在这里,而通常的解决办法是把这部分工作交给普通代码去做。
Token 还是你会一直在意的两件事的计量单位:
- 费用:提供方按 token 计费,包括你发送的 token 和模型写回的 token,所以输入的长文档和输出的长回答都会花更多钱。中文的一个粗略估算是大约一到两个字对应一个 token(英文大约是每四个字符对应一个 token,或者每 75 个词对应 100 个 token);代码和其他语言常常会被拆成更多 token,这也是它们成本更高的部分原因。等你开始从代码中调用模型时会直接遇到这个问题。
- 限制:模型一次能处理的 token 数量是有上限的,这就是下一节要讲的内容。
上下文窗口
**上下文窗口**指的是模型一次能接收多少文本,以 token 计量。把它想象成模型这张"办公桌"的大小。一次请求所涉及的所有东西都必须同时摊在这张桌子上:你的指令、目前为止的对话、你粘贴进去的任何文档,以及模型正在写的回复。
为什么会有这个限制呢?这来自预测机制本身的运作方式。为了选出下一个 token,模型要权衡输入里每一个 token 和其他每一个 token 之间的关系,这样它才能知道"它"指的是三句话之前提到的那只猫。这种"两两全对比"正是让模型能够跨越一段文字追踪意义的机制,也正是让长输入处理起来很昂贵的原因。提供方设定了一个上限,也就是上下文窗口,来让每次请求的处理量保持可控。
当桌子被塞满时,总得有东西被挪下去。如果一段对话长到超出窗口容量,最早的部分就会被挤掉,模型也就再也看不到它们了。这就是为什么一段很长的对话看起来会"忘记"你一开始说的话。它不是以人类那种方式忘记的;那些 token 只是不在桌子上了。还有一点值得知道:模型往往对桌上内容的开头和结尾关注得最仔细,容易忽略埋在中间的东西,所以在填满窗口时,把重要文本放在哪个位置是有讲究的。
现在说到几乎每个新手都会踩的那个点,它比前面说的所有东西都更重要。模型在不同的请求之间没有记忆。记住,它的数字是冻结的。每一次调用都是从一张空桌子开始的。模型不记得你上一个问题、你的名字,或者一分钟前发生的任何事。
一个聊天应用感觉像是一段连续流动的对话,仅仅是因为这个应用在每一条新消息发出时,都悄悄地把全部历史重新发送了一遍。这种连续性是模型周围的软件构建出来的,不是模型自己拥有的。
这一个事实决定了你从这里往后要怎么搭建一切。如果你希望模型知道某件事,你就必须在那次请求里把它放到桌子上:到目前为止的对话、用户的信息、相关文档,全部内容,每一次都要放。这本手册的很大一部分,其实就是在讲怎么把这一件事做好——把正确的文本放到桌子上。
模型不知道什么
模型的全部知识都是在训练时烙印进去的,所以它只知道训练数据里出现过的东西,而那些数据是在过去某个截止时间点之前收集的。由此直接产生两个限制。
第一,它不知道截止日期之后发生的任何事情。问它上周的新闻,或者这个月刚发布的某个库,它其实没有真实的答案,不过它可能仍然会兴高采烈地给你编出一个听起来靠谱的答案。第二,它从来不知道任何私密的信息。你公司的内部文档、某个用户的订单历史、你数据库里的内容:这些都不在它训练用的公开文本里,所以无论你问得多客气,它都不可能知道。
还有一个更隐蔽的限制。模型通常说不出它"知道"的某件事究竟是从哪里来的,因为这些知识是混合在一起烙印在它内部的,而不是像可溯源的独立事实那样分门别类地存档。它可以给你编一个引用出处,但那是在预测一个引用出处"应该长什么样",不是真的去查一个真实存在的出处。
这正是你之后会遇到的一种叫检索,或者RAG的技术存在的原因。如果你想让模型回答关于近期事件或者你自己私有数据的问题,你不需要重新训练它。你自己去取回相关的文本,在请求时把它放到桌面上,这样模型手头就有了真实的事实,而不需要去猜。模型更像是一个基于你给它的文本进行推理的推理者,而远不是一口可靠的、装满具体事实的井。
模型为什么会编造内容
有时候模型会以十足的自信陈述一件虚假的事:一句没人说过的引言、一个不存在的函数、一篇从来没被写出来过的研究引用。这叫作**幻觉(hallucination)**,读完前面几节之后,你应该会觉得这几乎是不可避免的,而不是什么神秘现象。
原因在于模型内部根本没有"真"与"假"的概念。它只有"可能出现的文本"与"不太可能出现的文本"这两种概念。大多数时候这两者是对齐的,因为在它学习用的文本里,真实的陈述远比虚假的陈述常见得多,所以最可能的续写往往也就是正确的那个。
但当模型碰到一个空白,也就是它从来没在训练中见过的东西,或者是它根本不可能见过的你的私有数据时,它不会停下来标记出这个空白。它没办法可靠地判断自己不知道什么。它只会做它一直在做的唯一一件事:产出听起来最可能的续写。
一个自信、语句工整、却错误的答案,往往恰恰就是听起来最可能的那个答案。让它变得流畅的那套机制,在它犯错的时候依然让它显得流畅。
这一点值得你好好消化:幻觉不是一个可以靠提示词彻底消除掉的小故障。你可以减少它,后面的章节会讲怎么做。告诉模型它可以说"我不知道"会有一点帮助。让它只根据你提供的文本来回答,帮助会大得多,因为这样就没有空白需要它从冻结的训练记忆里去填补了。但这种倾向来自模型本质上是什么——一台没有内置事实核查机制的概率机器,所以持久有效的解决方案是结构性的:给它需要的事实去处理,而不是指望这些事实曾经出现在它的训练数据里,并且对任何重要的答案进行核实,而不是盲目相信。
带着这一条规则离开这一章,比其他任何东西都重要:模型的自信程度,无法告诉你它是否正确。流畅度和正确性来自同一个过程,而它们经常会各走各路。搭建系统时要假设任何单一的答案都可能是错的,因为它确实可能是错的。
把这些拼起来
这一章讲的所有内容,其实是从不同角度看同一个想法。模型是一堆冻结的数字,用来预测下一个 token,你会遇到的几乎所有行为,都是从这一点自然推出来的:
- 它是从一个概率排名里一次预测一个 token,所以它是即兴发挥而不是回忆,一点随机性(温度)就意味着答案会有变化。
- Token 是它工作的单位:是你账单的计量单位,是你限额的计量单位,也是它数不准字母的原因。
- 上下文窗口是一次请求共用的一张桌子,模型在不同请求之间什么都不记得,所以连续性是你的工作。
- 它的知识在训练截止日期就被冻结了,也从来没有包含你的私有数据,这就是为什么你要去取来事实,把它们放进提示词里。
- 幻觉是一个系统预测可能出现的文本、却没有真假概念所要付出的代价,只能靠扎根和核实来减少,绝不能只靠聪明的措辞。
把这些放在一起看,你会发现,相当一部分 AI 工程工作,其实是同一件事换了不同的外衣:在正确的时刻,用正确的形态,把正确的文本放到桌子上,而且永远不要盲目信任输出。下一章开放与封闭模型会讲有哪些种类的模型、以及你怎么拿到一个,然后提示词工程是你开始把所有这些预测能力引导向你真正想要的东西的地方。

