---
area: tech-engineering
category: ai-ml
companies_orgs:
- Anthropic
- Google
- OpenAI
- Meta
- Databricks
- Stanford
date: '2025-11-05'
draft: true
guest: ''
insight: ''
layout: post.njk
media_books:
- arXiv
- Reddit
products_models:
- ChatGPT
- GPT-3
- GPT-3.5
- GPT-4
- GPT-4o
- Claude
- Claude 3 Opus
- Gemini
- Gemini 1.5
- Llama 4
- AlphaGo
- Gemini CLI
project: []
series: ''
source: https://www.youtube.com/watch?v=lVdajtNpaGI
speaker: Hung-yi Lee
status: evergreen
summary: 本文深入探讨了“上下文工程” (Context Engineering) 的核心概念，阐述了其与“提示工程” (Prompt Engineering)
  的异同。文章详细分析了构成语言模型上下文的各项要素，包括用户提示、系统提示、对话历史、外部知识（RAG）和工具使用，并解释了为何在 AI Agent 时代管理上下文至关重要。最后，介绍了选择、压缩和多智能体系统等关键的上下文工程技术，以避免“上下文过载”问题。
tags:
- ai-agent
- context-engineering
- generation
- learning
title: 上下文工程 (Context Engineering)：AI Agent 时代的关键技术
---
### 什么是上下文工程 (Context Engineering)？

今天我们要讲什么是**上下文工程**（Context Engineering: 一种管理和优化语言模型输入信息的技术，尤其在 AI Agent 场景下至关重要）。这是一个最近很热门的术语。我们会介绍它的概念，并告诉你它与你熟悉的**提示工程**（Prompt Engineering: 专注于设计和优化单个提示词以引导模型输出的技术）有什么差异。

Context Engineering 是当今在 **AI Agent**（AI 智能体: 能够自主感知环境、制定计划并执行复杂任务的 AI 系统）时代，能够让其成功运作的一项关键技术。如果你对 AI Agent 还没有什么概念，可以去看我们今年年初在机器学习课程中讲的《导读 AI Agent 的原理》。你可以选择先看那个影片再来听这堂课，也可以听完这堂课再去看，两堂课从不同观点讲解 AI Agent，都听完会有不一样的收获。

### 改变模型输出的两种路径：训练 vs. 调整输入

我们不断反复强调，语言模型本质上是在做文字接龙，即给它一个输入（Prompt），它会去预测接下来应该接哪个 Token。假设它接的 Token 不对怎么办呢？

我们可以将语言模型看作一个函数 f，输入是 x，输出是 f(x)。如果输出不是我们想要的，那么问题出在 f 或 x。因此，要么去改 f，要么去改 x。

如果你选择改变 f，这件事情叫做**训练**（Training）或**学习**（Learning）。通过改变函数 f 内部的参数来让它有不一样的行为，我们就进入了模型训练的领域，这部分内容我们到第五讲后才会提到。

今天我们先假设 f 本身没有问题，语言模型已经能够尽最大能力根据输入的 Prompt 选择最好的接龙结果。但现实中，语言模型的能力仍有极限，还有很多可以改进的地方。不过，多数情况下，你也已经改不了语言模型，因为它们大多是线上的闭源模型。

既然 f 改不了，我们能改的就是输入 x。我们可以为 f 准备合适的输入 x，让最后得到的 f(x) 是我们预期的结果。所以今天这堂课，我们专注于如何给语言模型合适的输入，让它得到正确的输出。这件事每个人都可以做，就算你没有预算资源，还是可以把 Prompt 修改好，让语言模型得到你想要的输出。需要强调的是，在这堂课中，没有任何模型被训练，我们唯一训练的只有人类自己。

### 上下文工程与提示工程的异同

刚才讲到修改语言模型的 Prompt，这不就是 Prompt Engineering 吗？Context Engineering 和 Prompt Engineering 有什么不同呢？

