跳转至

第二章 LLM 速通:从 Token 到生成

导读

这一章给工程师一个 30 分钟的 LLM 内部最小概览。本章不做数学推导,不展开 Transformer 架构细节,目标是建立**词汇表**——token、embedding、transformer block、attention、训练三阶段、上下文窗口、采样温度——后续章节会反复出现这些词,先把它们在脑子里建好映射,后面读起来就不会卡壳。如果你已经熟悉 HuggingFace Transformers 与预训练流程,可以快速浏览本章跳到第三章。如果你完全没接触过 LLM 工程,本章是后续 Prompt、推理 API、RAG、Agent 章节的前置基础,建议精读。

需要预先打个预防针:本章涉及的"训练阶段"和"模型选型"内容,工程上变化极快——模型版本每 3-6 个月一更新,API 价格每个季度调整,新的对齐方法(DPO、ORPO、SimPO 等)几乎每月都有论文。本章描述的是 2024-2025 年的"现状快照",重点在于建立心智模型("训练为什么分三阶段""为什么 7B 模型需要 14GB 显存"),具体数字和模型版本请用前查官方文档。

2.1 Token → Embedding → Transformer

要理解 LLM 怎么生成文本,最快的方法是跟着一次前向传播走一遍。LLM 的本质是**给定一段文本,预测下一个 token**——这一句话足够概括所有自回归语言模型(GPT 系列、Llama、Qwen、DeepSeek 都是这类)。下面逐步拆开这个"预测下一个 token"的过程。

Token 到生成流水线

第一步:Token——文本的数字表示

模型不认识汉字和字母,它只认识整数。文本进入模型前,先要经过**tokenizer**把它切成一段一段的子词单元(subword),每个子词对应一个整数 ID。这个切分方法叫 BPE(Byte-Pair Encoding)——核心思想是按字符出现频率合并:常见的组合("un"、"ing"、"the")合并成一个 token,罕见的字符单独成 token。

举例:英文 "ChatGPT is great" 用 GPT-4 的 tokenizer 切可能得到 5 个 token(["Chat","G","PT"," is"," great"]),中文 "今天天气真好" 可能切 4-6 个 token(BPE 对中文不友好,一个汉字常占 1-2 token)。这就是为什么中文 prompt 看起来字数不多,但 token 数却不少——计费是按 token 算的,不是按字数。

工程上要记住一个直觉:1 token ≈ 0.7-0.75 个英文单词 ≈ 0.5-0.6 个汉字。这个比例随 tokenizer 而变,但量级是对的。当你估算 prompt 成本时,先按这个比例粗算 token 数,再乘以模型单价,就能预估这一笔调用花多少钱。

Tokenizer 的工程细节

不同模型的 tokenizer 不同,这会带来几个工程影响。第一,不同模型同一段 prompt 的 token 数不同。同样一句中文,GPT-4o 切 8 个 token,Claude 切 6 个,Qwen 切 5 个——中文场景下国产模型 token 经济性更好。第二,tokenizer 决定模型能处理什么字符。如果 tokenizer 训练数据没见过某种语言(如某些低资源非洲语言),模型会把每个字符 fallback 到 byte 级 token,token 数爆炸(一个字符变 3-4 token)。第三,tokenizer 不能换。一个模型训练时用 32K vocab 的 BPE,你换 128K vocab 的 tokenizer,权重就废了——embedding 表的行数必须匹配。所以"换个 tokenizer 让中文更便宜"在已有模型上不可行,要等下一代模型训练时改。

工程师在调 API 时要养成"先看 tokenizer 切几 token"的习惯——OpenAI 和 Anthropic 都提供 tokenizer 工具,可以预切看 token 数。这一步能避免上线后才发现"prompt 居然烧这么多 token"的尴尬。多模态场景还要看图片 token——GPT-4o 一张 1024×1024 图片约 765 token,Agent 处理截图时这个成本要算进预算。

第二步:Embedding——从整数到高维向量

token ID 是个整数,但模型要做矩阵运算,需要把它变成浮点向量。这一步叫 embedding lookup——本质是一张可学习的大表,行数等于词表大小(V,通常 5 万到 25 万),列数等于模型隐层维度(d_model,7B 模型一般 4096,70B 模型 8192)。输入 token ID 后,从这张表里查出一行向量,就是该 token 的 embedding。

