上下文窗口预算管理
系列入口:如何使用 Agent。前置阅读:什么是上下文工程。
一、一个反复出现的现象:它「聊到后面就变笨」
很多人都遇到过:一个长任务刚开始时 Agent 思路清楚、改动精准,可随着对话拉长、读过的文件越来越多,它开始记不清前面的决定、重复犯同样的错、甚至开始说废话。这通常不是模型「累了」,而是上下文窗口被塞满了。
上下文窗口(Context Window)是 Agent 一次能同时处理的 token(模型处理文本的最小计费/计量单位)总量。它像一个固定大小的工作台:台上信息放得井井有条时,它什么都看得清;堆得太满,要么旧东西被挤掉,要么它在一片杂乱里抓不住重点。管理这块台面,就是预算管理。
二、预算被什么吃掉
- 固定开销:系统指令和规则文件每次都占一部分,通常不大。
- 对话历史:随着来回增多持续增长,是长会话的主要开销。
- 读入的代码:你让它读的文件越多、越大,占用越高。
- 工具输出:跑一条命令刷出几千行日志、读进一个超大文件,常常瞬间把窗口撑爆,是最容易被忽视的「预算小偷」。
- 还要给回答留地方:窗口塞满输入,它能用来思考和输出的空间就被挤压。
你不需要精确计算每个 token,但建立一个粗略的量级直觉很有用:中文一个字大约占 1~2 个 token,英文一个单词约 1 个或略多。据此可以心算——一个一千行的代码文件往往就是上万 token,一次刷出几千行的构建日志可能占掉几万。对照常见窗口(如 128k、200k),你会意识到「读几个大文件 + 几条长日志」其实能吃掉窗口的相当一部分,远没有想象中宽裕。
基于此,给你一个可参考的预算分配思路(不是硬性比例,而是帮你养成「留余量」的习惯):把系统指令和规则当作固定底座,一般只占小头;给本次任务真正需要的代码和对话留出主体空间;刻意保留两到三成作为缓冲,用于工具输出、中间思考和最终回答,而不是一开始就把窗口填到八九成。留出缓冲的好处是,当它执行中需要读新文件、处理意外输出时,不必立刻触发截断或仓促压缩。很多「聊着聊着突然失忆」,本质都是窗口平时就被填得太满、没有预留腾挪空间。
三、超限时会发生什么
不同工具处理方式不同,但结果都不是你想要的:静默截断(最早的对话或信息被丢掉,于是它「忘了」开头的关键决定)、自动摘要(把历史压缩成概述,细节可能丢失)、以及整体降质(信息太多时它抓不住重点,注意力被稀释)。理解这点,你就不会奇怪它为什么突然不记得半小时前自己说过的话。
超限很少是瞬间发生的,它通常沿一条可察觉的曲线下滑,提前认出这些症状,你就能在彻底塞满前主动处理:
- 开始重复自己:它在后面几轮里重新解释、重新确认前面已经讲定的事,说明早期信号正在变弱。
- 回答变啰嗦、套话增多:有效信息密度下降,用大量铺垫替代直接结论。
- 忽略中间交代过的细节:不是开头、也不是结尾,而是中段的某个约束被漏掉——这往往是注意力被稀释的典型表现。
- 前后不一致:它当下的做法和前几轮的决定相矛盾,且自己没意识到。
这四个症状是给你的「仪表盘报警灯」。看到任意一个,就别再继续往里堆信息,而应主动进入压缩或清理——这个时机由你掌握,比等系统粗暴截断要可控得多,因为你知道哪些信息此刻不能丢。
四、实战的预算管理手段
手段虽多,其实可以按「从源头到补救」排一个优先顺序,照这个顺序做最省力:最高优先是控制信息进入(精准读、过滤日志),让窗口一开始就不被塞爆;其次是及时小结,用短摘要替代长过程;再往后是用子代理把大量中间信息隔离在主窗口之外;最后才是被动地截断或仓促重开。 这个顺序的逻辑是——越靠源头的控制成本越低、效果越好,越靠后的越是补救。新手容易颠倒,平时不控制,等满了才手忙脚乱地删,此时既被动又容易误删关键信息。把力气放在前面,是这一节所有具体动作背后的统一思路。
1. 别让它无脑读大文件。 需要某个文件时,尽量指向具体位置或让它读相关片段,而不是整个灌进去。让它搜代码也用精准的模式,少返回无关结果。
2. 警惕超长工具输出。 会刷大量日志的命令,先让它过滤或只取关键部分(比如只看报错的前后几十行),别把完整日志倒进上下文。
3. 及时摘要。 一个阶段做完,可以让它用几句话小结当前决定和进度,再继续——用短摘要替代冗长的原始过程。
4. 用子代理隔离子任务。 把「去翻几十个文件、找出所有调用点」这种会产生大量中间信息的活,交给子代理,它只把最终结论带回主对话,主台面保持干净。
5. 任务边界清晰时,果断开新会话。 一个独立的新任务,没必要背着上一个任务的全部历史。把需要的背景用几句话带上即可。
这些手段配上具体说法更容易照做,给你几个能直接复制的指令模式:
- 控读取:「不要读整个文件,只看
parseConfig这个函数及其直接调用的部分,读完先告诉我你看到了什么。」 - 控日志:「这个命令输出很长,你先过滤出
error和warn,只把关键的前后 20 行给我,并给一句结论。」 - 做摘要:「先暂停。用五条要点小结我们已经确定的方案、已改的文件和待办,后面以这份小结为准。」
- 用子代理:「派一个子代理去全库找调用点,你这里只要它返回的清单,不用带回原始文件内容。」
这里特别说一下「开新会话」的判断,新手往往舍不得,觉得旧对话里有上下文。其实当一个任务已经干净收尾、下一个任务又相对独立时,背着整段历史反而是负担——其中绝大部分与新任务无关,却持续占预算、稀释注意力。正确做法是在新会话里用几句话带上真正需要的结论(比如「上个任务已把接口改成异步,契约是这样的……」),既轻又准。判断标准是:旧信息里有多大比例还会被新任务用到,比例很低就果断新开。
| 信号 | 可能的预算问题 | 对应动作 |
|---|---|---|
| 它忘了前面的决定 | 历史被截断 | 摘要 / 提醒 / 开新会话 |
| 读完大文件后变差 | 代码占满窗口 | 只读相关片段 |
| 跑完命令后啰嗦 | 日志灌入 | 过滤输出 |
五、截断、摘要、重开:三种腾空间策略怎么选
当窗口确实紧张,你主要有三种腾空间的办法,它们各有适用场景,选错了会丢该留的东西,这里把取舍讲清楚。
策略一:截断(丢弃无关部分)。 适用于被丢的信息确实不再需要——比如某个只在调试阶段有用、现在已经确认无关的命令输出。截断最干脆,但风险是误删,所以应针对「明确无用」的部分,而不是让系统按位置(比如总是最旧的)无差别丢弃。最旧的信息有时恰恰是最初定的目标和约束,丢掉它最危险。
策略二:摘要(压缩保留要点)。 适用于过程细节不再重要、但结论还要用——比如前面十几轮的探索可以收敛成「最终选定方案 B、原因、已改文件、待办」几条。摘要保住了决策脉络,但会丢实现细节,因此要由你指定哪些必须保留,并在摘要后快速核对,确认关键约束没被压没。
策略三:重开(新会话轻装上阵)。 适用于阶段边界清晰、下一任务相对独立。它最彻底地清掉了历史包袱,代价是要你手动带上新任务需要的结论。当旧信息利用率很低时,这往往比在旧会话里反复压缩更清爽。
怎么选,可以用一条简单判断:信息「还要不要用、用到的是细节还是结论」——完全不用就截断,只用结论就摘要,整个任务都翻篇就重开。还有一个常被忽略的点:无论用哪种,都最好在动作前让当前关键状态「落地」——把目标、已确认的约定、进度写成几条明确的文字(甚至落到规则或文档里),这样腾完空间后它仍有一个可靠的依据,而不是靠被压缩得模模糊糊的记忆继续。
六、一个连贯的长任务节奏示范
把前面的手段串成一次完整实践,帮你形成整体节奏。设想一个要持续一两个小时、涉及多文件的改动:
- 开工:先让它读最核心的文件,规则已注入,窗口只放真正相关的内容,留出缓冲。
- 第一阶段:完成一小块、验证通过后,让它用几条要点小结,随后继续,避免原始过程无限堆积。
- 中途要全库盘点:派子代理去做,主对话只接收结论清单。
- 意外刷出长日志:先要求过滤出关键错误行,而不是整段进窗口。
- 发现报警症状(开始重复、前后不一):主动压缩,指定保留目标、契约和待办,核对后再走。
- 任务收尾、进入独立新任务:新开会话,用几句话带上新任务需要的结论。
你可以看到,预算管理不是某一个动作,而是一套贯穿任务始终、小步进行的节奏。它的总体目标只有一个:让窗口在任何时刻都保持「相关、清爽、有余量」。 当这套节奏变成习惯,你几乎不会再遭遇「聊到后面突然变笨」的状况,也因此敢把更复杂、更久的任务交给 Agent。
七、一个贯穿始终的心法:主动管,别被动撑
把预算管理浓缩成一句可执行的心法:不要等到系统提示窗口满了才处理,而要像定期收拾桌面一样,主动、小步地清理。 被动等满,你面对的是粗暴截断或仓促摘要,且可能在最忙时被迫分心;主动管理,则由你决定什么信息此刻保留、什么可以浓缩或丢给子代理。
你可以为自己设几个固定的「收拾时点」:每完成一个明确阶段就小结一次;看到工具要输出大量日志前先要求过滤;任务之间如果关联很弱就新开。这些动作单次成本很低,但合起来能让整个长任务始终保持在清爽、留有余量的状态。预算管理做得好,最直观的感受是——Agent 在一个持续很久的任务里,从头到尾都像开头那样清楚,而不是越用越钝。
八、常见问题
Q:窗口不是越来越大吗,还需要费心管理吗? 窗口确实在变大,但任务规模、文件和日志的体量也在一起涨,且注意力稀释、成本这些问题并不会因窗口变大而消失。更大的窗口只是给了你更多腾挪空间,主动安排信息仍然能显著提升稳定性,尤其是长任务。
Q:自动摘要不是挺方便,为什么还要自己小结? 自动摘你控制不了保留什么,可能丢掉你恰好需要的细节;而你在阶段完成时主动让它小结,能明确指定「这几条必须保留」。把自动摘要当兜底,把主动小结当首选,更可靠。
Q:我怎么知道现在窗口还剩多少? 很多工具会显示大致的占用比例,你也可以靠前面给的量级直觉估算。不必追求精确,关键是保持「不要填太满、留缓冲」的意识,看到报警症状就清理。
Q:开新会话会不会很麻烦,要重新交代背景? 要交代的只是与新任务真正相关的那一小部分结论,通常几句话就够,这比背着一大段无关历史持续付出的代价小得多。把它想成换个干净工位开工,而不是从零开始。
Q:预算管理这么多动作,我应该最先养成哪个习惯? 如果只挑一个,就从「控制信息进入」开始——让它读具体片段而不是整个大文件、长日志先过滤。这一条成本最低、收益最大,且能从源头避免后面大部分麻烦。等这个成了习惯,再逐步加入阶段小结和子代理隔离,节奏不要贪多。
Q:我担心压缩或截断会丢掉关键约束,有什么稳妥办法? 最稳妥的是在任何腾空间动作前,把关键约束「移出窗口」落到更持久的地方——写进规则文件、文档或任务清单,而不是只留在会被压缩的对话里。这样即使对话被大幅清理,它仍能从持久文件中重新读到这些约束,不必担心丢。把重要信息放进不会被压缩的载体,是最可靠的兜底。
总结
把上下文窗口当成一块容量固定的工作台:无关代码和超长日志是最常见的预算小偷,靠精准读取、过滤输出、及时摘要和子代理隔离保持台面整洁,它才不会「聊到后面就变笨」。