我认为，它们在本质上没有太大不同。Context Engineering 就像是给 Prompt Engineering 取了一个新名字，让你觉得更“潮”一点。这好比早年的神经网络（Neural Network）这个名字后来名声不太好了，就有人把它改成深度学习（Deep Learning），其实是新瓶装旧酒，但听起来更时髦了。

所以，Context Engineering 和 Prompt Engineering 我认为本质上是同样的东西，只是名称不同。但它们还是有一点点差异，主要体现在关注的重点上。它们都指向同一个概念：把语言模型的输入弄好，让模型得到我们想要的输出。

过去，当我们谈论 Prompt Engineering 时，你脑海中浮现的可能是特定的输入格式，比如用 JSON format，或者不同段落间用井字号隔开。曾有一段时间，很多人在教如何用正确的格式来 prompt 语言模型。但随着语言模型越来越强，这些格式已经没那么重要了，通常人看得懂的，语言模型也就看得懂。

另一方面，Prompt Engineering 可能会让你联想到一系列的“神奇咒语”。在早年语言模型还没那么厉害的时候，它们的输入输出关系有时非常无厘头。这时，你可能会发现一些神奇的咒语，让语言模型发挥不可思议的力量。

例如，在 GPT-3（比最早的 ChatGPT-3.5 更早的版本，非常难用）上做的一个实验：我们想让 GPT-3 回应的长度越长越好。
*   不加任何指令，它平均回应长度是 18.6 个字。
*   在 prompt 中告诉它“回答要越长越好”，长度可以提升到 23.76 个字。
*   但我们发现一个神奇的咒语：在 prompt 里加上一连串的“位置”，它就会“暴走”，答案长度可以达到 34.3 个字，比明确要求它输出长答案更有效。

这种神奇咒语在早年语言模型输入输出关系还很莫名其妙的时候比较能发挥作用。这个方法出自我们实验室的一篇论文。通常在引用论文时，我会直接引用放在 **arXiv**（发音为 "archive": 一个存放物理学、数学、计算机科学等领域预印本论文的在线平台）上的链接。因为在人工智能领域技术变化非常快，研究人员通常会直接把研究成果公开在 arXiv 上，而不是等待长达六个月的国际会议投稿周期。从链接的数字可以看出论文公开的时间，例如 `2206` 就代表是 2022 年 6 月的论文，那是一个没有 ChatGPT 的上古时代。

后来出现了各式各样的神奇咒语，比如最知名的“Let's think step by step”（一步一步地思考），能让模型能力起飞。还有人发现加上“请确保你的答案是正确的”、“深呼吸再回答问题”、“这题的答案真的对我很重要”（情感勒索），甚至“如果你答对就给你小费”，都能提升模型的正确率。

有一个有趣的实验测试了语言模型最喜欢什么。作者尝试了给 Taylor Swift 的门票、达成世界和平、母亲为你骄傲、得到真爱等激励。结果发现，ChatGPT 最喜欢“世界和平”，这能让它在“写一个 200 字故事”的任务中表现最好。它最不在意的是母亲是否为它骄傲，这也很合理，因为它没有母亲。

然而，现在这些神奇咒语越来越不神奇了。一年半前，在 2023 年 6 月，对 GPT-3.5 使用“一步一步思考”的咒语，能将数学应用题的正确率从 72% 提升到 88%。但到了 2024 年 2 月，同样的实验中，正确率只能从 85% 提升到 89%。神奇咒语的效率正在降低。这是一个合理的发展方向，因为模型本就应该使尽全力做到最好，不应该需要额外的激励。

随着神奇咒语不再神奇，人们关注的重点变了，这个新的关注点被赋予了新名字，即 Context Engineering。它真正想做的是自动化地管理语言模型的输入，甚至用语言模型自己来管理自己的输入。

为了讲解方便，在接下来的课堂上，我们暂时将 Context 和 Prompt 划上等号。当我讲 Context 时，我指的就是 Prompt，即语言模型的输入。

### 一个完整的上下文应包含哪些内容？

我们先从一个完整的 Context 应该包含什么内容开始讲起。

#### 用户提示 (User Prompt) 的要素

