Context Engineering:比提示词工程更底层的那件事

AI Context Engineering 大模型

📎 说明:这篇文章是我在准备搭agent时学习过程的整理跟 《Agentic 入门:让 AI 不再一把梭,而是像人一样反复干活》 一起整理的。按理说这篇应该更早发,但当时一直没整理顺,所以拖到了后面。内容还是以我自己的学习理解为主。

我最早注意到 Context Engineering(上下文工程),大概是在 Prompt Engineering 被聊得很热之后。

Context Engineering(上下文工程)最早接触是Prompt Engineering 概念火了一段时间之后。
在这之前好像AI应用开发的核心焦点一直是“提示词工程(Prompt Engineering)”。然而,随着大语言模型(LLM)从单次问答向能够自主运行的智能体(Agent)演进,上下文工程(Context Engineering)变得更加重要。

很多时候,真正决定模型表现的,不是你那句话写得漂不漂亮,而是它在那一刻到底看到了什么,没看到什么。

所以我现在更愿意把这件事理解成:做大模型应用,重点正在从“怎么把话说漂亮”,慢慢转到“怎么把上下文组织对”。


一、先说问题:Prompt Engineering 到底卡在哪儿?

只要你认真用过一段时间 AI,大概率都会碰到这种情况:

你写了一个很长的 Prompt,感觉已经把话说明白了,结果模型要么没懂,要么回答得很飘。可你换个问法,它又突然正常了。

你开始怀疑:是我 Prompt 写得不好,还是模型本身忽强忽弱?

这个现象背后,其实是个更底层的问题:模型能不能干好活,很大程度上取决于它当下到底能看到什么。

Prompt Engineering 解决的是“怎么把问题问清楚”。这当然重要,但它管不了另一件更麻烦的事: 当你要处理的信息,已经不是一轮对话能装下的时候,该怎么办?

比如:

  • 你有一本 500 页的技术文档,想让 AI 帮你答用户问题
  • 你的系统里有十几个上下文来源(用户历史、实时数据、业务规则、代码片段……)
  • 你的 Agent 要跑十几步任务,中间状态要一直传下去

到了这些场景里,“怎么问”就不是最核心的问题了,“怎么喂”才是

这就是 Context Engineering 要解决的事。


二、那 Context Engineering 到底是什么?

Anthropic 的说法是,它可以看成是从 Prompt Engineering 往前走了一步《Effective context engineering for AI agents》,但两者盯的东西并不一样:

  • Prompt Engineering:怎么写好这一句话
  • Context Engineering:怎么组织整个信息环境

如果用我自己的话讲,后者更像是在做“信息架构”,你要决定:

  1. 哪些信息该放进上下文
  2. 这些信息按什么结构组织
  3. 什么时机、以什么方式把它们喂给模型
  4. 超出上下文窗口时,怎么选择性地保留和丢弃

这件事听起来像工程,不是因为这个词高级,而是它真的就是工程问题。它不是让你背几个提示词套路,而是要把整个信息流理清楚。

有一个比方我觉得很贴:

Prompt Engineering 是教你怎么跟一个人说话;Context Engineering 是在他开口之前,帮你决定他今天能看到哪些材料、能记得哪些背景、桌上摆的是什么资料。


三、它真正卡住的,不只是窗口大小,而是“注意力预算”

很多人第一次接触上下文工程,都会先盯着“上下文窗口够不够大”。

这个视角没错,但还不够。

但我现在越来越觉得,更准确的说法应该是:模型真正稀缺的,不只是 token 容量,而是注意力预算。

你可以把上下文窗口理解成模型工作的“临时内存”。窗口大,确实代表理论上能塞进去更多东西;但塞得进,不等于它就能稳定地理解、提取、关联这些内容。

这时候会出现一个很现实的问题:上下文腐烂(Context rot)