embedding 向量最神奇的地方在于:训练后,语义相近的 token 在向量空间里也相近。比如 "国王" 和 "女王" 的 embedding 距离,比 "国王" 和 "苹果" 近得多。这种"语义距离"是后续 attention 机制能工作的基础——attention 比较 token 之间的相似度,靠的就是 embedding 在向量空间里的位置关系。

第三步:Transformer Block——上下文交互

embedding 只表示单个 token 的语义,但句子含义取决于 token 之间的关系。比如 "猫追老鼠" 和 "老鼠追猫" 的 token 集合一样,但意思相反。要让模型理解这种关系,需要让序列中的 token 互相"看见"——这就是 Transformer Block 做的事。

一个 Transformer Block 主要包含两块:

  1. Self-Attention(自注意力):每个 token 给序列中所有 token(包括自己)打一个"注意力权重",然后加权求和得到新的表示。权重由 query、key、value 三个投影矩阵计算。直觉上:attention 让每个 token 决定"我应该关注序列里哪些 token"。这是 LLM 能做长距离依赖的根本机制——attention 是 O(L²) 的,所以序列里任意两个 token 都能直接交互,不像 RNN 要靠时间步传递。
  2. MLP(多层感知机):对每个位置独立做一次线性变换 + 非线性激活(现代 LLM 用 SwiGLU)。MLP 像"每个 token 的知识库"——它把 attention 聚合后的表示变换到新的空间,引入非线性。

一个 Transformer Block = Attention + MLP + 残差连接 + LayerNorm。现代 LLM 把 N 个这样的 Block 堆起来(7B 模型 N=32,70B N=80,405B N=120 左右)。每个 Block 让 token 之间多一轮交互,N 层之后,每个位置的表示都融合了整个序列的信息。

Attention 的几个工程直觉

读 attention 时工程师要建立几个直觉。第一,attention 是 O(L²) 的。序列长度翻倍,attention 计算量变 4 倍,显存变 4 倍——这就是为什么长上下文模型推理慢且贵。FlashAttention 这种优化只是把显存读写降到 O(L),但计算量仍是 O(L²)。第二,attention 不等于"理解"。模型在 attention 里算的是 token 之间的相似度,至于"理解"是 N 层堆叠后涌现出来的能力——单看一层 attention 看不出"模型懂了什么"。第三,KV cache 是 attention 的衍生优化。生成时第 N 个 token 的 attention 要看前面所有 token 的 key/value,这些 key/value 算一次后可以缓存,下一个 token 生成时直接复用。这是 LLM 推理优化的核心机制,vLLM 的 PagedAttention 就是优化 KV cache 显存管理的。

第四,attention 是 causal 的(因果的)。LLM 用的是 masked self-attention——每个 token 只能看到它前面的 token,看不到后面的。这是为了训练时可以并行(一次前向算所有位置的 loss),而不是真的模型不懂"未来"。这种因果 mask 让 LLM 自然成为"自回归"模型——只能根据已生成内容预测下一个,不能"看到全文再续写"。第五,Multi-Head Attention 让模型同时关注不同维度。一个 attention head 只能学一种关系(如"主谓关系"),多个 head 并行可以同时学语法、指代、语义等多种关系——现代 LLM 通常 32-96 个 head,GQA(Grouped Query Attention)让多个 head 共享 key/value 来省显存。

第四步:LM Head——输出下一个 token 的概率

N 层 Transformer 之后,序列每个位置都有一个 d_model 维的隐藏向量。最后一步是 LM Head——一个线性变换,把 d_model 维向量投影到 V 维(词表大小),得到每个 token 在该位置作为"下一个 token"的得分(logits)。

我们只关心序列末尾位置的 logits——它就是模型对"下一个 token 是什么"的预测。这 V 个 logits 经过 softmax 变成概率分布,按某种采样策略(贪心、温度、top-p)选一个 token,追加到序列末尾,然后再前向一次预测下一个——这就是 LLM 生成的本质循环。

工程视角下的前向流程要点