最基本的是**使用者的 Prompt**，即你对语言模型下的指令。除了任务本身，你最好还能提供详细的指引。例如，写信向老师请假，你可以告诉模型：
*   开头先道歉。
*   说明请假理由是身体不适。
*   之后会更新进度。
*   信件在 50 字以内。
*   语气要非常严肃。

因为语言模型不会读心术，你必须把条件讲清楚，它才能做得更好。

提供**前提**也能让模型做得更好。例如，你问模型“有人告诉我要用载具吗”是什么意思，它可能会解释“载具”是交通工具或电子设备。但如果你把前提讲清楚：“在超商结账时，店员问‘我要用载具吗’是什么意思？”模型就能准确回答，载具是指电子发票的储存工具。

在影像处理中，前提同样重要。我太太在曼谷运河上拍到一只像鳄鱼的动物，但周围的泰国人看起来很高兴。我问 ChatGPT 这是什么，它也认为是鳄鱼。但当我提供更多情报：“现在我们在泰国的曼谷，那水中的动物是什么？”ChatGPT 给出了不同的答案：水巨蜥。在泰国，水巨蜥是吉祥的象征，代表偏财运，所以大家看到它会很高兴。

在 User Prompt 中加入**范例**也会影响模型的答案。例如，我要求 ChatGPT 用火星文改写文章，它会把每个字替换成另一个固定的字。但这并非我想要的火星文。于是我举例：“所谓的火星文就是把‘要去冒险的人来找我’改写成‘要ㄑ冒险ㄉ人来找我’”。给了这个例子后，ChatGPT 的输出就正确了，它知道火星文是把一些中文字改成注音符号。

早在 GPT-3 的时代，人们就知道把范例放到 Context 里能让模型做得更好。在 GPT-3 的论文中，他们称之为 **In-Context Learning**（情境学习: 指模型在不更新参数的情况下，仅通过在输入中提供范例来学习并执行新任务的能力）。这里的“Learning”要加双引号，因为它并非传统意义上的机器学习，模型的参数没有任何改变，只是因为输入变了，输出才跟着改变。

Gemini 1.5 的 In-Context Learning 能力是一个经典例子。在其技术报告中，他们展示了一个神迹：让 Gemini 翻译一种非常稀有的语言——卡拉蒙语（Kalamang）。由于网上几乎没有这种语言的资料，模型一开始完全无法翻译。但是，当把卡拉蒙语的教科书、文法和字典作为 Context 输入给模型后，它竟然学会了翻译。实验表明，在提供了整本教科书后，Gemini 1.5 的翻译评分从不到 1 分（满分 6 分）飙升到 4 分甚至 5.5 分，接近人类水平。最近的研究发现，真正起作用的是教科书中的例句，而非文法说明。

#### 系统提示 (System Prompt) 的作用

语言模型还需要有**系统提示 (System Prompt)**。这是开发平台认为模型每次互动时都需要的固定信息。例如，Claude 3 Opus 的 System Prompt 超过 2500 个字，内容非常详尽，包括：
*   **身份认同**：告诉模型它叫 Claude，由 Anthropic 公司打造，以及今天的日期。
*   **使用说明与限制**：如何使用 API，禁止合成化学物质或制造核武器。
*   **互动方式**：如果用户不高兴，引导他们按“倒赞”；不要用“好问题”这类惯用语开头。
*   **知识截止日期**：知识只到 2025 年 1 月。
*   **自身定位**：不要说自己是人类或有意识。
*   **错误修正**：如果人类纠正你，要仔细思考后再回答，不要轻易承认错误。

通过阅读 System Prompt，你就能理解为什么语言模型会有某些特定的行为。

#### 对话历史与长期记忆

模型还需要**对话的歷史紀錄**作为短期记忆。例如，在一个对话中，我告诉 ChatGPT“隔壁老王姓‘法’，叫法老王”，它就能记住。但如果开启一个新对话，它就又忘了。这是因为在同一个对话中，前面的历史记录成为了后续文字接龙的 Context。你与模型的对话并不能改变其内部参数。

