# 模型只知道窗口里有什么

关于 context engineering 的速成课——也就是把恰到好处的文本组装进模型 context window 的功夫。18 个概念——Stateless Model、Context Window、Context Engineering、System Prompt、Few-shot、Context Dilution、Context Budget、Context Rot、Compaction、Context Evals 等——每个都有英文名称、一张图、一张卡片和一个例子。结尾附一页纸的全部概念速查表。

- **Author:** Fedor Chishchin
- **Level:** intermediate
- **Reading time:** 约 35 分钟阅读
- **Published:** 2026-06-13
- **Source:** https://fedorthinks.com/zh/learn/context-engineering-express

---

## 1. 窗口就是它知道的全部

这门课的一切都源自关于语言模型如何工作的一个事实:它没有记忆,任何一次调用中它的全部觉知就是你发给它的文本。理解了这点,其余都是显而易见的。

### 地图:七组共 18 个概念

> 一张地铁线路图:先整体看清各条线路,再一站一站地坐过去。

这门课走过七组概念。第一组——**窗口**:模型到底知道什么。接着——从措辞一个 prompt 到组装 context 的**转变**。然后——**窗口由什么构成**,以及让它变差的三种力量:**无关内容**、**预算**和**随时间腐烂**。最后——**实践**:有意识地构建窗口,并衡量结果。

_Diagram: 七组概念——第 1–7 章依次对应它们。_

### 如何阅读每个概念

> 一本护照:每个人的栏目都一样,所以很容易比较。

下面每个概念都用同样的方式讲:它的**英文名称**(记住它——文档和文章都这么叫),一幅日常生活的画面,一张**图**,以及一张带有*问题*、_思路_、_例子_、*代价*和*关联*等栏目的**卡片**。这门课的核心思想:**LLM 的质量由你放进窗口的东西决定,而不是巧妙的措辞。**

### Stateless Model——两次调用之间什么都不记得

> 一位才华横溢却彻底失忆的顾问——每次会面,你都得把每份文件重新递给他一遍,因为他对上次的事毫无记忆。

语言模型是**无状态**的(stateless)——这就是 **Stateless Model** 这个概念:它在两次请求之间什么都不保留。聊天机器人“记得”你的对话,不过是每次都把完整历史重新发了一遍。模型本身每次调用都从头开始,只知道此刻摆在面前的东西。

所以“模型知道什么?”从来不取决于模型——完全取决于你这一次选择放进去什么。

_Diagram: Stateless:每次调用,应用都会重新发送整个历史。聊天机器人的“记忆”活在你的代码里,不在模型里。_

#### Stateless Model (两次调用之间没有记忆)

- **是什么:** 模型在两次请求之间什么都不保留:每次调用都从空白开始。
- **如何运作:** 聊天之所以“记得”对话,只是因为应用在每次调用时都重新发送了整个历史。
- **例子:** 聊天里的第三个问题,会连同前两个问题和两条回复一起发给模型。
- **陷阱:** 指望模型“记得”过去某次会话里的规则——如果它不在这次调用里,它就不存在。
- **关联:** 这就是为什么 **Context Window** 决定一切;不断增长的历史会引出 **Context Budget** 和 **Context Rot**。

### Context Window——它唯一的工作记忆

> 一个工人只能依据钉在他面前白板上的便签行事——把白板擦干净,就仿佛什么都没发生过。

**Context window**(上下文窗口)是模型在一次调用中看到的那块文本——你的指令、对话、各种数据、工具。它是模型全部的工作记忆,而且大小有限。如果某个事实、某条规则或某条过去的消息不在窗口里,模型就是不知道。

模型能推理的一切,都是依据窗口来推理的——这使窗口成为你真正要去设计的东西。

_Diagram: 窗口就是模型看到的一切。窗口之外的东西(一段旧聊天、公司 wiki、被遗忘的规则)对它来说并不存在。_

#### Context Window (模型的工作记忆)

- **是什么:** 模型在一次调用中看到的全部文本:指令、历史、数据、工具。
- **如何运作:** 模型只依据窗口推理。窗口有以 token 计的最大长度。
- **例子:** 客服机器人不知道退款政策,除非这份文本被放进了本次调用的窗口。
- **陷阱:** “模型应该知道这个”——不:如果它不在窗口里,它对模型就不存在。
- **关联:** 窗口通过 **Context Assembly** 构建;它的大小就是 **Context Budget**。