工程师读这段流程时要建立几个直觉。第一,前向传播不便宜。一个 7B 模型在 A100 上生成一个 token 大约 10-20 毫秒(不含首 token 延迟),生成 1000 token 就是 10-20 秒——这就是为什么聊天产品都要做流式输出,否则用户等不了。第二,KV cache 是优化关键。每生成一个 token,模型都要重新前向一次,但前面 token 的 attention key/value 可以缓存复用,避免重复计算——这就是 KV cache。KV cache 让生成成本从 O(L²) 降到 O(L),是 vLLM、TensorRT-LLM 这些推理引擎的核心优化点。

第三,生成是串行的。前向传播时所有位置可以并行算(attention 是矩阵运算),但生成时下一个 token 必须等上一个 token 算完才能开始——这是 LLM 生成慢的根本原因。Speculative Decoding(推测解码)用小模型先生成几个候选 token,再用大模型并行验证,能把生成速度提升 2-3 倍,是 2024 年推理优化最热门的方向之一。第四,stop token 决定生成何时结束。模型生成时会输出特殊 token(如 EOS、end-of-turn),生成循环看到 stop token 就停。如果模型不输出 stop token 就会一直生成到 max_tokens 上限——Agent 系统里要小心设置 stop 条件,避免无意义生成浪费 token。

2.2 三阶段训练

知道了前向传播,下一个问题是:模型里的权重(embedding 表、attention 矩阵、MLP 矩阵、LM Head)从哪来?答案是从训练来。现代 LLM 训练分三个阶段,每个阶段目标不同、数据不同、成本差异巨大。

三阶段训练流程

阶段 1:预训练(Pretraining)

预训练目标是让模型学到**语言能力**——语法、世界知识、推理风格。方法是 next-token prediction:把海量文本切成 token 序列,让模型预测每个位置的下一个 token,用 cross-entropy loss 算误差,反向传播更新参数。

预训练数据规模极大——Llama-3 用了 15T tokens,DeepSeek-V3 用了 14.8T tokens。数据来源包括 Common Crawl 网页、GitHub 代码、ArXiv 论文、Wikipedia、数学题集、多语言语料。这些数据经过严格清洗(去重、过滤低质、PII 脱敏),保留 10-30% 高质量部分。

预训练成本极高:Llama-3 70B 训练用了约 6e23 FLOPs,对应约 3 万 H100·天;按 H100 租赁 3 美元/小时粗算约 200 万美元。Llama-3 405B 训练用了约 3.8e25 FLOPs,对应约 19 万 H100·天,粗算约 1.4 亿美元。这些是粗略估算——实际成本取决于 MFU、网络、集群效率、规模折扣。这就是为什么只有少数公司能预训练前沿模型——大部分工程师永远不会从零预训练一个 LLM,但你应该理解这个阶段在做什么,因为预训练决定了模型的"先天能力"。

参考文献:GPT-3 论文(arXiv:2005.14165)首次系统化展示了"规模带来能力"的规律,是预训练时代开启的标志;Llama 系列则把开源预训练模型带到工程界。

预训练的关键工程决策

预训练的几个关键决策决定了模型上限。第一,数据配比。Llama-3 训练数据里代码占 15%(推理能力)、数学 5-8%(数学能力)、学术 10%、多语言 5-10%——配比不同能力差异巨大。Phi 系列实验证明用"教材级数据"训小模型(1.4B)能逼近 7B 通用模型,说明数据质量比数量重要。第二,Scaling Laws。OpenAI Kaplan 2020 与 DeepMind Chinchilla 2022 论文给出"参数、数据、算力"的幂律关系——Chinchilla 建议每个参数训 20 个 token(70B 模型训 1.4T token),但 Llama-3 训了 15T(10 倍),证明"过训练"对最终质量仍有效,特别是对要部署的小模型。

第三,架构选择。早期 GPT 用 Multi-Head Attention + LayerNorm + ReLU;现代 Llama 用 Grouped Query Attention(省显存)+ RMSNorm + SwiGLU + RoPE 位置编码。这些选择影响推理速度和长上下文能力,但参数规模相同时最终质量差异不大。第四,分布式训练策略。7B 单机 8 卡数据并行(DP)即可;70B 要张量并行(TP)+ 流水并行(PP)+ DP 三维并行;405B 起要加上专家并行(EP)。这是为什么大模型训练工程门槛极高——一个 loss spike 可能就是几百万美元损失。第五,MoE 路线。DeepSeek-V3 用 256 个 expert,每次激活 8 个,总参 671B 但激活 37B——用相对小的算力达到 dense 大模型质量,是 2024 年开源界的性价比路线。