不过，从 2024 年 9 月之后，ChatGPT 具备了**长期记忆**功能。你可以在“自定义 ChatGPT”中开启记忆选项。当你提问时，你看不到的长期记忆已经被植入到 Context 中。OpenAI 做了一个营销活动，让大家问 ChatGPT“我是什么样的人”，模型会根据长期记忆中与你的互动历史来回答。

#### 外部知识：检索增强生成 (RAG)

为了克服知识有限和过时的问题，我们希望为模型提供来自其他数据源的相关信息，最常用的方法就是通过搜索引擎。这个技术有个鼎鼎大名的名字，就是 **Retrieval-Augmented Generation**（检索增强生成，简称 RAG: 一种通过从外部知识库检索相关信息，并将其作为上下文提供给语言模型，以生成更准确、更具时效性回答的技术）。

在提问前，系统先把问题丢到网络或数据库进行搜索，将得到的额外信息和你的 prompt 一起提供给模型，让它在文字接龙时更有可能得到正确答案。

但需要注意的是，结合搜索引擎并非万无一失。Google 的 AI Overview 在测试期间曾闹出笑话，当被问到“如何让披萨上的芝士不掉下来”时，它建议“加入八分之一的无毒胶水”。这是因为它从一篇 Reddit 的开玩笑帖子里学到了这个“方法”。即使是现在的 ChatGPT-4o，在开启搜索功能时也可能犯错。例如，我让它介绍台大专业学程联盟的课程，虽然网址对了，但它错误地声称所有课程都是进阶课程。

#### 工具使用：从 API 到操控电脑

现在的语言模型，如 Claude、Gemini、GPT，都能使用多种工具，例如搜索 Gmail、读写 Google Calendar 等。模型是如何使用工具的呢？

你需要在 Context 中写好工具的使用方法。你可以用自然语言向模型说明：
1.  **通用规则**：如果知识无法回答，就使用工具。工具指令放在 `<tool>` 和 `</tool>` 之间，输出放在 `<output>` 和 `</output>` 之间。
2.  **特定工具说明**：例如，有一个 `temperature(城市, 时间)` 工具，可以查询温度。

当用户提问（例如“2025年某日高雄的气温如何？”），模型会根据这些说明，生成一段文字指令，如 `<tool>temperature('高雄', '时间')</tool>`。需要注意的是，这串文字本身不会执行任何操作。你需要编写一个程序来捕获这段文字，真正去调用 `temperature` 函数，得到结果（如“摄氏32度”），再把这个结果包装成 `<output>摄氏32度</output>`，放回 Context 中。模型再根据这个新的 Context 进行文字接龙，最终回答用户：“某年某月某日高雄的气温是摄氏32度。”

在 Colab 演示中，我们创建了乘法和除法两个工具。一开始，模型只是“假装”调用了工具，它自己心算出结果，这是一种幻觉（hallucination）。为了让模型真正使用工具，我们需要编写一个循环：
1.  将用户的请求和工具说明放入 Context，让模型生成回应。
2.  检查模型的回应是否包含 `<tool>` 标签。
3.  如果包含，提取指令，用 `eval()` 函数在 Python 中实际执行它。
4.  将工具的真实输出放回 Context。
5.  重复此过程，直到模型的回应不再包含工具指令，这个最终的回应就是给用户的答案。

通过这种方式，模型可以准确地完成计算或查询天气。有趣的是，如果工具返回一个荒谬的结果（比如极高的温度），模型有能力识别并质疑这个结果。

在所有工具中，最通用和强大的就是使用电脑。我们很多人把它叫做 **Computer Use**（计算机使用: 指语言模型通过控制鼠标和键盘，直接操作计算机桌面环境以完成任务的能力）。模型接收屏幕画面和任务指示，然后输出控制鼠标和键盘的指令。ChatGPT 的 Agent Mode 就是一个例子，它可以在一个云端的虚拟电脑上帮你订高铁票。我演示了让它订票的过程，它会搜索网站、点击按钮、选择日期和票数，虽然操作有些笨拙，但展示了巨大的潜力。

