What Happens After a Prompt Enters an LLM? 提示词进了 LLM 之后,发生了什么?
AI Infra Track Technology
This is the first note in my series on learning AI infra from zero. I'm writing for readers like me: you've used AI and know roughly how it works, but you aren't an infra specialist. The token counts and examples below are teaching assumptions I chose to make the mechanisms clear, and the diagrams don't show any engine's full official implementation.
00How I Started Learning AI Infra
I knew nothing about AI infra. I didn't even know where to start. But the company I was interviewing with builds AI infra, so I had to figure out what the field actually does.
My first move was to ask AI to explain it.
On the first try, I asked for the basics. The answer was too shallow, and several parts didn't match AI infra at all. On the second try, I asked it to focus on the company's core technology. It started describing the company instead. My reaction: no, no, no, hold on. This is wrong.
That's when I noticed the most important lesson of the whole process:
When AI gives you something that feels wrong, don't ask it to try again and again. It hasn't understood what you want, so more attempts won't get you there. Stop, and work out with it what you actually need.
So I changed the question: "I don't understand this field yet. Can we build a knowledge tree first? Give me the structure, break it into steps, and then I'll work down the tree one level at a time."
This time, the learning plan it gave me was right.
One more habit made a big difference. After each concept, I had AI ask me a question, and I answered it. That way it could test whether I'd actually understood the idea. This is the Feynman technique: if you can explain something in your own words, you understand it. I wrote about how I use AI for this in How to Learn Anything (the AI Edition).
Stop, Don't Retry
Retrying only gives you new versions of the same misunderstanding. First agree with AI on what you actually want.
Get the Structure First
Ask AI to map the field as a knowledge tree with clear levels, then pick where to start.
One Question per Node
After each module, you should be able to explain one real question, not just recite definitions.
Quiz Me after Each Concept
After each concept, AI asks one question and I answer in my own words. If I can't, I haven't understood it yet.
The order of the four levels matters. First I need to understand one computation on its own: how the model computes and where the hardware gets stuck. Next comes serving many users, then improving the model over time, and last, how all of this becomes a business. This post covers module 01: what computation happens when a prompt enters an LLM, and which repeated work we can avoid?
To keep the ideas concrete, I use one example throughout: a startup that builds an AI coding agent on an open-source model such as Qwen. For each idea, I ask the same four questions in order. Why does this problem come up? How does the computation actually work? So what does it change? And how does it apply in a real product?
01Training, Inference, and the Life of a Request
Training adjusts the model's weights so the model learns to do a task. Ordinary inference uses the trained weights to compute outputs for new inputs, and the weights usually stay fixed. Inference doesn't pull a prepared answer from a database. It runs a fresh forward pass and generates tokens one by one.
Back to the AI coding agent. A user submits 20,000 input tokens of code context, and the model generates 50 output tokens. Here is the main flow:
- The application turns the content into token IDs the model can process.
- Prefill: the model runs over all known input tokens, computes each layer's hidden states and KV, and gets what it needs to generate the first token.
- Decode: the model usually generates one token per step, appends it to the context, and then generates the next one.
- The application turns the output tokens back into readable text and returns it.
Prefill vs. Decode
| Prefill | Decode | |
|---|---|---|
| Main job | Process the existing input | Generate new output step by step |
| Parallelism | Input positions are known, so the work runs largely in parallel | Each step in a request usually depends on the token the previous step produced |
| Typical metric | A large part of TTFT (time to first token) | TPOT (time per output token), generation speed |
| Engineering focus | Handling long prompts efficiently | Efficiency of each generation step and KV access |
A quick check: one request has 20,000 input tokens and 50 output tokens. Another has 100 input tokens and 2,000 output tokens. The first will likely spend most of its resources on prefill. The second will likely feel the long decode. Token counts alone can't predict total latency, though.
An easy detail to get wrong: 2,000 output tokens means roughly 2,000 sequential prediction steps, and each step still runs a huge amount of parallel GPU work. Batching also lets the GPU process different users' requests in the same decode step. In short, decoding is sequential across generation steps; parallel within each step and across batched requests. Methods such as speculative decoding can cut some of the sequential cost.
02Causal Attention: Why Past States Stay Fixed
In a Transformer's self-attention, each token produces three vectors: a query, a key, and a value. For the 4th token, attention conceptually matches Q₄ against K₁…K₄, then uses the resulting weights to combine V₁…V₄.
Causal means a position can't see tokens that come after it. When the 4th token arrives, the attention results for the first three positions don't change. The model only computes the output for the new position.
The standard attention formula:
Why Cache K and V but Not Past Q?
- Past Q: the model already used it to compute that position's attention output. A new position doesn't need to send queries from Q₁, Q₂, or Q₃ again.
- Past K: the new query Q₄ still compares against the past keys to compute new attention scores.
- Past V: the new attention weights still combine the past values to produce the current output.
- The full attention matrix: there's no need to keep every score for every past query. Each new query computes its own scores, and the full matrix can get very large.
So the KV cache stores the past key and value tensors for each attention layer. It doesn't store raw text, and it isn't the model's "memory database."
The cache doesn't remove attention itself. A new token still has to compute its own state, score it against the past keys, and combine the values.
03The Benefit and Cost of the KV Cache
Benefit: later steps in the same request don't recompute the whole history from scratch. Long conversations and multi-turn agent tasks gain the most.
Cost: the KV tensors have to live somewhere, usually in GPU memory. For common full-context attention models, with everything else fixed, KV cache size grows roughly linearly with context length and with the number of active requests. GPU memory is limited, so an engine can't keep every user's full history for free.
That leaves two goals pulling against each other:
Reuse the cache as much as possible to avoid repeated work, without letting it fill GPU memory and crowd out new requests.
Modules 02 (GPU memory and bandwidth) and 03 (serving) in the knowledge tree pick up this bottleneck.
04From One Request's KV Cache to Prefix Reuse across Requests
Ordinary incremental generation first reuses past KV within the same request. One step further: if different requests share exactly the same token prefix, and the model and inference settings are compatible, the engine can reuse that prefix's KV too.
Suppose there are three requests:
- A: shared system prompt (2,000) + Python code (5,000), 7,000 tokens in total.
- B: the same shared system prompt (2,000) + JavaScript code (3,000), 5,000 tokens in total.
- C: the same system prompt (2,000) + the same Python code (5,000) + a new question (150), 7,150 tokens in total.
Inference engines often manage these prefixes with a compressed prefix tree. One edge can represent a run of consecutive tokens, and requests with the same prefix share a branch. The engine maps token sequences to their KV cache locations, and uses the tree to match prefixes, insert new entries, reuse cached KV, and evict old entries. The tree is an index; the actual KV data lives separately in GPU memory.
In the ideal case, where the cache stays available:
| Request | Input to process without reuse | New input with prefix reuse |
|---|---|---|
| A | 7,000 | 7,000 |
| B | 5,000 | 3,000 |
| C | 7,150 | 150 |
| Total | 19,150 | 10,150 |
That cuts repeated prefill work by 9,000 / 19,150 ≈ 47% of input tokens. It doesn't mean real latency or FLOPs drop by 47%. Actual performance also depends on compute overhead, the implementation, and whether the cache is still there.
One key point: the same words don't mean the same KV. A token's higher-layer representation depends on the context before it. What an engine can reuse is the computed state of an identical prefix, with compatible positions and settings. Matching words across two different conversations doesn't count.
Eviction
When GPU memory runs short, an engine can't keep every branch. A common policy is LRU (least recently used): free cache starting from evictable leaf nodes, and protect the parts that active requests are using. Some engines also offer LFU, SLRU, or priority-based eviction. Whether a cache entry hits, or still exists, also depends on request scheduling, routing, and GPU capacity.
05Where I Got It Wrong: The Real Split Isn't B2B vs. B2C
My first instinct: B2B teams share code repositories, so their prompts seem more likely to repeat. B2C users each have different histories, so sharing seems hard.
Then I realized that sharing across users is only one source of reuse:
| Sharing scope | Example | What it means |
|---|---|---|
| Global / cross-user | A fixed system prompt and tool definitions | Different users can share a stable prefix |
| Project | The same codebase and project instructions | Team workflows may share an extra-long prefix |
| Session | One person's ongoing conversation and history | Even when every user differs, each session keeps reusing its own prefix |
The value of prefix caching depends on how much of a workload is repeated, stable, reusable prefix, and on whether the engine can keep and reach it. The B2B or B2C label doesn't decide it.
06Prompt Structure Is Engineering Too
A concrete question came up for me: suppose a prompt puts a changing user ID or timestamp at the very beginning. The 2,000-token system prompt after it is identical every time. Why does the cache still miss so often?
Prefix matching starts at the first token. Once the beginning differs, every later position has a different context. The engine can't skip the start and reuse the KV for the part after it.
The better principle: stable content first, dynamic content last.
You can layer a prompt by stability:
- Global: stable tool definitions and system instructions.
- Project: shared project instructions and codebase context.
- Session: the stable history of the current session.
- Dynamic: the current task, temporary state, the time, and anything else that changes.
If the user ID or timestamp only exists for application logs, leave it out of the model prompt entirely and manage it as application metadata. Two limits apply. Don't reorder instructions the model must follow just to raise the hit rate, and don't cross data isolation boundaries between tenants. Real APIs also often fix the serialization order as tools → system → messages.
A Real Case: Claude Code
In a 2026 engineering post, "Lessons from building Claude Code: Prompt caching is everything," Anthropic describes what they do in practice. They put the static system prompt and tool definitions in a stable prefix, then layer the project's CLAUDE.md, session state, and conversation after it. They also hit cache misses caused by timestamps and changes in tool order, and they stress stable prefixes and cache metrics.
To be precise: this describes prompt caching in Anthropic's own API. It says nothing about which open-source inference engine, if any, runs underneath Claude Code. What carries over is the engineering principle, not the implementation.
07Connecting the Chain
At this point I won't just say "this inference engine makes AI faster." A causal chain explains more:
An inference engine does far more than prefix caching. It also handles request scheduling, batching, model execution, and other optimizations. This post follows only one important technical thread. That thread leads to some product questions:
- Which developer workloads share a lot of stable prefix: agents, multi-turn coding, or RAG?
- How do you measure effective cache hits, TTFT, TPOT, throughput, and cost per request?
- Under which models, hardware, and request patterns are the gains large? When is the cache worth the GPU memory it takes?
After this module, I can walk from user input through prefill → decode → causal attention → KV cache → prefix reuse across requests, and explain the benefits, the costs, and when it applies.
—References
- Vaswani et al., Attention Is All You Need (2017)
- Kwon et al., Efficient Memory Management for Large Language Model Serving with PagedAttention (2023)
- vLLM: Automatic Prefix Caching (design doc)
- Anthropic: Lessons from building Claude Code: Prompt caching is everything (2026-04-30)
- Anthropic: Prompt Caching Docs
Limits of these notes: the diagrams are simplified and don't show any engine's full official implementation. The token counts are teaching assumptions. Sharing across requests depends on the model, its settings, whether the cache is still resident, and isolation rules. Prompt caching in Anthropic's API isn't the same as prefix caching inside an open-source inference engine. Fewer repeated input tokens don't translate into proportional savings in real GPU compute or cost.
这是我从零学 AI infra 的第一篇。写给和我一样的人:你用过 AI,大概知道它怎么工作,但不是做基础设施的。下面的 token 数和例子是我为了把机制讲清楚而设的假设。图也不代表任何一个引擎的完整官方实现。
00我是怎么开始学 AI infra 的
我对 AI infra 一无所知,连从哪开始都不知道。但我当时在面试的那家公司做的就是 AI infra,所以我得搞清楚这个领域到底在干什么。
我的第一步是让 AI 给我讲。
第一次我让它讲基础。答案太浅,而且有几段根本不是 AI infra。第二次我让它盯着那家公司的核心技术。它开始介绍公司了。我的反应是:不对不对,停一下。这不对。
这时候我注意到整个过程里最重要的一课:
AI 给你的东西感觉不对时,不要让它一遍遍重来。它没懂你要什么,再试也不会到那儿。停下来,跟它一起把你真正要的东西说清楚。
于是我换了问法:“这个领域我还不懂。我们能不能先建一棵知识树?把结构给我,拆成步骤,然后我一层一层往下学。”
这一次,它给的学习计划是对的。
还有一个习惯差别很大。每学完一个概念,我让 AI 问我一个问题,我来答。这样它能检验我是不是真懂了。这就是费曼技巧:你能用自己的话说出来,才算懂。我怎么用 AI 做这件事,写在 How to Learn Anything (the AI Edition)。
停下,别重试
重试只会给你同一份误解的新版本。先和 AI 对齐你到底要什么。
先要结构
让 AI 把这个领域画成一棵层次清楚的知识树,再决定从哪开始。
每个节点一个问题
一个模块学完,你应该能讲清一个真实的问题,而不是背定义。
每个概念之后考我
每个概念之后,AI 问一个问题,我用自己的话答。答不出,就是还没懂。
这四层的顺序有关系。我得先单独看懂一次计算:模型怎么算,硬件卡在哪。然后是同时服务很多用户,再是持续把模型改好,最后是这些东西怎么变成一门生意。这篇讲的是模块 01:一条提示词进了 LLM 之后,计算上发生了什么,哪些重复的工作可以避开?
为了让想法具体,全文用同一个例子:一家创业公司,用 Qwen 这样的开源模型做 AI 编程助手。每个想法我按同样四个问题往下问。这个问题为什么会出现?计算实际上怎么走?所以它改变了什么?在真实产品里怎么用?
01训练、推理,以及一个请求的一生
训练调整模型的权重,让模型学会做一件事。普通的推理用训练好的权重,给新的输入算出输出,权重通常不再变。推理不是从数据库里取出一份准备好的答案。它跑一次新的前向计算,一个一个生成 token。
回到 AI 编程助手。用户提交 20,000 个输入 token 的代码上下文,模型生成 50 个输出 token。主流程是这样:
- 应用把内容变成模型能处理的 token ID。
- Prefill:模型过一遍所有已知的输入 token,算出每一层的隐藏状态和 KV,得到生成第一个 token 需要的东西。
- Decode:模型通常每一步生成一个 token,把它接到上下文后面,再生成下一个。
- 应用把输出 token 变回可读的文字,返回去。
Prefill 和 decode
| Prefill | Decode | |
|---|---|---|
| 主要工作 | 处理已经有的输入 | 一步一步生成新的输出 |
| 能不能并行 | 输入位置已知,所以工作大体可以并行 | 一个请求里,每一步通常依赖上一步产出的 token |
| 常见指标 | TTFT(首 token 时间)里的一大块 | TPOT(每个输出 token 的时间)、生成速度 |
| 工程上盯什么 | 长提示词怎么高效处理 | 每一步生成的效率,以及读取 KV |
快速核对一下:一个请求有 20,000 个输入 token、50 个输出 token。另一个有 100 个输入 token、2,000 个输出 token。第一个多半把资源花在 prefill 上。第二个会明显感到 decode 很长。不过只看 token 数,预测不了总延迟。
一个容易弄错的细节:2,000 个输出 token,大约是 2,000 次按顺序的预测,而每一步里面 GPU 仍然做大量并行的工作。Batching 还让 GPU 在同一次 decode 里处理不同用户的请求。简单说,decode 是生成步骤之间串行;每一步内部、以及 batch 里的不同请求之间并行。投机解码这类方法可以削掉一部分串行成本。
02因果注意力:为什么过去的状态不再变
Transformer 的自注意力里,每个 token 产出三个向量:query、key、value。对第 4 个 token,注意力在概念上是拿 Q₄ 去对 K₁…K₄,再用得到的权重去组合 V₁…V₄。
因果是说,一个位置看不见它后面的 token。第 4 个 token 到来时,前三个位置的注意力结果不变。模型只算新位置的输出。
标准的注意力公式:
为什么缓存 K 和 V,不缓存过去的 Q?
- 过去的 Q:模型已经用它算过那个位置的注意力输出。新位置不需要再把 Q₁、Q₂、Q₃ 的 query 发一遍。
- 过去的 K:新的 query Q₄ 还是要和过去的 key 比较,才能算出新的注意力分数。
- 过去的 V:新的注意力权重还是要去组合过去的 value,才能得到当前的输出。
- 整张注意力矩阵:不必把每个过去 query 的每个分数都留着。每个新 query 自己算自己的分数,整张矩阵可以非常大。
所以 KV cache 存的是每一层注意力里,过去的 key 和 value 张量。它不存原文,也不是模型的“记忆数据库”。
缓存并没有把注意力本身去掉。一个新 token 还是要算出自己的状态,和过去的 key 打分,再把 value 组合起来。
03KV cache 的好处和代价
好处:同一次请求里,后面的步骤不必把整段历史从头重算。长对话和多轮的 agent 任务受益最大。
代价:这些 KV 张量得放在某个地方,通常是 GPU 显存。对常见的全上下文注意力模型,其他条件不变时,KV cache 的大小大致随上下文长度、以及同时活跃的请求数线性增长。GPU 显存有限,引擎没法免费把每个用户的完整历史都留着。
于是有两个互相拉扯的目标:
尽可能复用缓存,避开重复的工作,又不能让它占满 GPU 显存,把新请求挤出去。
知识树里的模块 02(GPU 显存和带宽)和模块 03(服务)接着讲这个瓶颈。
04从一次请求里的 KV cache,到请求之间的前缀复用
普通的增量生成,先是在同一次请求内部复用过去的 KV。再进一步:如果不同请求的 token 前缀完全一样,而且模型和推理设置兼容,引擎也可以复用这段前缀的 KV。
假设有三个请求:
- A:共用的系统提示(2,000)+ Python 代码(5,000),一共 7,000 个 token。
- B:同一段系统提示(2,000)+ JavaScript 代码(3,000),一共 5,000 个 token。
- C:同一段系统提示(2,000)+ 同一段 Python 代码(5,000)+ 一个新问题(150),一共 7,150 个 token。
推理引擎常常用一棵压缩过的前缀树来管理这些前缀。一条边可以代表连续的一段 token,前缀相同的请求共用一条分支。引擎把 token 序列映射到它们的 KV cache 位置,用这棵树来匹配前缀、插入新条目、复用缓存的 KV、驱逐旧条目。树是索引;真正的 KV 数据另外放在 GPU 显存里。
理想情况下,缓存还在:
| 请求 | 不复用时要处理的输入 | 前缀复用后的新输入 |
|---|---|---|
| A | 7,000 | 7,000 |
| B | 5,000 | 3,000 |
| C | 7,150 | 150 |
| 合计 | 19,150 | 10,150 |
重复的 prefill 少了 9,000 / 19,150 ≈ 47% 的输入 token。这不是说真实延迟或 FLOPs 会降 47%。实际表现还取决于计算开销、具体实现,以及缓存还在不在。
一个关键点:字面相同,不等于 KV 相同。一个 token 在更高层的表示,取决于它前面的上下文。引擎能复用的,是一段完全相同的前缀、在兼容的位置和设置下已经算好的状态。两段不同对话里碰巧出现同样的词,不算。
驱逐
GPU 显存不够时,引擎没法留下每一条分支。常见策略是 LRU(最近最少使用):从可以驱逐的叶子节点开始释放缓存,并保护正在被活跃请求使用的部分。有的引擎也提供 LFU、SLRU,或按优先级驱逐。一条缓存命中没有、还在不在,也取决于请求调度、路由和 GPU 容量。
05我一开始想错了:真正的分界不是 B2B 和 B2C
我的第一反应:B2B 团队共用代码仓库,提示词似乎更容易重复。B2C 用户每人历史都不同,共享似乎很难。
后来我发现,跨用户共享只是复用的一个来源:
| 共享范围 | 例子 | 它是什么意思 |
|---|---|---|
| 全局 / 跨用户 | 固定的系统提示和工具定义 | 不同用户可以共用一段稳定的前缀 |
| 项目 | 同一份代码库和项目说明 | 团队的工作流可能共用一段更长的前缀 |
| 会话 | 一个人正在进行的对话和历史 | 即使用户彼此都不同,每个会话也会反复复用自己的前缀 |
前缀缓存有没有价值,取决于一份负载里有多少是重复的、稳定的、可以复用的前缀,以及引擎能不能留住它、用到它。B2B 还是 B2C 这个标签决定不了。
06提示词怎么排,也是工程
我碰到一个具体问题:假设提示词把会变的用户 ID 或时间戳放在最前面。它后面那 2,000 个 token 的系统提示每次都一样。为什么缓存还是经常没命中?
前缀匹配从第一个 token 开始。开头一不一样,后面每个位置的上下文都变了。引擎不能跳过开头,去复用后面那一段的 KV。
更好的原则是:稳定的内容在前,会变的内容在后。
可以按稳定程度把提示词分层:
- 全局:稳定的工具定义和系统说明。
- 项目:共用的项目说明和代码库上下文。
- 会话:当前会话里稳定的历史。
- 动态:当前任务、临时状态、时间,以及其他会变的东西。
如果用户 ID 或时间戳只是给应用日志用的,就不要放进给模型的提示词,把它当成应用自己的元数据来管。有两条限制。不要为了提高命中率,打乱模型必须遵守的指令顺序;也不要越过租户之间的数据隔离。真实的 API 也常常把序列化顺序固定成 tools → system → messages。
一个真实的例子:Claude Code
在 2026 年的一篇工程文章里,Anthropic 写了他们实际怎么做:《Lessons from building Claude Code: Prompt caching is everything》。他们把静态的系统提示和工具定义放在一段稳定的前缀里,然后依次放上项目的 CLAUDE.md、会话状态和对话。他们也碰到过时间戳和工具顺序变化造成的缓存未命中,并且强调稳定的前缀和缓存指标。
说准确一点:这里讲的是 Anthropic 自己 API 里的 prompt caching。它没有说 Claude Code 底下跑的是哪个开源推理引擎,或者有没有。能搬过来的是工程原则,不是那套实现。
07把这条链接上
到这里,我不会只说“这个推理引擎让 AI 更快”。一条因果链能解释更多:
推理引擎做的远不止前缀缓存。它还要管请求调度、batching、模型执行,以及其他优化。这篇只顺着一条重要的技术线走。这条线会引出一些产品问题:
- 哪些开发者负载有大量稳定前缀:agent、多轮写代码,还是 RAG?
- 怎么衡量有效的缓存命中、TTFT、TPOT、吞吐,以及每个请求的成本?
- 在哪些模型、硬件和请求形态下,收益是大的?这块缓存占用的 GPU 显存,什么时候划算?
这个模块之后,我可以从用户输入走到 prefill → decode → 因果注意力 → KV cache → 请求之间的前缀复用,并讲清好处、代价,以及它在什么时候适用。
—参考
- Vaswani 等人,Attention Is All You Need(2017)
- Kwon 等人,用 PagedAttention 为大规模语言模型服务做高效显存管理(2023)
- vLLM:自动前缀缓存(设计文档)
- Anthropic:Lessons from building Claude Code: Prompt caching is everything(2026-04-30)
- Anthropic:Prompt Caching 文档
这些笔记的边界:图是简化的,不是任何一个引擎的完整官方实现。token 数是教学假设。请求之间能不能共享,取决于模型、设置、缓存还在不在,以及隔离规则。Anthropic API 里的 prompt caching,和开源推理引擎内部的前缀缓存不是一回事。少了一些重复的输入 token,并不按比例变成真实 GPU 计算或成本上的节省。