阶段 2:SFT(Supervised Fine-Tuning,监督微调)

预训练后的"基础模型"(Base Model)只会续写文本,不会对话——你输入"今天天气如何?",它可能续写"明天天气如何?后天呢?",因为它学的是网页里"问句后面跟问句"的模式。要让模型"听懂指令",需要 SFT。

SFT 的数据是 (prompt, ideal_response) 形式的监督对,规模通常 1 万到 100 万条。这些数据要的是质量而非数量——OpenAI InstructGPT 论文(arXiv:2203.02155)显示 1 万条高质量 SFT 数据效果就远超 10 万条低质数据。SFT 只训练几个 epoch,成本低得多——单机 8 张 H100 跑一两天就能完成 7B 模型的 SFT。

SFT 之后,模型从"续写器"变成"对话助手"——它能听懂"翻译这段话""总结这篇文章""帮我写邮件"这种指令格式,并给出符合格式的回复。这一步是开源模型能否被实际使用的关键,没做 SFT 的 base 模型对工程几乎不可用。

阶段 3:RLHF / DPO(对齐阶段)

SFT 之后的模型能听懂指令,但回答可能不"对齐"——可能输出有害内容、不诚实、答非所问。要让模型更"符合人类偏好",需要第三阶段:基于人类偏好的强化学习(RLHF)或更简洁的直接偏好优化(DPO)。

RLHF 数据形态是 (prompt, chosen, rejected) 三元组——同一个 prompt,标注员选出"更好的回答"和"更差的回答",训练一个奖励模型(reward model)来打分,然后用 PPO 算法优化策略模型让它输出高分回答。流程复杂、训练不稳。

DPO(arXiv:2305.18290)跳过奖励模型和强化学习,直接用偏好对训练——把"chosen 概率比 rejected 概率高"作为目标,用 logistic loss 直接优化。DPO 比 RLHF 简单得多,稳定得多,成为 2024 年开源社区主流对齐方法。Llama-3、Qwen-2.5、DeepSeek-V3 都用 DPO 或其变体做最终对齐。

为什么分阶段而不是一步到位?

可能有人问:为什么不把指令数据和原始文本混在一起一次性训?答案是为了避免**任务干扰**。预训练学"语言能力"需要海量无标注文本;SFT 学"指令跟随"需要少量高质指令数据;对齐学"人类偏好"需要偏好对。三者数据量级差 1000 倍,混在一起训练会让指令数据被淹没,模型既学不好语言也学不好指令。分阶段是工程上的"任务解耦"——每个阶段只优化一个目标,效率高、可控性强。

这个分阶段思路不只用在 LLM——Agent 训练也类似:先让模型学基础工具调用(SFT 阶段),再让模型学多步规划(对齐阶段),最后让模型在真实环境里跑(强化学习)。后续章节会反复出现这种"分阶段"的工程思路。

训练阶段的工程现实

工程师视角看这三个阶段,有几个现实问题必须直面。第一,预训练阶段你永远不会做。除非你在前沿 lab(OpenAI / Anthropic / Meta / DeepSeek 等),否则你不会从零预训练一个 70B+ 模型——成本太高、数据太散、运维太复杂。你能做的是"继续预训练"(CPT,Continue Pre-Training),用领域数据(医疗、法律、金融)在开源基座上继续训,让模型对领域术语更熟。第二,SFT 是工程师能上手做的最高价值训练。一个 7B 开源模型 + 一万条高质量领域 SFT 数据 + 8 张 H100 + 两天,就能做出比 GPT-4o 在你特定垂直领域更强的模型——这是创业公司差异化的重要路径。

第三,对齐阶段大多省略或简化。RLHF 工程复杂度高(要训 reward model + PPO),DPO 简单但需要偏好数据,普通团队没有精力做完整对齐。很多开源模型(包括 Llama-3)发布时已经做完对齐,下游用户直接用即可。只有当模型在你的业务场景下输出"风格不合适"或"有安全风险"时,才需要自己跑对齐。第四,评测要贯穿每个阶段。预训练后跑 MMLU / HumanEval;SFT 后跑 AlpacaEval / MT-Bench;对齐后跑安全 benchmark(HarmBench)。没有评测就没有反馈信号,模型改了不知道是变好还是变坏——这是新手最容易忽略的工程纪律。

