推理与部署
推理与部署
解码、采样、缓存、量化、提示、幻觉和推理部署。
044 · 中 · 在LLM的推理阶段,有哪些常见的解码策略?请解释 Greedy Search, Beam Search, Top-K Sampling 和 Nucleus Sampling (Top-P) 的原理和优缺点。
来源:Hello-Agents Extra01
在LLM的推理(或称解码)阶段,模型会生成一个词元概率分布,解码策略决定了如何从这个分布中选择下一个词元。常见的策略可以分为确定性和随机性两类。
1. Greedy Search (贪心搜索)
- 原理: 在每个时间步,总是选择当前概率分布中概率最高的那个词元作为输出。
- 优点:
- 速度快: 计算开销最小,实现最简单。
- 缺点:
- 局部最优: 每一步的“贪心”选择可能导致整个序列不是全局最优的。一个高概率的词后面可能跟着一系列低概率的词,最终序列的总概率反而不高。
- 缺乏多样性: 输出是完全确定的,对于同一个输入,每次生成的结果都一样,内容往往比较呆板、重复。
2. Beam Search (集束搜索)
- 原理: 这是对贪心搜索的改进。它在每个时间步会保留 $k$ 个( $k$ 称为 "beam width" 或 "beam size")最有可能的候选序列。在下一步,它会从这 $k$ 个候选序列出发,生成所有可能的下一个词元,然后从所有这些扩展出的新序列中,再次选出累计概率最高的 $k$ 个。最后,从最终的 $k$ 个完整序列中选择最优的一个。
- 优点:
- 质量更高: 通过探索更广的搜索空间,通常能找到比贪心搜索概率更高、质量更好的序列。
- 缺点:
- 计算成本高: 需要维护 $k$ 个候选序列,计算和内存开销是贪心搜索的 $k$ 倍。
- 仍然倾向于安全和高频: 优化目标是全局概率,这使得它还是倾向于生成常见、安全的句子,可能缺乏创造性,并且在长文本生成中容易出现重复。
3. Top-K Sampling (Top-K 采样)
- 原理: 这是一种随机采样策略。在每个时间步,不再是选择最优的,而是:
- 从整个词汇表的概率分布中,筛选出概率最高的 $K$ 个词元。
- 将这 $K$ 个词元的概率进行归一化(使它们的和为1)。
- 在这 $K$ 个词元中,根据新的概率分布进行随机采样。
- 优点:
- 增加多样性: 引入了随机性,使得生成内容更加丰富、有趣和不可预测。
- 避免低概率词: 通过限制在Top-K范围内,过滤掉了那些概率极低、可能不通顺或奇怪的词元。
- 缺点:
- K值固定: $K$ 是一个固定的超参数。当概率分布很尖锐时(模型非常确定下一个词),一个大的K可能会引入不相关的词;当概率分布很平坦时(模型不确定),一个小的K可能会限制模型的选择。
4. Nucleus Sampling / Top-P Sampling (核心采样)
- 原理: 这是对Top-K采样的改进,它使用一个动态的候选词元集。
- 将所有词元按概率从高到低排序。
- 从概率最高的词元开始,逐个累加它们的概率,直到总概率之和超过一个预设的阈值 $p$(例如 $p=0.95$)。
- 这个累加过程中包含的所有词元构成了“核心(Nucleus)”候选集。
- 然后,在这个动态大小的候选集中,根据它们的原始概率进行归一化和随机采样。
- 优点:
- 自适应候选集: 候选集的大小会根据上下文动态变化。当模型对下一个词非常确定时,概率分布尖锐,可能只有一两个词的概率和就超过了 $p$,候选集就很小,生成更精确;当模型不确定时,概率分布平坦,需要包含更多词才能达到 $p$,候选集就变大,允许更多探索。
- 兼顾质量与多样性: 相比Top-K,它是一种更原则性和鲁棒性的方法,是目前大多数LLM应用默认的采样策略。
045 · 易 · 大模型生成文本时的解码策略有哪些?贪心、Beam Search、采样分别什么时候用?
来源:小林 coding
每一步模型给出词表上的分布,词表通常是 5 万到 15 万。解码就是从这个分布里取下一个 token。策略背后是两种假设:存在唯一最优序列,或者存在一大片都合理的答案。
贪心每步取最大概率。确定、便宜、可复现,适合代码、SQL、JSON。毛病是复读:刚生成的片段会让下一步更倾向再生成它,循环出不来。开放写作也会偏保守。
Beam Search 每步留 B 条路径,常见 B=4 或 8,最后取整段概率最高的一条。它能避开贪心早走错的死胡同。翻译时代它是默认,因为源句对应相对明确的译文。
开放生成里它失宠,不只是因为慢 B 倍。目标是「整段概率最高」,这往往等于每步都选最稳的词,最稳的词又常常是重复。B 越大有时越乏味。KV Cache、Flash Attention、PagedAttention 按单条前缀设计,B 条前缀要把缓存复制 B 份。所以它从默认退成工具:翻译、约束生成、候选重排还能用,对话和写作很少用。
采样按分布抽,多样性来了,长尾也会抽到不合理的 token。三个旋钮截长尾:温度把 logit 除以 T 再 softmax;Top-K 只留前 K 个;Top-P 从高到低累加到 P 再抽。T 趋近 0 时行为接近贪心。T=1 是原分布。
| 任务 | 怎么解 |
|---|---|
| 代码、SQL、JSON | 贪心或温度 0–0.2 |
| 数学 | 贪心求稳;要更高准确率就多次采样再投票 |
| 日常对话 | 温度大约 0.7,Top-P 大约 0.9 |
| 创意、头脑风暴 | 温度 1.0–1.2,Top-P 大约 0.95 |
| 翻译 | 贪心或低温 |
各家 API 默认值会改,先用官方默认,再按「有没有标准答案」调。
两个叠加项。推测解码用小模型起草几个 token,大模型一次验证,访存次数下降,结果与大模型一致,速度常见 2–3 倍。Self-Consistency 对同一道推理题采多条路径,取最终答案的多数票,GSM8K 一类任务上常见再涨 5–15 个百分点,成本按次数乘。
046 · 易 · 大模型的参数:温度值、Top-P、Top-K 分别是什么?各个场景下的最佳设置是什么?
来源:小林 coding
三个参数都在管「从分布里怎么抽」,维度不同,不要一起大幅拧。
温度把 logit 除以 T 再 softmax。T 低,分布变尖,高概率词更独占,输出稳也单调。T 高,分布变平,低概率词有机会,多样,也更容易跑偏。T=1 是模型原始分布。T=0 退化成贪心,同输入同输出。
Top-K 只保留概率最高的 K 个,其余置零。K 是死的。问「中国的首都」,「北京」可能已经 99%,前 50 里仍有 49 个不该出现的词。写诗时概率很散,第 51 个词可能比第 50 个更好,固定截断会切掉它。
Top-P 按概率从高到低累加,超过 P 就停,只在这个核里抽。确定的上下文核很小,开放的上下文核变大。所以它比固定 K 更贴分布形状。
实践上先只动温度。官方文档通常也建议温度和 Top-P 二选一为主旋钮。
| 场景 | 温度 | Top-P |
|---|---|---|
| 代码、SQL、抽取、数学 | 0–0.2 | 1.0,不截断 |
| 对话、摘要、翻译 | 0.5–0.7 | 0.9 或官方默认 |
| 写作、头脑风暴、角色 | 0.8–1.2 | 0.95 |
两个坑。温度拉到 1.2 同时把 Top-P 收到 0.5,等于先把分布摊平再砍掉一半,结果不可解释。Top-K 和 Top-P 都在截断,叠在一起候选集会很怪。默认不设 Top-K,只用 Top-P;要调 Top-P 就先把温度固定。
这些区间是任务类型的起点,不是某一家某个版本的默认值。模型更新后默认策略会变,要用自己的测试集看跑偏率。
047 · 中 · KV Cache 是什么?Prompt Caching 的原理是什么?
来源:小林 coding
两者是同一份 K/V 缓存,时间尺度不同。KV Cache 复用在一次生成的 token 之间。Prompt Caching 复用在不同请求的相同前缀之间。
没有缓存时,生成第 i 个 token 要把前 i 个 token 的注意力重算一遍,总开销约 O(N³)。前缀的 K、V 不会因为新 token 改变,缓存之后每步只算新 token 的 Q、K、V,再和历史拼接,总开销降到约 O(N²)。这不是可选优化。vLLM、SGLang、TGI、llama.cpp 默认都开着。
显存按全长留:
2 × batch × 序列长 × 层数 × 头数 × d_k × 2 字节7B、32 层、32 头、128 维、32K,大约 17GB。所以才有 MQA/GQA、分页和缓存量化。
Prompt Caching 把这个池子按前缀留在服务端。客服系统每天十万次请求、系统提示 3000 token,如果每次重算,算力都花在同一段上文。第一个请求算完留下,后面的请求前缀一致就只算新增部分。
Claude 要在内容上显式打 cache_control 断点。写入那次大约 1.25 倍输入价,命中后的读取可以到普通输入的 10%。OpenAI 对超过约 1024 token 的前缀自动尝试缓存,命中情况写在响应里。延迟下降取决于前缀长度、命中率和负载,不要背一个固定加速比。
命中条件是前缀逐字节相同。日期和用户名放在固定知识库前面,缓存永远 miss。固定内容在前,动态内容在后。Claude 的 ephemeral 缓存大约 5 分钟,高流量能靠持续命中续上,几小时一次的调用可能连写入溢价都赚不回来。
适合三类形状:固定系统提示、同一份长文档上的多次提问、大段 Few-shot 不变而用户问题在变。
进阶两句就够:KV Cache 量化比权重量化更敏感,长链推理容易掉点;PagedAttention 把缓存切成固定 block,用块表映射,把碎片从「预分配最大长度」里收回来。
048 · 中 · 大模型量化是什么?INT8/INT4/AWQ/GPTQ 怎么选?
来源:小林 coding
量化把 FP16/FP32 权重映射到更少的离散整数。7B 的 FP16 大约 14GB,INT4 大约 3.5GB;70B 从大约 140GB 降到大约 35GB。访存也变成四分之一,推理常见快 2–4 倍,前提是硬件有对应的低精度 kernel。
线性量化用 scale 和 zero point 把一段浮点区间映射到 2^bits 个整数,再反映射。对称量化假设分布关于 0 对称,适合权重。非对称量化留 zero point,适合 ReLU 之后那样一边倒的激活。算法之间的差别是:scale 怎么算、离群值怎么保护、误差怎么补偿。
位数不是线性掉点。INT8 在很多任务上损失很小。INT4 是部署上的甜点,通用对话也许只掉 1%–3%,数学和长代码可以掉到 5%–10% 甚至更多。INT3 开始陡,INT2 通常不可用。论文里的平均损失不能代替自己的业务集。
| 算法 | 在干什么 | 取舍 |
|---|---|---|
| GPTQ | 用一小批校准数据逐层量化,按敏感度量化,把误差补偿到还没量化的权重 | 能做到更低位,量化要几个小时;通常只压权重,激活仍是高精度 |
| AWQ | 大约 1% 的显著权重贡献了大部分输出,按激活大小保护这些通道,其余激进压到 INT4 | 推理 kernel 往往更快,量化更快;极低位不如 GPTQ 稳 |
| NF4 / QLoRA | 按权重近似正态来放 16 个刻度,0 附近更密,再加双重量化和分页优化器 | 为了微调,不是为了把推理服务做到最快 |
GGUF 是 llama.cpp 的容器,里面可以装 Q4_K_M、Q5_K_M、Q8_0。它不是和 AWQ、GPTQ 并列的算法。
选型先看框架和 GPU 上哪条 kernel 成熟,再压测。追求速度,在 AWQ、GPTQ、FP8 和框架原生 INT4 里选能跑起来的。追求精度,留 FP16,或先试 INT8/FP8。个人微调用 QLoRA 的 NF4。手机和笔记本用 GGUF 的 Q4_K_M。没有 GPU 的批量推理用 llama.cpp。
离群权重会把量化区间拉得很宽,普通权重的刻度就被稀释。KV Cache 量化比权重量化更伤长链推理,仍在演进。量化还要和 Flash Attention、推测解码一起看,格式和 kernel 不匹配就快不起来。
049 · 易 · 如何写好 Prompt?分享下 Prompt 工程实践经验?
来源:小林 coding
同一个模型,Prompt 模糊时输出空间就大。写不好通常不是因为短,而是没说清五件事。
- 角色:专业方向、经验、回答时先指出问题再给改法。只写「你是助手」没有约束。
- 任务:动词和边界。受众、长度、不能用什么,都写进任务,不要留「帮我写一篇文章」。
- 上下文:用途和读者。同一段话,给海外投资人的商业计划,和随口翻译,用词完全不同。
- 格式:要被程序解析就必须定死字段。情感分析写成 JSON 的 summary、sentiment、keywords,比一段自由评论有用。
- 示例:格式怪、风格特殊时,1–3 个输入输出比长篇说明更准。
改一版只加一个约束,才能知道是哪一句起了作用。摘要任务从「帮我总结」到「技术编辑、100–150 字、后端工程师、一句话结论加三条要点」,稳定性和可复用性会差一个台阶。
进阶三件套。多步任务可以要求先分析再给结论,但不要把完整思考链默认展示给用户,对外留简要依据。多段材料用标签隔开,Claude 这条路上尤其吃结构。Prompt 是工程:准备 30–50 条覆盖正常和边界的用例,每次改动跑一遍通过率。
长 Prompt 还有压缩。费用和首 token 延迟都随长度涨。LLMLingua 用小模型丢掉信息量低的 token,把几千 token 压到大约五分之一,损失大约 1%–3%,仍要用自己的测试集找还能接受的长度。把 Few-shot 编成软提示向量,需要模型支持,还没普及。
压缩适合检索进来的长文档,以及示例池大到几十条的时候。压得越狠,效果掉得越多。
050 · 中 · 什么是 CoT?为啥效果好?它有什么缺点或局限性?
来源:小林 coding
模型一个 token 一个 token 生成,每步都能看见已经写出的内容。CoT 就是先把中间步骤写出来,再写答案。那些步骤变成后面答案的工作记忆,相当于草稿纸,不必把全部中间状态塞在隐层里。
「小明有 5 个苹果,给出去 2 个,又买 3 个」直接报数容易漏一步。写成「剩 3,再加 3 得 6」,每步都可以核对。它减少的是跳步,不是推理错误本身。第 2 步错了,后面会沿着错前提走下去。
两种用法:
- Few-shot CoT:提示里放几道带完整步骤和答案的例题,模型套同样的格式。稳,提示长。
- Zero-shot CoT:结尾加「分步想完再给结论」。不用写例题,通常略逊于带例题。
让模型内部推理,和把整条链展示给用户,不是一回事。产品里可以只留关键步骤或可核查结论,省 token,也少暴露不稳定的中间文本。
Self-Consistency 在 CoT 上再采样多条路径,对最终答案做多数投票。正确路径更容易汇合,错误路径更散。数学题上常见再涨 5–15 个百分点,调用一般是 5–10 次。
不该用的时候也很明确。链本身要多几百到上千 token,延迟和费用一起涨。简单算术、分类、抽取用它只是变慢。纯记忆题,比如某年奥运会在哪,没有推理可做。CoT 留给数学、逻辑和代码调试。
051 · 中 · 大模型为什么会出现幻觉?怎么缓解?
来源:小林 coding
幻觉是生成了读起来流畅、查证是错的内容。语法崩溃不算,那种一眼能看出来。模型不是数据库:数据库查不到会空,模型的任务是续写下一个 token,没有「查询失败」这个状态。
三层原因要分开。
训练语料里就有过时条目、谣言和互相矛盾的说法,参数把它们都记住了。但数据全对也还会编。知识是分布式编码在权重里的,记得多准取决于见过多少次,模型自己不知道某条事实落在哪,也没法给出来源。问「鲁迅的原名」,如果分布里错名字的概率略高,温度 0 会稳定地输出那个错名字。温度只减少随机抽到低概率词,不修正「最高概率本身是错的」。
对齐会加重这件事。标注员很少把「我不知道」写成标准答案,偏好排序也经常给「详细、自信」打高分,即使内容是错的。奖励模型学到自信等于高分,主模型就更不拒答。校准拒答是让自信度和正确率对齐,公开产品具体用了哪套配方,没写出来就不要断言。
三类表现:
- 事实:编造书名、论文、时间和地点。
- 推理:事实起点对,中间跳步或前后矛盾,代码里引用没定义的变量。
- 不忠实:不违反世界知识,但违反用户给的材料或系统约束,例如要求只根据文档回答,却改用参数记忆。
缓解也是三层,没有单点。
训练层在 SFT 里放拒答样本,让「错误且自信」成为负样本。推理层用分步分析暴露跳步,事实问答把温度放到 0–0.3,可验证题用多次采样投票,JSON 和 SQL 用约束解码。系统层用 RAG 把参数记忆换成可追溯的检索结果,效果取决于召回、重排和引用校验,不是固定下降一个数量级;输出后再核查,或强制每条事实带引用。
目标是把发生率降下来,并让用户看得出不确定。概率续写只要还在,就不可能彻底消灭。医疗和法律要有人把关。
052 · 中 · 大模型部署有哪些主流方案?vLLM、TGI、llama.cpp、SGLang 实际项目里怎么选?
来源:小林 coding
直接用 Transformers 的 generate 有三个浪费。每个请求按最大长度预分配 KV Cache,200 token 的请求占着 4096 的坑,显存利用率只有 30%–40%。静态 batch 要等最长的那条结束,短请求占着 GPU。相同系统提示每次重算。
| 框架 | 核心机制 | 适合 |
|---|---|---|
| vLLM | PagedAttention + 连续批处理 | 高吞吐 API |
| SGLang | RadixAttention,共享前缀树 | Agent、多轮、大段 Few-shot |
| TGI | 贴着 Hugging Face 的模型和模板 | 已有 HF 流程、要鉴权和指标 |
| llama.cpp | C++ 推理栈 + GGUF | Mac、CPU、边缘、离线 |
| TensorRT-LLM | 按 NVIDIA 卡做 kernel | 集群上要再榨一截吞吐 |
PagedAttention 把显存切成固定 block,常见 16 个 token 一块。请求拿到的是逻辑序列,块表映射到物理块,用完释放。利用率可以到 90% 以上,同样的卡并发大约 2–4 倍。连续批处理让请求在 token 步之间进出,不必等一整批结束,吞吐相对静态批处理常见再高 3–5 倍。
RadixAttention 用基数树存 KV。十条请求开头 1000 token 相同,只存一份,分叉之后各自存。前缀重复高时显存能省下一半到八成,历史请求还能按 LRU 留下。Agent 场景里首 token 延迟相对 vLLM 常见降 2–3 倍,吞吐高 30%–50%。单请求、没有共享前缀时,优势不明显。两者是互补,不是替代。
TGI 直接吃 Hub 上的模型、分词器和 chat template,带鉴权、Prometheus、健康检查和 SSE。极致吞吐通常不是它的第一卖点。
llama.cpp 用 GGUF 装 Q8、Q5_K_M、Q4_K_M、Q3,并按 AVX、NEON、Apple Metal 写矩阵核。统一内存的 Mac 可以跑很大的模型。它不适合高并发 API,批量调度弱,也不是为多卡集群设计的。
TensorRT-LLM 要为模型和卡编译 engine,换模型就重编译,只覆盖 NVIDIA。POC 和经常换模型的阶段不该先上它。
上线还有三个坑。长度差两个数量级时,分页后仍会有少量碎片,显存利用率掉下去要看 max length。KV Cache 量化各框架的支持随版本变,选型前查当前文档。MoE 还要专家并行和 all-to-all,vLLM 和 SGLang 能配,但比 Dense 难,先在测试环境跑通。
053 · 中 · 模型推理速度是怎么优化的?
来源:ai-agent-interview-guide
这里指本地的 embedding 和 rerank,不是云端大模型。
INT8 量化:精度损失小于约 0.5%,速度大约加 40%。ONNX Runtime 相对 PyTorch 大约再快 30%,再叠 CUDA / TensorRT。
计算按批:embedding batch_size 约 64,rerank 一次给大约 40 个候选打分。短时间的请求可以动态合并。模型在启动时进显存,避免第一击冷启动。
单条 embedding 大约 15 毫秒;1000 条一批大约 3 秒,均摊约 3 毫秒。40 条 rerank 大约 120 毫秒。GPU 利用率从约 30% 到约 75%。利用率低通常是 batch 太小或数据没喂上。
054 · 中 · 模型幻觉怎么控制?
来源:ai-agent-interview-guide
企业场景里编造价格和条款比答得慢更严重。控制分五层,RAG 是底。
Prompt 写明只根据给定资料回答,不够就说无法回答。回答里的事实要带引用,后处理检查引用是否真的在检索结果中,没有引用的事实标成待验证。
输出再查:用 NLI 看关键陈述能否从 context 推出;数字、日期、名称和原文比对;同一问题采样多次,答案不一致就降置信度。
检索最高分低于约 0.4,直接说知识库没有,不要生成。事实问答 temperature 取 0,创意任务才到大约 0.7。
源笔记幻觉率从无防控的约 18% 到约 3%,报价和合同条款低于约 0.5%。温度和引用都代替不了「没检索到就不答」。
055 · 易 · KV Cache 是什么?为什么需要?
来源:ai-agent-interview-guide
自回归生成第 n 个 token 时,前 n−1 个 token 的 Key 和 Value 已经算过。不缓存的话,每生成一个词都把前文重算一遍,总计算大约随 n³ 涨。缓存每一层的 K、V 之后,新 token 只算自己的 Q、K、V,注意力用缓存拼接,总量大约随 n²。
内存是代价:2 × 层数 × 头数 × 长度 × head_dim × batch × 字节数。长上下文的显存经常被 KV 而不是权重占住。
省内存的办法:GQA 让多组 Query 共享一组 K、V;MQA 是所有 Query 头共享一组;PagedAttention 按页管理,减少碎片;KV 从 FP16 量化到 INT8,大约省一半。这些不改变「要缓存」这件事,只改变缓存多大。
056 · 易 · Prompt Engineering 有哪些关键技巧?
来源:ai-agent-interview-guide
一份能解析的 Prompt 至少有角色、任务、输出格式、约束,再加上少数例子。缺格式例子,输出经常无法程序读取。
Chain of Thought 是把推理步骤写出来,适合多步题,不适合只想要一个分类标签的短任务。Few-shot 给 2 到 3 个覆盖边界的例子,比堆十个相似例子有用。否定约束(不要编造)通常比正面的「请准确」更清楚。输出锚定是在 Prompt 末尾先写下格式的开头,让模型接着填。
Self-consistency 是多次采样再投票,用成本换稳定。ReAct 是思考-行动-观察的循环,不是一句更长的提示。指令层级要固定:系统指令高于用户内容,否则注入就是把用户句子写成新的系统规则。
过长、自相矛盾、没有格式,是三种最常见的失败。技巧叠得多,不如先去掉互相打架的句子。
057 · 易 · 解码策略有哪些?Temperature 和 Top-p 怎么影响输出?
来源:ai-agent-interview-guide
贪心每次取概率最高的 token,稳定,也容易重复。采样按分布抽,才有多样性。
温度改的是分布形状:softmax(logit / T)。T 趋近 0 就是贪心。T = 1 是原始分布。T 大于 1 更平,小概率词更容易出现。T 小于 1 更尖。事实问答用接近 0,开放生成大约 0.7 到 1。
Top-p 从高到低累加概率,取刚好超过 p 的最小集合再采样。top_p = 0.9 就是只在累计约 90% 的词里抽。它比固定的 top-k 更能跟着分布变:分布很尖时候选少,分布很平时候选多。Top-k 只留前 k 个,实现简单,k 却要按任务改。
常见组合是先用温度调分布,再用 top-p 截断,例如 0.7 和 0.9。两个都调很大,输出会散;事实任务把温度打开,幻觉会跟着采样一起上来。