### 所以质量取决于你放进去什么

> 一位天才只依据你递给他的那一个文件夹作答——给他对的文件夹,答案就精彩;给他错的,他就自信地一无是处。

因为模型只依据窗口工作,它输出的质量大多在模型运行*之前*就已决定——取决于你组装了什么。同一个模型,给出精彩的答案还是糟糕的答案,完全取决于摆在它面前的是不是正确的 context。这重新定义了整份工作:你不是在从模型里哄出智能,而是在**筛选它能看到什么。**这种筛选就是 context engineering。

_Diagram: 同一个模型:有正确的 context——答案精彩;没有——自信地一无是处。杠杆是输入,不是模型。_

> **框架性问题:** “模型要答好这个问题所需的一切,现在真的都在窗口里吗——还是我在指望它知道一些我从未摆到它面前的东西?”

> 模型是无状态的,只知道它的 context window。输出质量由你组装进这个窗口的东西决定——所以你要设计的是窗口,而不是模型。

## 2. Prompt 与 context

人们谈论“prompt engineering”,但随着应用变得严肃,真正的手艺转移了——从措辞一个请求,转向围绕它组装正确的信息。这个转变是这门课的核心。

### Prompt Engineering vs Context Engineering——措辞与组装

> 律师赢官司靠的不是巧妙的措辞,而是把恰好正确的文件、按正确的顺序、不带任何无关内容递给法官——案子在卷宗里,不在演讲里。

**Prompt engineering** 关心的是你怎么措辞指令。**Context engineering** 是更大的工作:每次调用时,把模型需要的*全部*信息——相关事实、历史、示例、工具——组装进窗口。

随着应用变大,措辞越来越不重要,组装越来越重要。大多数“AI 给了个糟糕答案”的时刻,并不是措辞不好,而是模型缺少从未给过它的 context。

_Diagram: Prompt engineering 只是窗口的一部分(措辞)。Context engineering 是每次调用时组装起来的全部输入。_

#### Context Engineering (相对于 prompt engineering)

- **问题:** 质量靠调 prompt 措辞来“调优”,而模型缺少的是真正的事实。
- **思路:** 设计整个窗口:系统规则、事实、历史、示例、工具——每次调用都是如此。
- **例子:** 与其写“请详细而准确地回答!”——不如把正确的文档和关键规则放进窗口。
- **代价:** 你需要组装窗口的代码,以及对放什么进去的自律。
- **何时使用:** 一旦某个 LLM 功能超出了单个演示用 prompt 的范围。
- **关联:** Prompt engineering 是其中一部分;实践中就是 **Context Assembly** 和 **Deliberate Assembly**。

### Missing Context——大多数质量问题都是 context 问题

> 一个助手给出了错误答案,只因你忘了提那个改变一切的约束——他不蠢,只是不知情。

当某个 LLM 功能表现不佳时,本能反应是调整 prompt 措辞或怪罪模型。更常见的真正原因是 **context 缺失或错误**(**missing context**):相关文档没有被检索到,关键规则没有被包含,过时的历史把它搞糊涂了。

在改写任何措辞之前,先问问模型实际上面前有什么。修好 context 比修好措辞能解决多得多的 bug。

_Diagram: 答案不好?本能是重写 prompt。正确的第一步是看窗口里有什么:没检索到的文档、没包含的规则、过时的历史。_

#### Missing Context (缺失或错误的 context)

- **问题:** 模型回答得很差,团队一遍又一遍地重写 prompt——毫无效果。
- **思路:** 先看出错那次调用里窗口中有什么;之后才去动措辞。
- **例子:** 机器人引用了旧的价格方案:窗口里是过时的历史,没有新的价目表。
- **典型原因:** 文档没被检索到,规则没被包含,过时的历史把它搞糊涂了。
- **关联:** 用 **Context Assembly** 和 **Curation** 修复;用 **Context Evals** 验证。

### 模型的好坏取决于它的输入

> 最好的厨师也只能用台面上的食材做菜——给他错的食材,手艺也救不了这道菜。

