fedorthinks

速成课 · No. 26

LLM 既聪明又空白:两次调用之间它什么都不记得,而每次调用它只知道你摆到它面前的文本。Context engineering 就是把恰到好处的文本组装进那个窗口的功夫——指令、事实、历史、工具,不多也不少。LLM 的质量真正活在这里,而它大多无关乎巧妙的措辞。

18 个概念 · 每个都配一张图 · 结尾有速查表

§ 01

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

地图:七组共 18 个概念

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

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

1 · The windowStateless modelContext window2 · The shiftPrompt vs context engineeringMissing context3 · AssemblySystem promptFew-shotContext assembly4 · RelevanceRelevance > completenessContext dilutionCuration5 · BudgetContext budgetTrim & summarizeLong context windows6 · Rot & driftContext rotCompactionRe-anchoring7 · PracticeDeliberate assemblyContext evals
七组概念——第 1–7 章依次对应它们。

如何阅读每个概念

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

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

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

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

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

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

call 1msg 1call 2msg 1reply 1msg 2call 3msg 1reply 1msg 2reply 2msg 3LLM — statelessstarts from a blank page on every callthe app re-sends the whole history every time — that is the "memory"
Stateless:每次调用,应用都会重新发送整个历史。聊天机器人的“记忆”活在你的代码里,不在模型里。
ConceptStateless Model· 两次调用之间没有记忆
是什么
模型在两次请求之间什么都不保留:每次调用都从空白开始。
如何运作
聊天之所以“记得”对话,只是因为应用在每次调用时都重新发送了整个历史。
例子
聊天里的第三个问题,会连同前两个问题和两条回复一起发给模型。
陷阱
指望模型“记得”过去某次会话里的规则——如果它不在这次调用里,它就不存在。
关联

这就是为什么 Context Window 决定一切;不断增长的历史会引出 Context Budget 和 Context Rot。

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

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

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

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

CONTEXT WINDOW · finite sizeSystem promptConversation historyData / retrieved factsToolsUser messageModelreasons only from thisold chatcompany wikiforgotten rule✗ not in the window → the model simply doesn't know it
窗口就是模型看到的一切。窗口之外的东西(一段旧聊天、公司 wiki、被遗忘的规则)对它来说并不存在。
TermContext Window· 模型的工作记忆
是什么
模型在一次调用中看到的全部文本:指令、历史、数据、工具。
如何运作
模型只依据窗口推理。窗口有以 token 计的最大长度。
例子
客服机器人不知道退款政策,除非这份文本被放进了本次调用的窗口。
陷阱
“模型应该知道这个”——不:如果它不在窗口里,它对模型就不存在。
关联
窗口通过 Context Assembly 构建;它的大小就是 Context Budget。

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

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

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

quality is decided before the model runsRight contextthe right folderSame modelGreat answerMissing contextthe wrong folderSame modelUseless answerbut confidentyou engineer the input, not the model
同一个模型:有正确的 context——答案精彩;没有——自信地一无是处。杠杆是输入,不是模型。

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

§ 02

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

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

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

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

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

Prompt engineeringInstruction wordinghow you phrase itone part of the windowContext engineeringSystem promptRetrieved factsHistoryExamplesToolsInstructionall the inputs, assembled every call
Prompt engineering 只是窗口的一部分(措辞)。Context engineering 是每次调用时组装起来的全部输入。
ConceptContext Engineering· 相对于 prompt engineering
问题
质量靠调 prompt 措辞来“调优”,而模型缺少的是真正的事实。
思路
设计整个窗口:系统规则、事实、历史、示例、工具——每次调用都是如此。
例子
与其写“请详细而准确地回答!”——不如把正确的文档和关键规则放进窗口。
代价
你需要组装窗口的代码,以及对放什么进去的自律。
何时使用
一旦某个 LLM 功能超出了单个演示用 prompt 的范围。
关联

Prompt engineering 是其中一部分;实践中就是 Context Assembly 和 Deliberate Assembly。

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

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

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

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

Bad answerfrom the LLMReword the promptrarely the real causeinstinctCheck the windowwhat did it actually see?doc not retrievedkey rule not includedstale historyfix the context → fixes the bug
答案不好?本能是重写 prompt。正确的第一步是看窗口里有什么:没检索到的文档、没包含的规则、过时的历史。
ConceptMissing Context· 缺失或错误的 context
问题
模型回答得很差,团队一遍又一遍地重写 prompt——毫无效果。
思路
先看出错那次调用里窗口中有什么;之后才去动措辞。
例子
机器人引用了旧的价格方案:窗口里是过时的历史,没有新的价目表。
典型原因
文档没被检索到,规则没被包含,过时的历史把它搞糊涂了。
关联
用 Context Assembly 和 Curation 修复;用 Context Evals 验证。

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

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

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

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

