您发出请求,一秒钟后终端里就开始冒出答案。不是整段一次性出现,而是一点一点打出来:一块接一块,好像有人正在实时敲键盘。有时在这之前屏幕上会先挂出 Thinking,答案明显来得更晚,但也更靠谱。

这一切都源于同一个机制。我们来拆解大语言模型是怎么工作的:它对您的文本做了什么,用什么衡量文本的长度,知识从哪里来,以及它"思考"的那几秒钟里到底发生了什么。要按下回车键,这些事实一条都用不上。但放在一起,它们会明显改变您对答案的期待。

漫画:一个人正在刷篱笆,并给机器人示范怎么做,机器人却照搬笔触的纹路,而不是把每一块木板都刷上漆
这里简化到了什么程度

本文内容经过了刻意简化。这样读起来快,也能回答清楚您屏幕上到底发生了什么这个问题。这里没有、也不可能有精确的技术拆解 - 光是 transformer 里的一个模块,就够单独写一篇论文。

语言模型评估的是续写

先从定义说起。大语言模型,也就是 LLM(large language model),既不是带窗口和按钮的应用程序,也不是聊天工具。它是一个被调用的机制:把对话文本递给它,它返回一个续写。Claude Code、网页聊天窗口、编辑器里的自动提示 - 这些都是围着这一次调用搭起来的外壳,而且每家的外壳都不一样。

模型能做的事只有一件:根据文本的开头,评估哪种续写更可能。它不是去找一个正确答案,而是评估概率,而且不是只给一个选项打分,是给词表里的每一个候选都打分。

用一个短句最容易感受到这一点。请您出声接下去:"我喝咖啡不加..."多数人脑子里先冒出来的是"糖",然后是"奶",而"网络"根本接不上,尽管语法上完全说得通。您几乎是瞬间、不假思索地做出了这个判断。模型做的是同一件事,只是走得更彻底、更正式:它会过一遍整个词表,给每个候选打一个分数。

模型评估句子续写的可能选项:在"我喝咖啡不加"之后,"糖"的可能性很高,"奶"也会出现,"网络"几乎不可能句子的开头我喝咖啡不加糖可能性很高奶也会出现网络几乎不可能
每个选项都有自己的分数,但没有哪一个被标记为"正确"

请注意这张图里缺了什么。没有哪个选项被标成"正确的":只有更可能和更不可能的续写。而且这些数字不是靠数这个组合在文本里出现过多少次算出来的 - 那是完全不同的一种技术,简单得多,早在现在的模型出现之前就被淘汰了。概率是根据训练过程中沉淀在模型内部的规律计算出来的。这也是为什么它能给一句从来没人写过的话打出分数。

LLM 和聊天、智能体有什么区别

这三个词经常被当作同义词使用,其实它们说的是系统里不同的层。

  • LLM - 语言模型本身。接收上下文,生成下一条消息。
  • 聊天 - LLM 外面的界面和程序。它保存历史记录,组装请求,发给模型,再把回答显示出来。
  • 智能体 - 带有目标、工作循环和工具的 LLM。它可以让应用程序读取文件、执行搜索或运行测试,查看结果,再决定下一步做什么。
三层嵌套结构的简化示意图:智能体内部是聊天,聊天内部是语言模型。LLM 生成消息,聊天在此基础上加上历史记录和界面,智能体再加上目标、工作循环、工具和权限智能体目标 · 工作循环 · 工具 · 权限聊天界面 · 历史记录 · 上下文组装LLM上下文 → 下一条消息每一层外壳都在模型基础上添加自己的能力
LLM 是核心;聊天和智能体各自在模型外面添加自己的能力

简单说:LLM 给出方案,聊天负责组织对话,智能体把模型给出的方案和外部世界的具体动作连接起来。

模型处理的是 token,不是单词

上面那张图得补充一句:图上的词都是完整的,那只是为了看得直观。实际上模型把文本切成 token - 自己词表里的一个个碎片。一个 token 可能是一整个单词,也可能是单词的一部分,或者一个标点符号;空格通常会并入后面那个 token,不会单独算成一个单位。