其原理与使用普通工具类似：给模型一张屏幕截图，并告诉它可以使用的工具是键盘输入、移动鼠标到某个坐标、点击鼠标左右键。然后问它下一步该做什么，它就能规划出完整的操作流程，例如搜索、点击、输入文本等。

#### 模型自身的思考过程

现在很多模型，如 GPT 的 O 系列和 DeepMind 的 R 系列，都号称可以进行深度思考。这意味着当你提问时，模型不会直接给出答案，而是先进行一个“脑内小剧场”。它会演练多种解法，进行规划、尝试和验证，然后根据这个思考过程生成最终答案。这个思考过程本身也成为了 Context 的一部分，只不过这是模型自己产生并放入的，而不是由外部提供的。

### 为何 AI Agent 时代亟需上下文工程？

总结一下，一个完整的 Context 可以包含：User Prompt、System Prompt、对话历史、长期记忆、RAG 结果、工具使用结果以及模型自身的思考过程。这个 Context 会变得非常非常长。因此，Context Engineering 的核心目标就是一句话：“避免塞爆 context”，想办法只放需要的东西，并清理掉不需要的内容。

在 AI Agent 时代，这一点尤其重要。过去我们使用 AI 是一问一答。后来有了 **Agentic Workflow**，即为模型设定一个 SOP（标准作业程序）来完成复杂任务。而 **AI Agent** 更进一步，让模型自己决定解决问题的步骤，并根据过程中的变化灵活调整计划。

AI Agent 可以看作一个循环：人类给出目标 -> 模型根据观察（Observation）采取行动（Action） -> 行动改变环境 -> 产生新的观察 -> 模型采取新的行动。从语言模型的角度看，这始终是文字接龙：根据 `Observation 1` 产生 `Action 1`，再根据 `Observation 1, Action 1, Observation 2` 产生 `Action 2`，以此类推。

#### AI Agent 的挑战：上下文窗口的极限

运行 AI Agent 的最大挑战之一是任务可能非常复杂，需要大量步骤，导致输入（Context）过长。每个模型都有其**上下文窗口大小**（Context Window Size: 指模型一次可以处理的输入文本的最大长度，通常以 token 数量计算）的上限。超过这个上限，模型可能会“发疯”，输出奇怪的内容。

近年来，模型的 Context Window 迅速增长，从 GPT-4 的 3 万 token，到 Claude 的 10 万，再到 Gemini 的 100 万，甚至 Llama 4 号称的 1000 万。Gemini 1.5 Pro 可以输入 200 万个 token，相当于读完哈利波特全集外加三本魔戒。

然而，能输入上百万 token，不代表能读懂上百万 token。许多实验表明，在远未达到上限时，模型就已经开始对输入感到困惑。
*   **RAG 效果下降**：Databricks 的研究发现，当通过 RAG 提供的文档过多时，许多模型的正确率先升后降，因为过多的信息让模型“头晕目眩”。
*   **中间迷失 (Lost in the middle)**：一篇论文发现，模型对长文本的开头和结尾记忆更深刻，而容易忽略中间部分的内容。如果正确答案位于一大堆文档的中间，其表现甚至不如不提供任何文档、仅凭自身知识回答。
*   **冗长互动导致能力下降**：近期研究表明，将一个问题拆分成多个步骤、以“挤牙膏”的方式提问，会导致模型表现变差且更不稳定，不如一次性把所有要求讲清楚。
*   **上下文腐烂 (Context Rot)**：一篇知名文章指出，Context 过长时会“腐烂”。在一个简单的复制任务中，随着输入文本变长（即使远未达到窗口上限），各大模型的复制正确率都迅速下降。

### 上下文工程的三大基本策略

既然 Context 不能太长，Context Engineering 的基本概念就是：把需要的东西放进去，把不需要的东西清出来。这通常也需要语言模型的辅助。以下是三个常用的策略。

#### 策略一：选择 (Selection)