说白了就是,上下文越长、信息越杂,模型越容易出现下面这些毛病:

  • 前面明明给过规则,后面还是忘
  • 中间插入很多工具输出后,开始抓不住重点
  • 看起来“都读了”,但真正回答时只抓住开头和结尾
  • 局部结论没问题,一到多步任务串起来就开始漂

所以 Context Engineering 的核心不是“拼命往里塞”,而是:用尽量少、但信号强的信息,占住模型最宝贵的注意力。

所以很多 AI 系统上线以后表现不稳,问题不一定出在模型不够聪明,很多时候就是上下文里混进了太多低信号内容。


四、底层是什么?先聊 Self-Attention

要真正理解”上下文”对模型意味着什么,绕不开一篇 2017 年的论文:《Attention Is All You Need》《Attention Is All You Need》,也就是提出 Transformer 架构的那篇。

它里面最核心的东西是 Self-Attention(自注意力机制)

粗暴一点讲,模型在生成每一个词的时候,都会去“扫一眼”上下文里别的词,算一遍“谁跟我现在最相关”,再决定往下吐什么。

这意味着:模型的能力,很大程度上取决于窗口里装了什么

你给它看的内容越准确、越有结构、越聚焦,它的注意力就越能集中在真正重要的部分。你塞一堆无关信息进去,它不会自动过滤掉,它只会”稀释”它的注意力。

所以“上下文工程”这件事,如果往底层追,本质上就是在跟 Self-Attention 的工作方式打交道。


五、系统提示词也有讲究:别太死,也别太飘

很多人一提上下文工程,第一反应还是去改 System Prompt。

这当然要改,但我现在觉得,问题通常不是“写得不够长”,而是写得那个劲儿不对

我现在更认同一个判断:好的系统提示词,应该在“规则足够清楚”和“保留模型推理空间”之间找到平衡。

两个极端都不行:

  • 写成 if-else 说明书,模型像被绑住手脚,遇到复杂情况反而不会变通
  • 写得过于抽象,只说“请你专业、严谨、友好”,基本等于没说

我现在更倾向于把系统提示词拆成几个清楚的区块,比如:

  • 背景信息:这个 Agent 是干什么的
  • 目标:这次任务最终要达成什么结果
  • 约束:哪些事情不能做,哪些风险要优先规避
  • 工具说明:什么时候该调用什么工具
  • 输出要求:最后结果要长什么样

你会发现,这时候你做的已经不只是“写一句提示词”了,而是在给模型搭一个小型运行环境。


六、RAG 里最容易踩的坑,Anthropic 想了个解法

现在很多 AI 应用都在做 RAG(检索增强生成)——就是把一堆文档切片,存进向量数据库,等用户提问时捞出相关片段塞给模型。

这条路当然没错,但里头有个很容易被忽略的问题:文档一切片,背景信息很容易丢。

举个例子:你有一份技术文档,里面有一段话:

“这个接口的超时时间配置建议设为 5 秒。”

这句话单独拿出来是完整的,但如果你不知道这是在说”内网服务调用”而不是”公网 HTTP 请求”,这条建议可能直接坑掉你。

Anthropic 在 2024 年提出了 Contextual Retrieval《Contextual Retrieval》 来解这个问题。核心思路其实不复杂:

在切片存储之前,先让模型给每个片段加一段 **”上下文注释”**,说明它来自哪个文档、属于哪个章节、要解决什么问题。然后把这个带注释的片段再做向量化。

这样检索出来的内容,就不只是一句话,而是“一句话 + 它原本待着的语义背景”,命中质量会明显好一些。

配合 BM25 关键字检索(而不是单纯依赖语义向量),精确度进一步提升。

简单来说:不是切得多就能捞得准,要让每一块碎片都知道自己是从哪来的。


七、真正有用的方式,不是预加载全部,而是按需取用

很多系统在早期都会很自然地走一条路:既然上下文重要,那就多塞一点。

