返回课程目录

第 8 课  上下文工程:管理上下文窗口

管理上下文窗口就是管理注意力。

预计 18 分钟  ·  系列:从 0 到 1 设计一个 Agent

本课要点

  • 理解模型上下文窗口与 Agent 自己上下文预算的区别
  • 看懂上下文如何组装,以及固定前缀、截断、压缩与检索的作用
  • 决定这一轮到底应该让模型看到什么,并识别哪些信息不能忘

当我们向 ChatGPT、Codex、豆包、WorkBuddy 这些 AI 应用发出一句请求时,模型真正收到的内容,通常远远不止我们刚刚输入的这一句话。

它看到的内容可能包括:系统提示词、当前可以使用的工具、历史对话、历史工具调用结果、当前任务的状态,以及用户最新发出的一句话。这些信息放在一起,就组成了当前的上下文(Context)。

系统提示词
可用工具
历史对话
工具结果
任务状态
最新请求
Agent判断 → 行动

Agent 会基于这些上下文,判断自己现在应该做什么、调用什么工具、下一步怎么行动。

你可以把上下文想象成 Agent 此刻摆在桌面上的所有资料。桌面上的资料越多,不一定越好。如果当前任务需要的是一份合同,但桌子上同时堆着几十份历史对话、工具说明、旧任务记录和无关材料,Agent 就需要从一大堆信息里找到真正重要的东西。

管理上下文,本质上就是管理 Agent 的注意力。

1. 上下文窗口大小

模型自己的上下文窗口

模型一次能够看到的信息是有限的。这个限制通常被称为上下文窗口(Context Window)。你可以把它理解成模型的「工作台大小」。工作台再大,也不可能无限大。

模型需要同时处理上下文中的所有 Token。上下文越长,需要计算和保存的信息也越多,会影响显存、计算量和推理速度。不同模型支持的 Token 上限也不同,有的支持几十万 Token,有的可以达到百万 Token。

输入 96K预留输出 32K
128K
输入 + 输出,共同占用窗口
128K 资料塞满后,就没有空间继续生成。

上下文窗口通常同时包含输入和输出。比如一个模型支持 128K Token,并不意味着你可以塞进去 128K Token 的资料,然后再让它继续输出大量内容。模型之前看到的内容,以及接下来准备生成的内容,都要占用这个窗口。

智能体自己的上下文窗口

用户的请求理论上可以不断延续,但模型的窗口有限。上下文越长,成本越高,响应可能越慢,输出质量也可能下降;当历史信息超出模型自身窗口后,还需要有办法保持对话的连续性。

所以很多 Agent 产品会设置自己的上下文窗口大小。设计 Agent 时,不光要知道模型窗口有多大,还需要考虑:这一轮到底应该让模型看到什么。

智能体上下文窗口上限
本轮占用容量
固定指令任务资料近期历史
输出与安全余量
智能体上下文窗口上限不直接等于模型上下文窗口上限。

2. 智能体的上下文由什么组成?

智能体需要设置一个自己的上下文窗口大小,因为用户的请求理论上是无限的,但是:

1、模型自己的上下文是有限的,上下文越长,成本越高,响应可能越慢,输出的质量也会下降,同时还可能让模型被大量无关信息干扰

2、当历史信息大小超出模型自身上下文大小之后,需要有办法保持对话的连续性

智能体的上下文窗口容量不直接等于模型的上下文窗口。

把信息组装成这一轮的上下文
固定不变的基础信息系统提示词工具名称与说明
对话与执行过程信息用户请求历史对话工具调用记录工具返回结果
当前任务相关信息当前任务计划已完成进度文件 / 知识库 / 网页资料
发送给模型
系统提示词工具名称与说明用户请求历史对话工具调用记录工具返回结果当前任务计划已完成进度文件 / 知识库 / 网页资料
固定前缀动态变化的内容任务相关的补充信息
Token

比如一个 Agent 连续调用了 20 次工具,如果每一次工具返回的完整结果都一直留在上下文里,窗口很快就会变得非常拥挤。

随着工具调用次数增加,上下文会越来越拥挤
第 1 次调用
工具结果占用少量 Token
第 10 次调用
工具结果占用较多 Token
第 20 次调用
工具结果也占窗口

尽量把固定不变的内容放在前面。

系统提示词、工具说明等内容,在很多轮请求里都不会发生变化。把固定内容放在前面,有助于利用提示词缓存(Prompt Caching),减少重复计算、降低成本并提升响应速度。

提示词缓存 Prompt Caching
第 1 轮系统提示词 + 工具说明本轮变化内容建立缓存
第 2 轮系统提示词 + 工具说明本轮变化内容复用前缀
第 3 轮系统提示词 + 工具说明本轮变化内容复用前缀
复用相同前缀
命中缓存还需满足模型与接口的缓存规则。