选择的核心思想是，只挑选有用的东西放入 Context。RAG 本身就是最好的例子，它通过搜索引擎只挑选出最相关的资料。在这个框架下，还可以做更多优化：
*   **查询转换**：让语言模型将用户的自然语言任务转换成更有效的搜索关键词。
*   **重排序 (Reranking)**：用一个小的语言模型对搜索结果进行二次筛选，只保留最相关的文章。
*   **句子级检索**：用一个极小的模型（如 < 300M 参数）去挑选文章中的相关“句子”，进一步精简 Context。
*   **工具选择**：当有成百上千个工具时，可以像 RAG 一样，根据用户需求只检索出相关工具的使用说明放入 Context。这解释了为什么早期 ChatGPT 的插件功能每次最多只能选三个。
*   **记忆选择**：对于长期记忆，不能把所有历史都塞进去。可以像“史丹佛小镇”实验那样，将记忆存储在外部，然后根据“新近度”、“重要性”和“相关性”三个指标用 RAG 的方式检索出最相关的记忆放入 Context。一个有趣的发现是，给模型看过去答错的负面例子，有时反而会损害其表现，模型似乎更容易重蹈覆辙。

#### 策略二：压缩 (Compression)

当 AI Agent 的互动历史变得过长时，需要对历史记录进行压缩。你可以定期（比如每 100 个回合或当 Context 达到 90% 满时）调用一个专门做摘要的语言模型，将过去的互动历史压缩成关键信息，作为长期记忆。这种递归式的压缩会让久远的记忆逐渐模糊，只保留大概轮廓。

我怀疑 ChatGPT 的长期记忆就用了类似技术。它有一套会随风而逝的记忆，越近的事情记得越清楚，这可能就是递归压缩的结果。

压缩之所以有效，是因为 Agent 与环境的互动会产生大量琐碎信息，尤其是在 Computer Use 场景下。例如，在预订餐厅的过程中，可能会遇到弹出广告、点击关闭等操作，这些细节对于未来的任务毫无意义。整个冗长的订位过程完全可以压缩成一句话：“A 餐厅 9 月 19 日下午 6 点 10 人订位成功。”如果担心摘要会丢失关键信息，可以将摘要前的完整内容存到硬盘，并在摘要中留下一个索引，以便日后通过 RAG 或直接读取文件来检索。

#### 策略三：多智能体 (Multi-Agent)

**多智能体**（Multi-Agent: 指由多个独立的 AI Agent 协同工作以完成复杂任务的系统架构）是另一个有效的 Context 管理方法。以一个叫 ChatDev 的系统为例，它模拟一个软件公司，有 CEO、CTO、程序员、测试员等不同角色的 Agent 各司其职。

从 Context Engineering 的角度看，即使所有 Agent 的能力都一样，多智能体架构也能带来好处。假设一个 Agent 负责组织出游，它需要规划行程、订餐厅、订旅馆。订餐厅和订旅馆都需要大量的 Computer Use 互动，很快就会塞满它的 Context。

但如果采用多智能体设计：一个“总召”Agent 负责总体规划，当需要订餐厅时，它把这个任务交给 Agent 1；需要订旅馆时，交给 Agent 2。Agent 1 和 Agent 2 完成任务后，只需向总召回报结果。这样一来：
*   总召的 Context 中没有订位和订房的琐碎细节，只保留了“餐厅已订好”、“旅馆已订好”等高层信息。
*   订餐厅的 Agent 不需要知道任何关于订旅馆的信息，反之亦然。

每个 Agent 的 Context 都保持了简洁和专注。这就像写一篇综述论文（overview paper），与其让一个 Agent 读上百篇论文导致 Context 爆炸，不如让多个 Agent 各自读一篇论文并写出摘要，最后再由一个主 Agent 整合所有摘要来完成论文。

LangChain 的一篇论文也验证了这一点：在简单任务中，Single-Agent 可能表现更好，因为它掌握所有信息。但在复杂任务中，Multi-Agent 的分工协作能够避免单个 Agent 因 Context 过载而崩溃，从而展现出巨大优势。