比如:

  • 用户资料全塞进去
  • 历史对话全塞进去
  • 检索结果 top 10 全塞进去
  • 工具执行日志原样全塞进去

一开始看起来确实会有一种“信息很全”的安全感,但很快就会遇到两个问题:

  1. 模型越来越贵
  2. 模型越来越乱

更像样一点的做法,其实是 Just-in-time context,也就是“即时上下文”。

它的思路是:默认只保留索引、摘要、标识符,真正需要的时候再去取原文。

比如不要把整个代码库文档直接扔进上下文,而是先给模型:

  • 文件路径
  • 模块索引
  • 函数签名
  • 哪些文档可能相关

然后让它在任务执行过程中,通过检索、搜索、读取工具,一步步把真正需要的信息拿进来。

这种方式本质上是在做“渐进式披露”。不是一上来把整个图书馆砸给模型,而是先把目录递给它,再让它决定该翻哪几页。

这比一次性预加载所有材料,更接近人类真正工作的方式。


八、长任务为什么特别容易翻车?因为上下文会被历史污染

上面说的 Contextual Retrieval,主要解决的是“单次检索”的质量问题。但到了更复杂的 Agent 场景里,还会多出另一个麻烦:上下文不是一开始就完整的,它是任务跑着跑着一点点堆起来的

多步 Agent 工作流最烦人的地方,不一定是某一步直接做错,而是前面做过的所有事,最后都会变成后面的上下文负担。

比如一个任务跑了二十几步之后,上下文里可能已经混着:

  • 早期已经失效的假设
  • 很长但价值不高的工具输出
  • 中途试错留下来的噪音
  • 真正关键但只出现过一次的结论

这时候问题就不是“窗口够不够”,而是历史信息正在污染当前决策

所以长周期任务里,通常就得想办法处理这件事。常见做法大概有三类:

① 压缩(Compaction)

当窗口快满时,不是简单截断,而是把已经完成的阶段总结成高保真摘要,把冗长原始过程替换掉。

② 外部记忆(Structured note-taking / Agent memory)

把待办、关键决策、阶段性结论写到上下文窗口外,比如 NOTES.md、状态文件或者数据库。后续即使重新开一个新窗口,也能快速续上。

③ 子智能体隔离(Sub-agent)

把特别耗 token 的探索任务丢给独立子智能体去做,让它在自己的“干净窗口”里完成搜索、归纳,再把浓缩后的结论返回主智能体。

这三件事,本质上都在解决一个问题:别让历史细节一直赖在窗口里,持续污染当前判断。


九、Anthropic 的工程实践:XML 标签、工具边界和 Prompt Caching

具体到工程实践,Anthropic 在这篇文章里《Effective context engineering for AI agents》 给了几个我觉得挺接地气的抓手:

① XML 标签

当你需要在上下文里放多个来源的信息(用户资料 + 业务规则 + 代码片段 + 历史记录),用纯文本堆在一起,模型很容易把它们”混为一谈”。

用 XML 标签把它们显式分开,能让模型更清楚哪块是哪块:

1
2
3
4
5
6
7
8
9
10
11
<user_profile>
用户是一个年营收 500 万的 SaaS 创业公司 CTO
</user_profile>

<business_rules>
禁止直接推荐未上线的功能
</business_rules>

<user_query>
我们应该怎么设计权限系统?
</user_query>

这玩意儿不是什么魔法,说白了就是把结构摆明白,别让模型自己猜。

② 工具边界要清楚

很多 Agent 失败,不是因为工具不够多,而是因为工具太多、定义太像、边界太模糊。

如果一个工具库里同时有:

  • search_docs
  • lookup_docs
  • find_doc_context
  • query_knowledge

那别说模型,人都得先愣一下。

我现在越来越觉得,工具其实就是模型和外部世界的契约。契约越清楚,模型越稳;契约越含糊,它越容易瞎试。

③ Prompt Caching(提示词缓存)

