- 原文作者 DAIR.AI Academy
- 中文翻译 gemini & kuhung
- 备注评论 kuhung
什么是上下文工程?
几年前,许多人,甚至是顶尖的AI研究人员,都声称提示工程(prompt engineering)将不复存在。(注:当时的语境是说:当大模型足够强,人类就不需要写那些提示词。)
显然,他们错了。事实上,提示工程现在比以往任何时候都更加重要。它的重要性如此之高,以至于现在被重新命名为上下文工程 (context engineering)。
是的,又是一个花哨的术语(注:不就是从单点的提示词描述,扩大范围到上下游的整个流程嘛)。被用来描述调整指令和相关上下文这一重要过程,以便让大语言模型(LLM)有效执行其任务。
关于上下文工程已经有很多文章(Ankur Goyal、Walden Yan、Tobi Lutke 和 Andrej Karpathy),但我想写下对这个主题的看法,并向读者展示一个在开发 ai agent workflow 时将上下文工程付诸实践的步骤指南。
我不太确定是谁创造了"上下文工程"这个词,但我们将基于 Dex Horthy 的这张图来展开,它简要地解释了上下文工程是什么。(注:当然是热衷写 guide 的推特流量弄潮儿)
我喜欢"上下文工程"这个术语(注:那为啥不叫 ai agent system design),因为它感觉更广泛(注:因为它流量更好),能更好地解释提示工程中包含的大部分工作以及其他相关任务。
许多人认为提示词工程不算工程,是因为很多人将其与"和chatgpt对话时的简短任务描述"相混淆。在该过程中,你只是在向系统提问。而在提示工程中,你必须更仔细地考虑提示的上下文和结构。也许它一开始就应该被称为上下文工程。(注:嗯,之前的故事讲不下去了,大家都知道是啥,我得重新定义一个方便我卖课)
上下文工程是下一个阶段,你需要构建完整的上下文,这在许多情况下需要的不仅仅是越简单的提示,而是更严谨的方法来获取、增强和优化系统的知识。
从开发人员的角度来看,上下文工程涉及一个迭代的过程,通过优化你提供给大语言模型的指令和上下文,从而达到预期的结果(注:意思就是,想获得好的效果的一切方式,都可以统称为上下文工程)。这包括采用正式的流程(例如,评估流水线)来衡量你的策略是否有效。
鉴于AI领域的快速发展,我建议对上下文工程下一个更广泛的定义:设计和优化指令及相关上下文,以便大语言模型和高级AI模型有效执行其任务的过程。 这不仅包括基于文本的大语言模型,还包括为日益普及的多模态模型优化上下文。这可以涵盖所有的提示工程工作以及相关流程,例如:
- 设计和管理提示链(如果适用)
- 调整指令/系统提示
- 管理提示的动态元素(例如,用户输入、日期/时间等)
- 搜索和准备相关知识(即 RAG)
- 查询增强
- 工具定义和指令(在 agent 系统中)
- 准备和优化少样本示范(few-shot demonstrations)
- 结构化输入和输出(例如,分隔符、JSON 模式)
- 短期记忆(即管理状态/历史上下文)和长期记忆(例如,从向量存储中检索相关知识)
- 以及许多其他用于优化大语言模型系统提示以实现所需任务的技巧。
(注:中间部分其实就是提示词工程需要考虑的事情,前后实际上是系统设计需要考虑的事情)
换句话说,你在上下文工程中在做的就是:优化你在大语言模型上下文窗口中提供的信息。其意味着过滤掉嘈杂的信息(注:这里又没有分类器,实质上是通过规则限定信息的分布),这本身就是一门科学(注:实际上是个体力活,科学显得更牛逼。潜台词就是科学的才是更好的)。因为它需要系统地衡量大语言模型的性能(注:嗯,衡量=科学)。
每个人都在写关于上下文工程的文章,但在这里,我们将通过一个具体的例子,带你了解在构建AI agent 时上下文工程是什么样的。
上下文工程实践
来看一个我最近为个人使用而构建的 multi-agent deep research 应用。
我是在 n8n 中构建这个 agent 工作流的,但工具本身并不重要。我构建的完整 agent 架构如下所示:
我的工作流中的"搜索规划器" agent 负责根据用户查询生成搜索计划。
系统提示
以下是我为这个子 agent 编写的系统提示:
你是一位专业的研究规划师。你的任务是将一个复杂的研究查询(由 <user_query></user_query> 分隔)分解为具体的搜索子任务,每个子任务关注不同的方面或来源类型。
当前日期和时间是:{{ $now.toISO() }}
对于每个子任务,请提供:
1. 子任务的唯一字符串 ID(例如,'subtask_1', 'news_update')
2. 针对主查询的某个方面提出的具体搜索查询
3. 要搜索的来源类型(web, news, academic, specialized)
4. 时间段相关性(today, last week, recent, past_year, all_time)
5. 领域焦点(如果适用)(technology, science, health, 等)
6. 优先级(1-最高 到 5-最低)
除了 time_period 和 domain_focus 在不适用时可以为 null 外,每个子任务的所有字段(id, query, source_type, time_period, domain_focus, priority)都是必需的。
创建 2 个子任务,这些子任务将共同全面覆盖该主题。请关注信息的不同方面、视角或来源。
每个子任务将包括以下信息:
id: str
query: str
source_type: str # 例如:"web", "news", "academic", "specialized"
time_period: Optional[str] = None # 例如:"today", "last week", "recent", "past_year", "all_time"
domain_focus: Optional[str] = None # 例如:"technology", "science", "health"
priority: int # 1 (最高) 到 5 (最低)
获取上述子任务信息后,你将添加两个额外的字段。这两个字段对应于 start_date 和 end_date。请根据当前日期和选择的 time_period 推断此信息。start_date 和 end_date 应使用如下示例中的格式:
"start_date": "2024-06-03T06:00:00.000Z",
"end_date": "2024-06-11T05:59:59.999Z",
上述提示的许多部分都需要仔细考虑:到底向 planning agent 提供什么确切的上下文,以使其有效地执行任务。如你所见,这不仅仅是设计一个简单的提示或指令;这个过程需要实验,并为模型提供重要的上下文以使其更好地执行任务。
让我们将问题分解为有效上下文工程的关键核心组件。
指令
指令是提供给系统的高级指令,用以确切地指示它该做什么。
你是一位专业的研究规划师。你的任务是将一个复杂的研究查询(由 <user_query></user_query> 分隔)分解为具体的搜索子任务,每个子任务关注不同的方面或来源类型。
许多初学者甚至经验丰富的AI开发人员可能就到此为止了(注:咋可能到这里就停了,达不到预期的效果要么换模型,要么就是丢给模型让他自己丰富提示词)。鉴于我上面分享了完整的提示,你可以发现为了让系统按我们的意愿工作,我们还需要给它多少上下文。这就是上下文工程的意义所在:它让系统更了解问题的范围以及我们究竟期望它做什么的细节。
用户输入
用户输入没有在系统提示中显示,但下面是它可能的样子:
<user_query> OpenAI 有哪些最新的开发者新闻? </user_query>
请注意分隔符的使用,这是为了更好地构建提示。这对于避免混淆很重要,且增加了用户输入是什么以及我们希望系统生成什么的清晰度。有时,我们输入的信息类型与我们希望模型输出的内容有关(例如,查询是输入,子查询是输出)(注:这句话没看懂想说啥)。
结构化输入和输出
除了高级指令和用户输入之外,你可能已经注意到,我花了相当大的精力在planning agent需要生成的子任务的细节上。以下是我为planning agent提供的详细说明,以便根据用户查询创建子任务。
对于每个子任务,请提供:
1. 子任务的唯一字符串 ID(例如,'subtask_1', 'news_update')
2. 针对主查询的某个方面提出的具体搜索查询
3. 要搜索的来源类型(web, news, academic, specialized)
4. 时间段相关性(today, last week, recent, past_year, all_time)
5. 领域焦点(如果适用)(technology, science, health, 等)
6. 优先级(1-最高 到 5-最低)
除了 time_period 和 domain_focus 在不适用时可以为 null 外,每个子任务的所有字段(id, query, source_type, time_period, domain_focus, priority)都是必需的。
创建 2 个子任务,这些子任务将共同全面覆盖该主题。请关注信息的不同方面、视角或来源。
我希望planning agent生成的信息结构化为一个列表,并附上一些提示/示例,以更好地引导数据生成过程。这对于给 agent 提供关于预期结果的额外上下文至关重要(注:这在早期的大部分提示词教程都有提到,并不是新鲜玩意儿。但实际上并不总是可控的)。例如,如果你不告诉它你希望优先级是 1-5 的范围,那么系统可能会倾向于使用 1-10 的范围。再次强调,这个上下文非常重要!
接下来,让我们谈谈结构化输出。为了从planning agent那里获得一致的输出,我们还提供了一些关于我们期望的子任务格式和字段类型的上下文。以下是我们作为额外上下文传递给 agent 的示例。这将为 agent 提供关于我们期望输出的提示和线索:
每个子任务将包括以下信息:
id: str
query: str
source_type: str # 例如:"web", "news", "academic", "specialized"
time_period: Optional[str] = None # 例如:"today", "last week", "recent", "past_year", "all_time"
domain_focus: Optional[str] = None # 例如:"technology", "science", "health"
priority: int # 1 (最高) 到 5 (最低)
除此之外,在 n8n 内部,你还可以使用工具输出解析器,它实质上将用于结构化最终输出(注:这个技巧很常见了)。我使用的选项是提供一个 JSON 示例如下:
{
"subtasks": [
{
"id": "openai_latest_news",
"query": "最新的 OpenAI 公告和新闻",
"source_type": "news",
"time_period": "recent",
"domain_focus": "technology",
"priority": 1,
"start_date": "2025-06-03T06:00:00.000Z",
"end_date": "2025-06-11T05:59:59.999Z"
},
{
"id": "openai_official_blog",
"query": "OpenAI 官方博客近期帖子",
"source_type": "web",
"time_period": "recent",
"domain_focus": "technology",
"priority": 2,
"start_date": "2025-06-03T06:00:00.000Z",
"end_date": "2025-06-11T05:59:59.999Z"
},
...
}
然后,该工具将自动从这些示例中生成模式(schema),这反过来又允许系统解析和生成正确的结构化输出,如下例所示:
[
{
"action": "parse",
"response": {
"output": {
"subtasks": [
{
"id": "subtask_1",
"query": "OpenAI 最近的公告或新闻或更新",
"source_type": "news",
"time_period": "recent",
"domain_focus": "technology",
"priority": 1,
"start_date": "2025-06-24T16:35:26.901Z",
"end_date": "2025-07-01T16:35:26.901Z"
},
{
"id": "subtask_2",
"query": "OpenAI 官方博客或新闻稿",
"source_type": "web",
"time_period": "recent",
"domain_focus": "technology",
"priority": 1.2,
"start_date": "2025-06-24T16:35:26.901Z",
"end_date": "2025-07-01T16:35:26.901Z"
}
]
}
}
}
]
这些东西看起来很复杂,但如今许多工具都提供了开箱即用的结构化输出功能,你不需要自己实现。n8n 使这部分上下文工程变得轻而易举。这是我看到许多AI开发者忽略原因(注:其实就是工具高度封装了,不需要关心了)。希望上下文工程能更多地揭示这些重要技术。这是一个非常强大的方法,特别是当你的 agent 得到的输出不一致。
工具调用
我们正在使用 n8n 来构建我们的 agent ,所以很容易将当前日期和时间放入上下文中。你可以这样做:
当前日期和时间是:{{ $now.toISO() }}
这是一个在 n8n 中调用的简单便捷的函数,但通常会将其构建为一个专用工具,可以帮助使事情更具动态性(即,仅在查询需要时才获取日期和时间)。这就是上下文工程的意义所在。它迫使你,作为构建者,就传递什么上下文以及何时将其传递给 LLM 做出具体的决定(注:其实这部份在MCP里面也是这么用的)。这很好,因为它消除了你应用程序中的假设和不准确性。
日期和时间是系统的重要上下文;否则,它在处理需要了解当前日期和时间的查询时往往表现不佳。例如,如果我要求系统搜索上周发生的 OpenAI 最新开发者新闻,它只会猜测日期和时间,这将导致次优的查询,从而导致不准确的网络搜索。当系统拥有正确的日期和时间时,它可以更好地推断日期范围,这对于搜索 agent 和工具非常重要。我将此作为上下文的一部分添加,以允许 LLM 生成日期范围:
获取上述子任务信息后,你将添加两个额外的字段。这两个字段对应于 start_date 和 end_date。请根据当前日期和选择的 time_period 推断此信息。start_date 和 end_date 应使用如下示例中的格式:
"start_date": "2024-06-03T06:00:00.000Z",
"end_date": "2024-06-11T05:59:59.999Z",
我们专注于我们架构的planning agent,所以这里不需要添加太多工具。唯一有意义的另一个工具是检索工具,该工具根据查询检索相关的子任务。让我们在下面讨论这个想法。
RAG 与记忆
我构建的这个深度研究应用的第一个版本不需要使用短期记忆,但我们构建了一个版本,可以缓存不同用户查询的子查询。这对于在工作流中实现一些加速/优化很有用。如果一个类似的用户查询之前已经被使用过,可以将这些结果存储在向量存储中,并通过搜索它们来避免为我们已经生成并存在于向量存储中的计划创建一组新的子查询(注:这个思想其实也很朴素,在搜索技术里面已经很常见了)。请记住,每次调用 LLM API 时,你都在增加延迟和成本。
这是聪明的上下文工程,因为它使你的应用程序更具动态性、更便宜、更高效。你看,上下文工程不仅仅是优化你的提示;它是关于为你的目标选择正确的上下文。你还可以更有创意地维护该向量存储以及如何将那些现有的子任务拉入上下文中。富有创意和新颖的上下文工程就是护城河(注:其实也不是,很快大模型都能把这些事情做到。真切解决用户需求,且能规模化低成本复制才是护城河)!
状态与历史上下文
这部份内容没有在深度研究 agent 的 v1 版本中展示它,但这个项目的一个重要部分是优化结果以生成最终报告。在许多情况下, agent 系统可能需要修改所有或部分的查询、子任务,以及可能从网络搜索 API 中提取的数据。这意味着系统将多次尝试解决问题,并且需要访问先前的状态和系统所有可能的历史上下文。
在我们的用例中,这意味着什么?在我们的例子中,这可能意味着让 agent 访问子任务的状态、修订(如果有的话)、工作流中每个 agent 的过去结果,以及任何其他有助于修订阶段的必要上下文(注:其实也类似于MCP里面的序列思考)。对于这类上下文,我们传递的内容将取决于你优化的目标。这里会发生大量的决策。上下文工程并非总是直截了当的,我想你可以开始想象这个组件需要多少次迭代。这就是为什么我一直强调其他领域(如评估)的重要性的原因。如果你不衡量所有这些事情,你怎么知道你的上下文工程努力是否奏效(注:那咋衡量你倒是说啊)?
高级上下文工程 [施工中]
本文没有涵盖上下文工程的许多其他方面,例如上下文压缩、上下文管理技术、上下文安全性和评估上下文有效性(即,衡量该上下文随时间变化的有效性)。我们将在未来的文章中分享更多关于这些主题的想法。
上下文可能会被稀释或变得低效(即,充满了陈旧和不相关的信息),这需要特殊的评估工作流来捕获这些问题。
我预计上下文工程将继续发展,成为AI开发者/工程师的一套重要技能。除了手动上下文工程,还有机会构建自动化有效上下文工程处理的方法。我见过一些工具尝试过这一点,但这个领域需要取得更多进展。
资源
原文链接: 谷歌文档
以下是一些最近撰写过关于上下文工程的其他人的推荐读物:
- https://www.promptingguide.ai/
- https://rlancemartin.github.io/2025/06/23/context_engineering/
- https://x.com/karpathy/status/1937902205765607626
- https://www.philschmid.de/context-engineering
- https://simple.ai/p/the-skill-thats-replacing-prompt-engineering?
- https://github.com/humanlayer/12-factor-agents
- https://blog.langchain.com/the-rise-of-context-engineering/
如果本文中有任何错误,请联系原作者。
译者注
通读全文其实不难发现:这实际上就是DAIR.AI Academy的卖课软文。不管现在国内外有多少人讲这个Context Engineering,其核心实质不会变:那就是如何高效的构建一个低成本、高响应、满足用户需求的agent。只要抓住这个核心点去思考,很多传统工程的思想都可以复用。各位看官们,无论你是产品、还是开发、抑或是创始人,不必被这种咋咋呼呼的文章搞的焦虑。沉下心去做满足用户需求的应用,市场终给予反馈的。