§ 03

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

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

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

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

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

System promptrole · rules · tone · output formatthe same on every callUser: where's my order?User: can I get a refund?User: open on Sunday?changes every callwho the model IS vs what it is asked THIS time
System prompt 每次调用都一样(角色、规则、语气、格式)。用户消息每次都不同。
TermSystem Prompt· 相对于用户消息
是什么
适用于整个交互的长期指令:角色、规则、语气、输出格式。
对比
用户消息——这一次的具体请求。
例子

System:“你是一家商店的客服机器人,回答要简短,绝不承诺折扣。”用户:“我的订单到哪了?”

陷阱
把长期规则混进请求里,它们就会在不同问题之间“飘来飘去”。
关联
Context Assembly 的第一块;输出格式往往用 Few-shot 展示更好。

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

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

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

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

Tell: instructions onlyDescribe the formata paragraph of rulesAlmost rightshape driftsShow: few-shot examplesinput 1ideal output 1input 2ideal output 2input 3ideal output 3new inputsame shape ✓
左——用语言描述格式,得到“差不多对”。右——展示“输入 → 理想输出”的配对,新的输入就会得到同样的形态。
PatternFew-shot Prompting· context 里的示例
问题
模型差不多能做到,但输出的形态会跑偏。
思路
在窗口里放 2–3 对“输入 → 理想输出”——模型会重复这个模式。
例子

三个“评论 → 带情感和主题的 JSON”的示例,然后给一条新评论——答案就以同样的 JSON 返回。

代价
示例每次调用都占 token——它们是 Context Budget 的一部分。
何时使用
形态很重要,而一段话的指令没有帮助时。
关联
Context Assembly 的组成部分之一;与 System Prompt 互补。

Context Assembly——用零件构建窗口

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

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

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

System promptHistoryRetrieved factsExamplesToolsUser requestyour codepicks per callthis call's windowSystem promptHistoryRetrieved factsExamplesToolsUser request
每次调用,你的代码挑选各个部件——system prompt、历史、事实、示例、工具、请求——并用它们组装出窗口。
PracticeContext Assembly· 用部件构建窗口
问题
窗口“只是一段 prompt”,手边碰巧有什么就往里放什么。
思路
在代码里用部件组装窗口:system prompt、历史、RAG 事实、示例、工具、请求。
例子

一个订单问题:机器人的规则 + 最近 3 条消息 + 这个订单的数据 + 问题本身。而不是整个商品目录。

代价
每个部件都要挑选并说明理由——这是工作,不是魔法。
关联

部件——System Prompt、Few-shot;过滤——Curation;习惯——Deliberate Assembly。

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

§ 04

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

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

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

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

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

Everything, just in casethe signalsignal diluted · slower · pricierOnly what this call needskey factthe one rulethe requestsharp answer
左——什么都“以防万一”:信号淹没在噪声里。右——只放这次调用需要的:答案锋利。
PrincipleRelevance over Completeness· 刚好够用,而不是全部
问题
什么都“以防万一”地放进窗口。
思路
目标不是把一切都给模型——而是给它刚好够用的。
例子
不放整个知识库——只放真正回答这个问题的那三段。
代价
你得会挑选:好的检索、裁剪、对舍弃什么做出决定。
关联

为什么——Context Dilution;怎么做——Curation;它还能节省 Context Budget。

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

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

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

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

Modelattention spread thinnoisenoiseright factnoisenearby, wrongnoisemore noise → more chance it latches onto the wrong thing
模型的注意力被摊在噪声上——它抓住了旁边某个看似相近却不对的东西,而不是正确的事实。
ConceptContext Dilution· 信号淹没在噪声里
是什么
无关的 token 稀释了模型对关键信号的注意力。
风险
在长 context 中,幻觉和出错的比率会上升:模型抓错了那一段。
例子
窗口里有二十份相似的文档——模型引用了隔壁那份合同,而不是对的那份。
陷阱
“以防万一”的 context 感觉无害——却可能正是失败的原因。
关联
用 Curation 修复;更大的窗口(Long Context Windows)并不能抵消它。

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

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

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