2.3 上下文窗口 / 温度 / Top-p / 采样

理解了模型怎么训出来,下一步要理解模型怎么用——这就是上下文窗口和采样参数。

上下文窗口(Context Window)

上下文窗口是模型一次前向能"看到"的最大 token 数。GPT-4o 是 128K,Claude 3.5 是 200K,Gemini 1.5 Pro 是 2M,开源 Llama-3 8K-128K 不等。窗口越大,能塞进去的文档越长,但推理成本和延迟也越高。

工程师视角的关键点:

  1. 上下文长 ≠ 推理强:长上下文 benchmark(如 LongBench、RULER)单独评测,发现有的模型虽窗口 128K 但实际有效记忆只 32K——超过 32K 后准确率断崖式下降,这叫"lost in the middle"现象(Liu 等 2023)。
  2. 窗口长不等于成本低:长上下文时 KV cache 显存爆炸(线性增长),推理速度也下降——这是为什么 Claude 200K 调用比 8K 慢且贵几倍。
  3. 窗口是物理上限:超过窗口的输入会被截断(早期 GPT-3.5)或报错(GPT-4),Agent 系统必须做记忆管理避免超窗。

长上下文模型的工程现实

长上下文听起来很美,工程上却有几个现实问题。第一,长上下文时延迟线性涨。128K 上下文一次前向要几秒到十几秒(首 token 延迟 TTFT),生成时还要保持这个延迟,对实时交互不友好。第二,有效记忆远小于窗口。把 128K 文档塞进去问"中间某段写了什么",模型可能答错——这就是 lost in the middle。要测真实长上下文能力,要看 needle-in-a-haystack 测试结果,而不是只看厂商宣传的窗口大小。第三,长上下文单价贵。OpenAI 与 Anthropic 都对超过阈值(如 32K 或 64K)的上下文加价,GPT-4o 128K 是基础价的 3 倍。Agent 跑长任务时要监控 context length,超过阈值要么压缩历史,要么换便宜模型。

第四,RoPE 外推不是免费的。Llama-3 训练时序列长度 8K,要支持 128K 需要用 RoPE scaling(如 YaRN、NTK-aware)外推——外推后长上下文质量下降是必然的,工程师要做 benchmark 验证。第五,Agent 长上下文要主动管理。一个跑 50 步的 Agent,对话历史 + 工具结果很容易累积到 50K+ token,单步成本暴涨。解决方案包括:上下文压缩(摘要旧消息)、记忆外置(vector DB 存历史)、滑窗(只留最近 N 轮)。本书第九章会展开。

温度(Temperature)

温度控制采样的"随机性"。模型输出的是 V 个 logits,softmax 时除以温度 T:T=0 时退化为 argmax(永远选最高分),T=1 时是标准 softmax,T 越大概率分布越平。

温度 行为 适用场景
0 完全确定(理论) 代码生成、JSON 输出、评测复现
0.3-0.7 低多样性 客服、问答、结构化任务
0.8-1.0 高多样性 创意写作、brainstorm、对话

注意:温度 0 不等于完全确定。如果两个 token 的 logit 完全相等(logit tie),即使温度 0,argmax 也可能在不同硬件/不同 batch 上选不同的——这种情况在短 token 序列末尾其实不少见。要保证完全可复现,需要固定随机种子 + 单输入单次调用 + 强制 argmax。

Top-p(核采样)与 Top-k

温度调的是分布形状,top-p / top-k 调的是"考虑多少个候选 token"。Top-p=0.9 表示只从累计概率前 90% 的 token 里采样,过滤掉长尾的"低概率乱七八糟 token"。Top-k=40 表示只从得分前 40 名的 token 里采样。

实际工程中通常组合:温度 0.7 + top-p 0.95 是 OpenAI 默认推荐配置,能保证既多样又不会跳出合理范围。代码生成场景建议温度 0 + top-p 1(确定性输出),创意场景建议温度 0.9 + top-p 0.95。

采样参数的工程意义