一个能力强但 context 糟糕的模型,会输给一个较弱但 context 出色的模型。这就是为什么 context engineering 而不是选模型,通常是最值得投入精力的地方:同一个模型的输出会随你喂给它的东西剧烈波动。想要更好的答案,不是靠更用力地要求,而是靠往窗口里放更好、更锋利、更相关的材料。输入就是杠杆。

> **手艺问题:** “我是不是在靠改写 prompt 来解决这个问题——而真正的问题是哪些信息进了 context、哪些没进?”

> Prompt engineering 是措辞;context engineering 是组装正确的信息。质量活在后者里——而大多数糟糕的答案是 context 缺失,不是措辞不好。

## 3. System prompt 与示例

放进窗口的东西,有的是长期不变的,有的是按请求而定的,而少数几种特定的要素承担了大部分工作。弄清它们是什么,组装 context 就变得具体了。

### System Prompt——长期行为与一次性请求

> 餐厅的长期政策——“我们是素食餐厅,十点打烊”——对比今晚的具体点单。前者框定一切;后者是所求之事。

**System prompt** 放的是适用于整个交互的长期指令:模型的角色、必须遵守的规则、语气、输出格式。**用户消息**则是具体的请求。

把你的人设、护栏和长期规则放进 system prompt,它们就能保持稳定,而用户的问题则千变万化。这就是模型在每次调用中*是谁*与它这一次被要求*做什么*之间的区别。

_Diagram: System prompt 每次调用都一样(角色、规则、语气、格式)。用户消息每次都不同。_

#### System Prompt (相对于用户消息)

- **是什么:** 适用于整个交互的长期指令:角色、规则、语气、输出格式。
- **对比:** **用户消息**——这一次的具体请求。
- **例子:** System:“你是一家商店的客服机器人,回答要简短,绝不承诺折扣。”用户:“我的订单到哪了?”
- **陷阱:** 把长期规则混进请求里,它们就会在不同问题之间“飘来飘去”。
- **关联:** **Context Assembly** 的第一块;输出格式往往用 **Few-shot** 展示更好。

### Few-shot Prompting——展示,而不只是讲述

> 给人展示三个做好的范例来教一种格式,比用语言描述它、指望对方想象得对,既更快也更清楚。

想得到你要的输出形态,最可靠的办法往往是在 context 里直接**放几个**输入与理想输出的**示例**。这就是 **few-shot prompting** 模式。模型对示例的模仿,远比对抽象描述的遵循来得好。

两三个锋利的示例,可以胜过一段话的指令,而且当模型*差不多*做对、却又不太对时,它们往往是最快的修复办法。

_Diagram: 左——用语言描述格式,得到“差不多对”。右——展示“输入 → 理想输出”的配对,新的输入就会得到同样的形态。_

#### Few-shot Prompting (context 里的示例)

- **问题:** 模型差不多能做到,但输出的形态会跑偏。
- **思路:** 在窗口里放 2–3 对“输入 → 理想输出”——模型会重复这个模式。
- **例子:** 三个“评论 → 带情感和主题的 JSON”的示例,然后给一条新评论——答案就以同样的 JSON 返回。
- **代价:** 示例每次调用都占 token——它们是 **Context Budget** 的一部分。
- **何时使用:** 形态很重要,而一段话的指令没有帮助时。
- **关联:** **Context Assembly** 的组成部分之一;与 **System Prompt** 互补。

### Context Assembly——用零件构建窗口

> 为一次会议收拾公文包:议程、两份相关报告、一张写着约束条件的便条——有意挑选的,而不是把整个文件柜都倒进去。

真正的 context window 每次调用都由若干部件组装而成:system prompt、相关历史、检索到的事实(**RAG**)、示例、可用的工具,最后是用户的请求。这就是 **context assembly**:每一次都有意识地决定哪些部件进来、哪些留在外面。

把窗口看作你用部件*构建*出来的东西,而不只是你敲出来的一段 prompt,这个思维转变会让其余一切豁然贯通。

_Diagram: 每次调用,你的代码挑选各个部件——system prompt、历史、事实、示例、工具、请求——并用它们组装出窗口。_

#### Context Assembly (用部件构建窗口)

