【摘要】探讨了从提示工程到上下文工程的范式转变,深入剖析了在LLM有限注意力预算下面临的核心挑战,并系统性地提出了包括“最小高信号集”原则、结构化设计、即时检索及面向长时任务的压缩、笔记、子代理等高级工程策略与落地清单。
引言
在过去几年,我们见证了AI应用开发焦点的迁移。最初,大家的目光都集中在提示工程(Prompt Engineering),试图为大型语言模型(LLM)找到最完美的词语与短语。但随着AI代理(Agent)系统从单轮问答走向多轮、长期、复杂的任务,一个更宏大、更系统性的问题浮出水面:“哪种上下文配置,最有可能促使我们的模型产生期望的行为?”
这便是上下文工程(Context Engineering)的由来。
它不再仅仅是关于“说什么”,而是关于“让模型看到什么”。上下文,即模型在进行推理时所能感知到的全部信息集合。我们面临的工程挑战,正是在LLM固有的约束下,优化这组信息的效用,以持续获得稳定、可控的结果。有效地驾驭LLM,需要我们从一个全新的视角思考——将模型可用的整体状态,以及该状态可能催生的潜在行为,作为一个完整的系统来设计。
这篇文章将深入剖析上下文工程这门新兴的艺术,为你提供一个改进的思维模型,用于构建更高效、更可控的AI代理。
一、🌊 上下文工程的提出与意义
上下文工程的出现,并非凭空创造,而是技术发展的必然。当AI的应用场景从简单的文本生成扩展到能够自主规划、执行、反思的代理系统时,原有的工程方法便显得捉襟见肘。
1.1 从提示工程到上下文工程的演进
提示工程,专注于为LLM编写和组织指令,以期达到最佳的单次输出。它更像是一种“指令的艺术”。而上下文工程,则是一套更宏大的策略,它在LLM整个推理生命周期中,动态地策划和维护一个最佳的信息集合。
我们可以将提示工程视为上下文工程的一个重要子集。上下文的范畴远比提示要广阔,它是一个动态变化的信息生态系统。
正如上表所示,上下文工程要求工程师的角色发生转变。我们不再仅仅是“提示词作者”,而更像是“信息架构师”或“系统设计师”。我们需要思考数据如何在代理系统中流动,如何管理短期记忆与长期知识,以及如何协调模型与外部工具的交互。这种转变,对工程师的能力提出了远超“写作技巧”的更高要求。
1.2 为何代理系统必须拥抱上下文工程
代理系统以循环方式运行。它感知环境,进行思考,采取行动,然后再次感知行动后的新环境。这个循环会不断产生新的信息,这些信息对于下一轮的决策至关重要。
如果一个代理只依赖一次性注入的静态提示,它在实际部署中几乎必然会失败。因为它无法处理在任务执行过程中出现的新情况、新数据。一个动态的系统,必须能够在运行时自动为模型装配“正确的信息、正确的工具与相关的历史”,这正是上下文工程的核心价值所在。
二、🎯 核心挑战:与有限注意力的博弈
构建高效的上下文系统,意味着我们必须直面LLM的固有局限。这些局限构成了上下文工程必须解决的核心挑战。
2.1 上下文窗口的物理限制
LLM的上下文窗口(无论是8k, 32k, 还是更大的128k tokens)决定了模型在任一时刻能“看见”的信息总量。这扇窗户的大小是有限的。当信息过载时,一系列问题便会随之而来。
因此,一个朴素的观念——“上下文窗口越长越好”——在实践中是站不住脚的。更长的上下文窗口仅仅是提供了更大的“场地”,但如何在这块场地上高效地组织信息,避免上述问题,才是关键。长上下文的边际收益是递减的。
2.2 “上下文衰减”与注意力预算
即便信息没有过载,随着上下文长度的增加,模型的性能也会自然下降。关于“大海捞针”(Needle in a Haystack)的基准测试清晰地揭示了这一现象。测试将一个关键信息(“针”)放置在大量无关文本(“干草堆”)的不同位置,然后要求模型找出它。结果显示,随着“干草堆”越来越大,模型找到“针”的准确率会显著下降。
这种“上下文衰减”(Context Decay)或“上下文腐烂”(Context Rot)的现象,源于几个深层原因。
架构限制:LLM大多基于Transformer架构,其核心的自注意力机制理论上允许每个token关注所有其他token。这导致了对于
n
个token,需要处理n²
对关系。随着n
的增长,模型有效捕捉所有这些成对关系的能力会变得稀疏。注意力被分散了。训练数据分布:在模型的训练数据中,短序列文本通常远比极长的序列文本更常见。这意味着模型在处理长距离依赖关系方面“经验较少”,专门用于处理这类任务的参数也相对不足。
位置编码的挑战:诸如位置编码插值等技术,虽然允许模型处理比其预训练时更长的序列,但代价是牺牲了一部分对token精确位置的理解力。
这些因素共同作用,导致了模型性能的渐变式下降,而非硬性的断崖。模型在长上下文上依然强大,但相比于在短上下文中的表现,其信息检索的精准度和长距离推理的可靠性可能会降低。
我们可以将此比作人类的“注意力预算”。每个人都拥有有限的工作记忆容量。当处理的信息过多时,我们也会感到困惑、遗忘细节。LLM同样如此,每个新引入的token都会消耗一部分宝贵的“注意力预算”。这使得我们必须像管理稀缺资源一样,去仔细管理模型可用的每一个token。
2.3 动态任务的循环难题
如前所述,代理是循环运行的。这意味着上下文是“活”的,它在不断演变。
第一轮:代理接收初始任务,上下文相对干净。
第二轮:代理调用了一个工具,返回了大量数据。这些数据现在成了上下文的一部分。
第三轮:代理根据返回的数据进行了分析,生成了中间结论。这些结论也进入了上下文。
第N轮:上下文窗口中已经充满了历史对话、工具输出、中间思考……此时,最初的核心任务指令可能已经被“淹没”。
如何在这种动态演变中,周期性地完善和筛选信息,确保模型在每一轮都能聚焦于最重要的部分,是上下文工程必须解决的动态难题。
2.4 记忆与工具的集成鸿沟
LLM本身是无状态的,它们没有长期记忆。一次会话结束后,所有的上下文都会丢失。为了让代理能够执行长期任务,我们必须为其设计外部记忆机制。
这里的挑战在于融合与检索。
如何融合:当代理通过工具与外部世界(如数据库、文件系统、API)交互后,如何将返回的结果以一种高效、易于理解的方式注入到上下文中?是直接塞入原始JSON,还是先进行总结?
如何检索:当代理需要回忆过去的某个关键信息时,如何设计一个高效的检索系统,从庞大的外部记忆库中,精准地找到那一小段最相关的内容,并呈现给模型?
解决这个集成鸿沟,是实现代理长期连贯性和任务执行能力的前提。
三、🛠️ 核心原则与策略:精雕细琢的艺术
面对上述挑战,上下文工程提出了一系列核心原则与实践策略。它们的目标统一,即在LLM有限的注意力预算下,实现性能的最大化。
3.1 “最小高信号集”原则
这是上下文工程的最高指导原则。上下文不是越多越好,而是要追求最相关、最有用的信息。我们的目标,是在有限的token预算内,找到一个信息量最大、噪声最小的“最小高信号集”(Minimum High-Signal Set),以最大化模型产生期望行为的概率。
这个原则贯穿于上下文设计的每一个环节。它要求我们不断自问:
这段信息是必需的吗?
它能否用更简洁的方式表达?
它对于模型接下来的决策,提供了多少“信号”?
实践这一原则,比说起来要困难得多。但它是我们优化上下文的北极星。
3.2 结构化与分层设计
混乱是注意力的天敌。通过结构化和分层,我们可以极大地降低模型的理解成本,帮助它快速定位关键信息。
3.2.1 系统提示的“黄金高度”
系统提示是代理行为的基石。一个好的系统提示,应该处在一个“黄金高度”(Golden Altitude)上。这个高度,介于两种常见的失败模式之间。
过低的高度(硬编码逻辑):工程师在提示中用僵化的if-else式伪代码,试图精确控制代理的每一步行为。这种方法非常脆弱,难以维护,并且扼杀了模型的灵活性。
过高的高度(模糊指导):工程师提供过于笼统、高层次的指导,例如“请成为一个有用的助手”。这种提示未能提供具体、可操作的行为信号,或者错误地假设了模型与我们共享了大量隐性知识。
最佳的“高度”在于取得平衡。它既要足够具体,以有效指导行为;又要足够灵活,为模型提供强大的启发式方法,而非僵化的规则。
一个有效的实践是,将提示组织成不同的逻辑部分,并使用XML标签或Markdown标题等技术来明确区分。
xml:
<background_information>
你是一个专业的代码审查机器人。你的目标是帮助开发者发现潜在的bug和不符合规范的代码。
</background_information>
<instructions>
1. 首先,通读整个代码文件,理解其核心功能。
2. 其次,重点检查以下几个方面:空指针引用、资源未释放、不一致的命名风格。
3. 最后,以JSON格式输出你的审查意见。
</instructions>
<tool_guidelines>
你可以使用
file_reader.read(path)
工具来读取文件内容。</tool_guidelines>
<output_description>
请严格按照以下JSON格式输出,不要添加任何额外的解释性文字。
{
"reviews": [
{
"line_number": <line>,
"issue_type": "<type>",
"comment": "<your_comment>"
}
]
}
</output_description>
这种结构化的方式,就像为模型提供了一份清晰的“阅读指南”,让它能快速理解自己的角色、任务、可用工具和期望的输出格式。
3.2.2 工具设计的“契约精神”
工具是代理与外部世界交互的桥梁,它们定义了代理与环境之间的“契约”。一个设计良好的工具集,对于上下文效率至关重要。
功能单一与独立:每个工具应该只做一件事,并把它做好。这类似于软件工程中的“单一职责原则”。
容错与清晰:工具应该能优雅地处理错误,并返回清晰、可操作的错误信息,而不是简单地崩溃或返回空值。
参数无歧义:工具的输入参数应该有描述性,避免使用像
data
,input
这样模糊的名称,并利用模型的自然语言理解能力。Token高效:工具的返回值应该尽可能简洁。如果一个API返回了一个巨大的JSON对象,最好在工具层面就将其处理成一个更小、更结构化的摘要,再送入上下文。
我们遇到的最常见的失败模式之一,就是工具集臃肿。过多的工具,或者功能严重重叠的工具,会给模型带来不必要的决策负担。如果一个人类工程师都无法在某个场景下快速判断应该使用哪个工具,我们就不应该对AI代理抱有更高的期望。
因此,为代理精心策划一个“最小可行工具集”(Minimal Viable Toolset),是保证其长期可靠运行的关键一步。
3.2.3 少样本示例的“范式力量”
提供示例,即少样本提示(Few-shot Prompting),是一种广为人知的最佳实践。然而,这里的关键是“质”而非“量”。
很多团队倾向于在提示中塞入一长串边缘案例,试图覆盖所有可能的情况。我们不建议这样做。这会迅速消耗宝贵的上下文空间,并可能引入噪声。
相反,我们应该努力精心挑选一小组多样化、规范化的示例。这些示例应该能有效地展示代理的预期行为模式、思考过程和输出格式。对于LLM来说,一个好的示例,真正是“一图胜千言”。它能帮助模型捕捉到那些难以用语言精确描述的“感觉”或“风格”。
例如,与其用大段文字描述如何写一份好的代码审查评论,不如直接给出一两个高质量的示例。
用户输入:
def process_data(data):
if data is not None:
print(data['key'])
审查示例:
{
"reviews": [
{
"line_number": 3,
"issue_type": "Potential KeyError",
"comment": "在访问`data['key']`之前,建议先检查'key'是否存在于字典`data`中,例如使用`data.get('key')`或`'key' in data`,以避免在'key'不存在时引发KeyError。"
}
]
}
通过这样的范式,模型能更快地学会期望的输出结构和评论的专业口吻。
3.3 上下文检索的“即时”智慧
面对海量信息,我们不可能把所有内容都预先加载到上下文中。一种更智能、更高效的策略正在兴起,即“即时”(Just-in-Time)上下文加载。
这种方法模仿了人类的认知习惯。我们通常不会记住整本书的内容,而是记住书名、章节和索引,然后在需要时去翻阅。对于AI代理,这意味着:
维护轻量级引用:代理不直接持有大量数据,而是维护指向这些数据的轻量级标识符,如文件路径、数据库查询语句、网页链接等。
按需动态加载:当任务需要某部分信息时,代理使用工具(如文件读取器、数据库查询工具)在运行时动态地将这部分数据加载到上下文中。
例如,一个用于分析大型代码库的代理,它不需要在一开始就读取所有.py
文件。相反,它可以先使用ls -R
或glob
等命令来了解文件结构。当它发现一个名为src/core_logic/payment_processing.py
的文件时,其路径和命名本身就提供了强烈的信号。然后,它可能只使用head
或tail
命令先看文件的开头和结尾,以快速评估其内容,只有在确定高度相关后,才将整个文件读入上下文。
这种“渐进式披露”(Progressive Disclosure)的策略,允许代理通过探索逐步构建对环境的理解,每次只将最必要的信息保留在“工作记忆”(即上下文窗口)中。
当然,这种方法也有权衡。运行时探索比预先计算和检索要慢。因此,在实践中,混合策略通常是最高效的。
预检索/预置:对于那些静态、高价值、几乎肯定会用到的信息(如核心配置文件、项目需求文档),可以在任务开始时就通过RAG等技术检索并置入上下文。
自主探索:对于那些动态、复杂或不确定的信息空间,则赋予代理自主探索和即时检索的能力。
“正确”的自主级别取决于任务的性质。随着模型能力的提高,代理设计的趋势将是让智能模型更智能地运作,减少人类的预先策划。
四、🏗️ 高级工程策略:构建坚固的上下文大厦
当任务的复杂度超越了单次交互,尤其是对于需要跨越数小时甚至数天的长时域任务时,我们需要更高级的工程策略来系统性地管理上下文。这些策略就像是建造一座坚固大厦的脚手架和结构梁,确保代理的行为在长时间跨度内保持连贯和目标导向。
4.1 四大核心操作:写入、选择、压缩、隔离
我们可以将复杂的上下文管理操作,归纳为四个核心的工程原语:写入(Write)、选择(Select)、压缩(Compress)和隔离(Isolate)。这四个操作共同构成了一个完整的上下文管理生命周期。
这四大操作并非孤立存在,而是在代理的运行循环中协同工作。
这个流程图展示了一个典型的上下文管理循环。新信息进入后,系统通过选择操作从外部记忆中检索相关内容。LLM推理后产生的输出,一部分通过写入操作持久化,另一部分可能通过压缩操作精简后保留在当前上下文中。在需要处理并行或独立的子任务时,隔离操作会创建独立的上下文环境。
4.2 面向长时域任务的组合技术
对于那些需要持续工作数小时甚至数天的长时域任务,例如大型代码库迁移或全面的学术研究项目,单一策略往往不够。我们需要将上述策略组合起来,形成更强大的技术方案。
4.2.1 压缩(Compaction):滚动的记忆窗口
这是处理超长对话最直接有效的方法。当对话历史接近上下文窗口的上限时,系统会触发一个压缩流程。
触发:监控上下文token数量,达到预设阈值(例如80%)。
概括:调用LLM自身,对当前的对话历史进行一次高保真的概括,要求其提炼出关键决策、未解决的问题和当前的任务状态。
重置:开启一个全新的上下文窗口,将这个新生成的摘要作为对话的开场白。
继续:代理在这个包含了历史精华的新窗口中继续工作。
这种方法就像一个滚动的记忆窗口,它丢弃了琐碎的细节,但保留了对话的主线,从而在理论上无限长的交互中保持连贯性。
4.2.2 结构化笔记(代理记忆):外部的思考便签
结构化笔记,或称为代理记忆(Agentic Memory),是一种更主动的记忆管理技术。代理不再被动地等待上下文溢出,而是有意识地、定期地将自己的“思考”写入外部存储。
这种技术非常强大,因为它以极小的开销提供了一个持久化的“第二大脑”。
实践形式:最简单的形式,就是让代理维护一个
NOTES.md
或TODO.md
文件。在系统提示中明确指示它:“在每一步行动后,更新你的笔记文件,记录你的进展、发现和下一步计划。”惊人效果:在一些实验中,例如让Claude模型玩《宝可梦》游戏,这种简单的笔记策略展现了惊人的能力。代理能够精确地记录成千上万个游戏步骤中的统计数据,比如“在1号道路上训练皮卡丘,已从8级升至9级,目标10级”。它会自发地绘制已探索区域的地图,记录关键成就,甚至维护战斗策略笔记,分析哪种攻击对不同对手最有效。
恢复能力:当上下文因为某种原因(如系统重启)重置后,代理只需读取自己的笔记,就能无缝地继续之前的任务,无论是多小时的练级序列还是复杂的地下城探索。这种跨越上下文重置的连贯性,是单纯依赖LLM内置上下文窗口无法实现的。
Anthropic等公司已经开始将这种能力产品化,例如提供专门的“记忆工具”,通过一个简单的基于文件的系统,让代理能更方便地存储和查阅上下文之外的信息。
4.2.3 子代理架构:分而治之的智慧
当任务的复杂度高到单一代理难以维护其全部状态时,子代理架构(或多代理系统)就成了必然选择。
其核心思想是“分而治之”。
任务分解:一个高层的主代理(Master Agent)负责理解总体任务,并将其分解为多个更小、更专注的子任务。
分派工作:主代理将这些子任务分派给专门的子代理(Sub-agents)。例如,一个“研究员”子代理负责文献检索,一个“程序员”子代理负责代码实现,一个“测试员”子代理负责编写和运行测试。
独立探索:每个子代理在自己独立的上下文窗口中工作。它们可以进行广泛的探索,调用大量工具,消耗数万甚至更多的token,而不必担心污染主代理的上下文。
精炼汇报:当子代理完成其任务后,它不会返回所有的原始过程和数据。相反,它会生成一份精炼、浓缩的摘要(通常在1000-2000 token以内),只包含最终结果和最重要的发现。
综合决策:主代理收集所有子代理的汇报,进行综合、分析,并做出最终的决策或生成最终的报告。
这种模式实现了关注点的清晰分离。详细、嘈杂的探索过程被隔离在子代理的“房间”里,而主代理的“会议室”则保持干净,只专注于高层次的战略合成。研究表明,在复杂的研发和分析任务上,这种多代理系统的表现显著优于单代理系统。
当然,这种架构也带来了更高的总体token成本和更复杂的系统设计。工程师需要在任务价值与实现成本之间做出权衡。
五、📈 工程落地与未来展望
理论和策略最终要服务于实践。如何将上下文工程的理念,转化为可操作的工程实践,并为未来的技术演进做好准备,是每个AI工程师都需要思考的问题。
5.1 可操作的工程落地清单
以下是一份可以帮助你开始实践上下文工程的清单,它融合了多家AI研究机构的最佳实践。
工具集审查:
构建最小可行工具集。审计你现有的工具,移除功能重叠或很少使用的工具。
确保工具返回结构化、简洁的结果。避免直接返回庞大的、未处理的API响应。
上下文检索策略:
实施动态检索。对于大型知识库,优先采用RAG或关键字检索,只将最相关的片段注入上下文。
探索混合策略。将静态、高价值的信息(如核心配置)预置到上下文中,同时为动态信息提供即时检索工具。
利用重排(Re-ranking)。对于检索到的多个文档片段,可以再用一个轻量级模型或规则对其进行重排,将最可能相关的放在最前面或最后面(“Lost in the Middle”现象)。
记忆架构设计:
建立分层记忆系统。一个简单的实现是:短期记忆(最近几轮对话)保留在上下文中,中长期记忆(关键决策、摘要)写入外部文件或数据库。
为代理提供明确的笔记指令。在系统提示中鼓励或要求代理使用笔记工具。
监控与压缩:
建立token审计机制。监控每次调用中上下文的token构成(提示、历史、工具输出各占多少),识别优化点。
配置自动压缩策略。当上下文长度达到阈值时,自动触发对话摘要流程。
提示与输出格式:
使用结构化提示。采用XML或Markdown等格式组织系统提示。
固定输出模板。对于需要稳定、可解析输出的场景,提供清晰的少样本示例和输出格式描述(如JSON Schema)。
5.2 与长上下文模型的关系
随着技术发展,模型厂商正在不断推出具有更大上下文窗口的模型,甚至达到了百万级token。这是否意味着上下文工程将变得不再重要?
答案是否定的。长上下文窗口并不能完全替代上下文工程,它们是互补关系。
新的可能性:百万级token窗口确实为一些过去难以实现的应用打开了大门,例如对整本小说进行分析,或一次性处理数百页的法律文件。
挑战依然存在:
成本激增:长上下文的推理成本(无论是时间还是金钱)远高于短上下文。盲目地填充上下文是一种巨大的浪费。
“上下文分散”问题:即使在长窗口中,“大海捞针”的问题依然存在,甚至可能更严重。信息密度过低,会导致模型注意力分散,性能下降。
质量与长度的非线性关系:实践表明,简单地将上下文长度翻倍,并不能带来性能的线性提升。如果没有良好的信息组织,性能甚至可能下降。
因此,即使拥有了巨大的上下文窗口,检索、压缩、重排和结构化表示等上下文工程技术,仍然是确保模型高效、可靠运行的关键。长窗口为我们提供了更大的“舞台”,而上下文工程则是指导演员在这个舞台上如何表演的“剧本”。
5.3 未来趋势
上下文工程是一个快速发展的领域。未来,我们可以预见以下几个趋势:
从指令性工程到自主性代理:随着模型本身能力的提升,我们将需要更少的“微观管理”。工程师的工作将更多地转向设计良好的环境、工具和高层目标,而不是编写详尽的指令。上下文工程的重点将从“如何告诉模型做什么”转向“如何为模型创造一个能让它自己想明白做什么的环境”。
更智能的上下文管理工具:未来,可能会出现更多由AI驱动的上下文管理工具。例如,能够自动学习何时压缩、如何总结、以及从外部记忆中检索什么信息的“元代理”(Meta-Agent)。
模型架构的演进:新的模型架构,如分层注意力、稀疏注意力或基于状态空间模型(如Mamba)的架构,可能会在原生层面更好地处理长上下文,从而改变我们进行上下文工程的具体方法。
对于工程师而言,保持对这些前沿领域的关注,持续学习和实践,将是保持核心竞争力的关键。
结论
上下文工程标志着我们构建AI系统范式的深刻转变。它要求我们从一个“提示词工匠”,进化为一个“信息生态设计师”。我们不再仅仅是与模型对话,而是在为其构建一个高效、有序、信号清晰的“世界”。
在这个世界里,每一步操作——无论是为长时任务实现压缩,设计一个token高效的工具,还是让代理能够即时探索其环境——都遵循着一个不变的核心原则:找到最小的高信号令牌集,以最大化期望结果的可能性。
随着模型能力的不断演进,我们对代理的指令性工程会越来越少,代理的自主性会越来越高。但是,将上下文视为一种宝贵且有限的资源,并用系统性的工程思维去精心管理它——这种理念,将长久地作为构建可靠、有效AI代理的基石。
📢💻 【省心锐评】
上下文工程,本质是为AI代理设计一个高效的“信息消化系统”。别再迷信无限窗口,学会剪枝、摘要和分层,才是通往生产级应用的正道。
评论