第 2 章 大模型的运作原理
"你不需要知道发动机怎么造,但你得知道油门、刹车、油箱在哪里。"
上一章我们搞清楚了大模型"是什么"和"从哪里来"。这一章,我们要搞懂它"怎么工作"——或者说,作为使用者,你必须知道的那些核心概念。
你不需要推导反向传播公式,也不需要理解注意力机制的矩阵乘法。但你必须知道:
- Token 是什么?为什么它直接影响你的账单?
- 上下文窗口 有多大?超出会怎样?
- 温度(Temperature) 是干什么的?调高调低有什么区别?
- 幻觉 是怎么产生的?怎么防?
- 大模型有哪些能力边界?什么时候该换方案?
这些概念会直接体现在你的代码里、你的架构设计里、你的成本核算里。搞懂它们,你就能写出更可靠、更经济的大模型应用。
2.1 "预测下一个词"——大模型工作的本质
大模型干的事情,用一句话概括就是:根据前面已经出现的词,预测下一个最可能出现的词。
然后把这个预测出来的词加回去,继续预测下一个……如此循环,直到生成完整的回答。
2.1.1 一个直观的例子
假设你让模型续写这句话:
"今天天气很好,我想去"
模型会计算每个可能的下一个词的概率:
| 候选词 | 概率 | 理由 |
|---|---|---|
| "公园" | 35% | 天气好去公园很合理 |
| "爬山" | 20% | 天气好适合户外活动 |
| "上班" | 5% | 语法通顺但和"天气好"不太搭 |
| "吃" | 15% | 可能想说"去吃饭" |
| "火星" | 0.01% | 语法上可行,但极不常见 |
模型会选择概率最高的(或者按概率随机选一个),然后继续:
"今天天气很好,我想去公园"
接下来预测"公园"后面跟什么词……如此往复,直到生成结束标记或达到长度限制。
2.1.2 为什么这能工作?
你可能会疑惑:只是"预测下一个词",怎么能理解问题、回答复杂问题、甚至写代码?
关键在于规模。当模型看过万亿级别的文本后,它学到的不是简单的"词与词的统计关系",而是深层的语义模式、逻辑结构、甚至某种程度的"世界知识"。
这就像你读了几万本小说后,虽然你只是在"预测作者接下来会写什么",但你的预测能力已经包含了你对人物性格、情节发展、因果关系的理解。
对后端开发者的类比:
大模型的"预测下一个词",有点像LRU 缓存的命中率预测——表面上是简单的统计,但当数据量足够大、模式足够复杂时,它能捕捉到深层的访问规律。
只不过大模型的"缓存"有几百亿参数,"训练数据"是整个互联网。
2.1.3 自回归生成
这种"预测一个、加一个、再预测"的方式,叫做**自回归(Autoregressive)**生成。
# 伪代码示意
context = "今天天气很好,我想去"
while not should_stop(context):
next_token = model.predict(context) # 预测下一个词
context += next_token # 加到上下文里
这带来一个重要的工程特性:生成是串行的,没法像矩阵乘法那样并行加速。这也是为什么长文本生成会比较慢——它得一个词一个词地"蹦"出来。
2.2 Token 是什么?为什么它决定了费用和效果上限?
2.2.1 Token 的本质
大模型处理的不是"字符",也不是"单词",而是 Token。
Token 是模型处理文本的最小单位。它可能是:
- 一个完整的英文单词(如
"hello") - 一个中文汉字(如
"你") - 一个中文词语(如
"人工智能"可能被切成"人工"+"智能") - 一个标点符号(如
"。") - 甚至半个单词(如
"unbelievable"可能被切成"un"+"believ"+"able")
Token 是由训练时使用的分词器(Tokenizer)决定的,不同模型的分词规则不同。
2.2.2 Token 与费用的关系
大模型的计费方式是:按 Token 数量收费。
- 输入 Token:你发给模型的 Prompt
- 输出 Token:模型生成的回复
两者加起来,就是你的账单。
| 模型 | 输入价格(每百万 Token) | 输出价格(每百万 Token) |
|---|---|---|
| GPT-4o | $2.50 | $10.00 |
| GPT-4o-mini | $0.15 | $0.60 |
| Claude 3.5 Sonnet | $3.00 | $15.00 |
| DeepSeek-V3 | ¥2 / 百万 | ¥8 / 百万 |
注意:中文通常 1 个汉字 ≈ 1-2 个 Token,英文通常 1 个单词 ≈ 1-2 个 Token。所以同样的内容,中文可能比英文贵一点。
2.2.3 Token 与效果的关系
Token 不仅关乎费用,还直接限制了你能给模型看多少内容。
假设模型的上下文窗口是 128K Token,你想让它总结一份 200K Token 的文档——抱歉,装不下。你得先想办法压缩、截断、或者分段处理。
对后端开发者的类比:
Token 就像数据库连接池的连接数——
- 它是稀缺资源,用完了就得等(或报错)
- 它直接影响成本(连接数越多,服务器资源消耗越大)
- 你需要监控它、优化它、在架构设计时考虑它的限制
2.2.4 如何估算 Token 数量
OpenAI 提供了一个 Python 库 tiktoken 来精确计算:
import tiktoken
# 获取 GPT-4 的分词器
encoder = tiktoken.encoding_for_model("gpt-4")
text = "今天天气很好,我想去公园散步。"
tokens = encoder.encode(text)
print(f"文本: {text}")
print(f"Token 数量: {len(tokens)}")
print(f"Token 列表: {tokens}")
print(f"还原: {encoder.decode(tokens)}")
输出示例:
文本: 今天天气很好,我想去公园散步。
Token 数量: 14
Token 列表: [220, 64401, 30976, 54480, 177, 63842, 54480, 177, 177, 63842, 54480, 177, 177, 63842]
还原: 今天天气很好,我想去公园散步。
核心代码要点:
- 不同模型用不同分词器,不能混用
- 实际开发中,建议在调用 API 前先估算 Token 数,避免超限
📌 插图 2-1:Token 切分示意图
原始文本: "Hello world, 今天天气很好!" 分词结果: ┌─────────┬─────────┬───────┬─────────┬─────────┬─────────┬───────┐ │ Hello │ world │ , │ 今天 │ 天气 │ 很好 │ ! │ │ 15496 │ 995 │ 11 │ 220 │ 64401 │ 30976 │ 54480│ └─────────┴─────────┴───────┴─────────┴─────────┴─────────┴───────┘ Token 1 Token 2 Token 3 Token 4 Token 5 Token 6 Token 7 计费时: 输入 Token = 7, 输出 Token = 模型生成的 Token 数
2.3 上下文窗口(Context Window):模型的"工作记忆"
2.3.1 什么是上下文窗口
上下文窗口(Context Window)是模型能"记住"的最大 Token 数量。你可以把它理解为模型的工作记忆容量。
当对话或文档超过这个容量时,最早的内容会被丢弃,模型就"忘"了。
| 模型 | 上下文窗口 | 大约能容纳 |
|---|---|---|
| GPT-3.5 | 16K | 约 12,000 汉字 |
| GPT-4 | 128K | 约 100,000 汉字 |
| Claude 3.5 Sonnet | 200K | 约 150,000 汉字 |
| Kimi | 2M | 约 150 万字 |
| DeepSeek-V3 | 64K | 约 50,000 汉字 |
2.3.2 超出窗口会怎样?
当输入超过窗口限制时,不同模型的处理方式不同:
- 直接报错:API 返回 400 错误,提示超出长度限制
- 自动截断:从开头截断,保留最近的内容
- 需要手动处理:你必须自己在代码里做截断或摘要
最安全的做法:在调用 API 前,自己检查 Token 数,主动做截断或分段。
def truncate_to_max_tokens(text, max_tokens, encoder):
"""将文本截断到最大 Token 数"""
tokens = encoder.encode(text)
if len(tokens) <= max_tokens:
return text
truncated = tokens[:max_tokens]
return encoder.decode(truncated)
# 使用示例
encoder = tiktoken.encoding_for_model("gpt-4")
long_text = "..." # 很长的文本
truncated = truncate_to_max_tokens(long_text, 120000, encoder)
2.3.3 上下文窗口的工程挑战
上下文窗口的限制给系统设计带来了几个实际问题:
1. 长文档处理
如果文档太长,装不进上下文窗口,怎么办?
- 分段处理:把文档切成多个小块,分别处理
- RAG(检索增强):先检索相关段落,只把相关部分喂给模型(第 9 章详细讲)
- 摘要压缩:先用模型生成摘要,再用摘要替代原文
2. 多轮对话管理
聊天机器人在多轮对话中,历史消息会累积。如果不处理,很快就会超出窗口。
常见策略:
- 只保留最近 N 轮对话
- 对早期对话做摘要,保留摘要而非原文
- 根据相关性动态选择保留哪些历史消息
对后端开发者的类比:
上下文窗口就像分页查询的 page size——
- 它有限制,你不能一次性加载全部数据
- 你需要设计"分页"或"懒加载"策略
- 关键是如何决定"哪些数据优先保留"(就像缓存淘汰策略 LRU/LFU)
📌 插图 2-2:上下文窗口示意图
上下文窗口(假设 4K Token 容量) ┌─────────────────────────────────────────────────────────────┐ │ System Prompt (固定) │ │ "你是一个 helpful 的助手..." │ ├─────────────────────────────────────────────────────────────┤ │ 历史对话(按时间倒序,新的保留,旧的丢弃) │ │ ┌───────────────────────────────────────────────────────┐ │ │ │ User: "帮我总结一下" ← 最新 │ │ │ │ Assistant: "好的,以下是总结..." │ │ │ │ User: "第三段再详细说说" │ │ │ │ Assistant: "第三段主要讲了..." │ │ │ │ ... │ │ │ │ User: "你好" ← 最早,即将被挤出窗口 │ │ │ └───────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ 当新消息进来时,如果总 Token 数超过窗口限制, 最早的消息会被丢弃(就像 LRU 缓存淘汰)
2.4 温度(Temperature)与随机性:控制模型的输出风格
2.4.1 什么是 Temperature
Temperature(温度)是一个控制模型输出随机性的参数,取值范围通常是 0 到 2。
- Temperature = 0:几乎完全确定,每次输出都一样(贪婪解码)
- Temperature = 0.7:默认值,平衡确定性和创造性
- Temperature = 1.0+:更随机,更有创造性,但也可能更离谱
2.4.2 温度如何工作
回忆一下 2.1 节的例子,模型预测下一个词时,每个候选词都有一个概率分布。
Temperature 的作用是调整这个概率分布的"尖锐程度":
- 低温(T→0):概率分布变得更"尖锐",高概率词更容易被选中,低概率词几乎不会被选
- 高温(T→∞):概率分布变得更"平坦",所有候选词的概率趋于均等,选择更随机
# 伪代码示意 Temperature 的作用
import numpy as np
probs = np.array([0.5, 0.3, 0.15, 0.05]) # 原始概率
temperature = 0.7
# 应用温度
adjusted = probs ** (1 / temperature)
adjusted = adjusted / adjusted.sum() # 重新归一化
# T=0.7 时,高概率词概率更高,低概率词概率更低
# 结果大概是: [0.58, 0.28, 0.10, 0.04]
2.4.3 不同场景的温度选择
| 场景 | 推荐 Temperature | 理由 |
|---|---|---|
| 代码生成 | 0.0 - 0.3 | 代码需要精确,随机性会导致 Bug |
| 数据分析 | 0.0 - 0.3 | 事实性内容,需要准确 |
| 问答系统 | 0.3 - 0.7 | 平衡准确性和自然度 |
| 创意写作 | 0.7 - 1.0 | 需要多样性,允许一定随机性 |
| 头脑风暴 | 1.0 - 1.5 | 追求创意,可以"离谱"一点 |
2.4.4 核心代码示例
import openai
# 精确模式(适合代码、数学)
response = openai.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "计算 123 * 456"}],
temperature=0.0 # 几乎确定性的输出
)
# 创意模式(适合写作、头脑风暴)
response = openai.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "给我 5 个产品名称创意"}],
temperature=1.2 # 更有创意,结果更多样
)
对后端开发者的类比:
Temperature 就像负载均衡的权重策略——
- T=0 类似于"总是选权重最高的服务器"(确定性)
- T=1 类似于"按权重概率随机选择"(平衡)
- T>1 类似于"故意引入随机性,让流量更分散"(探索)
2.5 模型的"幻觉"问题:为什么大模型会一本正经地胡说?
2.5.1 什么是幻觉
幻觉(Hallucination)是指模型生成听起来合理、但实际上错误或虚构的内容。
典型表现:
- 编造不存在的事实("张三在 2020 年获得了诺贝尔奖"——实际上没有)
- 引用不存在的文献("根据《Nature》2023 年的研究..."——这篇论文不存在)
- 错误地关联信息(把两个不相关的事情说成因果关系)
最危险的是:幻觉内容往往语气自信、逻辑通顺,看起来很像真的。
2.5.2 幻觉为什么会发生
理解幻觉的根源,有助于你设计更可靠的系统。主要原因有三:
1. 训练数据的局限性
- 模型只"知道"训练数据中的内容,对训练截止日期之后的事一无所知
- 训练数据本身可能包含错误信息,模型学到了这些错误
2. 生成机制的本质
模型做的是"预测下一个最可能的词",而不是"查证事实"。当它没有足够信息时,它会根据概率"编"一个最合理的答案,而不是说"我不知道"。
这就像一个人被问到不知道的问题时,为了面子硬编一个答案,而且编得还挺像回事。
3. 对齐训练的副作用
RLHF 训练鼓励模型"有帮助",这可能让模型更倾向于给出一个答案(哪怕是编的),而不是说"我不知道"。
2.5.3 如何缓解幻觉
完全消除幻觉很难,但可以通过工程手段大幅降低风险:
| 策略 | 说明 | 适用场景 |
|---|---|---|
| RAG(检索增强) | 只让模型基于提供的资料回答,不依赖其内部知识 | 客服、知识库问答 |
| 事实核查 | 对关键事实,用其他数据源二次验证 | 医疗、法律、金融 |
| 置信度标注 | 让模型标注哪些内容不确定 | 研究报告生成 |
| 人工审核 | 高风险内容必须经过人工确认 | 发布到生产环境的内容 |
| Prompt 约束 | 明确要求"不知道就说不知道" | 通用场景 |
Prompt 示例:
你是一个严谨的助手。回答问题时请注意:
1. 只基于我提供的资料回答,不要编造信息
2. 如果你不确定,请明确说"我不确定"或"我不知道"
3. 对于关键事实,请标注信息来源
对后端开发者的类比:
幻觉就像缓存穿透——
- 缓存里没有的数据,系统本该去数据库查
- 但大模型不会"查数据库",它会根据概率"编"一个答案
- 解决方案是RAG(给模型一个"数据库"去查),就像给缓存加回源逻辑
📌 插图 2-3:幻觉产生原因与应对策略
幻觉产生机制: ┌─────────────────────────────────────────────────────────────┐ │ 用户提问: "张三在 2020 年获得了什么奖项?" │ └──────────────────────┬──────────────────────────────────────┘ ▼ ┌─────────────────────────────────────────────────────────────┐ │ 模型内部知识检索 │ │ ❌ 没有找到"张三获奖"的信息 │ └──────────────────────┬──────────────────────────────────────┘ ▼ ┌─────────────────────────────────────────────────────────────┐ │ 生成机制: "预测下一个最可能的词" │ │ → "张三" + "2020年" + "获得" → 最可能的下一个词是"诺贝尔奖" │ │ → 生成: "张三在 2020 年获得了诺贝尔奖" │ └──────────────────────┬──────────────────────────────────────┘ ▼ ┌─────────────────────────────────────────────────────────────┐ │ 结果: 听起来合理,但完全是编造的 ❌ │ └─────────────────────────────────────────────────────────────┘ 应对策略 - RAG(检索增强): ┌─────────────────────────────────────────────────────────────┐ │ 用户提问 → 检索知识库 → 找到相关资料 → 把资料喂给模型 │ │ → 模型基于提供的资料回答 → 有据可查 ✅ │ └─────────────────────────────────────────────────────────────┘
2.6 大模型的能力边界
了解大模型不能做什么,和了解它能做什么同样重要。这能帮你避免在错误的场景硬上大模型,浪费时间和资源。
2.6.1 知识截止时间
大模型的知识截止到训练数据的时间点,对之后发生的事一无所知。
- GPT-4 的知识截止:2023 年 4 月(具体取决于版本)
- Claude 3.5:2024 年 4 月
- 国内模型:各有不同,需要查官方文档
应对:需要实时信息的场景,必须通过 RAG 或外部 API 补充最新数据。
2.6.2 数学和逻辑推理的局限
虽然大模型能写代码、能做简单数学,但在复杂数学推理上容易出错。
例如:大数乘法、复杂几何证明、多步骤逻辑推导。
应对:
- 对关键计算,用代码执行而非依赖模型
- 使用专门的推理模型(如 OpenAI o1、DeepSeek-R1)
- 让模型生成代码来解决问题,然后执行代码
# 不好的做法:让模型直接计算
prompt = "计算 123456789 * 987654321"
# 模型可能算错
# 好的做法:让模型生成 Python 代码
prompt = """计算 123456789 * 987654321
请生成 Python 代码来计算,只返回代码,不要直接给答案"""
# 然后执行模型生成的代码
2.6.3 长文本理解的局限
虽然上下文窗口越来越大,但模型对长文本中细节的捕捉能力仍然有限。
实验表明,当关键信息藏在长文档的中间位置时,模型找到它的概率会显著下降("Lost in the Middle"问题)。
应对:
- 关键信息放在 Prompt 的开头或结尾
- 使用 RAG 只检索相关段落,而非全文
- 对超长文档做分段处理
2.6.4 安全和合规边界
大模型可能生成:
- 有害内容(暴力、歧视、违法指导)
- 敏感信息泄露(训练数据中的个人信息)
- 版权内容(训练数据中的受版权保护文本)
应对:
- 使用内容过滤 API(如 OpenAI Moderation)
- 在输出前做安全审核
- 对敏感场景做人工复核
- 遵守数据隐私法规(GDPR、个人信息保护法等)
本章小结
这一章我们深入理解了大模型的几个核心运作机制:
-
预测下一个词:大模型的本质工作方式,自回归生成决定了它的串行特性。
-
Token 是计费单位:理解 Token 的切分规则,学会用
tiktoken估算,直接关乎你的成本和架构设计。 -
上下文窗口是硬限制:就像数据库连接池,你需要设计截断、摘要、RAG 等策略来应对。
-
Temperature 控制随机性:0 到 2 之间调整,根据场景选择——代码用 0,创意用 1+。
-
幻觉是固有问题:源于训练数据局限和生成机制本质,通过 RAG、事实核查、Prompt 约束来缓解。
-
了解能力边界:知识截止、数学推理局限、长文本细节丢失、安全合规——知道不能做什么,才能设计可靠的系统。
思考题
-
你正在设计一个客服机器人,用户可能上传很长的产品手册。考虑到上下文窗口限制,你会如何设计文档处理策略?
-
Temperature 参数在你的业务场景中应该如何设置?如果是一个"自动生成单元测试"的功能,你会用 0 还是 0.7?为什么?
-
假设你的系统用大模型生成医疗建议,如何设计多层防护来降低幻觉带来的风险?
下一章预告:现在你已经理解了大模型"怎么工作"。第 3 章,我们将放眼市场——GPT、Claude、文心一言、DeepSeek……主流大模型产品各有什么特点?价格如何?限制是什么?如何选择适合你业务的模型?