这些参数直接影响产品体验:温度太低客服机器人回答呆板,温度太高 JSON 输出格式飘;top-p 设太小生成陷入循环(反复输出同一 token),设太大生成偏离主题。Agent 系统里,建议**根据任务类型动态切采样参数**:规划/工具调用阶段温度 0-0.3(要稳定),自然语言回复阶段温度 0.7(要自然)。

工程上常见的采样陷阱

工程师在调采样参数时容易踩的坑有几个。第一,温度低不等于好。客服机器人用温度 0 看起来"稳定",但同一问题永远给同一答案,对话会显得呆板;用户问"今天天气如何"两次回答一模一样,体验差。建议温度 0.3-0.5 兼顾稳定与自然。第二,top-p 设太小会导致循环。top-p=0.1 表示只采样概率前 10% 的 token,候选集太小,模型可能在两个 token 间反复横跳,输出 "the the the the the..." 这种垃圾。OpenAI 默认 top-p=1.0 就是为了避免这个问题。第三,seed 不等于完全可复现。即使你设了 seed=42,模型在不同 GPU 型号、不同 batch size、不同推理框架下,可能产生不同输出——这是因为浮点运算的累加顺序在不同硬件上不同,导致 logit 微小差异,进而在 argmax tie 时选不同 token。

第四,采样参数不影响上下文理解。温度只影响"如何从 logits 选 token",不影响模型对 prompt 的理解。如果你的模型在温度 0 下答错题,温度 1 下也大概率答错——是模型能力问题,不是采样问题。新手经常误以为"调温度能让模型更聪明",其实温度只能让输出"更随机"或"更稳定",不能让模型"更对"。第五,结构化输出场景要强制确定性。生成 JSON、生成代码、生成 SQL 这种要被解析的输出,建议温度 0 + top-p 1 + response_format=json_object,最大程度保证可解析。

2.4 主流模型速览

下面表格是 2024-2025 年工程界常见 LLM 的速查表。注意:模型版本和定价变化快,本章数据有不确定性,使用前请查官方文档。

模型 参数规模 上下文 强项 许可证 API 价格档(input/1M token)
GPT-4o 未公开(估计 200B 级) 128K 综合强、多模态、代码 闭源 $5 / 1M
GPT-4o mini 未公开 128K 性价比、轻量任务 闭源 $0.15 / 1M
Claude 3.5 Sonnet 未公开 200K 代码、长上下文、Agent 闭源 $3 / 1M
Claude 3 Haiku 未公开 200K 速度快、便宜 闭源 $0.25 / 1M
Llama-3.1 70B 70B dense 128K 开源旗舰、社区生态 Llama 协议 自部署 / Groq $0.59
Llama-3.1 8B 8B dense 128K 本地部署、低延迟 Llama 协议 自部署
Qwen-2.5 72B 72B dense 128K 中文、多语言、工具调用 Apache 2.0 自部署
Qwen-2.5 7B 7B dense 32K 中文小模型 Apache 2.0 自部署
DeepSeek-V3 671B MoE(激活 37B) 128K 数学、代码、性价比 开源(非商业需授权) 自部署 / API 极便宜

模型选型的工程直觉

读这张表不要只看参数规模——参数规模不等于能力。MoE 模型(DeepSeek-V3 总参 671B 但激活 37B)推理时实际算力接近 37B dense 模型。还要看:

  1. 上下文长度:长上下文 ≠ 推理强,但长上下文对 RAG 与 Agent 跑长任务必要。
  2. 许可证:私有数据 / 合规场景必须用开源(Llama 协议、Apache 2.0)。Llama 协议对商业使用有限制(>700M MAU 需授权)。
  3. API 价格 vs 自部署:自部署 70B 单台 8×H100(约 30 万元硬件 + 折旧 + 人力),月活用户少时 API 更便宜;调用量上来后自部署成本反而低。
  4. 生态:工具调用支持、JSON 模式、function calling 等特性,GPT-4o 和 Claude 3.5 最成熟,开源模型 Qwen-2.5 和 Llama-3.1 也支持但稳定性略差。
  5. 中文能力:GPT-4o 中文不错,但 Qwen、DeepSeek、Claude 中文都很好;GPT-4o mini 中文偶有 token 切分问题导致多花 token。

工程师选型的真实路径是:先用最便宜的(GPT-4o mini / Claude Haiku)跑通流程,发现瓶颈再加钱上 Sonnet / GPT-4o;只有"合规 + 大量调用 + 中等难度"三条件同时满足才考虑自部署开源模型。