- **问题:** 窗口“只是一段 prompt”,手边碰巧有什么就往里放什么。
- **思路:** 在代码里用部件组装窗口:system prompt、历史、RAG 事实、示例、工具、请求。
- **例子:** 一个订单问题:机器人的规则 + 最近 3 条消息 + 这个订单的数据 + 问题本身。而不是整个商品目录。
- **代价:** 每个部件都要挑选并说明理由——这是工作,不是魔法。
- **关联:** 部件——**System Prompt**、**Few-shot**;过滤——**Curation**;习惯——**Deliberate Assembly**。

> **组装问题:** “这个窗口由哪些部件构成——系统规则、历史、检索到的事实、示例、工具——每一个都在发挥作用,还是只是跟着凑数?”

> System prompt 设定长期行为;用户消息是请求;few-shot 示例展示你想要的形态。窗口就是由这些部件,在每次调用时有意识地组装起来的。

## 4. 相关性胜过完整性

context engineering 里初学者最大的错误,是以为越多越好。事实恰恰相反:你每加一个无关的 token,都在实实在在地让答案变差。

### Relevance over Completeness——更多的 context 不等于更好的 context

> 一页锋利的简报胜过 200 页的堆砌——读者能找到信号,而不是淹没其中,于是决定得更快更好。

把一切可能相关的东西“以防万一”都塞进窗口,很诱人。但更多并不更好——通常更糟。原则是 **relevance over completeness**(相关性胜过完整性):每个 token 都在争夺模型的注意力,无关的材料会**稀释**信号。

真正的功夫,是挑出少数重要的东西,而不是把所有可能重要的都放进去。

_Diagram: 左——什么都“以防万一”:信号淹没在噪声里。右——只放这次调用需要的:答案锋利。_

#### Relevance over Completeness (刚好够用,而不是全部)

- **问题:** 什么都“以防万一”地放进窗口。
- **思路:** 目标不是把一切都给模型——而是给它刚好够用的。
- **例子:** 不放整个知识库——只放真正回答这个问题的那三段。
- **代价:** 你得会挑选:好的检索、裁剪、对舍弃什么做出决定。
- **关联:** 为什么——**Context Dilution**;怎么做——**Curation**;它还能节省 **Context Budget**。

### Context Dilution——噪声提高了答错的概率

> 把唯一相关的事实藏进一座大多无关的纸山里,连认真的读者也会开始引用错误的那一页——噪声本身造成了错误。

又长又被灌水的 context 不只是浪费空间;它在实实在在地拉低质量。这就是 **context dilution**:埋在无关材料之中,模型的注意力被摊得很薄,在长 context 中这会可测量地**提高幻觉和出错的比率**——它自信地用上了某个本不该是答案的东西。

“以防万一”添加的 context,可能恰恰就是造成失败的原因。更少、更锋利的 context,才是更可靠的 context。

_Diagram: 模型的注意力被摊在噪声上——它抓住了旁边某个看似相近却不对的东西,而不是正确的事实。_

#### Context Dilution (信号淹没在噪声里)

- **是什么:** 无关的 token 稀释了模型对关键信号的注意力。
- **风险:** 在长 context 中,幻觉和出错的比率会上升:模型抓错了那一段。
- **例子:** 窗口里有二十份相似的文档——模型引用了隔壁那份合同,而不是对的那份。
- **陷阱:** “以防万一”的 context 感觉无害——却可能正是失败的原因。
- **关联:** 用 **Curation** 修复;更大的窗口(**Long Context Windows**)并不能抵消它。

### Curation——为这次调用毫不留情地筛选

> 好编辑不加东西——他删,只把配得上留在这一页的句子交给你。

这门功夫是**毫不留情的筛选**:针对*这一次*具体的调用,只放模型真正需要的少数东西,其余一概留在外面。这意味着只检索最相关的片段,把历史裁剪到重要的部分,丢掉已经完成使命的 context。

_Diagram: 筛选漏斗:在所有可能有用的东西中——只留最好的片段、历史中重要的部分,以及没有任何已完成使命的内容。_

#### Curation (毫不留情地筛选 context)

- **问题:** 窗口自己越长越大:手边有什么就发给模型什么。
- **思路:** 每次调用:只放最相关的片段、裁剪过的历史,不放任何已完成使命的东西。
- **例子:** 搜索找到 50 个片段,最好的 3 个进窗口;已经消化过的工具输出被丢掉。
- **代价:** 你可能砍掉了需要的东西——所以修改要用 **Context Evals** 来检验。
- **关联:** 体现了 **Relevance over Completeness**;是 **Trim & Summarize** 和 **Compaction** 的近亲。