词表是提前在大量文本上建立起来的,而且是一点一点建的:算法找出频繁出现的字符序列,把它们拼成更大的碎片。出现得越频繁,就越可能拿到属于自己的 token。所以建好的词表里,整词和词的碎片是混在一起的。

词表里每个 token 都有自己的编号,文本进入模型的时候已经变成了数字:先把字符串切成一个个碎片,再把每个碎片换成它对应的编号。反过来,回答要变成可读文本时,也是靠同一个词表展开的。

同一个意思用两种语言表达:英语短语 coffee every morning 被切成三个 token,而德语 Kaffee jeden Morgen 同样是三个词,却被切成五个 token。灰色矩形表示空格,它并入了跟在它后面的 token英语3 个词,3 个 token德语同样 3 个词,却已经是 5 个 tokencoffeeeverymorningKaffeejedenMorgen
灰色矩形就是空格:它不会消失,只是并入了后面那个 token。切分方式是示意性的,每个模型都有自己的词表

由此有两件事值得记在心里。第一,每个模型家族的词表都不一样,同一个字符串在不同模型里的切分方式也不一样,像"一个 token 大约是四分之三个单词"这种估算,只是针对英语的粗略参考,仅此而已。第二,训练文本里出现得越少的语言,被切得越碎。一个德语单词经常会被拆成两三个 token,而对应的英文词只用一个就够了。

这种事看一眼比读文字描述直观得多。打开 The Tokenizer Playground,把您平时常发的几条请求粘进去,再粘一遍对应的英文 - 立刻就能看到字符串被拆成了哪些碎片,一共多少个。有一点要说明:那个页面上的分词器属于某个具体的模型,您实际用的模型分法可能不一样。去那儿是为了看现象,不是为了拿到某个精确数字。

这带来一个意想不到的实际后果。模型看到的是碎片,不是单个字符,所以关于字符本身的问题,明显比关于含义的问题更难回答。让它数一数一个长单词里字母"o"出现了几次,答案很可能是错的。不是因为这个任务本身难,而是因为这个词到达模型的时候已经变成了两个碎片,碎片内部的单个字母对它来说根本不存在。

答案是怎么从 token 拼出来的

现在把整个机制拼起来看,它会比想象的简单。模型给各个选项打分,选出其中一个,接到文本末尾。然后整个过程重新开始 - 还是同样的文本,只是多了一个 token 的长度。

连续三步生成过程:在"我喝咖啡不加"这句话后面加上 token "糖",接着在新句子后面加上 token "已经",然后再加上 token "十"目前已经写的内容下一个 token每一个被选中的 token 都会回到下一步的输入里我喝咖啡不加我喝咖啡不加糖我喝咖啡不加糖已经糖已经十
答案不是一次性拿到的:它一次长出一个 token,每个新 token 都会影响下一个

完整的答案不是提前存在某个地方、拿出来就行的 - 它是一步一步拼出来的,有多少个 token 就走了多少步。结束的时机也不是靠计时器:某一时刻,最可能的续写变成了一个表示"到此为止"的特殊 token,生成就停下来了。

从同一张图还能看出另一个细节。模型没法把已经写下的内容擦掉:一个 token 一旦进入文本,就会留在那里,参与到后面每一步的输入里。它能做的纠正,跟人在对话里纠正自己是一回事 - 靠接下来那句话。

还有一个让很多人意外的结果:同一个问题问两次,可能得到两个不同的答案。每一步选中的不一定是最可能的那个选项,而一个偏离主线的 token 会把它后面的所有内容都带偏。多数情况下只是措辞变了,但有时连给出的方案都会变。

终端里到底发生了什么

答案在 Claude Code 窗口里一点点浮现出来的样子,不是加载动画,而是生成过程本身:模型每选出一个 token 就立刻发出来,程序马上把它显示在屏幕上。所以长答案才会逐渐出现,而不是停顿之后整段一起冒出来。

为什么这种模型叫"大"模型

"大"这个字说的不是某个文件占多少存储空间。它背后其实是两种完全不同的规模,两者都值得老老实实弄清楚。