模型选型的隐藏成本

工程师选型时容易只看 token 单价,忽略几个隐藏成本。第一,长上下文溢价。GPT-4o 128K 上下文时单价涨到 $15/1M(基础价 $5/1M 的 3 倍),Claude 200K 上下文也是基础价 2 倍。Agent 跑长任务时上下文越长单价越高,最后几步成本可能比第一步贵几倍。第二,输出 token 比输入 token 贵 3-5 倍。GPT-4o 输入 $5/1M,输出 $15/1M。Agent 生成几千 token 时输出成本远高于输入,要重点优化输出长度(用 max_tokens 限制、用 stop 提前截断)。第三,Function Calling 调用要付 token。工具描述(function schema)每次调用都塞进 prompt,工具一多就占用大量 input token;这是为什么 Agent 框架要做"工具压缩"或"动态工具加载"。

第四,cached input 折扣。Anthropic 和 OpenAI 都推出了 prompt caching——重复的 prompt 部分只收 10-25% 的费用。Agent 系统里 system prompt + 工具描述 + few-shot 例子这些不变部分,缓存的成本节省能达到 50% 以上。第五,多模态 token。GPT-4o 处理图片时按图片分辨率折算 token,一张 1024×1024 图片约 765 token,长文档多图时成本会爆。工程师做产品时要把图片预处理(裁剪、压缩、分块)作为成本优化点。

代码片段:最小 HuggingFace 推理

下面这段代码用 HuggingFace Transformers 加载一个 7B 模型并生成文本,约 25 行。这是开源 LLM 本地推理的最小骨架:

import torch
from transformers import AutoTokenizer, AutoModelForCausalLM

model_id = "Qwen/Qwen2.5-7B-Instruct"  # 也可换 Llama-3 8B / DeepSeek
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    torch_dtype=torch.bfloat16,  # 7B fp16 ≈ 14GB 显存
    device_map="auto",           # 自动分配多 GPU
)

prompt = "用一句话解释什么是 RAG"
messages = [{"role": "user", "content": prompt}]
text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
inputs = tokenizer(text, return_tensors="pt").to(model.device)

outputs = model.generate(
    **inputs,
    max_new_tokens=128,
    do_sample=True,
    temperature=0.7,
    top_p=0.95,
)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))

这段代码做的事:加载 tokenizer + 模型权重(fp16 节省显存)→ 把 prompt 包成 chat template → 前向 generate → 解码。生产环境一般不直接用 transformers,而是用 vLLM 包一层(吞吐量 10-50 倍),但理解这段代码就能看懂后续 RAG / Agent 章节里的模型调用部分。

工程实战要点

  • 7B fp16 ≈ 14GB 显存:计算很简单——7e9 参数 × 2 bytes/param (fp16) = 14e9 bytes ≈ 13 GB;加上 KV cache 与 activation 实际 16-18 GB。70B fp16 约 130 GB 需要 2×80GB H100。这是工程师做模型选型的第一道门槛。
  • 温度 0 ≠ 完全确定:logit tie 会导致 argmax 不稳定,要可复现必须固定随机种子 + 单输入单次调用,重要评测场景建议跑 5 次取众数。
  • 上下文长 ≠ 推理强:长上下文 benchmark(LongBench、RULER)要单独看,128K 窗口的模型实际有效记忆可能只 32K;选型时不能只看窗口数字。
  • SFT 数据质量 >> 数量:1 万条人工写的高质量 SFT 数据效果好过 10 万条爬虫爬的低质数据;InstructGPT 论文已证伪"数据越多越好"。
  • 开源 vs 闭源选型:私有数据 / 合规场景必须走开源(Llama / Qwen / DeepSeek);创业项目快速验证走闭源(GPT-4o / Claude),规模上来再切开源。