如果你的系统里有一段很长的固定上下文(比如一份 300 页的产品手册),每次用户提问都要把这段内容完整喂给模型,成本很高。

Prompt Caching 允许你把这段内容缓存在 API 层,后续调用直接复用,不重复计算。

这事看起来像纯工程优化,但很关键。因为它会直接决定:“长期带着一大坨稳定上下文工作”这件事,在成本上到底能不能成立。


十、Karpathy 的那个比喻:上下文窗口是模型工作的“临时内存”

在 OpenAI 前首席科学家 Andrej Karpathy 的一个演讲里《Software Is Changing (Again)》演讲,他把上下文窗口比作大模型的”有限内存”。

这个比方我觉得挺好懂:

模型本体里存的是”知识”,但它在干活时看到的,只有上下文窗口里的内容。超出窗口的东西,它看不见,也不存在。

这就是为什么:

  • 你聊了很长一段时间之后,模型开始”忘事”
  • 你让它处理一个超长文档,它只抓住了开头和结尾
  • 你的多轮 Agent 任务执行到一半开始乱套

根本原因都一样:窗口装不下了,或者装的东西不对

上下文工程要做的,说到底就是在这个有限空间里,把最该放进去的东西,用合适的方式放进去。


十一、整理一张表:四个角度看上下文工程

来源 核心关键词 解决的问题
Anthropic Contextual Retrieval / XML 标签 / Prompt Caching 如何结构化组织海量背景,避免信息丢失和成本失控
Transformer 论文 Self-Attention 模型如何在机制层面消费上下文
Agentic Workflow 动态上下文 / 外部记忆 / 多步传递 如何在多轮任务里持续维护有效上下文
Karpathy Context Window / Working Memory 上下文为什么像“临时内存”,以及为什么会忘事

把这四个角度放在一起看,我自己现在的理解是,Context Engineering 其实横跨了四层:

  • 模型层:注意力到底怎么分配
  • 检索层:拿进来的资料到底准不准
  • 工作流层:多步任务怎么传递状态
  • 工程层:成本、延迟、缓存、工具契约怎么控制

也正因为它跨层,所以它不是一个“提示词小技巧”,而是 AI 系统设计里绕不过去的一部分。


十二、我目前的几个实际感受

老实说,我自己学这块之前,踩过的坑还真不少:

  1. 把所有背景信息一股脑塞进 System Prompt。当时总觉得“多给一点总没错”,结果就是模型越来越飘。后来才明白,不是信息越多越好,是相关信息越准越好

  2. 以为 RAG 就是检索 + 拼接。直接切片、存向量、捞出来就完事。后来真碰到上下文断裂的问题,才意识到:片段不能只被捞出来,它还得“知道自己是谁、从哪来”。

  3. 把 Prompt Engineering 和 Context Engineering 混在一起。一开始总觉得问题问对了就行,后来才发现,一到 Agent 场景里,“信息怎么组织”很多时候比“问题怎么问”更靠前。

  4. 误以为长上下文天然更强。后来越做越发现,长上下文只是给了你“可以多放点东西进去”的机会,但如果没有筛选、压缩、分层和按需取用,它反而更容易把模型带偏。

说白了,上下文工程是软件工程在 AI 时代的一个延伸——你不只是在写 Prompt,你在设计信息流。


结尾

这篇还是偏学习整理,没有往代码实现那层展开太多,主要先把我自己脑子里这套概念骨架搭起来。

如果你也在做 AI 应用,或者已经开始搭 Agent / AI 系统,我现在会更建议先盯住这几个问题:

  1. 你给模型的,到底是不是“最小但高信号”的信息?
  2. 你的检索结果,是不是保留了足够的背景语义?
  3. 你的多步任务里,有没有一套压缩、记忆、续跑机制?
  4. 你的工具和提示词结构,是否清晰到让模型不用猜?

这些问题如果没想清楚,模型就算再聪明,系统表现也还是会一阵一阵的。