> **相关性问题:** “这个窗口里的每一块对答案真的都相关吗——还是我在“以防万一”地灌水,悄悄地让模型变差?”

> 更多的 context 并不更好——无关的 token 会稀释注意力、提高幻觉。毫不留情地筛选:只给模型这次调用恰好需要的,别的一概不给。

## 5. 窗口是一份预算

除了质量,窗口还是一种有限且要付费的资源。把它当作稀缺的预算,而不是无限的垃圾场,这正是玩具与产品的分野。

### Context Budget——窗口有限,每个 token 都要花钱

> 一只有重量上限、按公斤收费的行李箱——你装的是真正会用到的东西,而不是整个衣柜,因为有硬上限,也有价格。

Context window 有最大长度,而其中每个 token 都要花费**延迟和金钱**——更大的 context 在每一次调用中都更慢、更贵。所以 context 不是等着你去填满的免费空间;它是你要花的 **context budget**。

一个每次请求都塞满窗口的功能,规模一大就又慢又贵,甚至还没轮到质量受损。窗口是要分配的资源,而不是要填满的空洞。

_Diagram: 窗口有硬上限,其中每个 token 都要用延迟和金钱来买单——每一次调用都是如此。_

#### Context Budget (作为稀缺资源的窗口)

- **是什么:** 窗口是有限且要付费的资源:有大小上限,每个 token 都有价格。
- **你付出什么:** 延迟和金钱——每次调用都付,再乘以流量。
- **例子:** 某个功能每次请求都发送完整历史和整本参考手册——还没轮到质量受损,就已经又慢又贵。
- **何时考虑:** 从第一天起,一旦这个功能面对真实用户。
- **关联:** 通过 **Trim & Summarize** 精打细算;**Long Context Windows** 并不能取消它。

### Trim & Summarize——把窗口花在配得上位置的东西上

> 紧巴巴的旅行预算会逼你做出真正的取舍——你把钱花在对旅行重要的事上,其余的省掉,而这趟旅行因这份自律而更好。

把窗口当作预算,会改变你构建的方式:你**裁剪**(**trim**)对话历史,把旧的轮次**总结**(**summarize**)而不是原样带着走,并且只检索现在相关的东西,而不是你拥有的一切。每个 token 都应该配得上它的位置。

这与性能优化或缓存是同一种自律——有意识地把稀缺资源花在真正左右结果的事情上。

_Diagram: 八轮原文 → 前六轮的简短总结,加上最后两轮原样保留。token 更少,意思不变。_

#### Trim & Summarize (裁剪与总结历史)

- **问题:** 对话历史不断增长,每一轮都原样跟在窗口里。
- **思路:** 旧的轮次变成简短总结,近期的保持原样;只检索现在需要的。
- **例子:** 不放 40 条聊天消息——而是一句总结“客户想退订单 #…,已经发过照片”+ 最后 2 条消息。
- **代价:** 总结可能丢掉某个细节——用 evals 来检查。
- **关联:** 精打细算地花 **Context Budget**;在长任务中会演变成 **Compaction**。

### Long Context Windows——更大的窗口并没有终结这门自律

> 租一辆更大的卡车,并不意味着你该往里塞满垃圾——更大的容量是给更多有用东西的空间,而不是不再仔细打包的许可证。

模型不断推出更大的 context window(**long context windows**)——一百万 token,甚至更多——于是很容易以为预算问题就此消失。并没有。更大的窗口依然更贵,每个 token 也依然更慢,而且关键的是,更满的窗口依然会稀释注意力、招致错误。

更大的容量不是倾倒的许可;它只是你仍然必须精打细算去花的更多空间。筛选窗口这门自律,不会因为任何尺寸的增长而失效。

_Diagram: 两个窗口装着同样一小撮有用的材料。大的那个只是给噪声留了更多空间——而你依然按 token 付费。_

#### Long Context Windows (百万 token 以上的窗口)