everything that might be relevantretrieve only top chunkstrim history to what mattersdrop finished contextExactly enough
筛选漏斗:在所有可能有用的东西中——只留最好的片段、历史中重要的部分,以及没有任何已完成使命的内容。
PracticeCuration· 毫不留情地筛选 context
问题
窗口自己越长越大:手边有什么就发给模型什么。
思路
每次调用:只放最相关的片段、裁剪过的历史,不放任何已完成使命的东西。
例子
搜索找到 50 个片段,最好的 3 个进窗口;已经消化过的工具输出被丢掉。
代价
你可能砍掉了需要的东西——所以修改要用 Context Evals 来检验。
关联

体现了 Relevance over Completeness;是 Trim & Summarize 和 Compaction 的近亲。

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

§ 05

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

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

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

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

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

context windowhard capsystemhistoryretrievedrequestfreeLatencyevery call slowerMoneyevery call priciereach token you add is paid for on every single call
窗口有硬上限,其中每个 token 都要用延迟和金钱来买单——每一次调用都是如此。
ConceptContext Budget· 作为稀缺资源的窗口
是什么
窗口是有限且要付费的资源:有大小上限,每个 token 都有价格。
你付出什么
延迟和金钱——每次调用都付,再乘以流量。
例子

某个功能每次请求都发送完整历史和整本参考手册——还没轮到质量受损,就已经又慢又贵。

何时考虑
从第一天起,一旦这个功能面对真实用户。
关联

通过 Trim & Summarize 精打细算;Long Context Windows 并不能取消它。

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

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

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

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

verbatim historyturn 1turn 2turn 3turn 4turn 5turn 6turn 7turn 8summarizewhat you sendSummaryturns 1–6 in a few linesturn 7turn 8fewer tokens, same meaning
八轮原文 → 前六轮的简短总结,加上最后两轮原样保留。token 更少,意思不变。
PracticeTrim & Summarize· 裁剪与总结历史
问题
对话历史不断增长,每一轮都原样跟在窗口里。
思路
旧的轮次变成简短总结,近期的保持原样;只检索现在需要的。
例子

不放 40 条聊天消息——而是一句总结“客户想退订单 #…,已经发过照片”+ 最后 2 条消息。

代价
总结可能丢掉某个细节——用 evals 来检查。
关联
精打细算地花 Context Budget;在长任务中会演变成 Compaction。

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

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

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

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

usefulusefulusefulsmall windowusefulusefuluseful1M tokens: more room, still costs, still dilutes
两个窗口装着同样一小撮有用的材料。大的那个只是给噪声留了更多空间——而你依然按 token 付费。
TermLong Context Windows· 百万 token 以上的窗口
是什么
窗口达到一百万 token 乃至更多的模型。
诱惑
以为既然什么都装得下,就不再需要筛选了。
例子
“因为装得下”就把整个代码仓库倒进窗口——又贵又慢,模型还会被搞糊涂。
陷阱
窗口越满,Context Dilution 越强,Context Rot 的空间也越大。
关联

提高了 Context Budget 的上限,但并不取消 Relevance over Completeness。

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

§ 06

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

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

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

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

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

goalstep 1goaltool outputfactstep 5goaltool outputfactstale facttool outputstep 10goaltool outputstale factfacttool outputcontradictiontool outputstale factstep 20sharpnoisy — reliability decays
每一步窗口都在变大:工具输出、过时的事实、矛盾。目标沉到底部,可靠性下降。
ConceptContext Rot· context 衰退,漂移
是什么
随着累积的 context 越来越嘈杂,质量随之衰退。
表现
过时的事实挨着新鲜的事实,出现矛盾,最初的目标渐渐失焦。
例子

第 30 步时,agent 依赖的是某个文件的一个版本,而那是它自己在第 10 步改写掉的。

陷阱
更大的窗口会让它更糟:它给腐烂提供了更多堆积的空间。
关联
用 Compaction 和 Goal Re-anchoring 修复。

Compaction——边走边压缩

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

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

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

raw transcriptstep 1: reasoningtool outputstep 2: reasoningtool outputstep 3: reasoningtool outputstep 4: reasoningtool outputcompressRunning summarygoal + constraintsdecisions madeopen questionscurrent step
原始记录(推理 + 工具输出)被压缩成一份滚动总结:目标、已做的决定、未决的问题、当前的步骤。
PracticeCompaction· 边走边压缩 context
问题
长时间运行的 agent 拖着整份记录往前走,开始变得糊涂。
思路
已完成的步骤变成简短的当前状态;已消化的工具输出被丢掉。
例子
不放 200 行测试日志——而是“测试在 auth.ts 中失败,原因:token 过期”。
代价
压缩可能丢掉重要的东西——写总结时要小心。
关联

面向 agent 的 Trim & Summarize;与 Goal Re-anchoring 搭配,对抗 Context Rot。

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

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

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

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