第一种规模是模型训练时读过的文本量:书籍、文章、文档、论坛帖子、代码,加起来的量是一个人几辈子都读不完的。第二种是参数的数量。参数是模型内部的一个数字,是训练过程中被不断调整的设置之一。这样的数字有几十亿个。开源模型往往直接把这个数字放进名字里:7B、14B、70B,这里的 B 就是 billion,十亿。

接下来就是最容易搞错的地方。参数数量不是质量评分。结果还取决于训练用的数据、模型的架构、针对哪些任务做了调优,以及为了塞进某种硬件而做了怎样的压缩。一个更小的模型完全可能在某项具体工作上超过更大的模型。名字里的大数字本身什么都不保证。

还有一件事,在这个规模上似乎是自然而然发生的。要顺畅地续写一句关于测试失败的话,光知道哪些词经常挨在一起是不够的,还得抓住测试这件事本身是怎么运作的。模型学的是预测下一个词,但在这个过程中,这些词所描述的事实和关系也顺带沉淀进了它的参数里。它给人的那种"懂行"的感觉正是由此而来,尽管底层机制一步都没变。

模型的知识从哪里来

来源正好只有两个,把它们混为一谈的代价不小。

第一个是参数。训练过程中学到的规律固化在了参数里。这不是那种每条记录都标着出处的卡片索引:知识分散在大量数字里,没办法从中提取出精确的原文引用。所以模型给出的答案可能"几乎对":格式对了,名字也眼熟,但某个具体细节是错的。

第二个是眼下就在对话里的东西:您的请求、之前说过的一切、打开过的文件内容、执行过的命令的输出。这个来源很精确,但寿命很短。它不会沉淀进参数,下一次对话对它一无所知。

其余那些看起来像"独立来源"的东西 - 记忆文件、搜到的文档、外部服务返回的结果 - 走的都是同一条路:先进入对话,然后才能影响回答。模型自己并没有通向项目或互联网的专属入口。

第一个来源有一个日期,这个日期有个名字,叫 knowledge cutoff(知识截止日期)。它是一个参考点,标志着模型的内置知识通常更新到什么时候。对于这个日期之后发布的库,模型只知道当前对话里给它看过的那部分。

这里有一点补充,比日期本身更重要。cutoff 不代表这一天之前模型什么都知道,之后就什么都不知道。这段时期内部也会有空白:有的主题相关文本本来就少,有的资料相互矛盾,有的干脆没进训练数据。日期划的是上限,不是这条线以下的完整性保证。

还有一件小事,但很实用。直接问模型自己的 cutoff 是哪天,不是个好主意:面对这个问题它照样会用生成的方式回答,也就是挑一个听起来合理的答案。准确的日期写在具体版本的文档里,同一个系列里相邻的模型,日期完全可能不一样。

Thinking 到底是什么意思

屏幕上出现 Thinking 的时候,模型并没有切换到什么别的"意识模式"。只是在正式回答之前,它得到了一点思考的空间。从技术上说,这仍然是同一种生成:模型先给自己写一份草稿 - 拆解任务、比较各种可能性、跟自己的想法较劲 - 然后才给出最终文本。具体要想多久,很大程度上由现在的模型自己决定:简单问题的草稿很短,甚至没有;复杂问题的草稿会更长。

同一个请求既可以直接给出快速答案,也可以先经过任务分析和检查,再给出最终答案同一个请求 - 不同的思考预算快速请求快速答案Thinking请求分析检查答案第二条路线在最终答案之前会多花时间和 token
同一个请求既可以得到快速答案,也可以得到额外的分析和检查时间

为什么需要这样,看个例子就明白了。智能体在找一个测试失败的原因。第一个说得通的解释指向了访问外部服务的客户端,但相邻的测试和报错文本却说的是另一回事:问题出在数据解析上。有了足够的思考空间,模型能在给出修改方案之前发现这个矛盾并改变方向。这里的好处不是推理写得多长,而是检查这一步真的改变了下一步。

第一个解释其实经常是错的。它看起来说得通,但"说得通"正是这套机制选中它的标准。

接下来说说额外的推理什么时候值得。它是要花时间的,没必要每件小事都用上。