- **是什么:** 窗口达到一百万 token 乃至更多的模型。
- **诱惑:** 以为既然什么都装得下,就不再需要筛选了。
- **例子:** “因为装得下”就把整个代码仓库倒进窗口——又贵又慢,模型还会被搞糊涂。
- **陷阱:** 窗口越满,**Context Dilution** 越强,**Context Rot** 的空间也越大。
- **关联:** 提高了 **Context Budget** 的上限,但并不取消 **Relevance over Completeness**。

> **预算问题:** “我是把这个窗口的 token 花在真正改善答案的东西上——还是因为有空间就把它填满,用延迟、成本和被稀释的注意力来买单?”

> 窗口是有限的,每个 token 都要花延迟和金钱。把它当预算来花——裁剪、总结、只检索需要的——别让更大的窗口终结这门自律。

## 6. Context rot 与漂移

在长的、多步骤的交互中,context 不会静止不动——它会累积,也会衰变。管理这种衰变,是大规模 context engineering 中最难也最重要的部分。

### Context Rot——长 context 会累积过时且自相矛盾的状态

> 一长排人玩传话游戏——到最后,消息已悄悄变了样,而每个人都自信地重复着一个略有错误的版本。

在一段长对话或多步骤的 agent 任务中,窗口会被历史填满:更早的轮次、工具输出、做到一半的推理。久而久之,这堆东西变得杂乱——过时的事实挨着新鲜的事实,矛盾不断累积,最初的目标渐渐失焦。

业界把由此造成的质量衰退称为 **context rot**:随着模型自己积累的 context 越来越嘈杂,同一个模型会变得越来越不可靠。

_Diagram: 每一步窗口都在变大:工具输出、过时的事实、矛盾。目标沉到底部,可靠性下降。_

#### Context Rot (context 衰退,漂移)

- **是什么:** 随着累积的 context 越来越嘈杂,质量随之衰退。
- **表现:** 过时的事实挨着新鲜的事实,出现矛盾,最初的目标渐渐失焦。
- **例子:** 第 30 步时,agent 依赖的是某个文件的一个版本,而那是它自己在第 10 步改写掉的。
- **陷阱:** 更大的窗口会让它更糟:它给腐烂提供了更多堆积的空间。
- **关联:** 用 **Compaction** 和 **Goal Re-anchoring** 修复。

### Compaction——边走边压缩

> 好的记录员不会保留一场长会议的每一个字——他把它提炼成决定和未决问题,带走结论,而不是逐字稿。

解决办法是随着 context 增长而主动**压缩**它。这就是 **compaction**:把已完成的步骤总结成一份简短的滚动状态,而不是拖着完整的记录往前走;一旦提取出重要的内容,就丢掉工具输出;保留一份紧凑的工作总结,而不是原始历史。

模型带走的是结论,而不是产生结论的每一个字。长时间运行的 agent 就是这样保持连贯的——它们管理自己的 context,而不是任由它堆积。

_Diagram: 原始记录(推理 + 工具输出)被压缩成一份滚动总结:目标、已做的决定、未决的问题、当前的步骤。_

#### Compaction (边走边压缩 context)

- **问题:** 长时间运行的 agent 拖着整份记录往前走,开始变得糊涂。
- **思路:** 已完成的步骤变成简短的当前状态;已消化的工具输出被丢掉。
- **例子:** 不放 200 行测试日志——而是“测试在 `auth.ts` 中失败,原因:token 过期”。
- **代价:** 压缩可能丢掉重要的东西——写总结时要小心。
- **关联:** 面向 agent 的 **Trim & Summarize**;与 **Goal Re-anchoring** 搭配,对抗 **Context Rot**。

### Goal Re-anchoring——重新锚定目标

> 在漫长曲折的徒步中,你会定期核对地图和目的地——否则,你会一个看似合理的转弯接着一个,慢慢偏离本来要去的地方。

经过许多步骤,最初的目标会在此后发生的一切重压下被侵蚀。所以你要**重新锚定**它(**re-anchoring**):在每一步都把目标和关键约束重新写进窗口,让模型始终对准真正的目标,而不是随着对话漂移。

更大的窗口会让这更糟,而不是更好——它给漂移提供了更多累积的空间。让长任务保持在正轨上的,是主动管理,而不是原始容量。

_Diagram: 没有锚点,每一步看起来都合理,但累加起来就走偏了。有了锚点,目标在每一步都回到窗口里。_

