<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>VLLM on 小盒子的技术分享</title><link>https://xiaobox.github.io/tags/vllm/</link><description>Recent content in VLLM on 小盒子的技术分享</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Fri, 06 Mar 2026 03:44:58 +0000</lastBuildDate><atom:link href="https://xiaobox.github.io/tags/vllm/index.xml" rel="self" type="application/rss+xml"/><item><title>昨天面试官问我：一个 Prompt 进入大模型后，内部到底发生了什么？</title><link>https://xiaobox.github.io/p/2026-03-06-zuo-tian-mian-shi-guan-wen-wo-yi-ge-prompt-jin-ru-da-mo-xing/</link><pubDate>Fri, 06 Mar 2026 03:44:58 +0000</pubDate><guid>https://xiaobox.github.io/p/2026-03-06-zuo-tian-mian-shi-guan-wen-wo-yi-ge-prompt-jin-ru-da-mo-xing/</guid><description>&lt;img src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2026-03-06-zuo-tian-mian-shi-guan-wen-wo-yi-ge-prompt-jin-ru-da-mo-xing/cover.jpg" alt="Featured image of post 昨天面试官问我：一个 Prompt 进入大模型后，内部到底发生了什么？" /&gt;&lt;p&gt;昨天面试时，面试官抛给我一道很典型的问题：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;“描述一下一个请求 prompt 经过 LLM 直到返回结果，这中间的推理过程，越详细越好。”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这类题看起来开放，实际上很考验基本功。&lt;/p&gt;
&lt;p&gt;因为它不是在问你会不会背几个名词，而是在看你是否真的理解：&lt;/p&gt;
&lt;p&gt;●一个请求在系统里是怎么流动的&lt;/p&gt;
&lt;p&gt;●进入模型之后到底算了什么&lt;/p&gt;
&lt;p&gt;●为什么大模型是一个 token 一个 token 地往外生成&lt;/p&gt;
&lt;p&gt;●为什么会有 prefill、decode、KV cache、sampling 这些概念&lt;/p&gt;
&lt;p&gt;●为什么工程侧还要引入 batching、FlashAttention、continuous batching 之类的优化&lt;/p&gt;
&lt;p&gt;如果回答得太浅，就会变成泛泛而谈；如果一上来就扎进公式，又很容易失去结构。&lt;/p&gt;
&lt;p&gt;我后来复盘了一下，觉得这道题最好的答法，不是“想到哪说到哪”，而是按一条完整链路去讲：&lt;strong&gt;服务层怎么处理请求，LLM 内部怎么做前向计算，生成阶段又是如何一步步产出结果的&lt;/strong&gt;。 这也是 GPT-3 所代表的自回归语言模型在推理时的基本工作方式：它不会在一次请求里更新参数，而是在固定权重下做前向传播，并逐 token 预测后续内容&lt;/p&gt;
&lt;h2 id="一个高分回答最好先把整体框架立住"&gt;&lt;a href="#%e4%b8%80%e4%b8%aa%e9%ab%98%e5%88%86%e5%9b%9e%e7%ad%94%e6%9c%80%e5%a5%bd%e5%85%88%e6%8a%8a%e6%95%b4%e4%bd%93%e6%a1%86%e6%9e%b6%e7%ab%8b%e4%bd%8f" class="header-anchor"&gt;&lt;/a&gt;一个高分回答，最好先把整体框架立住
&lt;/h2&gt;&lt;p&gt;如果让我在面试里先用一句话概括，我会这样回答：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;一个 prompt 从输入到输出，大体会经历 6 个阶段：请求封装、tokenization、推理调度、prefill、decode、结果反解码返回。其核心本质是：模型先并行“读懂”整段输入，建立上下文状态和 KV cache，然后再进入自回归生成循环，每次只预测下一个 token。&lt;/strong&gt; 这种“自回归 + 不做本次梯度更新”的推理方式，正是 GPT 类语言模型的基本范式；而 Transformer 则提供了它内部 attention 和前馈网络的计算骨架。&lt;/p&gt;
&lt;p&gt;&lt;img alt="图片" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2026-03-06-zuo-tian-mian-shi-guan-wen-wo-yi-ge-prompt-jin-ru-da-mo-xing/001-6e34d687.png"&gt;&lt;/p&gt;
&lt;p&gt;这句话为什么重要？&lt;/p&gt;
&lt;p&gt;因为它先把&lt;strong&gt;系统层和模型层&lt;/strong&gt;分开了，也先把&lt;strong&gt;prefill和decode&lt;/strong&gt;分开了。很多人答这道题失分，不是因为不会，而是因为把所有层次混在一起，听起来就没有脉络。&lt;/p&gt;
&lt;h2 id="第一阶段用户输入的-prompt并不是模型真正看到的内容"&gt;&lt;a href="#%e7%ac%ac%e4%b8%80%e9%98%b6%e6%ae%b5%e7%94%a8%e6%88%b7%e8%be%93%e5%85%a5%e7%9a%84-prompt%e5%b9%b6%e4%b8%8d%e6%98%af%e6%a8%a1%e5%9e%8b%e7%9c%9f%e6%ad%a3%e7%9c%8b%e5%88%b0%e7%9a%84%e5%86%85%e5%ae%b9" class="header-anchor"&gt;&lt;/a&gt;第一阶段：用户输入的 Prompt，并不是模型真正看到的内容
&lt;/h2&gt;&lt;p&gt;我们在聊天框里看到的是自然语言，但模型真正接收到的，通常不是这段原始文本本身。&lt;/p&gt;
&lt;p&gt;在送入模型之前，服务层一般会先把 system、user、assistant 等多轮消息按固定模板组织起来，再补上一些特殊标记。随后，文本会经过 tokenizer，被切成 token 序列。像 OpenAI 开源的 tiktoken 就明确说明，它是一个用于模型的 BPE tokenizer。也就是说，对模型来说，文本首先会被变成一串离散的 token IDs，而不是“句子”本身。&lt;/p&gt;
&lt;p&gt;这一层很多人容易忽略，但它很关键。&lt;/p&gt;
&lt;p&gt;因为后面所有推理，都是建立在 token 序列上的。你输入的是一句中文、一段英文、还是一段代码，对模型来说，第一步都得先转换成 token IDs。&lt;/p&gt;
&lt;p&gt;&lt;img alt="图片" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2026-03-06-zuo-tian-mian-shi-guan-wen-wo-yi-ge-prompt-jin-ru-da-mo-xing/002-48de7d31.png"&gt;&lt;/p&gt;
&lt;h2 id="第二阶段请求不会立刻进模型而是先进入推理服务和调度层"&gt;&lt;a href="#%e7%ac%ac%e4%ba%8c%e9%98%b6%e6%ae%b5%e8%af%b7%e6%b1%82%e4%b8%8d%e4%bc%9a%e7%ab%8b%e5%88%bb%e8%bf%9b%e6%a8%a1%e5%9e%8b%e8%80%8c%e6%98%af%e5%85%88%e8%bf%9b%e5%85%a5%e6%8e%a8%e7%90%86%e6%9c%8d%e5%8a%a1%e5%92%8c%e8%b0%83%e5%ba%a6%e5%b1%82" class="header-anchor"&gt;&lt;/a&gt;第二阶段：请求不会立刻进模型，而是先进入推理服务和调度层
&lt;/h2&gt;&lt;p&gt;在真实工程系统里，一个请求到达后，通常不会马上冲进 GPU 执行。&lt;/p&gt;
&lt;p&gt;它往往还要经过一层推理服务框架，比如 TGI、vLLM 这一类系统。它们会负责请求排队、动态 batching、缓存管理、流式返回等工作。Hugging Face 的 TGI 文档明确把 &lt;strong&gt;continuous batching、token streaming、Flash Attention、Paged Attention&lt;/strong&gt; 等列为核心特性；而 Transformers 的 continuous batching 文档也说明，这种动态调度的目的是提高 GPU 利用率、降低延迟，并允许请求在每一步动态加入和退出批次。&lt;/p&gt;
&lt;p&gt;所以，从系统视角看，链路通常是这样的：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;用户输入 → prompt 模板展开 → tokenization → 请求调度 / batching → 送入模型&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这一步的意义在于：&lt;/p&gt;
&lt;p&gt;模型推理不是单个请求的“裸跑”，而是和其他请求一起，由推理引擎统一组织和优化的。&lt;/p&gt;
&lt;p&gt;我们上一阶段说的 tokenization ，&lt;strong&gt;严格来说， 不属于 Transformer 前向推理本身，模型只接收 input_ids。但在现代推理服务里，tokenizer 往往和 serving 引擎绑定在一起，所以工程上看起来像是推理引擎在处理原始字符串。像 vLLM 就同时支持 text prompt 和 pre-tokenized prompt，两种模式都能跑。&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;用户通常把原始字符串发给后端；后端中的推理服务通常持有 tokenizer，先把字符串编码成 token IDs，再交给模型执行 prefill/decode。只有在某些架构下，tokenization 才会提前在客户端或独立预处理层完成。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="第三阶段进入模型后token-会先变成向量表示"&gt;&lt;a href="#%e7%ac%ac%e4%b8%89%e9%98%b6%e6%ae%b5%e8%bf%9b%e5%85%a5%e6%a8%a1%e5%9e%8b%e5%90%8etoken-%e4%bc%9a%e5%85%88%e5%8f%98%e6%88%90%e5%90%91%e9%87%8f%e8%a1%a8%e7%a4%ba" class="header-anchor"&gt;&lt;/a&gt;第三阶段：进入模型后，token 会先变成向量表示
&lt;/h2&gt;&lt;p&gt;真正进入 LLM 后，第一步不是“开始回答”，而是把 token IDs 映射成高维向量。&lt;/p&gt;
&lt;p&gt;这一步叫 &lt;strong&gt;embedding lookup&lt;/strong&gt;。每个 token 都会查一张巨大的 embedding 表，得到自己的向量表示。到这时，模型才真正进入连续空间的数值计算。Transformer 的基础论文《Attention Is All You Need》所定义的，就是这样一种基于 attention 的序列建模方式。&lt;/p&gt;
&lt;p&gt;不过只有 token 向量还不够，因为模型还得知道“谁在前、谁在后”。&lt;/p&gt;
&lt;p&gt;早期 Transformer 使用位置编码，后来很多大模型会用 &lt;strong&gt;RoPE&lt;/strong&gt;（Rotary Position Embedding）。RoPE 的核心价值，是把位置信息融入 attention 计算中，让模型在处理 token 时同时保留相对位置信息。&lt;/p&gt;
&lt;p&gt;&lt;img alt="图片" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2026-03-06-zuo-tian-mian-shi-guan-wen-wo-yi-ge-prompt-jin-ru-da-mo-xing/003-100bf39a.png"&gt;&lt;/p&gt;
&lt;h2 id="第四阶段真正的推理核心发生在一层层-transformer-block-里"&gt;&lt;a href="#%e7%ac%ac%e5%9b%9b%e9%98%b6%e6%ae%b5%e7%9c%9f%e6%ad%a3%e7%9a%84%e6%8e%a8%e7%90%86%e6%a0%b8%e5%bf%83%e5%8f%91%e7%94%9f%e5%9c%a8%e4%b8%80%e5%b1%82%e5%b1%82-transformer-block-%e9%87%8c" class="header-anchor"&gt;&lt;/a&gt;第四阶段：真正的“推理核心”发生在一层层 Transformer Block 里
&lt;/h2&gt;&lt;p&gt;这是这道题最核心的部分。&lt;/p&gt;
&lt;p&gt;如果面试官说“越详细越好”，你就必须把 Transformer Block 讲清楚。&lt;/p&gt;
&lt;p&gt;一个典型的 decoder-only LLM，每一层大体都会做两件事：&lt;/p&gt;
&lt;p&gt;●&lt;strong&gt;第一，Self-Attention&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;●&lt;strong&gt;第二，FFN / MLP（前馈网络&lt;/strong&gt;）&lt;/p&gt;
&lt;p&gt;中间再配合残差连接和归一化。Transformer 论文给出的主体结构就是这样。&lt;/p&gt;
&lt;p&gt;你可以把它想成：&lt;/p&gt;
&lt;p&gt;●attention 负责“读群聊”&lt;/p&gt;
&lt;p&gt;●FFN 负责“自己想一想、整理一下”&lt;/p&gt;
&lt;h3 id="self-attention-在干什么"&gt;&lt;a href="#self-attention-%e5%9c%a8%e5%b9%b2%e4%bb%80%e4%b9%88" class="header-anchor"&gt;&lt;/a&gt;Self-Attention 在干什么？
&lt;/h3&gt;&lt;p&gt;可以把它理解成：&lt;strong&gt;当前位置的 token，要去看上下文里哪些 token 最相关。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;模型会把当前隐藏状态投影成 Query、Key、Value 三组向量，然后通过 Query 和所有 Key 的相似度算出注意力权重，再对 Value 做加权求和。Transformer 论文把它定义为 &lt;strong&gt;Scaled Dot-Product Attention&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;对于生成式语言模型，还有一个必须强调的点：causal mask。&lt;/p&gt;
&lt;p&gt;也就是当前位置只能看见自己和前面的 token，不能偷看未来。这一点决定了模型天然是自回归生成的：它永远只能基于已有上下文，去预测下一个 token。GPT-3 论文里所讨论的 few-shot/in-context learning，本质上也是建立在这种&lt;strong&gt;自回归&lt;/strong&gt;预测机制之上的。&lt;/p&gt;
&lt;p&gt;&lt;img alt="图片" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2026-03-06-zuo-tian-mian-shi-guan-wen-wo-yi-ge-prompt-jin-ru-da-mo-xing/004-a52cdfd4.png"&gt;&lt;/p&gt;
&lt;p&gt;关于 Q、K、V，可以简单这样理解：&lt;/p&gt;
&lt;p&gt;Q = 我现在想找什么&lt;/p&gt;
&lt;p&gt;K = 每个词身上贴的“索引标签”&lt;/p&gt;
&lt;p&gt;V = 每个词真正携带、可被取走的信息。&lt;/p&gt;
&lt;p&gt;最通俗的比喻是“图书馆检索”：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;你现在脑子里有一个问题，这就是 Q（Query）；书架上每本书卡片上的主题标签，是 K（Key）；书里真正的内容，是 V（Value）。系统先拿你的问题 Q 去和所有标签 K 比一比，看看“像不像、相关不相关”；相关度高的那些书，它们的内容 V 就会被更多地取出来，最后合成当前这一步该看的信息。Transformer 论文对 attention 的定义，本质上就是“一个 query 对一组 key-value 对做匹配，输出是 values 的加权和”。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="ffn-又在干什么"&gt;&lt;a href="#ffn-%e5%8f%88%e5%9c%a8%e5%b9%b2%e4%bb%80%e4%b9%88" class="header-anchor"&gt;&lt;/a&gt;FFN 又在干什么？
&lt;/h3&gt;&lt;p&gt;如果说 attention 负责“从上下文搬运信息”，那么 FFN 更像是“对当前位置做进一步加工”。&lt;/p&gt;
&lt;p&gt;它不会跨位置交互，而是对每个 token 的表示单独做非线性变换，把特征进一步提纯和增强。Transformer 论文把它称为 position-wise feed-forward network。&lt;/p&gt;
&lt;p&gt;所以一个 Transformer Block 可以粗略理解成：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;先决定我该关注上下文里的谁，再把取回来的信息做一轮更深的特征变换&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="图片" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2026-03-06-zuo-tian-mian-shi-guan-wen-wo-yi-ge-prompt-jin-ru-da-mo-xing/005-ea012f28.png"&gt;&lt;/p&gt;
&lt;p&gt;注意在整个流程中，&lt;strong&gt;prefill 和 decode 阶段，都要做 self-attention 和 FFN。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;但要分清楚：“都要做”不等于“做法完全一样”。&lt;/p&gt;
&lt;p&gt;●Prefill 把整段 prompt 一次性送进去。 这时每一层都会对这批 token 做 masked self-attention，然后再过 FFN。因为整段 prompt 一开始就都已知，所以这一步可以在单个请求内部并行处理很多 token。Hugging Face 对 prefill 的描述也是：prefill 会处理整段输入，并建立 KV cache。&lt;/p&gt;
&lt;p&gt;●Decode 开始一个 token 一个 token 往后生成。 这时每生成一个新 token，它仍然要在每一层里经过：一次 self-attention，一次 FFN&lt;/p&gt;
&lt;p&gt;decode 不是把旧 token 全部再跑一遍 attention 和 FFN。有了 KV cache 后，旧 token 的 K/V 会被缓存起来；新 token 到来时，只需要为这个新 token 计算当前层需要的表示，再和历史 K/V 做注意力计算，然后继续过 FFN。Hugging Face 官方缓存文档明确说了：后续生成时，只传入尚未处理的新 token，并把 key/value 写入和读取自 cache。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;FFN 就是 Transformer 每层里、紧跟在 self-attention 后面的前馈网络，本质上是对每个 token 单独做的 MLP 加工。在标准 LLM 里，prefill 和 decode 两个阶段都要经过 self-attention 和 FFN；区别只是 prefill 处理整段已知 token，decode 只处理当前新 token，并复用历史 KV cache&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="第五阶段prefill先把整段-prompt-读完"&gt;&lt;a href="#%e7%ac%ac%e4%ba%94%e9%98%b6%e6%ae%b5prefill%e5%85%88%e6%8a%8a%e6%95%b4%e6%ae%b5-prompt-%e8%af%bb%e5%ae%8c" class="header-anchor"&gt;&lt;/a&gt;第五阶段：Prefill——先把整段 Prompt “读完”
&lt;/h2&gt;&lt;p&gt;很多人会误以为模型一进来就开始逐字生成。&lt;/p&gt;
&lt;p&gt;其实不是。生成前通常会先有一个很重要的阶段：&lt;strong&gt;Prefill&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;Prefill 的意思是：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;先把整段 prompt 一次性跑完整个前向过程。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在这个阶段，模型会为输入中的所有 token 计算各层隐藏状态，并且生成后面 decode 要用到的 KV cache。Hugging Face 的缓存文档明确指出，KV cache 会把注意力层中之前 token 产生的 key-value 对存下来，后续生成时直接复用，从而避免重复计算。&lt;/p&gt;
&lt;p&gt;Prefill 的一个重要特点是：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;它通常可以高度并行。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;因为整段输入已经完整给定了，GPU 能把很多矩阵操作一起做完。所以 prefill 更像“先整体读题”，吞吐通常更高。vLLM 文档也明确把 prefill 归类为更偏 compute-bound 的阶段&lt;/p&gt;
&lt;p&gt;你可以把 prefill 想象成一个正在考试的人，prefill 就是他正在读题，把题目先读到脑子里，填充好上下文，然后再开始做答（输出 token）&lt;/p&gt;
&lt;p&gt;&lt;img alt="图片" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2026-03-06-zuo-tian-mian-shi-guan-wen-wo-yi-ge-prompt-jin-ru-da-mo-xing/006-a96fea1e.png"&gt;&lt;/p&gt;
&lt;h2 id="第六阶段kv-cache为什么不会每次都重算全文"&gt;&lt;a href="#%e7%ac%ac%e5%85%ad%e9%98%b6%e6%ae%b5kv-cache%e4%b8%ba%e4%bb%80%e4%b9%88%e4%b8%8d%e4%bc%9a%e6%af%8f%e6%ac%a1%e9%83%bd%e9%87%8d%e7%ae%97%e5%85%a8%e6%96%87" class="header-anchor"&gt;&lt;/a&gt;第六阶段：KV Cache——为什么不会每次都重算全文
&lt;/h2&gt;&lt;p&gt;这部分是面试里非常加分的点。&lt;/p&gt;
&lt;p&gt;因为它体现你不只懂“算法”，还懂“推理为什么能跑得起来”。&lt;/p&gt;
&lt;p&gt;如果没有 KV cache，那么每生成一个新 token，模型都要把整个历史上下文从头再算一遍，成本会非常高。&lt;/p&gt;
&lt;p&gt;而有了 KV cache 后，历史 token 在每层 attention 中算出的 K 和 V 都会被缓存起来。下一个时间步只需要为新 token 计算新的 Query、Key、Value，再用新的 Query 去和历史缓存里的 Key 做匹配即可。Hugging Face 的官方文档把这一点解释得很清楚：KV cache 的目标就是消除重复计算，加速自回归生成。&lt;/p&gt;
&lt;p&gt;一句话说明就是：&lt;/p&gt;
&lt;p&gt;●&lt;strong&gt;没有 KV cache，像每次都重读整篇文章&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;●&lt;strong&gt;有 KV cache，则像前文已经做好笔记，现在只补最后一句。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="为什么-kv-cache-只缓存-k-和-v而不缓存-q"&gt;&lt;a href="#%e4%b8%ba%e4%bb%80%e4%b9%88-kv-cache-%e5%8f%aa%e7%bc%93%e5%ad%98-k-%e5%92%8c-v%e8%80%8c%e4%b8%8d%e7%bc%93%e5%ad%98-q" class="header-anchor"&gt;&lt;/a&gt;为什么 KV cache 只缓存 K 和 V，而不缓存 Q？
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;一个东西值不值得缓存，不看它“重不重要”，而看它“后面还会不会再次被用到”。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;KV cache 只缓存 K 和 V，不缓存 Q，不是因为 Q 不重要，而是因为 Q “只在当前这一步有用一次”；而 K、V 会在后面每一步继续被反复用到。 这正是 Hugging Face 官方对缓存机制的解释：过去 token 的 K 和 V 可以缓存并复用，而在推理时，只需要“最后一个 token 的 query”来计算当前步的表示。&lt;/p&gt;
&lt;h2 id="第七阶段decode开始逐-token-生成答案"&gt;&lt;a href="#%e7%ac%ac%e4%b8%83%e9%98%b6%e6%ae%b5decode%e5%bc%80%e5%a7%8b%e9%80%90-token-%e7%94%9f%e6%88%90%e7%ad%94%e6%a1%88" class="header-anchor"&gt;&lt;/a&gt;第七阶段：Decode——开始逐 token 生成答案
&lt;/h2&gt;&lt;p&gt;当 prefill 完成后，模型已经“读懂”了整段输入。&lt;/p&gt;
&lt;p&gt;接下来，系统会取最后一个位置的隐藏状态，通过输出层映射成整个词表上的 logits，也就是“下一个 token 的打分”。随后再通过 softmax 和解码策略，决定下一个 token 输出什么。Transformer 的输出逻辑与 Hugging Face 的生成文档都说明了这一点。&lt;/p&gt;
&lt;p&gt;这里又有一个容易被问到的点：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;下一个 token 是怎么选出来的？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;并不是只有“选概率最大”这一种方式。常见解码策略包括 greedy、sampling、top-k、top-p 等。不同策略会影响文本的稳定性、多样性和创造性。Hugging Face 的生成策略文档对此有系统说明。&lt;/p&gt;
&lt;p&gt;然后，流程进入一个循环：&lt;/p&gt;
&lt;p&gt;●把刚生成的 token 接到上下文后面&lt;/p&gt;
&lt;p&gt;●复用 KV cache&lt;/p&gt;
&lt;p&gt;●只为这个新 token 跑一遍前向计算&lt;/p&gt;
&lt;p&gt;●再得到新的 logits&lt;/p&gt;
&lt;p&gt;●再生成下一个 token&lt;/p&gt;
&lt;p&gt;&lt;img alt="图片" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2026-03-06-zuo-tian-mian-shi-guan-wen-wo-yi-ge-prompt-jin-ru-da-mo-xing/007-469317f3.png"&gt;&lt;/p&gt;
&lt;p&gt;这就是为什么你看到的大模型回答，总是一个 token 一个 token 流式地吐出来，而不是整段瞬间出现。&lt;/p&gt;
&lt;h2 id="为什么第一个字慢后面快"&gt;&lt;a href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e7%ac%ac%e4%b8%80%e4%b8%aa%e5%ad%97%e6%85%a2%e5%90%8e%e9%9d%a2%e5%bf%ab" class="header-anchor"&gt;&lt;/a&gt;为什么“第一个字慢，后面快”？
&lt;/h2&gt;&lt;p&gt;这也是一个非常像面试 follow-up 的问题。&lt;/p&gt;
&lt;p&gt;很多候选人知道 prefill 和 decode，但解释不清为什么两者速度特征不同。&lt;/p&gt;
&lt;p&gt;vLLM 的优化文档明确提到，&lt;strong&gt;prefill 更偏 compute-bound，decode 更偏 memory-bound。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;原因在于：prefill 可以把整段输入并行做大矩阵乘法，吃满 GPU 算力；而 decode 虽然每步只算一个 token，但它强依赖历史 KV cache，频繁访问显存，并且步骤之间有严格的顺序依赖。&lt;/p&gt;
&lt;p&gt;这也是为什么工程上会有很多针对推理性能的优化，比如：&lt;/p&gt;
&lt;p&gt;●FlashAttention：通过 IO-aware 的 attention 计算方式，减少显存读写&lt;/p&gt;
&lt;p&gt;●continuous batching：动态调整批次，减少 GPU 空转&lt;/p&gt;
&lt;p&gt;●chunked prefill / Paged Attention：改进长上下文和缓存管理效率&lt;/p&gt;
&lt;p&gt;要注意，这些技术优化的是执行效率，不是模型的“语义本质”。模型本质上做的事情仍然是：基于已有上下文，反复预测下一个 token&lt;/p&gt;
&lt;p&gt;我现在觉得，这道题最稳妥的回答方式，就是最后收束成一句话：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;一个 LLM 请求的推理过程，本质上是：先把 prompt 模板化并 token 化，经由推理服务调度进入 GPU；模型通过 embedding 和多层 Transformer block 并行完成 prefill，建立上下文表示和 KV cache；随后进入 decode 循环，基于历史缓存逐 token 执行注意力、前馈网络和采样，直到生成结束，再把 token 序列反解码成文本返回。 这条链路同时体现了 Transformer 的计算机制、自回归生成范式，以及现代推理系统在 batching、缓存和 attention kernel 上的工程优化&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="看起来都是推理引擎的活儿啊"&gt;&lt;a href="#%e7%9c%8b%e8%b5%b7%e6%9d%a5%e9%83%bd%e6%98%af%e6%8e%a8%e7%90%86%e5%bc%95%e6%93%8e%e7%9a%84%e6%b4%bb%e5%84%bf%e5%95%8a" class="header-anchor"&gt;&lt;/a&gt;看起来都是推理引擎的活儿啊？
&lt;/h2&gt;&lt;p&gt;从整个流程上看，几乎都是推理引擎在负责，所以可以这么理解，但要再往前走半步：&lt;/p&gt;
&lt;p&gt;●从“流程编排”角度看，LLM 本体确实很被动；&lt;/p&gt;
&lt;p&gt;●从“核心计算与语义生成”角度看，LLM 才是全链路里最不可替代的部分。&lt;/p&gt;
&lt;p&gt;如果把整个链路拆开，职责大致是这样的：&lt;/p&gt;
&lt;p&gt;1.&lt;strong&gt;推理引擎 / serving 系统负责&lt;/strong&gt;：接 HTTP 请求、做 tokenization / 输入处理、调度 batching、管理 KV cache、协调 GPU worker、流式返回结果、做一部分采样与系统优化。vLLM 的官方文档甚至把这几层写得很直白：最少会有 1 个 API server 负责 HTTP、tokenization 和输入处理，1 个 engine core 负责 scheduler 和 KV cache 管理，再加上 N 个 GPU worker 负责执行模型前向计算。&lt;/p&gt;
&lt;p&gt;2.&lt;strong&gt;LLM 模型本体负责&lt;/strong&gt;：对 input_ids 做 embedding，经过多层 Transformer block 的 self-attention 和 feed-forward network，输出 logits，也就是“下一个 token 的分数分布”。Transformer 论文给出的核心结构就是 attention + FFN；Transformers 文档也明确说 causal language modeling 本质上是在左侧上下文条件下做 next-token prediction，而模型输出里的 logits 是对词表中每个 token 的预测分数。&lt;/p&gt;
&lt;p&gt;所以，**推理引擎决定“怎么高效地跑”，模型决定“到底生成什么”。**前者偏“编排与优化”，后者偏“语义计算与内容生成”&lt;/p&gt;
&lt;p&gt;&lt;img alt="图片" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2026-03-06-zuo-tian-mian-shi-guan-wen-wo-yi-ge-prompt-jin-ru-da-mo-xing/008-d8a4beaa.png"&gt;&lt;/p&gt;</description></item></channel></rss>