Taskgoal + limitsTargetwhat you meantrestate goalrestate goalrestate goalDriftedeach turn looks reasonable — the sum driftsre-anchoring: put the goal back in the window at every step
没有锚点,每一步看起来都合理,但累加起来就走偏了。有了锚点,目标在每一步都回到窗口里。
PracticeGoal Re-anchoring· 每一步重申目标
问题
步骤一多,目标就被侵蚀,模型随对话一起漂移。
思路
每一步都把目标和关键约束放回窗口。
例子
agent 的每一步都以一个区块开头:“目标:把 API 迁移到 v2,不改变公共方法。”
代价
每步多几行 token——与漂移的代价相比很便宜。
关联
与 Compaction 配合使用;滚动总结的第一行就是目标。

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

§ 07

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

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

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

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

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

By accidentfull historyrandom docall 40 toolsold logslast errorOn purpose✓ system prompt: what it holds✓ history: keep or summarize✓ retrieval: what to fetch✓ examples: which to show✓ tools: which to exposeflakyreliable
出于偶然——手边有什么就用什么(完整历史、所有工具、旧日志)。有意识地——每个部件都有决定和理由。
PrincipleDeliberate Assembly· 有意识地构建窗口
问题
context 是出于偶然组装的——功能只是有时能用。
思路
为每个部件做决定:system prompt、历史、检索、示例、工具。
例子

agent 拿到的是它需要的 5 个工具而不是全部 40 个——还有一份简短总结而不是整个历史。

代价
花在设计窗口上的时间——会以可靠性的形式回报。
关联
建立在 Context Assembly 之上的习惯;用 Context Evals 验证。

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

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

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

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

Change the contextwhat goes in the windowRun the evalsa fixed test setCompare the scorebetter or worse?Keep or revert✗ not: eyeball one output and hope
这个循环:改动 context → 运行 evals → 比较分数 → 保留或回退。而不是“瞄一眼某个答案然后祈祷”。
PracticeContext 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 检验每一次改动是否真的有帮助。

Stateless modelContext windowContext engineeringwhat goes into the windowSystem promptFew-shotContext assemblymade ofthree forces that degrade itIrrelevancedilutionBudgetlatency · moneyContext rotdrift over timefixed byfixed byfixed byCurationrelevance firstTrim & summarizespend tokens wiselyCompaction+ re-anchoringContext evalsmeasure every change
这门课概念的链条:从无状态的模型,到设计窗口,到让它变差的三种力量,到对付它们的实践,再到作为检验的 evals。

速查表:全部 18 个概念

窗口

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

两次调用之间什么都不记得;聊天的“记忆”是重新发送的历史。

Context Window工作记忆

一次调用的全部文本——模型唯一的工作记忆。不在窗口里——就根本不存在。

转变

Context Engineering相对于 prompt engineering

不是措辞请求,而是把所需的全部信息组装进窗口。

Missing Context缺失或错误的 context

大多数糟糕的答案并非措辞不好——而是窗口里缺了东西。

组装窗口

System Prompt相对于用户消息

长期的角色、规则、语气、格式——对比一次性的请求。

Few-shot Promptingcontext 里的示例

展示 2–3 对“输入 → 输出”——模型会重复这个形态。

Context Assembly由部件构成

窗口每次调用都在代码里组装:规则、历史、事实、示例、工具、请求。

相关性

Relevance over Completeness刚好够用

给模型的不是全部,而是刚好够用的。

Context Dilution淹没在噪声里

无关的 token 把注意力摊薄,并提高幻觉。

Curation毫不留情的筛选

只留最好的片段、裁剪过的历史,不放任何已完成使命的东西。

预算

Context Budget稀缺资源

窗口是有限的;每个 token 在每次调用中都花费延迟和金钱。

Trim & Summarize裁剪与总结历史

旧的轮次变成总结,近期的保持原样;每个 token 都要配得上它的位置。

Long Context Windows百万 token 以上

更大的空间不是倾倒的许可;噪声和价格依然存在。

腐烂与漂移

Context Rotcontext 衰退

长 context 会堆积过时且自相矛盾的状态——质量下降。

Compaction边走边压缩

已完成的步骤进入简短的滚动总结,而不是留着完整记录。

Goal Re-anchoring重申目标

每一步都把目标和约束放回窗口。

实践

Deliberate Assembly有意识地

窗口的每个部件都有决定和理由——而不是“手边有什么就是什么”。

Context Evals衡量改动

窗口的每次改动都用测试检验,而不是凭肉眼。

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

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

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