#### Goal Re-anchoring (每一步重申目标)

- **问题:** 步骤一多,目标就被侵蚀,模型随对话一起漂移。
- **思路:** 每一步都把目标和关键约束放回窗口。
- **例子:** agent 的每一步都以一个区块开头:“目标:把 API 迁移到 v2,不改变公共方法。”
- **代价:** 每步多几行 token——与漂移的代价相比很便宜。
- **关联:** 与 **Compaction** 配合使用;滚动总结的第一行就是目标。

> **漂移问题:** “在这次长交互中,窗口还是目标的一幅锋利、当下的图景吗——还是已经腐烂成了过时、矛盾的状态,而模型正在基于它推理?”

> 长 context 会腐烂——过时、矛盾的状态不断累积,质量随之衰退。把已完成的步骤压缩成滚动总结,并重新锚定目标,因为更大的窗口只会给漂移更多空间。

## 7. 用好它

做得好的 context engineering 是有意识的组装,并且像其他一切一样被衡量。整个实践归结为:有意识地构建窗口,并检查它是否真的有帮助。

### Deliberate Assembly——有意识地构建窗口,而不是出于偶然

> 厨师是有意识地摆盘的——每个元素都有放在那里的理由——而不是把台面上有的东西一股脑刮到盘子里。

核心习惯是 **deliberate assembly**:把窗口当作你有意*构建*的东西。决定 system prompt 里放什么、历史保留或总结哪些、检索什么、展示哪些示例、暴露哪些工具。

许多 LLM 应用组装 context 是出于偶然——碰巧手边有什么就发什么。有意识地构建,并为每个部件说明理由,在很大程度上就是可靠功能与不稳定功能的分野。

_Diagram: 出于偶然——手边有什么就用什么(完整历史、所有工具、旧日志)。有意识地——每个部件都有决定和理由。_

#### Deliberate Assembly (有意识地构建窗口)

- **问题:** context 是出于偶然组装的——功能只是有时能用。
- **思路:** 为每个部件做决定:system prompt、历史、检索、示例、工具。
- **例子:** agent 拿到的是它需要的 5 个工具而不是全部 40 个——还有一份简短总结而不是整个历史。
- **代价:** 花在设计窗口上的时间——会以可靠性的形式回报。
- **关联:** 建立在 **Context Assembly** 之上的习惯;用 **Context Evals** 验证。

### Context Evals——像衡量代码那样衡量 context

> 你不会猜一个改动有没有帮助——你会去测试它。放进窗口的东西也是如此:一个答案变好了还是变差了,你应该知道是哪一种。

Context 的改动是真实的改动,所以要验证它们:当你调整放进窗口的东西——更多示例、不同的检索、裁剪过的历史——要用 **evals** 来检验效果,而不是只凭肉眼看一个输出。

没有度量的 context engineering 是凭感觉调优,一个“无害”的新增就是这样悄悄拉低质量的。把窗口的内容当作要测试的东西,用与 evals 课程相同的自律。

_Diagram: 这个循环:改动 context → 运行 evals → 比较分数 → 保留或回退。而不是“瞄一眼某个答案然后祈祷”。_

#### Context Evals (针对 context 改动的 evals)

- **问题:** 窗口的某个改动“看上去”更好——实际上悄悄让质量变差了。
- **思路:** 每次 context 改动都在固定的测试集上跑一遍,并比较分数。
- **例子:** 历史裁剪到 5 条消息——跑 100 段测试对话,看是变好了还是变差了。
- **代价:** 你得建一个测试集并持续运行它——这是工作。
- **关联:** 检验 **Curation**、**Trim & Summarize**、**Compaction**;深入内容见 evals 课程。

#### 发布 LLM 功能之前

- **模型需要的一切都在窗口里吗**——还是你在指望它知道你从未给过它的东西?
- **System 与 user**——长期规则放在 system prompt,请求放在用户消息里?
- **示例会有帮助吗**——这是不是 few-shot 胜过更多指令的情形?
- **每一块都相关吗**——还是灌水在稀释注意力、增加错误?
- **你在预算之内吗**——是在裁剪和总结,而不是什么都倒进去?
- **对于长任务,你有没有压缩并重新锚定**,来对抗 context rot?

#### 你把 context 做得好的迹象

