为什么上下文决定了大模型的命运
第 1 章 为什么上下文决定了大模型的命运
在开始这一章之前,请允许我先抛出一个可能让你不太舒服的观点:在 2024—2026 年这波大模型浪潮中,绝大多数应用层的失败案例,根因都不在模型本身,而在我们对"上下文"的无知。无论你的团队用的是 GPT-4、Claude、Gemini 还是开源的 Llama、Qwen,最终决定产品上限的,几乎都不是模型选型,而是你喂给模型的"那一坨信息"是怎么组织、压缩、检索和管理的。本章,我们将从一次真实的生产事故出发,重新理解"上下文"这件事的工程重量,并建立后续 14 章都会反复用到的认知坐标系。
1.1 一次价值数百万的生产事故:上下文溢出如何让 AI 助手"翻车"
2024 年春天,我参与了一起 AI 产品事故的复盘。出事的是某头部券商的智能投顾助手,部署在他们的手机 App 里已经半年多,月活用户超过 80 万。事故的导火索,是一个看起来极其普通的客户咨询。
事情经过大致是这样的:一位持仓比较分散的散户客户,连续 30 多轮向助手咨询自己过去半年的交易记录、税费优化和再平衡建议。前 20 轮对话中,助手表现非常专业,不仅准确调用了交易明细接口,还主动给出了止盈止损的提醒。但从第 21 轮开始,助手开始"幻觉"——它突然忘记客户在前几轮明确说过的"我已经清仓了贵州茅台"这件事,转而推荐客户加仓茅台。客户基于这个建议执行了一笔 50 万元的买入,结果第二天遭遇停牌核查公告,账面浮亏超过 12 万。客户随即投诉、维权,最终券商不得不做出赔偿,并暂停了该助手上线。
事后技术复盘发现,事故原因简单到令人发指:助手的后端把所有对话历史都塞进 prompt,每一轮都把完整的对话原文传给模型。当对话积累到第 21 轮时,总 token 数已经接近 GPT-4 Turbo 8K 上下文的极限,后端采取的策略是"截断最早的消息"。结果,截断的位置恰好位于"我已清仓茅台"这句话的中间——模型看到的不是完整句子,而是一个语义残缺的片段。在接下来的生成中,模型基于不完整的上下文做出了"用户可能还持有茅台"的推测,并据此生成了看似合理的加仓建议。
这起事故的讽刺之处在于:模型本身并没有错。换一个 128K 上下文的模型,或者在 prompt 里加上明确的"用户已清仓"提示,事故都不会发生。换句话说,这不是一个模型能力问题,而是一个上下文工程问题。
但这件事让我更不安的不是事故本身,而是复盘时发现的一个规律:这家券商的产品团队把 70% 的精力花在了 prompt 调优、模型评测、回答风格打磨上,只有不到 10% 的精力花在了"如何管理对话历史"这件事上。而事后测算显示,正是这被忽视的 10%,决定了用户是用得舒心还是亏钱。
这不是个案。我在过去两年里看过的大模型 ToB 项目,超过六成都在重复同样的错误:产品经理以为大模型是"一个更聪明的搜索引擎",工程师以为只要 prompt 写得好就万事大吉,PMF(产品市场契合度)卡住的时候,大家第一时间想到的是"换个更强的模型",却很少有人抬头看一眼那个被反复填满又被反复截断的上下文窗口。
如果你正在做或计划做大模型应用,我请你先记住一句话:大模型的上限,由上下文决定;大模型的下限,由工程决定。 模型本身只是这两者之间的一个翻译器。
1.2 重新理解"上下文"——大模型本质就是一个上下文处理器
要真正理解为什么上下文如此重要,我们需要暂时把"大模型"这四个字从神坛上请下来,从信息和认知的角度重新审视它。
1.2.1 信息论视角:大模型是一个有损压缩器
从信息论的角度看,一个预训练好的大语言模型,本质上是一个被压缩到参数里的世界知识库。你可以把它理解成一个极其庞大的、自回归的概率分布 $\Pr(x_i \mid x_{<i})$,这个分布在训练时被"压"进了千亿级别的浮点数里。在推理时,模型根据输入的 token 序列,逐个预测下一个最可能的 token。
注意,这里有一个关键细节:模型在推理时,并不能"访问"自己的参数之外的世界。它所有的"知识"都必须通过输入的 token 序列(即上下文)来传递。这意味着,无论你把模型做得多么庞大,它在某个特定时刻的"认知边界",就是当前上下文窗口所能容纳的信息量。
这个事实常常被忽视。我们习惯性地以为 GPT-4 "知道"很多事情,是因为它确实"知道"——但这种"知道"是被固化在参数里的静态知识。对于"这个客户的交易记录是什么"、"上一轮对话里用户说了什么"、"这份 100 页的合同里第 47 条写了什么"这类问题,模型本身一无所知,必须依靠上下文来"喂"给它。
由此可以推导出第一个重要结论:在推理阶段,决定模型表现的,不是模型的参数量,而是上下文的信息密度与覆盖度。
1.2.2 认知科学视角:上下文是大模型的"工作记忆"
如果把大模型类比成人类大脑,那么上下文窗口就是它的工作记忆(working memory)。认知科学早已证明,人类在处理复杂任务时,工作记忆的容量是有限的——米勒的"魔术数字 7±2"指出,人类一次能在工作记忆中保持的信息块大约是 7 个;后续研究进一步把容量压低到 4 个左右。超过这个容量,多余的信息要么被遗忘,要么必须借助外部笔记(long-term memory)来扩展。
大模型的情况惊人地相似。上下文窗口虽然从 4K、8K 一路扩展到了 128K、200K 甚至 1000K,但研究表明,模型在长上下文中的"有效注意力"是高度不均匀的。Stanford 和 MIT 的几项独立研究都发现,大模型在长上下文中存在"中间遗忘"(lost-in-the-middle)现象:对开头和结尾的信息关注度高,对中间部分的信息关注度显著下降。换句话说,单纯把窗口做大,并不等于把上下文质量做高。
更糟糕的是,上下文窗口是有限的、昂贵的、互相竞争的稀缺资源。每一 token 都要花钱(推理成本),每一 token 都要耗时(latency),每一 token 都会稀释其他 token 的注意力权重。把无关的、冗余的、过时的信息塞进上下文,等于在有限的工作记忆里堆满了垃圾,真正重要的信号反而被淹没。
1.2.3 为什么参数升级打不过上下文优化
让我们做一个思想实验。假设你有一个 8B 参数的模型 A 和一个 70B 参数的模型 B。在某个具体业务任务上,B 的基准得分比 A 高 15%。但如果你允许对 A 进行精心的上下文工程——比如使用检索增强生成(RAG)来补充领域知识,使用对话压缩来保留关键历史,使用工具调用来扩展实时信息——A 的实际表现可能在 90% 的真实场景中反超 B。
这不是夸张,这是过去两年我在多个企业项目中反复验证过的规律。原因有三:
第一,模型升级带来的能力提升是"平均"的,但上下文优化是"定向"的。70B 模型在所有任务上的平均能力都比 8B 强,但具体到你的某个垂直任务,二者的差距往往没有宣传的那么大;而上下文优化是针对你的具体任务、具体数据、具体用户来调的,提升幅度可以非常陡峭。
第二,上下文优化的边际成本极低。换模型要重做评测、重做部署、重做兜底,而优化上下文往往只需要改几个 prompt 模板、调整一下分块策略,成本可以忽略不计。
第三,上下文优化的可解释性远高于模型升级。当系统出错时,你可以精确定位到是上下文里哪个部分出了问题;而模型输出的偏差,往往很难归因。
所以,当你的 AI 产品表现不佳时,正确的第一反应不是"换更强的模型",而是"打开上下文窗口看看里面到底装了些什么"。
1.3 上下文工程的五大核心问题:一个被严重低估的系统
既然上下文如此重要,那么"上下文工程"到底包含哪些内容?很多团队误以为上下文工程就是"写 prompt",但实际上,它是一个由五个紧密耦合的子问题组成的系统工程。这五个问题看似各自独立,实际上在任何一个稍微复杂的大模型应用中,都必须协同设计。
1.3.1 长上下文:窗口不是越大越好
第一个问题,也是最直观的一个:如何让模型能够处理尽可能长的输入?
过去三年,上下文窗口经历了从 4K 到 8K、32K、128K、200K、1000K 的指数级增长。听起来很美好,但工程实践告诉我们三件事:
第一,窗口越大,推理成本越高,且不是线性增长。主流 Transformer 架构的自注意力复杂度是 $O(n^2)$,其中 $n$ 是序列长度。这意味着上下文从 8K 扩展到 128K,理论上计算量会增加 256 倍。虽然业界通过 Flash Attention、Ring Attention 等技术大幅优化了实际开销,但成本曲线仍然非常陡峭。
第二,有效注意力是稀疏的。前面提到的"中间遗忘"现象说明,模型在长上下文中的行为并不均匀。如果你以为把 200K 的文档塞进 prompt,模型就会"认真读完每一页",那你一定会失望。
第三,长上下文是其他四个问题的"原材料"。没有长上下文,压缩、摘要、检索都失去了意义;但反过来,长上下文的工程难题,也必须借助压缩、摘要、检索来缓解。
因此,长上下文的研究方向不是"把窗口做到无限大",而是如何让模型在有限的窗口内,尽可能多地保留对真正有用信息的关注。这包括位置编码的改进(如 RoPE、YaRN)、注意力机制的优化(如 Sliding Window Attention、Global Attention)、上下文位置策略(如把关键信息放在首尾)等等。本书第 3 章和第 4 章将深入讨论这些技术。
1.3.2 压缩:在信息损失和效率之间走钢丝
第二个问题是压缩——如何在保留关键信息的前提下,把超长上下文压缩到模型能"舒服"处理的范围内。
压缩和长上下文是一对永恒的矛盾体:长上下文想要"装得多",压缩想要"装得精"。但它们不是对立的,而是协作的——没有压缩的长上下文是奢侈的浪费,没有长上下文的压缩是无米之炊。
压缩通常发生在两个阶段。第一阶段是输入压缩:在把外部数据送入模型之前,先用算法或模型把内容压缩成更短的表示。典型技术包括上下文分块(chunking)、语义去重、关键词提取、向量量化等。第二阶段是输出压缩:在模型的输出端,把生成的冗长内容压缩成更紧凑的形式,比如把多轮工具调用的中间结果折叠成摘要、把过长的代码块替换为伪代码描述等。
压缩的核心挑战是保真度。一个糟糕的压缩算法会把"客户已清仓茅台"压缩成"客户调整了持仓",表面上没丢信息,实际上已经造成了致命的事实偏差。在金融、医疗、法律等高风险领域,这种"看似无损实则有损"的压缩是事故的高发区。本书第 5 章和第 6 章将系统讨论压缩的工程实践,包括基于 LLM 的压缩、基于规则的压缩、以及混合压缩策略。
1.3.3 摘要:让上下文拥有"分段记忆"
第三个问题是摘要——它和压缩看起来很像,但有一个关键区别:摘要强调语义的层级化和结构化,而压缩强调长度控制和忠实度。
打个比方,压缩像是把一件衣服叠进更小的箱子里,摘要则是给一本长篇小说写章节梗概。前者关心"塞得下",后者关心"读得懂"。
摘要的核心价值,是让模型拥有"分段记忆"的能力。在一个长对话中,最早的几轮对话可以被压缩成一段摘要,中间几轮对话被压缩成另一段摘要,最近的几轮对话保留原文。这样模型既不会丢失历史信息,又能把注意力集中在当前任务上。这正是 OpenAI 在 ChatGPT 中后期引入的"对话历史摘要"机制的底层逻辑。
摘要的工程挑战在于层级一致性。如果你有一个三层摘要(原文 → 段落摘要 → 全文摘要),那么任何一层的信息更新都必须同步到其他两层,否则会出现"摘要自相矛盾"的诡异现象。本书第 7 章将专门讨论摘要系统的设计与一致性维护。
1.3.4 检索记忆:让大模型拥有"外接大脑"
第四个问题是检索记忆——如何让模型突破上下文窗口的限制,访问远超窗口容量的历史信息。
这是过去两年最火热的领域,也就是大家熟悉的 RAG(Retrieval-Augmented Generation)。但请注意,RAG 只是检索记忆的一种实现方式,远不是全部。检索记忆还包括:
- 长期对话记忆(跨会话的用户偏好、习惯、历史任务)
- 任务记忆(在某个长任务中产生的中间结果、决策记录)
- 知识记忆(企业内部文档、产品手册、规范标准)
- 工具记忆(可调用的 API、函数、数据源的索引)
每一种记忆的检索策略都不一样。对话记忆通常用时间衰减加权,任务记忆通常用图结构索引,知识记忆通常用向量+关键词混合检索,工具记忆通常用结构化匹配。
更深一层看,检索记忆解决的根本问题是"信息在时间维度和空间维度上的分布与模型注意力的有限性之间的矛盾"。模型一次只能"看到"有限的内容,而真实业务需要的信息是分散在过去、散落在不同数据源中的。检索记忆的作用,就是在这个"无限信息海洋"和"有限注意力窗口"之间架一座桥。本书第 8 章到第 11 章将分四个维度拆解检索记忆的工程实现。
1.3.5 状态管理:让上下文拥有"时序一致性"
第五个问题,也是最容易被忽视的一个:状态管理——如何让模型在长时间、多轮、多任务、多用户的复杂场景下,保持上下文的一致性。
状态管理听起来很抽象,但实际场景比比皆是。想象一个 AI 助手同时服务 100 个用户,每个用户都有自己的对话历史、偏好设置、当前任务进度。模型如何在多个并发会话之间不串台?当用户中途切换任务、暂停几个小时再回来时,模型如何"接上"之前的状态?当系统升级、模型更换时,长期积累的状态如何平滑迁移?
这些问题的根源在于,大模型本身是无状态的——它不"记得"任何事,所有的"记忆"都必须通过上下文来重建。当上下文窗口被重置、对话被切换、模型被重启时,所有上下文都会丢失。状态管理的任务,就是在这些"断点"之间维护一个连续的、一致的、可恢复的状态图。
状态管理的工程复杂度极高,它涉及会话隔离、并发控制、版本管理、快照恢复、一致性协议等一系列分布式系统中的经典问题。本书第 12 章到第 14 章将专门讨论这些内容。
1.3.6 五大问题的耦合关系
这五个问题不是孤立的模块,而是一个相互咬合的齿轮组。下图展示了它们的内在关系:
```mermaid flowchart TD raw[原始数据流] --> lc[长上下文] lc --> comp[压缩] lc --> summ[摘要] comp --> summ comp --> rm[检索记忆] summ --> rm rm --> sm[状态管理] sm --> lc sm --> out[最终输出] ```
读这张图有三个关键点:
第一,长上下文是起点也是终点。所有其他四个问题的输入,最终都要回到长上下文中,再交给模型处理。状态管理的结果,也要重新组装成长上下文送入下一轮推理。
第二,压缩、摘要、检索记忆是三个不同维度的"减法"。压缩做的是"token 减法",摘要做的是"语义减法",检索记忆做的是"按需取用"——把不需要的信息从上下文中彻底剔除,只在需要时拉回来。三者经常组合使用。
第三,状态管理是统筹者。它不直接处理内容,而是协调其他四个模块的输入输出,决定什么时候压缩、什么时候摘要、什么时候检索、什么时候刷新。
理解了这五个问题的耦合关系,你就拥有了后续章节的认知地图。接下来的每一章,都将聚焦其中一个或两个问题深入展开,并展示它们在实际系统中如何协同工作。
1.4 一个真实改造案例:8K 上下文如何蜕变为百万级文档处理能力
理论讲完,我们来看一个具体的改造案例。这个案例来自一个法律科技初创公司,是我亲自参与过的项目。它非常典型地展示了"上下文优先"思维能带来多大的业务价值。
1.4.1 起点:被 8K 困死的合同审查助手
客户的产品是一个面向中小企业法务的 AI 助手,主要功能是"上传一份合同 → 自动审查风险条款 → 给出修改建议"。最初的产品形态是单次调用:用户上传一份合同,模型给出审查报告。
上线两个月后,问题出现了。用户反馈主要集中在三点:
1. 长合同(>20 页)经常审查不完整,要么漏掉条款,要么给出"凭空捏造"的建议; 2. 用户希望"结合公司之前的合同模板"给出建议,但产品根本不支持; 3. 用户希望"在多份合同之间做对比审查",例如"对比这份销售合同和上一份的差异",但同样做不到。
问题的根结是显而易见的:当时他们用的是 GPT-3.5 Turbo,8K 上下文。一份 20 页的合同大约有 6000—8000 个 token,留给系统提示、模板、历史对话的空间几乎为零,更别提跨文档对比。
团队的最初想法是"换模型"——升级到 GPT-4 32K。我也一度认为这是正确的方向。但当我们真正开始做技术评估时,发现了几个被忽视的事实:
- GPT-4 32K 的 API 成本是 8K 版本的 6—8 倍,按客户的用户量级算,每月仅推理成本就增加 40 万以上;
- 即使升级到 32K,单份合同就可能吃掉一半以上的窗口,跨文档对比依然无解;
- 用户的合同库规模在快速增长,未来单用户可能上传数百份历史合同,32K 也很快不够用。
换模型不是出路。我们需要重新设计整个上下文架构。
1.4.2 改造方案:分层上下文架构
我们最终设计的方案分为四层,每一层都对应上下文工程五大核心问题中的某一两个:
第一层:长期知识库(检索记忆) 把所有历史合同、模板、法律条文构建成一个向量数据库,并附带关键词索引。每次用户上传新合同时,系统先从知识库中检索出最相关的 10 份历史合同和 5 条相关法条,作为"外部记忆"注入上下文。
第二层:会话级摘要(摘要 + 状态管理) 对每个用户的会话维护一个滚动摘要。当对话超过 10 轮时,自动触发摘要——把早期对话压缩成一段结构化摘要,包含"已识别的风险点、用户偏好、待澄清问题"等字段。摘要本身也持久化在向量库里,方便跨会话检索。
第三层:动态压缩(压缩) 对用户上传的合同本身做语义分块。每份合同被切分成 200—500 token 的小块,每个小块生成一段"摘要向量"。审查时,系统先根据用户的具体问题检索出最相关的小块(通常是 5—10 个),再把这些小块连同它们的上下文位置信息注入 prompt,而不是把整份合同都塞进去。
第四层:精排与组装(长上下文 + 状态管理) 最后,系统把检索结果、对话摘要、用户当前问题、相关法条拼装成一个精心组织的长上下文。关键信息(用户的具体问题、检索到的强相关条款)放在 prompt 的开头和结尾,背景信息放在中间。这是基于"中间遗忘"研究的反直觉设计——我们故意把最重要的内容放在模型"最不会忘"的位置。
1.4.3 改造效果:数据不会说谎
改造上线三个月后,我们对比了关键业务指标:
| 指标