缓存是否命中,还需要满足具体模型与接口的缓存规则。

3. 智能体如何在有限窗口中处理无限上下文

上面已经提到,模型能够处理的上下文有限。而 Agent 在运行过程中会不断产生新的信息:用户继续聊天、Agent 调用工具、工具返回结果、任务继续执行……

如果什么都不处理,上下文一定会越来越长。所以不同的 AI 应用,会采用不同的上下文控制策略。

比如:

  • 最多保留多少轮对话
  • 上下文达到多少 Token 后开始压缩

常见的方法大概有下面几种:

3.1 硬截断

最简单粗暴的方法,就是直接丢掉一部分历史信息。

滑动窗口

永远只保留最近几轮对话。假设只保留最近 3 轮,第 4 轮进来以后,第 1 轮就会被挤出去。

第 3 轮结束
第 1 轮第 2 轮第 3 轮
当前上下文
(最近 3 轮)
第 4 轮进入
第 1 轮第 2 轮第 3 轮第 4 轮
当前上下文
(最近 3 轮)
离开当前上下文 窗口向前走,旧信息被挤出去。
窗口往前走,旧信息被挤出去。

固定轮次截断

比如最多允许 5 轮对话。达到限制以后,直接开启一个新的上下文,之前的信息全部清空。

旧上下文(最多 5 轮)
第 1 轮第 2 轮第 3 轮第 4 轮第 5 轮
清空
新上下文第 1 轮

真的会忘。实现简单、成本低。但如果前面的信息之后又变得重要,单靠当前上下文已经找不回来了。

3.2 压缩

内容太多以后,把历史信息总结一下。原来有 30,000 Token 的历史信息,可以提炼成 3,000 Token,再带着这份总结继续执行任务。

把一桌材料,整理成一页会议纪要
历史对话工具日志用户要求关键决策30,000 Token
压缩
提炼总结
会议纪要目标与约束关键决策已完成事项待办与阻碍3,000 Token
体积缩小,关键状态继续传递
教学示例,压缩可能丢失细节。

这有点像你开了一个很长的会议。会议进行到一半,桌面上的材料已经堆满了,于是有人把前半场的结论整理成一页会议纪要,接下来大家只拿着这页纪要继续讨论。

固定压缩

当前上下文使用量达到 90%,就进行一次压缩。

当前使用量90% · 示例阈值
0%100%
压缩后继续阈值由产品策略决定。

动态压缩

根据任务复杂度与信息类型,决定保留多少细节。

用户要求 · 尽量完整保留
关键决策 · 保留依据
工具日志 · 提炼结果
复杂任务保留更多细节,简单任务提炼结论。

哪些信息可以忘,哪些信息绝对不能忘。

3.3 历史信息检索

不把所有历史信息一直放在上下文里,先存起来,需要的时候再找回来。

比如 Agent 之前和用户已经聊了几百轮。这些内容全部保存到外部存储中,当前上下文只保留最近的内容。当 Agent 发现“这个问题之前好像聊过”,它就去历史记录里搜索相关信息,再把搜索结果放回当前上下文。

外部历史存储已保存的几百轮对话
历史对话记录 1历史对话记录 2历史对话记录 3历史对话记录 4历史对话记录 5
① 搜索相关历史
相关片段
② 回填当前上下文
当前上下文
我之前问过类似的问题吗?这个问题之前好像聊过是的,基于之前的讨论…
③ 继续推理
历史可以留在外部,单次模型窗口仍然有限。

从这个角度看,Agent 能够使用的历史信息几乎可以无限延长。忘掉也没关系,需要的时候再查。但历史检索解决了「存不下」的问题,却又带来了「能不能准确找回来」的问题。

历史检索的局限性:
1搜索需要额外时间2可能搜不到关键信息3可能召回无用内容4可能缺少当时语境5检索结果也占用窗口

检索出来的内容可能缺少当时的语境,检索结果本身也会占用新的上下文;实际系统还需要处理搜索耗时、召回质量与失败兜底。

4. 不同产品是怎么做的?

现实中的 Agent 产品,通常会组合使用上面几种方法,具体实现也会不断变化。

产品上下文处理阅读提示
Codex自动压缩后继续执行窗口与阈值依模型、配置而定
Claude Code压缩历史,保留重要状态200K / 1M 等,依模型与配置而定
参考:OpenAI Agent Loop ↗Claude Code 官方文档 ↗产品机制以当前官方说明为准。
管理上下文窗口就是管理注意力。

Agent 每一步能看到什么、忘掉什么、压缩什么、什么时候重新找回来,都会直接影响它接下来的判断。