04|输出是怎样一个Token一个Token生成的
本章目录
本章预备知识
推理分为先处理已有输入,再逐个产生新Token。输出分数不是词表编号,概率也不是答案正确率;采样从分布中选编号,解码再把编号变成文字。
本章各题列出所需基础。可先完成相应基础课,也可通过自检确认掌握程度。
进入深读前的小检查:用同一组logits分别取最大值与按概率抽样,解释两者为什么可以产生不同结果;再解释为什么实际生成长度不一定等于最大预算。
术语带虚线时可点击速查。公式中的字母先看定义;不要用猜缩写替代推导。
理解生成过程要同时跟踪两条线:模型此刻预测哪个位置,以及服务此刻已经缓存到哪个位置。很多关于首Token、输出长度、推理缓存的误解都来自把两条线混为一谈。
沿着对象与状态理解本章
一次预测完成只表示刚选出一个新Token。该Token还没经过自身的各层计算;继续生成时它才作为新输入。下图给出固定小模型的真实中间结果,并明确标出EOS如何终止循环,与最大长度截断分开。
下方图解的固定输入在“输入与适用条件”中声明。它用于解释本章机制,不与本章其他独立例子的数值暗中接续。
一次输入如何连着预测,直到结束
预测到的Token什么时候显示,什么时候成为下一轮输入?
生成像接一条未完的序列,但不是把整句想好再逐字揭幕。每一轮使用已有前缀产生下一项分布,选择一个Token,把它加入已生成序列,再进行下一轮。使用KV缓存时,程序只把尚未处理的新Token送入模型;历史并没有被丢掉,而是通过每层缓存参与计算。
输入与适用条件:独立、可复算的微型模型:7项教学词表、4维表示、单层单头因果Attention、残差与tanh前馈;省略归一化和位置编码。输出头只用三条指定前缀拟合,目的是演示“学习→!→EOS”,不具有通用语言能力。完整参数与中间值随包提供。
1 / 10 · 输入是“我爱”,还没有输出
窄屏可左右滑动图形,或点击“放大图形”。文字解释紧随图后。
本例教学分词得到[1,2]。这是一台极小的因果模型;下面的候选分数由程序计算,不是商业模型实测。
输入=[1,2];缓存长度=0默认静止。用“下一步”看完解释再继续;播放到最后一步自动停止。键盘聚焦播放器后,可用左右键逐步查看、空格播放/暂停。图中颜色辅助区分,含义同时用文字注明。
为什么需要
先区分已处理、已选出、待处理三种状态,才能正确实现生成与缓存。
怎样实现
循环中先前向、再选Token、判停止;未停止时只追加新Token作为下一次输入。
可能的代价与误解
把刚选出的Token算进缓存长度,会造成位置偏移、重复追加或漏算;更改模型参数还会让缓存失效。
如何判断是否做对
本图实际算出三轮选择[3,5,6],缓存长度[2,3,4];每轮与从头计算整个前缀的结果比较。
Q013|Prefill与Decode有什么区别?第一个输出Token何时产生?
核心回答
Prefill处理整个已知输入前缀并建立各层缓存;输入最后一个位置的logits已经能够预测第一个新Token。采样得到这个Token后,下一次Decode才把它作为输入经过全部层,预测再下一个Token。输出不是先一次性想好再分段发送。[CACHE][TR]
按时间和位置走完三步生成
假设Prompt是x0,x1,x2,x3,长度P=4。我们要生成y0,y1,y2。
| 时刻 | 本次输入网络的Token | 本次计算位置 | 结束后KV包含 | 用哪个输出选下一Token |
|---|---|---|---|---|
| Prefill | x0…x3 | 0…3 | x0…x3 | 位置3的logits采样y0 |
| Decode 1 | y0 | 4 | x0…x3,y0 | 位置4的logits采样y1 |
| Decode 2 | y1 | 5 | x0…x3,y0,y1 | 位置5的logits采样y2 |
表里已经采样出y2,但y2还没有作为输入经过网络;此时缓存还不包含它。若继续生成,下一步才处理y2。这种“一步偏移”会影响缓存长度、停止条件和恢复逻辑。不要把“已经输出几个Token”直接当“已经有几个输出Token进入KV”。具体服务可能封装这些步骤,但底层条件依赖仍存在。
为什么Prefill能把多个位置一起算?因为输入Token已经全部已知,各层通过矩阵运算同时处理多个位置,再用因果mask禁止未来依赖。为什么标准Decode不能一口气算出后面100个真实Token?因为y1依赖采样出来的y0,y2又依赖y1;未选出的Token还不知道,无法直接作为下一层输入。
生成时所有模型层仍要执行。KV缓存省的是旧位置的重复计算,不是新Token只经过最后一层。每个新位置在第l层都有自己的Q/K/V,并从该层历史缓存读取信息。
Prompt长3,再生成2个Token,逐轮列出长度
输入与条件。请求只需生成两个新Token,原Prompt是 [1,2,3]。选出的Token依次为4、5,这是教学给定输出。
| 步骤与对象 | 内部动作 | 中间结果 / 新状态 |
|---|---|---|
| 1Prefill输入 | [1,2,3] | 本轮算3个位置,缓存长3。 |
| 2Prefill末尾预测 | 选择4 | 可见序列长4,已计算缓存仍长3。 |
| 3Decode输入 | 仅输入[4]并带KV | 缓存长4,避免把1、2、3再算一遍。 |
| 4Decode末尾预测 | 选择5 | 已生成2个新Token,达到本例max_new_tokens=2。 |
| 5停止 | 不再处理5 | 最终可见序列长5、缓存长4;这不是少算错误,而是最后Token无需再用于下一次预测。 |
把过程连起来。第一个输出来自Prefill最后有效位置的logits;后面每次Decode消费刚生成而尚未处理的Token。
边界与反例。某些服务会在内部继续处理或管理缓存;这里是明确停止策略下的最小生成循环。
依据与适用范围:[CACHE]。示例输入和场景由本书明确设定。
追问:训练为什么能够并行预测一整段?
训练使用真实前缀进行teacher forcing,位置i的目标已知,可以同时计算不同位置的条件概率。推理时使用自己生成的前缀,前一个选择会改变后续输入。这也是训练分布与生成分布可能存在差异的来源之一,不代表训练时复制标签就能获得可靠推理。
追问:每次Decode只输入一个Token,模型如何知道完整问题?
这个Token通过每层Q读取该层历史K/V,而这些缓存包含对原始前缀的上下文化计算。输入张量短不代表条件信息短。若缓存丢失,服务就需要重建前缀或使用其他受支持状态,不能只给一个孤立Token而期待同样分布。
追问:流式显示是否意味着每个屏幕字符对应一次Decode?
不一定。Token可覆盖多个字符或不完整字节,服务可能批量发送增量,网络chunk也与Token边界无关。可见文字还可能不包含内部推理Token。UI显示粒度、网络事件粒度和模型Token生成粒度必须分开。
Q014|Temperature、Top-k、Top-p怎样改变输出?为什么温度为0也不等于百分之百复现?
核心回答
模型先给词表logits,解码策略再把它们变成候选分布并选择Token。温度缩放尖锐程度,Top-k限制候选数量,Top-p限制高概率候选的累计概率范围。它们影响探索和多样性,不为事实正确性提供保证。[GENERATION]
用同一组logits比较
假设三个候选的logits为[2,1,0],按softmax(z/τ)得到:
| 温度τ | 候选A | 候选B | 候选C |
|---|---|---|---|
| 0.5 | 0.8668 | 0.1173 | 0.0159 |
| 1 | 0.6652 | 0.2447 | 0.0900 |
| 2 | 0.5065 | 0.3072 | 0.1863 |
温度降低让已有最大项更占优势,并没有重新核验A是否真实。若最高概率项恰好是流畅的错误说法,低温只是更稳定地输出它。
Top-k先保留概率最大的k项,再归一化。Top-p先按概率排序,取累计概率达到阈值的最小前缀集合,再归一化。例如概率[0.55,0.25,0.15,0.05]、p=0.8,常见实现保留前两项;p=0.9则还要保留第三项。边界、最少保留数量及与其他处理器的先后顺序要看实现。
温度为0在API中通常表示某种贪心选择约定,不是直接计算除以0。贪心每步选择最大logit,是局部决策;它不保证整段序列的全局概率最大,更不保证任务质量最佳。Beam Search探索多个候选前缀,但对开放式回答也可能导致重复或不自然,不能把搜索宽度当万能质量旋钮。
相同logits经过温度、Top-k和Top-p后怎样重新分配
输入与条件。logits=[2,1,0]。温度1为基线;温度2只作独立对照。下面Top-k、Top-p两步分别回到温度1的基线分布重新开始,各自过滤并归一化,不是把上一行结果继续输入下一行。
| 步骤与对象 | 内部动作 | 中间结果 / 新状态 |
|---|---|---|
| 1温度1 | softmax原分数 | 约 [0.665241,0.244728,0.090031]。 |
| 2温度2 | softmax([1,0.5,0]) | 约 [0.506480,0.307196,0.186324],更分散。 |
| 3Top-k=2 | 回到温度1的基线 [0.665241,0.244728,0.090031],只做Top-k=2;保留前两个,丢第三个 | 重归一化为 [0.731059,0.268941,0]。 |
| 4Top-p=0.8 | 再次独立回到温度1的原概率(不接续Top-k),按降序累计0.665241、0.909969 | 必须保留前两个,不能只留第一项。 |
| 5故意改变实现 | 先过滤再温度缩放,或不同相等值排序 | 可能改变边界集合,所以要记录完整生成配置。 |
把过程连起来。温度改变候选相对概率;Top-k/p改变支持集合。注意本表第2、3、4行是独立对照,不是连续执行。关闭抽样也不消除底层浮点与服务差异。
边界与反例。不把“温度0”代入除法;贪心是单独策略。显示值舍入,计算使用完整精度。
依据与适用范围:[DERIVE]。示例输入和场景由本书明确设定。
追问:固定seed为什么仍可能不同?
seed控制随机采样的一部分。模型版本、请求模板、工具内容、并行kernel、浮点归约次序及服务配置变化,仍可能改变logits。靠近并列的候选可能因微小数值差异换位;一旦某个Token变了,后续前缀也变,差异会放大。应先固定可控制条件,再讨论可复现程度。
追问:重复惩罚能解决复读吗?
它可调整已出现Token的选择倾向,但复读也可能来自Prompt、停止条件、训练分布或任务本身。代码中重复符号和变量可能是正确输出,惩罚过强会破坏代码。先确认复读是内容问题还是协议循环,再选择解码或Harness修复。
追问:是否应该同时调很多采样参数?
不宜从多个维度同时改起,否则很难归因。先选任务所需的输出稳定性与探索程度,固定基线,再改一个关键参数并观察真实成功率。API和模型对参数支持不同,不能把某个开放模型示例原样套给全部推理服务。
Q015|模型怎么知道答案结束?EOS、停止字符串、长度限制和工具调用结束有什么区别?
核心回答
结束可能来自模型采样到结束标记,也可能由服务达到长度上限、命中停止条件、产生需要交给工具处理的输出、取消或异常而终止。“不再收到文字”不等于“答案完整”,更不等于“任务完成”。[GENERATION][STREAM][TOOLS]
四层结束语义
第一层是Token序列结束。模型可对EOS或消息结束Token给概率并采样,具体标记取决于模板。结束标记也经过训练,不是一个知道所有用户要求都已满足的独立证明器。
第二层是模型响应结束。服务可能因为最大输出预算终止;这种情况常有incomplete或长度相关状态。半截JSON、未闭合代码块或未完成工具参数不能因连接关闭就当作有效结果。停止字符串一般由解码或服务后处理检测,有可能跨多个Token,需要维护边界。
第三层是工具交接。模型生成一个完整调用项后,当前推理可能暂停,把控制交给宿主。工具完成后追加结果,再发起下一次推理。它是一个循环中的阶段完成,不是用户任务完成。返回call_id就是为了关联哪个调用得到了哪个结果。
第四层是业务完成。编码任务的结果主要是当前文件和测试证据,而不是一段“已修复”的文字。若最终回答出现但测试未运行、文件仍未写入、外部操作结果未知,任务依然可能没有完成。
四种停止信号在同一段输出中意味着不同事情
输入与条件。教学生成器可能输出文字、EOS或一个工具调用。用户要读文件并解释结果,限制最多100个新Token。
| 步骤与对象 | 内部动作 | 中间结果 / 新状态 |
|---|---|---|
| 1EOS | 模型选择了结束Token | 文本生成可结束;宿主还需确认业务任务是否完成。 |
| 2停止字符串 | 输出匹配预先配置的字符串“END” | 是界面/服务截断约定,不是模型天然的任务证明。 |
| 3长度上限 | 第100个新Token后仍没有结束 | 标记达到限制或不完整,不能伪装成自然完成。 |
| 4工具调用完成 | 完整产出read_file参数 | 只是模型暂停把控制交给执行器,整个用户任务并未结束。 |
| 5收到工具结果 | 重新进入模型循环 | 才能解释文件;工具参数生成完不能直接向用户宣称读到了内容。 |
把过程连起来。生成阶段结束、工具调用项结束、用户任务完成是三种不同边界。
边界与反例。具体API的结束原因字段不同;示例描述语义,不绑定所有接口都使用相同字段名。
依据与适用范围:[TOOLS]。示例输入和场景由本书明确设定。
追问:输出被截断后,直接说“继续”安全吗?
对纯文字可以尝试,但必须防止重复和结构损坏。对工具调用不能把半截参数拼成一个未经完整校验的动作直接执行;对写操作还要核对是否已有副作用。结构化状态应从协议支持的续接方式恢复,而不是依赖模型凭记忆补上缺失字段。
追问:为什么有时“回答很短”仍花了很多输出预算?
推理型服务可能包含不可见于最终答案的推理Token,且接口对它们的预算和使用量有专门语义。最终可见字符数不能代表全部模型输出计算。要读实际usage字段和响应状态,而不是从聊天气泡长度估计账单或上下文余量。
追问:合理的完成检查是否会让简单任务复杂化?
检查应与任务对应。解释概念不需要跑测试;修改一行配置只需相关验证;有外部副作用的任务才需要更明确的确认与对账。原则是验证用户真正关心的结果,不是为所有任务套上同一套重型工作流。
Q016|推理模型“多想一会儿”到底发生了什么?与多Agent、CoT有什么关系?
核心回答
推理型模型可通过额外推理时计算改善某些任务表现;具体内部机制与状态公开程度因产品而异。普通多轮Agent则通过外部工具和多次模型调用增加信息与执行步骤。CoT、搜索、自洽、多Agent和推理预算处在不同层,不能统称为“多想”。[REASON][R1][REACT]
区分四种额外计算
第一种是在同一次生成中产生更多中间推理。后续Token可利用前面的中间结果,但错误也可能延续。增加长度不自动保证有效推理,模型训练方式和任务结构都重要。
第二种是重复采样多个答案,再通过一致性或验证器选择。它使用多条生成路径,需要可靠聚合;若每条都依赖同一个错误事实,多数票仍错。程序可验证题和开放研究题的聚合难度完全不同。
第三种是搜索候选状态,例如Tree of Thoughts类方法显式生成、评价、保留或剪枝。其收益依赖评价器能否识别更好分支,且分支数与深度会增加成本。没有可靠评价器,搜索可能把正确路径过早剪掉。
第四种是Agent调用外部工具:读当前源码、运行测试、查询数据库。这不是单纯增加内部推理,而是引入模型原本没有的新证据。对“当前代码为什么失败”,一次正确的测试或读取可能比增加十倍无证据推理更有效。
更多推理、外部搜索和多Agent:同一问题的三种增加工作量
输入与条件。任务是找出测试失败原因。候选原因有“配置错”和“测试环境错”,当前缺运行环境信息。
| 步骤与对象 | 内部动作 | 中间结果 / 新状态 |
|---|---|---|
| 1增加模型计算 | 同一上下文内让推理模型投入更多推理预算 | 可能更认真比较已有线索,但缺失的环境变量不会凭空出现。 |
| 2增加外部证据 | 工具读取环境与依赖版本 | 新事实可能排除“配置错”。 |
| 3增加Agent | 一个读配置,一个读环境 | 只有两部分确实可独立调查时才可能有并行收益。 |
| 4记录成本 | 分别比较模型计算、工具调用与交接开销 | 不能把它们都写成“多想一会儿”。 |
| 5验证收益 | 用相同失败案例和结果标准对照 | 多生成文字不等于根因更准确。 |
把过程连起来。内部推理预算、外部信息和多Agent编排分别改变计算、证据和组织方式。
边界与反例。没有声称可见文本等于模型内部推理,也没有公开或编造任何隐藏推理过程。
依据与适用范围:[DERIVE]。示例输入和场景由本书明确设定。
贪心第一步最好,不等于两步序列概率最大
输入与条件。第一步P(A)=0.6、P(B)=0.4。若已选A,第二步P(E|A)=0.51、P(F|A)=0.49;若已选B,P(D|B)=0.99、P(F|B)=0.01。只比较固定长度2。
| 步骤与对象 | 内部动作 | 中间结果 / 新状态 |
|---|---|---|
| 1贪心选择 | 第一步先选A,再选E | AE联合概率0.6×0.51=0.306。 |
| 2保留两个前缀 | 宽度2的束在第一步保留A和B | 第二步必须分别使用各自条件概率,不能混用。 |
| 3展开四条路径 | AE=0.306,AF=0.294,BD=0.396,BF=0.004 | 两步内最高的是BD,而不是贪心得到的AE。 |
| 4观察代价 | 保留两条前缀就要维护对应状态 | 缓存、候选扩展与排序增加;这个两步例子没有证明固定束宽能找任意长度的全局最优。 |
把过程连起来。生成策略改变怎样选择模型给出的概率,不会凭空改变模型本身的条件概率。
边界与反例。固定长度避免了EOS与长度惩罚;这些机制加入后,排序目标必须重新明确。
依据与适用范围:[DERIVE]。示例输入和场景由本书明确设定。
追问:推理Token是不是模型真实思维的完整记录?
不能这样推断。可见的解释、推理摘要与模型内部计算不是一一对应的完整审计轨迹。隐藏内容的具体形式和训练机制可能未公开。工程诊断优先用可观察输入、工具、输出、状态与测试,不能把一段自述当作全部因果解释。
追问:复杂任务是不是一定选择最高推理强度?
先看瓶颈。证据缺失、工具不可用、权限错误不会因强度更高而自动解决。高强度可能适合复杂推导或方案比较,但会增加延迟与成本;需在同类真实任务上衡量增益。低风险简单任务通常不应为了“严谨”而机械增加推理与多轮Review。
追问:模型在当前对话中纠正错误,算学习了吗?
可以称上下文内适应或行为修正,但普通推理并没有因此更新参数。结束会话后能否保留,取决于外部记忆或训练系统。把反馈写入历史、持久化经验和微调权重是三种不同操作,需要分别设计存储、权限和验证。