快速回答通常就够了值得给点思考空间
解释屏幕上这段代码做了什么找出涉及多个文件的测试失败原因
改一个错别字或格式问题把两个方案连同各自的限制放在一起比较
复述一下您刚给出的文本规划一次步骤之间相互依赖的重构

参考标准很简单:任务里的分支和依赖越多,让模型多展开一些就越有用。改个变量名的话,您看一眼结果比读一遍推理过程更快。

还有一条老实话要说。展示出来的推理过程,并不是模型内部真实发生的事情的精确记录,很多时候是给读者准备的一份复述。一条又长又工整的推理链,完全可能是从一个错误前提长出来的,看起来却比实际更可靠。反过来的情况也存在:答案其实已经找到了,模型却继续犹豫,绕圈子,把自己越想越乱。这种情况甚至有个专门的名字 - overthinking。

比"好好想想"更管用的做法

让模型想久一点是个弱办法:草稿的长度本身不会带来任何改善。真正管用的是清晰的目标、明确写出来的限制条件,以及一个可以判断任务是否完成的具体标准。有了这些,模型才有东西可以拿来检验自己的推理。

模型做不到的事

这份清单不长,提前知道比在实际任务里踩坑发现要好。

  • 保证事实是对的。 这套机制选的是可能的续写,而不是拿论断去核对信息源。编出来但看着合理的细节,通常叫幻觉。
  • 不受措辞影响。 换个词序、加一句说明,答案就会变,因为一切都取决于这个位置之前的文本。
  • 自己学到新东西。 没有外部来源,内置知识就不会更新:关于昨天刚发布的库,模型只知道有人给它看过的那部分。
  • 逐字重复自己。 同一个请求可能给出不同的结果,这是这套机制本身的特性,不是故障。
  • 摆脱源文本自带的偏向。 源文本里哪儿说得片面、哪儿干脆没提到,答案里也会跟着体现出来。

围绕语言模型长出来的东西,几乎都是在回应这份清单里的某一条。搜索和文档查阅工具的出现,是因为内置知识会过时。工具和智能体的出现,是因为模型本身只会说话。

这能解释智能体的哪些行为

了解了这套机制,就能看懂 Claude Code 屏幕上直接发生的这些事:

  • 答案是一块一块出现的,因为它本来就是这么生成的。这是过程本身,不是某种视觉效果;
  • 两个一模一样的请求得到了不同的答案 - 这本来就该如此,生成过程不会逐字重复自己。需要之前的结果时,回到已经拿到的那个结果,比重新问一遍更靠谱;
  • Thinking 给的是打草稿的空间,不是正确性的保证。用在拆解多步骤任务上很划算,用在改个变量名上反而经常碍事;
  • 只要智能体还没读某个文件,关于这个文件的回答就只能靠通用规律撑着。进入对话的内容,分量比沉淀在参数里的内容更重;
  • 模型默认对库的最新版本知道得不多,最简单的补救办法就是把文档放进对话里;
  • 如果答案跑偏了,补上缺的信息比用同样的措辞重复请求更管用。这套机制靠的是答案之前的文本,不是您的坚持。

了解这套机制不会让模型变得更差。它只是说清楚了该对模型抱什么期待:它不是带保证的百科全书,而是一个非常擅长续写文本的机制,您给它一个开头,它接着往下写。

视频:同样的原理,用画面讲一遍

3Blue1Brown 频道有一个短视频,把主要内容浓缩成了一段直观的动画:token、下一个词的概率、attention,还有模型的参数到底是怎么来的。视频叫 Large Language Models explained briefly。

原片是英语的,但视频提供了好几条翻译音轨,在播放器设置里就能切换。如果没有您需要的语言音轨,直接在 YouTube 上打开这个视频:网页播放器里的选项更多。

这个频道不止这一个视频。频道里还有一整套关于神经网络、transformer 和 attention 的系列 - 同样的想法,只是讲得更细,还带上了数学推导。如果读完这篇文章之后,您想弄明白的不只是"发生了什么",而是"这背后为什么能成立",从那个系列开始正合适。