- 你修复糟糕的答案时,会先**检查窗口里有什么**,再去改写 prompt。
- 长期规则放在 **system prompt** 里;形态重要时你会用 **few-shot 示例**。
- 你**毫不留情地筛选**——相关性胜过完整性——而不是给窗口灌水。
- 你把窗口当作**预算**,裁剪和总结,而不是倾倒。
- 对于长任务你会**压缩并重新锚定**,并且**衡量** context 的改动,而不是靠猜。

### 这一切如何连在一起

> 完整的地铁线路图:现在你能看到各条线在哪里交汇。

模型是无状态的 → 所以窗口决定一切 → 所以窗口就是你要设计的东西。窗口由部件(system prompt、示例、事实)组装而成。三种力量让它变差:**无关内容**、**预算**和**随时间腐烂**。每一种都有对应的实践:**curation**、**trim and summarize**、**compaction 加 re-anchoring**。而 **evals** 检验每一次改动是否真的有帮助。

_Diagram: 这门课概念的链条:从无状态的模型,到设计窗口,到让它变差的三种力量,到对付它们的实践,再到作为检验的 evals。_

## 速查表:全部 18 个概念

### 窗口

- **Stateless Model** (两次调用之间没有记忆): 两次调用之间什么都不记得;聊天的“记忆”是重新发送的历史。
- **Context Window** (工作记忆): 一次调用的全部文本——模型唯一的工作记忆。不在窗口里——就根本不存在。

### 转变

- **Context Engineering** (相对于 prompt engineering): 不是措辞请求,而是把所需的全部信息组装进窗口。
- **Missing Context** (缺失或错误的 context): 大多数糟糕的答案并非措辞不好——而是窗口里缺了东西。

### 组装窗口

- **System Prompt** (相对于用户消息): 长期的角色、规则、语气、格式——对比一次性的请求。
- **Few-shot Prompting** (context 里的示例): 展示 2–3 对“输入 → 输出”——模型会重复这个形态。
- **Context Assembly** (由部件构成): 窗口每次调用都在代码里组装:规则、历史、事实、示例、工具、请求。

### 相关性

- **Relevance over Completeness** (刚好够用): 给模型的不是全部,而是刚好够用的。
- **Context Dilution** (淹没在噪声里): 无关的 token 把注意力摊薄,并提高幻觉。
- **Curation** (毫不留情的筛选): 只留最好的片段、裁剪过的历史,不放任何已完成使命的东西。

### 预算

- **Context Budget** (稀缺资源): 窗口是有限的;每个 token 在每次调用中都花费延迟和金钱。
- **Trim & Summarize** (裁剪与总结历史): 旧的轮次变成总结,近期的保持原样;每个 token 都要配得上它的位置。
- **Long Context Windows** (百万 token 以上): 更大的空间不是倾倒的许可;噪声和价格依然存在。

### 腐烂与漂移

- **Context Rot** (context 衰退): 长 context 会堆积过时且自相矛盾的状态——质量下降。
- **Compaction** (边走边压缩): 已完成的步骤进入简短的滚动总结,而不是留着完整记录。
- **Goal Re-anchoring** (重申目标): 每一步都把目标和约束放回窗口。

### 实践

- **Deliberate Assembly** (有意识地): 窗口的每个部件都有决定和理由——而不是“手边有什么就是什么”。
- **Context Evals** (衡量改动): 窗口的每次改动都用测试检验,而不是凭肉眼。

> Context engineering 就是有意识地组装窗口:正确的规则、正确的事实、正确的示例,按相关性筛选,控制在预算之内,并对抗腐烂——有意构建并加以衡量,而不是敲出来再祈祷。

速成课结束 · 7 章 · 18 个概念

接下来是实践:拿一个有时会给出糟糕答案的 LLM 功能,在动 prompt 措辞之前,先记录下一次出错调用里窗口中到底有什么——你通常会发现是 context 缺失、过时或无关,而不是措辞不好。然后修好组装:补上缺失的事实,砍掉噪声,总结历史。当一个构建得更好的窗口胜过一个更巧妙的 prompt 时,这门功夫就通了。但请把一个想法放在所有想法之上:模型只知道窗口里有什么。别再试图从它那里哄出智能,开始设计它能看到什么——质量一直就在那里。
