English: English
第六章:LLM 的固有局限¶
"It's not a bug, it's a fundamental architectural limitation."
上一章讲了大语言模型在高维模式匹配与符号转换上的长处。这一章要转过来看这幅图景的反面:那些受制于底层架构、模型天生就处理不好的计算任务。
这类问题并不是没来得及修复的工程缺陷,而是写在底层计算架构里的结构性约束。把这些限制背后的机理摸透,在工程上至少能想清楚三件事:
- 不在明摆着违背底层原理的地方耗费精力去盲目调优;
- 厘清系统的分工边界(让模型负责泛化理解,把确定性的计算留给现成的工具链);
- 为系统设立清醒的边界防御与故障隔离机制。
这一章的核心论点其实很明确:大语言模型身上的每一处短板,根子都在分词表示、因果注意力掩码或是自回归生成的底层机制里。把根源看透,工程上的解法自然就会浮现出来。
6.1 字符感知盲区与计数失效¶
经典失效案例¶
这个例子曾引来不少讨论。很多人觉得奇怪:一个连复杂代码都能写的模型,怎么偏偏在数字母这种小事上算错?但只要顺着分词器的切分逻辑看下去,就会发现这个结果完全合乎常理。
机理剖析:分词机制消解了字符级拓扑¶
回头看第一章:送进模型输入层的从来不是一串连贯的字符,而是经过 BPE 算法切分后的 Token 编号。
import tiktoken
enc = tiktoken.encoding_for_model("gpt-4")
tokens = enc.encode("strawberry")
print([enc.decode([t]) for t in tokens])
# 输出典型序列: ['str', 'aw', 'berry']
当模型处理 "strawberry" 时,注意力网络接收到的输入张量实际上是 str、aw、berry 这三个语义切片的嵌入向量。模型自始至终都没有直接看到单个字符 r 落在哪个具体位置上。
真想把数字数对,网络就必须在隐藏层里做一连串推演:
- 认出
str里面含有 1 个r; - 确认
aw里面没有r; - 认出
berry里面含有 2 个r; - 在前向传播的过程中把这几个数加起来。
这要求模型对 Token 内部的字符形态有清晰的感知。然而在无监督预训练里,Token 本身就是参与注意力计算的最小原子单元,模型内部并没有长出专门拆解这些细小结构的回路。
flowchart LR
subgraph 人类感知["人类直觉视界"]
H["s-t-r-a-w-b-e-r-r-y<br>(字符级完全可见)"]
end
subgraph 模型计算["模型表征视界"]
M1["str"] --- M2["aw"] --- M3["berry"]
M1 -.- N1["内部字符结构处于隐式黑箱"]
M3 -.- N2["内部字符结构处于隐式黑箱"]
end
style 人类感知 fill:#c8e6c9
style 模型计算 fill:#ffcdd2
工程应对策略¶
# 策略一:工具调用(Tool Use)交付确定性代码执行
def count_char(text: str, char: str) -> int:
return text.count(char)
# 策略二:在提示词中显式诱导符号解耦拆分
prompt = """
请将单词 "strawberry" 拆解为单字符序列,标注每个字符的索引位置,随后统计目标字母 "r" 的出现次数。
字符序列: s, t, r, a, w, b, e, r, r, y
目标字母 "r" 索引: [3, 8, 9]
统计结果: 3
"""
架构准则:凡是涉及字符级形态的操作,无论是精确计数、回文字符串检验还是反向推导正则表达式,都不要依赖模型的自由生成,必须把任务交给符号执行工具。
6.2 确定性算术的概率退化¶
数值规模与可靠性坍缩¶
问题: 7 + 5 = ?
输出: 12 (置信度极高)
问题: 347 + 289 = ?
输出: 636 (大概率命中)
问题: 7834 + 2917 = ?
输出: 10741 (错误,正确结果为 10751)
问题: 38472 × 9513 = ?
输出: 366,023,736 (错误,正确结果为 365,924,136)
机理剖析:模式联想替代精确算法¶
语言模型内部并没有算术逻辑单元(ALU),它在前向传播中所做的事情,说到底只有几步:
- 看到输入序列
"7 + 5 ="; - 唤起预训练语料里高频出现的
"7 + 5 = 12"关联记忆; - 输出概率最大的 Token
"12"。
数字很小的时候,海量语料里的高频共现让统计联想恰好撞上了真实的数学结果。可一旦数字的位数多起来,这套联想就会露馅:
更深层的矛盾出在计算拓扑上。多位数算术的进位是由低位向高位、严格自右向左传递的确定性过程;自回归模型生成文本时,却必须自左向右先输出高位再输出低位。当模型还在生成最高位数字的时候,由于因果掩码的阻隔,后面低位累加出来的进位根本还没算出来。
flowchart LR
subgraph 算术进位["确定性进位传播方向"]
direction RL
R4["个位: 4+7=11 (写1进1)"] --> R3["十位: 3+1+1=5 (写5)"] --> R2["百位: 8+9=17 (写7进1)"] --> R1["千位: 7+2+1=10 (写10)"]
end
subgraph 自回归生成["自回归生成时序"]
direction LR
L1["生成最高位 (万/千位)"] --> L2["生成百位"] --> L3["生成十位"] --> L4["生成个位"]
end
style 算术进位 fill:#c8e6c9
style 自回归生成 fill:#ffcdd2
自左向右的生成顺序与自右向左的进位依赖,在因果时序上形成了无法调和的错位。
算术任务可靠性分布¶
| 运算类型 | 数值范围 | 经验准确率 | 系统工程建议 |
|---|---|---|---|
| 基础加减 | 1 至 100 | > 98% | 可直接使用 |
| 多位加减 | 100 至 10,000 | ~ 80% | 需引入思维链或验证 |
| 大数加减 | > 10,000 | < 50% | 必须路由至代码执行 |
| 基础乘法 | 九九乘法表以内 | > 98% | 可直接使用 |
| 多位乘法 | 两位数乘法 | ~ 70% | 需引入草稿本(Scratchpad) |
| 高位乘除 / 根式 | 任意多位数 | < 25% | 坚决禁止直接推理 |
工程解耦实践¶
# 声明精确计算工具元数据
calculator_tool = {
"type": "function",
"function": {
"name": "execute_python_calculation",
"description": "执行严谨的数学计算、矩阵运算与复杂数值分析",
"parameters": {
"type": "object",
"properties": {
"code": {"type": "string", "description": "待执行的 Python 表达式或脚本"}
},
"required": ["code"]
}
}
}
6.3 长程推理断裂与因果误差累积¶
自回归生成的不可逆性¶
人在琢磨复杂逻辑时,靠的是所谓的系统 2(System 2):先挑一条路径往前推,撞上矛盾就退回上一步(Backtracking),重新推翻前面的假设,换个方向再试。
标准的自回归生成却没有退路可言:只要一个 Token 被生成出来,它就永久固化在上下文张量中,无法撤销,也不能动态擦除。
flowchart LR
subgraph 人类回溯推理["人类系统 2 思考 (支持试错与回溯)"]
direction TB
H1["前提 A"] --> H2["推演步 B"]
H2 --> H3["冲突分支 C (证伪)"]
H3 -.->|"回溯至上一步"| H2
H2 --> H4["修正分支 D (成立)"]
H4 --> H5["稳健结论"]
end
subgraph 自回归生成["自回归单向推演 (不可逆流)"]
direction TB
L1["Token 1"] --> L2["Token 2"]
L2 --> L3["Token 3 (偏离)"]
L3 --> L4["Token 4 (固化偏差)"]
L4 --> L5["Token 5 (严重幻觉)"]
end
style 人类回溯推理 fill:#c8e6c9
style 自回归生成 fill:#ffcdd2
条件概率链中的误差指数累积¶
设一条推演链包含 \(k\) 个步骤,每一步各自正确的概率是 \(p_i\),整条推演链走到最后的正确概率便是:
哪怕每一步的正确率都能达到 \(90\%\),连着推上 10 步,全局成功率也会一路跌到 \(0.9^{10} \approx 34.8\%\)。前序步骤哪怕只偏了一点,这个微小的偏差都会变成后续每一步采样的硬性条件,推着模型在错路上走得越来越自信。
"Lost in the Middle" 效应¶
Liu 等人(Liu et al., 2023)揭示了超长序列在注意力分配上的物理非对称性:
当输入的上下文急剧拉长时,模型对序列两端(头部与尾部)的信息检索准确率最高,夹在文档中段的内容却很容易被稀释的注意力直接漏掉。
graph LR
subgraph recall["长序列上下文注意力召回特征 (U 型曲线)"]
direction LR
P1["序列头部 (0-15%)<br>🟢 高置信召回"] --- P2["序列中段 (20-75%)<br>🔴 注意力稀释盲区"] --- P3["序列尾部 (85-100%)<br>🟢 高置信召回"]
end
工程加固方案¶
- 思维链结构化显式展开(Chain-of-Thought):生成详细的中间推演步骤,借此扩充计算图的思考容量;
- 外部搜索与多路径验证(Tree of Thoughts / Best-of-N):用多次采样配上外挂验证器,在外部模拟出回溯搜索的过程;
- 上下文首尾锚定优化:组装 Prompt 时,把核心业务约束与最关键的证据放到上下文最开头,或者紧贴着问答的最末尾。
6.4 知识时效性与静态权重约束¶
知识冻结的物理本质¶
大语言模型内部存储的事实知识,在预训练结束的那一刻,就已经彻底固定在静态权重矩阵中了:
提问: "2025 年全球人工智能安全峰会的主办城市是哪里?"
模型: (受限于 2024 年训练截断点)"该会议尚未召开或缺乏公开记录..."
隐蔽性风险提问:
提问: "当前 Next.js 的推荐架构规范是什么?"
模型: 自信地输出过时的 Pages Router 模式,而非最新的 App Router 范式。
后一种情形落到生产系统里,往往隐蔽得多,破坏力也大得多:模型根本不知道自己的知识已经随时间老去,依然会带着极高的确定性,输出早已过时的信息。
flowchart LR
D["预训练语料池<br>(知识截断点: T_cutoff)"] --> T["大规模梯度优化"] --> W["冻结的静态权重 W"]
E1["T_cutoff 之前的存量事实 ✓"] --> W
E2["T_cutoff 之后的动态世界状态 ✗"] -.->|"物理隔离,完全不可见"| W
style E1 fill:#c8e6c9
style E2 fill:#ffcdd2
知识注入方案对比¶
| 方案架构 | 知识更新周期 | 实施成本 | 适用场景 |
|---|---|---|---|
| RAG (检索增强生成) | 毫秒至分钟级 (实时向量化) | 极低 (仅检索索引开销) | 生产系统首选,高频变动的企业知识库 |
| 实时 Web Search 插件 | 实时调用 | 极低 (API 成本) | 开放领域最新资讯与事实核查 |
| 全量微调 (Fine-Tuning) | 天至周级别 | 高 | 调整领域行文风格与专业术语表达,不宜用于事实注入 |
| 模型全量重训 | 月至年级别 | 极高 (数百万美元算力) | 基础认知底座的周期性迭代 |
6.5 忠实性缺失与拒答机制的本质¶
续写器的本质决定了无条件响应¶
大语言模型的首要目标,是在给定的上下文下算出最大似然的延续。当模型的隐层权重里缺少特定领域的事实时,计算图并不会抛出 NullPointerException 报错停机,而是转向语义流形相近的区域搜寻看似合理的词元,将它们拼装成文。
"我不知道"仅是一种概率预测¶
经过强化学习对齐的模型,确实会更频繁地输出“我无法确定”。但这绝不意味着它拥有了内省式的真实不确定性度量,无非是在某些特定的提问模式下,生成拒答的 Token 恰好能给它换来更高的环境奖励。
当模型以极高的流畅度写下长篇大论时,调用方光看那副笃定的语气,根本无从分辨里面的事实是真是假。
# 脆弱架构:直接采信模型内隐事实
raw_answer = llm.generate("某初创企业最新的估值与轮次信息?")
# 模型可能输出看似精确的数值,实则完全源于参数流形的虚构拟合
# 健壮架构:受限 RAG 闭环验证
retrieved_docs = knowledge_retriever.query("某初创企业 最新 估值")
safe_answer = llm.generate(f"""
【严格约束】请仅依据以下参考资料回答问题。若参考资料未提及具体数值,请明确声明"依据已知材料无法确定",严禁结合外部常识推测。
参考资料:
{retrieved_docs}
""")
6.6 上下文窗口的物理与经济硬约束¶
\(O(n^2)\) 计算与显存带宽墙¶
标准的自注意力计算复杂度,会随着 Token 长度 \(n\) 呈平方级增长:
| 上下文长度 | 相对浮点计算量 | 单并发 KV Cache 显存占用 (70B 模型) |
|---|---|---|
| 4K | \(1\times\) | ~ 10.24 MB |
| 16K | \(16\times\) | ~ 40.96 MB |
| 128K | \(1024\times\) | ~ 327.68 MB |
| 1M | \(62500\times\) | ~ 2.56 GB |
超长上下文带来的计算与显存膨胀只是账面上的开销,落到工程实际中,首字延迟(TTFT)会被急剧拉长,系统的吞吐量也会跟着大幅恶化。
上下文并非无序信息垃圾桶¶
盲目将所有数据塞进上下文窗口,很快就会引出四大工程危机:
- API 调用成本线性激增;
- 推理时延超出实时交互容忍阈值;
- “大海捞针”检索衰减:关键信息被杂乱的噪声彻底淹没;
- 注意力分散导致输出质量降级。
graph TD
Q["业务检索需求"] --> D1{"输入数据体量评估"}
D1 -->|"轻量短文本 (< 8K tokens)"| S1["全量直接注入 Prompt"]
D1 -->|"中等文档集 (8K - 100K tokens)"| S2["分块向量检索 + Rerank 顶级精选"]
D1 -->|"超大规模知识库 (> 100K tokens)"| S3["分层图谱检索 (GraphRAG) + 递归摘要"]
style S1 fill:#c8e6c9
style S2 fill:#fff9c4
style S3 fill:#ffcdd2
6.7 系统工程可靠性分级框架¶
把前面的各项分析推演到底,我们便能理出一套系统工程可靠性分级框架。模型该接什么、不该碰什么,系统里的权责边界到底划在哪里,全看这把尺子。
三级可靠性拓扑¶
graph TD
subgraph L1["🟢 高可靠层 (模型直接处理)"]
T1["多语言互译"]
T2["结构化 Schema 转换"]
T3["受限文本摘要"]
T4["上下文信息蒸馏"]
T5["代码模式解释"]
end
subgraph L2["🟡 中可靠层 (模型生成 + 机制校验)"]
T6["业务代码生成 (依赖单元测试验证)"]
T7["复杂指令遵循 (依赖 AST / 校验器)"]
T8["少样本领域分类 (依赖置信度阈值)"]
end
subgraph L3["🔴 不可靠层 (必须交付外部确定性工具)"]
T9["高精度多位算术与科学计算 (交付 Python / ALU)"]
T10["字符级精细操作 (交付正则表达式 / 字符串函数)"]
T11["时效性事实检索 (交付搜索引擎 / 数据库)"]
T12["全局多步可回溯规划 (交付搜索算法 / 状态机)"]
end
style L1 fill:#c8e6c9
style L2 fill:#fff9c4
style L3 fill:#ffcdd2
全景可靠性矩阵¶
| 任务类型 | 固有可靠性 | 架构根因 | 工业级解决方案 |
|---|---|---|---|
| 语言翻译 | 🟢 高 | 海量平行先验 | 直接调用,设定 Temperature=0 |
| 文档摘要 | 🟢 高 | 预训练压缩目标一致 | 直接调用,控制输出长度 |
| 格式映射 | 🟢 高 | 双向平行语法对照 | 启用 JSON Mode / Grammar 约束 |
| 受限抽取 | 🟢 高 | 答案显式包含于输入 | 结合 Few-shot 约束输出 Schema |
| 代码生成 | 🟡 中 | 逻辑分支可能存在疏漏 | 配套沙盒执行与自动化单元测试 |
| 上下文问答 | 🟡 中 | 易受诱导性提示词干扰 | 强制要求生成原文引用(Citations) |
| 精确数值运算 | 🔴 低 | 模式联想非严谨计算 | 强制路由至代码解释器或计算器 |
| 字符级计数 | 🔴 低 | BPE 分词打碎字符拓扑 | 强制交由原生字符串函数处理 |
| 实时动态事实 | 🔴 低 | 静态权重时间截断 | 强制构建 RAG 检索管线 |
| 长程状态规划 | 🔴 低 | 自回归缺乏回溯机制 | 外置规划状态机与验证器 |
系统调度总线架构¶
flowchart TD
User["用户输入 Request"] --> Router["语义意图路由与分发器"]
Router -->|模式转换/摘要/翻译| LLM_Direct["LLM 确定性直出"]
Router -->|代码生成/逻辑综合| LLM_Verify["LLM 生成"] --> Verifier["静态分析 / 单元测试校验"]
Router -->|算术/字符/实时信息| Tool_Dispatch["工具调用总线 (Tool Bus)"]
Tool_Dispatch --> Tool_Calc["数值计算引擎"]
Tool_Dispatch --> Tool_RAG["RAG / 知识库检索"]
Tool_Dispatch --> Tool_Code["Python 沙盒执行环境"]
Tool_Dispatch --> Tool_DB["结构化数据库 API"]
LLM_Direct --> Aggregator["响应组装与渲染"]
Verifier -->|测试通过| Aggregator
Verifier -.->|测试失败| LLM_Verify
Tool_Calc --> Aggregator
Tool_RAG --> Aggregator
Tool_Code --> Aggregator
Tool_DB --> Aggregator
Aggregator --> Output["最终安全可信输出 Response"]
style LLM_Direct fill:#c8e6c9
style LLM_Verify fill:#fff9c4
style Tool_Dispatch fill:#ffcdd2
本章小结¶
graph TB
A["LLM 的架构硬伤"] --> B["字符盲区: Tokenizer 消解内部结构"]
A --> C["算术失效: 统计联想与自回归生成时序错位"]
A --> D["长程断裂: 误差单向累积且缺乏回溯搜索"]
A --> E["知识冻结: 静态参数无法感知动态演变"]
A --> F["忠实性缺失: 概率续写驱动无条件填充"]
B --> G["工程法则: 扬长避短,解耦路由"]
C --> G
D --> G
E --> G
F --> G
核心要点:
- 缺陷是架构的内生属性:数不清字符、算不对大数、长程推演半途走偏,根子全在底层的表征与生成算法里,由不得模型自己;
- 严禁依赖提示词解决架构缺陷:别指望靠优化 Prompt 让模型胜任精确计算,这类容不得差错的硬活,必须干脆地交付确定性工具;
- 建立三级可靠性工程分流:高可靠任务由模型直接输出,中可靠任务套上验证环再放行,不可靠任务则坚决剥离给外部工具;
- 以 RAG 与工具调用化解静态边界:让擅长泛化理解的语言模型坐镇调度中枢,至于数据与事实的绝对准确,交由专用系统稳稳守住。
下一章,我们将把目光转向大语言模型身上最显眼、破坏力也最强的一处失效:深挖幻觉(Hallucination)背后的统计本质,摸清消除它的现实路径。
延伸阅读¶
- Lost in the Middle: How Language Models Use Long Contexts, Liu et al., 2023
- Faith and Fate: Limits of Transformers on Compositionality, Dziri et al., 2023
- Toolformer: Language Models Can Teach Themselves to Use Tools, Schick et al., 2023
- Measuring and Narrowing the Compositionality Gap in Language Models, Press et al., 2022
- Large Language Models Cannot Self-Correct Reasoning Yet, Mirchandani et al., 2023