Appearance
第2章 接龙机器的真相——LLM
小a接了个任务:给公司的 AI 客服写第一版问答接口。需求很简单——把用户的问题发给模型,把回答展示出来。他半天就把代码写完了,高高兴兴地跑了几组测试。
然后他发现了一件事。同一个问题,用户问两次,第一次模型回答得规规矩矩,第二次却冒出一个根本不存在的 API,还一本正经地给出了用法。
参数一样,模型一样,代码一样。结果差这么多。
他把两次输出并排贴在屏幕上,越看越不对劲,把老z拉了过来。
“是我哪里写错了吗?”他指着屏幕问。
老z没接话,盯着看了一会儿,反问道:“你觉得,它到底在做什么?”
“在……回答问题?”小a不太确定,“它学的东西多,知道答案。”
老z不置可否,把电脑转过来,在终端里敲了一行字:“从前有座山,山里有座__”。回车。模型接出两个字:“庙”。
“再来一次。”老z又敲了一遍同样的话。模型还是接了“庙”。
小a没看懂:“这能说明什么?”
“说明它不是‘知道答案’。”老z说,“给你‘从前有座山,山里有座’,你也会接‘庙’——不是因为你查过,而是因为‘庙’是最顺的接法。它做的其实是同一件事:读你已经写下的所有文字,然后猜下一个最可能出现的字。”
比喻:接龙机器
它是一台只做一件事的打字机:读你已经写下的所有文字,然后打出下一个最可能的字。它不知道自己写的是代码还是诗,只知道顺着读下去,这里最该出现什么。
“可它能写代码、能解数学题,”小a不服气,“猜字怎么能猜出这些?”
“你把‘猜下一个字’重复几千遍,看看会发生什么。”老z在终端里画了个循环图:
text
输入 token ──> 下一个 token 的概率分布 ──> 采样一个 token
^ │
└──────────── 把结果追加回输入 ─────────┘“给定已有 token,语言模型输出的是下一个 token 的概率分布;选出一个 token,加回输入,再继续。这个过程叫自回归生成——自己接自己生成的结果,滚雪球一样往下滚。”
小a盯着这张图,半天没说话。他想起自己那句“它学的东西多,知道答案”,忽然觉得有点站不住脚。
“所以它输出的‘代码’,是一个字一个字续出来的?”
“对。这就是为什么它有时候给你一个不存在的 API——它不是查过了才写,是顺着读下去,这里‘最该出现’一个 API 调用。‘流畅、像真的回答’不能当事实证据。”老z顿了顿,“‘预测下一个 token’是已确认的模型目标和推理接口层面的事实;但它不能单独证明模型没有内部表征或不能完成推理。工程上更有用的结论是:输出是概率生成的文本,不是数据库查询结果。”
要点
- 大模型的本质是预测下一个 token,不是“查答案”
- 生成方式是确定的(自回归),能力是训练出来的——别混成一句“模型会思考”
先把名字对齐
| 中文术语 | 英文全称或缩写 | 本书工作定义 | 不等于什么 |
|---|---|---|---|
| 大语言模型 | Large Language Model, LLM | 根据输入 token 生成后续 token 概率分布的模型或服务 | 事实数据库或工具执行器 |
| token/分词器 | token/tokenizer | 文本被编码成模型处理的离散单位 | 汉字数、单词数或字符数 |
| 自回归生成 | autoregressive generation | 选中一个 token 后把它追加为条件继续生成 | 一次取回完整答案 |
| 参数 | parameters/weights | 训练中被优化的数值 | 每次请求都会写入的记忆 |
| 训练 | training | 用训练目标和数据更新模型参数的过程 | 一次普通模型请求 |
| 模型推理/推断 | inference | 使用固定参数处理新输入并生成输出 | 第3章 给思考留一张草稿纸——CoT讨论的 reasoning 过程 |
| 上下文窗口 | context window | 一次请求共同可见的 token 预算 | 跨请求自动持久化的会话 |
| 采样/温度 | sampling/temperature | 从候选分布选择 token 的过程/调节该分布的常见参数 | 正确性开关或统一厂商刻度 |
| 幻觉 | hallucination | 看似合理但不真实的事实、引用或代码细节 | 仅指措辞不够精确 |
| 提示词缓存 | prompt caching | 服务对可复用输入前缀复用计算的机制 | 正确性或应用侧自动记忆 |
2.1 它做的是条件续写
那天下午,小a坐在工位上,把“接龙”这个说法在心里翻来覆去地嚼。他还是觉得不对:模型会写代码、会翻译、会解题,怎么可能只是“接龙”?
他忍不住又去找老z:“你说它只做接龙,可它明明能干这么多事。”
“那你想想,说‘接龙’的时候,你脑子里最像的比喻是什么?”
“呃……打字机?”小a试着说。
“对。一台只做一件事的打字机:读你已经写下的所有文字,然后打出下一个最可能的字。它不知道自己写的是代码还是诗,只知道顺着读下去,这里最该出现什么。”
“可它能写函数,能推理数学题,”小a还是不肯松口,“打字机做不到这些。”
“它确实不是打字机。”老z承认,“我说‘接龙’,是为了让你先抓住生成方式,再谈能力。生成方式是确定的,能力是训练出来的——别把它们混成一句‘模型会思考’。”
要点
“接龙”说的是生成方式(怎么产生下一个 token),不是能力上限。能力是另一回事,后面几章会展开。
2.2 token 是计量单位,不是字数
小a回到工位,开始给接口加用量统计。他本来想按“字数”算账——用户发了几百个字,模型回了几个字,一目了然。可他打开账单明细,愣住了:账单上标的不是“字数”,而是一个叫 token 的单位,数字跟他数的字数对不上。
他拿着账单去找老z:“这 token 是什么?为什么比字数多?”
“它处理的不是‘汉字’,也不是‘单词’,而是分词器切出来的 token。”老z说,“切分方式随模型而变:一个词、一段代码片段、一个标点都可能构成一个 token;同一个字符串,在不同模型的 tokenizer 下数量也不一样。别用‘一个汉字等于一个 token’去估算,早晚会算错账。”
“那 token 到底影响什么?”小a问。
“三件事:上下文能放下多少输入;输出能生成多长;多数 API 的计量和计费方式。”老z扳着手指,“所以写程序时要先数一遍吗?只在接近模型限制、排查成本或设计截断策略时才需要。平时把长日志、整份仓库和重复规则当作有成本的上下文,而不是免费的字符串,就够了。”
“那不同语言的文本,token 数差很多吗?”小a追问。
“差很多。”老z说,“分词器是按训练语料的统计规律设计的——英文里一个常见单词可能就是一个 token,中文的一个汉字可能被切成两三个 token,代码里的缩进、括号、标识符各有各的切法。这意味着同样长度的文本,换一种语言或换一种内容类型,token 数和费用可能差几倍。”
| 内容类型 | 大致 token/字符比 | 备注 |
|---|---|---|
| 英文常见词 | 约 0.25(4 字符 ≈ 1 token) | 最经济 |
| 中文 | 约 0.5-1.5(1 汉字 ≈ 0.5-1.5 token) | 随分词器和字符频率变化 |
| 代码 | 高度 variable | 缩进、括号、长标识符各自切分 |
| JSON/结构化 | 偏高 | 大量标点和引号被单独切分 |
“这些比例是固定的吗?”小a问。
“不是。它们只是大致量级,精确值取决于具体模型的 tokenizer。”老z说,“要做精确估算,用目标 API 提供的 token 计数接口,或本地跑对应 tokenizer。没有通用的‘字数 ÷ N = token’公式——N 随模型和内容变。”
“那对上下文管理有什么影响?”
“直接影响截断策略。”老z说,“如果你按字符数截断历史消息,可能在 token 预算还有余量时就过早截断了(浪费空间),也可能在 token 已经超限时还没截断(请求被拒)。按 token 截断比按字符截断更准确,但需要能计数 token;没有计数能力时,留出安全余量比卡着上限更稳妥。”
2.3 参数、训练与推理
第二天,小a在调试时随口问了一句:“它这么会续写,是天生就会吗?”
“不是。参数(也常称权重)是模型在训练中学习得到的数值。”老z说,“训练以大量样本和优化过程更新参数;推理则使用固定参数,对新输入执行前向计算并生成输出。”
“那我也能训练一个吗?”小a的眼睛亮了一下。
“能,但要分清职责。应用开发通常调用推理服务,而不是在每次请求中改变模型参数。”老z给他列了一张表,“训练和推理的资源形态、成本,以及你能控制的东西,都完全不同。”
| 阶段 | 主要动作 | 应用工程师通常控制什么 |
|---|---|---|
| 训练 | 用训练目标更新参数 | 数据、训练方案或模型选择(若参与训练) |
| 推理 | 用固定参数生成输出 | 输入、模型、采样、工具和停止条件 |
“那训练和推理的成本差多大?”小a追问。
“差好几个数量级。”老z说,“训练一次大模型需要大量 GPU 跑数周或数月,成本以百万美元计;推理一次请求通常按 token 计费,几分钱到几毛钱。这不是同一个量级的游戏——应用开发者的工作是在推理预算内把任务做好,不是重新训练模型。”
“那微调(fine-tuning)呢?我看很多人在说。”
“微调介于两者之间——它用较小的数据集在已有模型上继续训练,调整部分参数。”老z说,“它的成本远低于从零训练,但仍远高于推理调用。微调适合你有大量领域数据、且通用模型在你的任务上表现不足的场景。它不是免费的性能提升——微调过的模型在通用能力上可能退步,且需要额外的评测和维护。”
| 方式 | 成本量级 | 适合场景 | 风险 |
|---|---|---|---|
| 从零训练 | 极高(百万美元级) | 基础模型研发 | 非应用开发者的事 |
| 微调 | 中等(需数据和 GPU) | 有大量领域数据、通用模型不足 | 通用能力可能退步 |
| 推理调用 | 低(按 token 计费) | 绝大多数应用场景 | 无(只是调用服务) |
“那参数越多的模型,是不是一定越聪明?”小a问。
老z摇头:“‘参数更多必然更聪明’不是可靠规则。模型架构、数据、训练方法、推理预算和任务类型都会影响结果;选型应以目标任务的评测为准。”
“那选型评测,要注意什么?”小a追问。
“在你的任务上测,而不是在排行榜上测。”老z说,“排行榜的分数是别人的任务分布算出来的,你的场景可能是长文本、是工具调用、是中文输出——排行榜上的一分之差,换成你的任务可能完全反过来。评测要构造自己的样本集:几组真实任务、几条失败路径、一段固定探针,跑同一份看输出是否满足契约。这样换模型时,你比的是‘谁更符合我的场景’,而不是‘谁的榜分更高’。”
要点
你作为应用开发者,只做推理——调用已训练好的服务。训练是模型厂商的事,两者成本差着好几个数量级。
2.4 上下文是一次请求的工作台
第三天上午,小a兴奋地跑来找老z:“我昨天跟模型聊了二十多轮,它全记得!你说它记不住,是不是说错了?”
老z没有直接反驳,只是问:“你今天给它发的那条消息里,有没有把你昨天说的话也带进去?”
小a一愣,翻了自己的代码——他的实现把整段历史都塞进了每次请求。
“记不住。”老z说,“每次模型调用都有一个有限上下文:系统指令、用户消息、历史消息、工具结果和当前问题都会占用它。模型本身不会在两次 HTTP 请求间自动记住上一次对话。”
“那我聊下去它明明‘记得’……”小a有点不甘心。
“那只是你的程序把有关内容再次带进了新请求。所谓‘记住’,是应用主动做的事。”老z在纸上画了个方框,“你可以把上下文想成一张工作台:桌上能摆的东西有限,摆不下就得取舍;换一个请求,就是换一张新桌子。”
text
系统规则 + 对话历史 + 工具结果 + 当前输入 + 预留输出
└──── 共同受上下文限制 ────┘“那 maxTokens 是不是就是桌子的尺寸?”小a觉得自己找到了答案。
“只对了一半。maxTokens(或相近命名)通常限制本次期望的输出上限;上下文窗口限制输入与输出的总预算,但不同服务对保留空间和字段名称的定义不同。”老z提醒,“实现时应读取目标 API 的当前文档,并在请求前预留输出空间,不能只看输入长度。”
“那输入输出都涨,先砍哪个?”小a追问。
“先砍‘可重建的’。”老z说,“系统规则和历史消息里,哪些能重建、哪些必须保留?通常的裁剪顺序是:能重新检索的项目资料先裁,历史对话按时间从旧到新裁,系统规则最后裁。**每次请求都该问一句:这段上下文如果没了,模型还能不能完成当前任务?**不能,就留着;能,就先裁它。”
“上下文满了怎么办?直接截掉会不会坏事?”
“截掉会损失信息,但有比截掉更糟的——不截,请求直接被拒绝。”老z说,“截断是显式丢弃旧内容并告知模型的边界;不截断则是让请求超限失败,任务根本没法开始。两者之间还有压缩(把旧对话压成摘要),但压缩会损失细节。截断、压缩、扩充窗口,是按代价从低到高排序的三条路,没有免费的。”
“那工具结果算哪一类?它也在桌上吧。”小a追问。
“算,而且是最容易被忽视的一块。”老z说,“一次工具调用返回的日志、文件内容、搜索结果,全部占用上下文,用完这一轮就得腾出来。它和对话历史一样,是可重建的——重跑一次工具就能再拿到,所以裁剪优先级很高。但能重建不等于重建没代价:重跑要重新付一次成本,能缓存的结果先缓存,实在要裁的,裁之前把引用位置留给审计。”
要点
- 上下文窗口:一次请求可见的有限预算(桌子的尺寸)
- maxTokens:单次输出上限(一口气能写多长)
- 两者各管一摊,别混为一谈;模型本身不跨请求记忆
2.5 采样让结果不是唯一答案
又过了两天,小a碰上一个新问题:同样的请求,跑两次,答案不一样。他怀疑是网络问题,正准备去排查,被老z拦住了。
“先别查网络。你把两次的输出并排看看,除了个别字,是不是大致对得上?”
小a照做了,发现确实如此。
“这就对了。因为模型给出的是概率分布,不是唯一答案。”老z说,“模型给出分布后,服务会按采样规则选 token。温度、top-p、top-k 等参数会改变候选分布或候选集合;并非每个提供方都支持全部参数,也不应随意叠加它们。”
“那把温度调低,是不是就‘准确’了?”小a问。
“不一定。低随机性通常更利于格式稳定和重复性,高随机性可能增加表达多样性。”老z说,“但它们不是‘准确模式’和‘创意模式’的保证:**错误事实在低随机性下仍可能稳定地重复。**若接口支持 seed,它也只能帮助复现某些条件下的结果,不应被当成跨模型、跨版本的确定性承诺。”
“那温度、top-p、top-k 到底各自控制什么?”小a追问。
“它们控制的是‘从候选里怎么挑’,三个层次不同。”老z说,“温度调节分布的平坦度——温度越高,低概率 token 越容易被选中,输出越发散;top-p(核采样)保留累积概率达到阈值的最小候选集,从里面挑;top-k 只保留概率最高的 K 个候选。三者都改的是采样路径,不改模型本身的能力——把参数调得再极端,模型不会凭空会做它本来不会的事。”
| 参数 | 控制什么 | 调高的效果 | 常见误用 |
|---|---|---|---|
| 温度 | 分布平坦度 | 更发散、更多样 | 以为能"纠正"事实错误 |
| top-p | 候选集的累积概率阈值 | 候选更集中在高概率区 | 与 top-k 同时叠加不加思考 |
| top-k | 候选集大小 | 只保留概率最高 K 个 | 固定 K 忽略分布形状 |
“这些参数要一起调吗?”小a问。
“不要随意叠加。”老z说,“温度、top-p、top-k 同时调,作用会互相干扰——你很难说清最终效果是哪层贡献的。实践上通常只动一两个:格式任务把温度调低,探索型任务把温度调高,多数情况保持默认。而且并非每个提供方都支持全部参数,先读文档再决定。”
“那怎么验证输出是稳定的?”
“靠测试,不靠参数。”老z说,“固定任务跑多次,看格式是否一致、关键事实是否每次都对;需要可复现时用 seed 加固定参数组合,并把它们作为请求的一部分记录下来。稳定性是测出来的结论,不是参数调出来的保证。”
“那把温度调到 0,格式是不是就保证合法了?”小a追问。
“不保证。”老z说,“温度调到 0,只是每次都选概率最高的那个 token——模型照样可能生成不闭合的 JSON,只是概率低一些,不是零。格式合法性是校验问题,不是采样问题:需要严格格式时,用 schema 约束加运行时校验,或让模型通过工具按受控模板产出,而不是寄望低温兜底。让一个本来不管格式的参数去干校验的活,等于把保证建在错误的位置上。”
要点
采样参数调的是“怎么选”,不是“对不对”。要格式稳定,收紧随机性并做测试;要事实正确,靠证据和校验。
2.6 幻觉是验证问题,不是措辞问题
折腾了两天,小a终于把话题拉回了一开始那个 bug:“它给出的那个不存在的 API,算是‘措辞不够好’吗?”
“不是措辞问题。”老z说,“当模型生成看似合理但不真实的事实、引用或代码细节时,常被称为幻觉。它的表现包括编造 API、误读文件、错误归因和虚构来源。由于模型生成的是可能的续写,单靠提示‘不要幻觉’不能消除风险。”
“那我能做什么?”小a记起自己踩过的坑,语气认真起来。
老z列了几条:
缓解幻觉的工程手段
- 对可查事实提供原始资料,并要求引用位置
- 让模型通过受限工具读取、搜索或运行验证
- 对高风险结果设置规则校验、测试或人工审批
- 把“不确定”和“验证失败”保留为可见状态,而不是强迫模型给结论
“那‘保留不确定状态’,具体怎么落地?”小a追问。
“就是把‘不知道’和‘没验证’都当成合法的输出类别。”老z说,“很多任务逼模型给结论——不答就是答错。但工程上,模型明确输出‘我无法从证据确认’比硬编一个答案安全得多。应用把这种状态单独展示,而不是当失败吞掉,用户才知道该去核实而不是照着做。允许模型说‘不知道’,是校验链路的一部分,不是模型偷懒。”
“那让模型去‘查一下’,它就一定对吗?”小a追问。
“这里的边界很重要。”老z说,“工具返回的内容也可能错误或被污染,所以工具不是‘真相按钮’,而是让证据链可检查的一环。”
“那幻觉是不是只有‘整段编造’一种?”小a问。
“不是,更难防的是部分失真。”老z说,“整段编造一眼能看出来,但更常漏网的是:引用了真实存在的文章,却把结论张冠李戴;数字本身没错,适用范围却讲错了;API 名是真的,参数却编了出来。这类幻觉每个片段单独看都‘查得到’,合起来才不对劲。验证不能只问‘这东西存在吗’,还要问‘它在这里用得对吗’——前者挡编造,后者挡失真。”
“那验证本身会不会出错?”小a追问。
“会,验证也是代码。”老z说,“正则可能匹配错、抓取的页面本身是错的、人工审批可能漏。所以验证的结论要保留原始证据的引用——模型引用了什么、你查了什么、结论是什么,三者存成一条记录。验证不是一锤子买卖,它是把‘怎么验证的’也变成可检查的数据。”
2.7 成本与提示词缓存
月底对账,小a看着模型账单傻了眼。他去找老z:“怎么这么贵?我就聊了几十个来回。”
“你每次都把整个历史重新发一遍,还带了几份长文档,对吧?”老z说,“一次调用的成本通常和输入、输出以及服务提供方的缓存规则有关。长上下文会增加延迟和费用,也会稀释真正重要的指令。许多服务提供提示词缓存或前缀复用:当稳定前缀满足其匹配和有效期条件时,服务可以复用部分计算。”
“那我是不是把资料都塞进提示词,缓存命中就省了?”小a眼睛一亮。
“别为了缓存把无关资料长期塞进提示词。”老z打断他,“通用设计建议是把稳定规则放在前缀,把频繁变化的信息放在后面;但缓存优化不能替代上下文管理。具体价格、命中条件和保留时间是产品政策,应以调用时的官方文档与账单为准。”
“那缓存命中有什么容易踩的坑?”小a追问。
“最大的坑是:前缀差一个字符,整段缓存就不命中。”老z说,“提示词缓存按稳定前缀精确匹配——前缀只要动一处,后面所有内容都要重新计算。如果你把会话号、时间戳这类每次都在变的字段放在前面,缓存就永远命中不了,账上却看不出问题。判断前缀稳不稳,就看它是不是每次请求逐字节相同;会变的内容放后面,别进前缀,命中率才保得住。”
要点
提示词缓存按“稳定前缀”命中——前缀一致才能省钱。别把缓存优化当成上下文管理的替代品。
2.8 一次生成如何变成可观测的请求
新的一周,小a把老z请到工位前,重新演示了一遍那个“不存在的 API”的 bug。
“我该从哪一步开始排查?”他问。
老z把电脑转过来,指着日志:“把‘接龙’落到程序里,至少有三个彼此不同的阶段:输入被 tokenizer 切分;服务在已有上下文上计算并逐步选择输出;应用收到文本、用量或结束信号。前两个阶段由模型服务完成,最后一个阶段由应用控制。把它们混成‘模型回答了一次’,会让排障失去位置。”
text
用户任务 → 应用装配上下文 → 服务生成 token 序列 → 流式事件 → 应用验证/展示
↑ ↑ ↑
可控输入 概率输出 可审计结果“那失败路径也不止‘答错’一种?”小a问。
“对。输入可能超过预算而被拒绝,输出可能因长度限制中断,流式连接也可能在得到部分文本后断开。”老z说,“UI 应把部分结果标成未完成;不要把它和自然结束的回答存成同一种状态。”
“那阶段之间怎么交接,才不会丢信息?”小a问。
“阶段之间传的是结构化记录,不是一句话。”老z说,“应用装配阶段记输入摘要和版本号;服务生成阶段记用量和停止原因;应用处理阶段记校验结果和落库位置。每个阶段的输出是下一个阶段的输入——如果上一阶段只留了一句‘模型回答完毕’,下一阶段就没有任何证据可用。把‘回答完毕’拆成‘用了多少 token、怎么停的、校验过没有’,排障时才能回答不同的问题。”
“那用户中途不想等了,能取消吗?”小a问。
“能,而且取消要和‘完成’分清楚。”老z说,“取消是应用主动中断——发出中断信号,服务停止生成,应用把已收到的部分标成‘未完成’。这和你前面看到的截断、断流都不是一回事:截断是输出到上限被切,断流是连接失败,取消是主动作废。三种都叫‘没答完’,但原因不同,记录时必须分开存,否则统计‘有多少次回答被中断’时只能靠猜。”
示意: 用户要求“列出仓库中的测试命令”。若应用没有提供仓库文件或检索工具,模型只能根据训练中常见项目继续生成;即使命令格式流畅,也不能说明它存在。若应用先读取项目配置,再要求模型引用读取结果,结论仍需由实际执行或人工检查确认。
2.9 把机制和结论分开
折腾了几天,小a终于把整条链路理清楚了。他列了一张表,贴在自己工位旁边:
| 已确认机制 | 可以安排的工程动作 | 不能据此推出 |
|---|---|---|
| token 逐步生成 | 为长度、取消和部分输出设计状态 | 输出一定经过完整推理 |
| 固定参数参与推理 | 不把一次聊天当成模型训练 | 参数多一定更准确 |
| 有限 context window | 预算、截断或压缩上下文 | 每条输入都会被正确使用 |
| 采样影响选择 | 对格式任务收紧随机性并做测试 | 低温必然事实正确 |
| prefix caching 是服务策略 | 稳定前缀与动态内容分层 | 一定命中缓存或省钱 |
“所以开头那个 bug——它给出了不存在的 API——不是网络问题,也不是我代码写错?”小a把整章的内容在脑子里过了一遍。
“对。同事在仓库走查中说‘读取配置后再回答’,只能说明应用把证据放进当前 context;仍应通过执行或人工核对确认结论。”老z最后总结,“正常完成但引用不存在的 API,是事实验证失败,不是网络失败;输入超预算、输出达到长度上限、流中断则分别需要缩减、标记未完成或停止恢复,不能统一保存为成功。”
“那排查的时候,怎么快速判断是哪个阶段的问题?”小a追问。
“按‘证据在谁手里’分。”老z说,“应用装配阶段的错误,日志里能看到输入字段不对——查应用代码;服务生成阶段的问题,看用量字段和流式事件——查请求参数和服务端状态;应用处理阶段的问题,看 UI 和存储——查你的展示与落库逻辑。每类错误的证据位置不同,混在一起排障就是在猜。”
“最后还有什么要留意的?”
“两个易混点。”老z说,“一是‘模型没报错’不等于‘结果正确’——正常完成只是生成了文本,文本内容仍需验证;二是‘截断了’和‘拒绝了’是不同状态——截断是输出超长被切断,拒绝是输入超预算请求没发出。把每种状态分开存,排障时才分得清。”
小结
理解 LLM 的第一步,是放下"它会思考"这个直觉。它本质上是一台接龙机器:以 token 为单位,根据已经看到的内容,预测下一个 token 该是什么。token 不等于字、词或半个词,它由分词器决定,同一个词在不同分词器下可能拆成不同的碎片。模型选中一个 token 后,把它追加到条件里继续生成下一个——这就是"自回归"的全部含义。训练阶段把海量语料压缩成参数,推理阶段用这些固定参数处理新输入,两者是完全不同的过程,不要混为一谈。
这台接龙机器有两个根本限制。第一是上下文窗口:超出窗口的内容,模型不是"忘了",而是"从未收到"——窗口是请求时一次性可见的预算,不是模型自己的记忆。第二是采样的概率性:温度、top-k、top-p 这些参数改变输出的分布,但不改变事实的对错;调高温度让输出更发散,调低让它更确定,可没有任何一个采样参数能保证生成的内容是真的。幻觉就是这种概率性的直接后果——模型不是在撒谎,它只是在按概率接龙,而接出来的内容恰好不真实。所以约束幻觉要靠证据、执行和校验,不能靠把温度调到零。
动手核验
用同一模型和同一问题运行两次:一次只要求结论,一次要求列出可核对的本地证据或官方来源。比较两份回答中可验证断言的比例。再把一段无关长文本加入输入,记录延迟、用量字段或输出质量的变化;若服务未暴露这些字段,不要据此猜测其内部计费。