小结

  • LLM 的本质是 next-token 预测:token → embedding → N 层 transformer block → LM head → logits → 采样下一个 token,循环生成。
  • 训练分三阶段:预训练(学语言,TB 数据,$10M+)、SFT(学指令,1 万-100 万条监督数据,单机可跑)、RLHF/DPO(学偏好,1 万-10 万对偏好数据)。
  • 上下文窗口是物理上限不是有效记忆;温度 0 仍有 logit tie 非完全确定;top-p 控制候选集。
  • 主流模型对比:闭源 GPT-4o / Claude 3.5 综合强但贵,开源 Llama-3 / Qwen-2.5 / DeepSeek-V3 适合合规与成本敏感场景。
  • 7B fp16 ≈ 14GB 显存是工程师选型的第一道门槛;模型选型不只看参数,还要看上下文、许可证、生态、中文能力。
  • 工程师不会从零预训练,但可以做 SFT;采样参数直接影响产品体验;模型选型的隐藏成本(长上下文溢价、输出贵于输入、cached input 折扣)要算清楚。

练习题

  1. 7B 模型 fp16 权重约多少显存?写出计算。
  2. 温度 0 与温度 1 行为差异?
  3. SFT 与 RLHF 阶段数据形态差异?
  4. 上下文窗口长度与"记忆能力"的关系?
  5. 列举 3 个主流开源 LLM 与其参数规模。
  6. 为什么要分预训练和 SFT 两阶段而不是一步到位?

参考答案

第 1 题答案 7e9 参数 × 2 bytes/param(fp16)= 14e9 bytes ≈ 13 GB;这是纯权重显存。运行时还要加 KV cache(与序列长度 × 层数 × hidden 成正比,7B 跑 4K 上下文约 1-2 GB)和 activation(与 batch × 序列 × hidden 成正比)。实际生产环境 7B 模型跑 4K 上下文总显存约 16-18 GB,需要单张 24 GB 的卡(如 3090 / 4090)或 16 GB 卡(如 T4 / A10)跑短序列。70B fp16 约 130 GB 需要双卡 80GB H100。
第 2 题答案 温度 0 在 argmax 取最大 logit,输出尽量确定,适合代码生成、JSON 输出、评测复现等需要可预测的场景;但仍可能 logit tie(两个 token logit 完全相等)导致非完全确定。温度 1 让概率分布更平,让低分 token 也有机会被采到,多样性高,适合创意写作、brainstorm、对话——但可能输出偏离主题或不稳定。工程上温度 0.7 + top-p 0.95 是大多数对话场景的甜点。
第 3 题答案 SFT 数据是 **(prompt, ideal_response)** 监督对——告诉模型"这种问题应该这样答";数据量 1 万-100 万条,每条都要人工写标准答案,质量 >> 数量。RLHF/DPO 数据是 **(prompt, chosen, rejected)** 偏好三元组——告诉模型"答 A 比答 B 好",但不要求 A 是完美答案;数据量 1 万-10 万对,标注成本低一些(选好 vs 写好)。SFT 教"做什么",RLHF 教"哪种更好"。
第 4 题答案 上下文长 ≠ 记忆强。长上下文减少 chunking 与信息丢失(不用切文档直接塞进去),但模型仍可能在长上下文中"忘"中间部分——Liu 等 2023 发现"lost in the middle"现象:模型对开头和结尾的 token 注意力强,中间部分注意力弱。要评测真实长上下文能力,需要看 LongBench、RULER、Needle-in-a-Haystack 等专项 benchmark,而不是只看模型宣传的窗口数字。
第 5 题答案 三个主流开源 LLM:1. Llama-3.1 系列(Meta),8B / 70B / 405B 三档,Llama 协议(>700M MAU 商用需授权);2. Qwen-2.5 系列(阿里),7B / 14B / 32B / 72B 多档,Apache 2.0 完全开放;3. DeepSeek-V3(深度求索),总参数 671B 的 MoE 模型,激活 37B,开源(商用需看协议条款)。其他还有 Mistral 7B / Mixtral 8x7B(Apache 2.0)、Yi 系列(01.AI)、ChatGLM(智谱)。
第 6 题答案 预训练学"语言能力"(语法、世界知识、推理风格)需要 TB 级无标注文本,SFT 学"指令跟随"只需要 1 万-100 万条标注数据。混合训练会让模型既要学语言又要学指令,两个任务数据量级差 1000 倍,指令数据被淹没;且预训练目标是 next-token,SFT 目标是对齐 response,两个 loss 优化方向不完全一致,互相干扰。分阶段是工程上的"任务解耦"——每阶段只优化一个目标,效率高、可控性强、便于回滚定位问题。

下一章:第三章 Prompt 与上下文工程