AI agent的有效上下文工程
Effective context engineering for AI agents
Anthropic 提出上下文工程(context engineering)作为提示工程(prompt engineering)的自然演进,旨在策划和维护大语言模型(LLM)推理过程中的最优token集合,包括系统提示词、工具、Model Context Protocol (MCP)、外部数据、消息历史等。文章指出,LLM受限于Transformer架构带来的注意力预算,随着上下文窗口token增加,信息检索和长程推理精度下降。Anthropic 团队(Prithvi Rajasekaran、Ethan Dixon、Carly Ryan、Jeremy Hadfield 等)介绍了压缩(compaction)、结构化笔记(structured note-taking)和多agent架构(multi-agent architectures)等技术,以在长周期任务中保持agent连贯性。Claude Code 采用混合策略,通过 `CLAUDE.md` 文件和 `glob`、`grep` 等原语实现即时上下文检索。
在提示工程(prompt engineering)成为应用AI领域关注焦点的几年之后,一个新术语开始崭露头角:上下文工程(context engineering)。使用语言模型构建应用,正逐渐从为提示词寻找恰当的词语和短语,转向回答一个更广泛的问题:“什么样的上下文配置最有可能让我们的模型产生期望的行为?”
上下文(context)指的是从大语言模型(LLM)采样时包含的token集合。当前面临的工程问题,是在LLM固有的约束条件下优化这些token的效用,以持续达成期望的结果。有效地驾驭LLM通常需要从上下文的角度思考——换句话说,要考虑LLM在任何给定时刻可用的整体状态,以及这种状态可能产生的潜在行为。
在这篇文章中,我们将探讨新兴的上下文工程艺术,并提供一种更精炼的心智模型,用于构建可控且高效的agent。
在Anthropic,我们将上下文工程视为提示工程的自然演进。提示工程指的是编写和组织LLM指令以获得最佳结果的方法(详情请参阅我们的文档,了解概述和有用的提示工程策略)。上下文工程则指的是一套策略,用于在LLM推理过程中策划和维护最优的token(信息)集合,包括提示词之外可能出现的所有其他信息。
在LLM工程应用的早期,提示是AI工程工作的最大组成部分,因为除了日常聊天交互之外的大多数用例,都需要针对一次性分类或文本生成任务优化提示词。顾名思义,提示工程的主要焦点是如何编写有效的提示词,特别是系统提示词。然而,随着我们转向构建能够在多轮推理和更长时间跨度内运行的、能力更强的agent,我们需要管理整个上下文状态(系统指令、工具、Model Context Protocol (MCP)、外部数据、消息历史等)的策略。
一个在循环中运行的agent会产生越来越多可能与下一轮推理相关的数据,这些信息必须被循环地精炼。上下文工程是一门艺术和科学,旨在从那个不断演变的、包含所有可能信息的宇宙中,策划出哪些内容将被放入有限的上下文窗口。
尽管LLM速度很快,并且能够管理越来越大的数据量,但我们观察到,它们和人类一样,在某个点上会失去焦点或感到困惑。对“大海捞针”式基准测试的研究揭示了“上下文腐烂”(context rot)的概念:随着上下文窗口中的token数量增加,模型从该上下文中准确回忆信息的能力会下降。
虽然有些模型的性能下降比其他的更平缓,但这种特性在所有模型中都会出现。因此,上下文必须被视为一种边际收益递减的有限资源。就像人类的工作记忆容量有限一样,LLM在解析大量上下文时,会动用它们的“注意力预算”。每引入一个新的token,都会在一定程度上消耗这个预算,从而增加了精心策划LLM可用token的必要性。
这种注意力稀缺源于LLM的架构限制。LLM基于Transformer(变换器)架构,该架构使得每个token都能关注整个上下文中的其他所有token。对于n个token,这会产生n²个成对关系。
随着上下文长度的增加,模型捕捉这些成对关系的能力会被稀释,从而在上下文大小和注意力焦点之间产生一种自然的张力。此外,模型从训练数据分布中发展出其注意力模式,在这些分布中,较短的序列通常比较长的序列更常见。这意味着模型在处理上下文范围的依赖关系方面经验较少,专用参数也较少。
像位置编码插值(position encoding interpolation)这样的技术,允许模型通过适应其最初训练的较小上下文来处理更长的序列,尽管在token位置理解上会有一些退化。这些因素创造了一个性能梯度,而不是一个硬性的悬崖:模型在较长的上下文上仍然具有很强的能力,但与在较短上下文上的表现相比,在信息检索和长程推理方面的精度可能会降低。
这些现实意味着,深思熟虑的上下文工程对于构建有能力的agent至关重要。
鉴于LLM受到有限注意力预算的约束,良好的上下文工程意味着找到尽可能小的、高信号token集合,以最大化某个期望结果的可能性。实施这种做法说起来容易做起来难,但在下一节中,我们将概述这一指导原则在上下文的不同组成部分中的实际含义。
系统提示词应该极其清晰,并使用简单、直接的语言,以适合agent的“正确高度”呈现想法。这个“正确高度”是两种常见失败模式之间的“金发姑娘区”。在一种极端情况下,我们看到工程师在提示词中硬编码复杂、脆弱的逻辑,以引发精确的agent行为。这种方法会随着时间的推移造成脆弱性并增加维护复杂性。在另一种极端情况下,工程师有时会提供模糊、高层次的指导,未能给LLM提供关于期望输出的具体信号,或者错误地假设了共享上下文。最佳的高度在于取得平衡:既要足够具体以有效指导行为,又要足够灵活,为模型提供强大的启发式方法来引导行为。
我们建议将提示词组织成不同的部分(例如 <background_information>、<instructions>、## Tool guidance、## Output description 等),并使用XML标签或Markdown标题等技术来划分这些部分,尽管随着模型能力的增强,提示词的确切格式可能变得不那么重要。
无论你决定如何构建你的系统提示词,你都应该力求使用最精简的信息集来完整地概述你的期望行为。(注意,精简并不一定意味着简短;你仍然需要预先给agent足够的信息,以确保它遵循期望的行为。)最好先使用可用的最佳模型测试一个最小化的提示词,看看它在你的任务上表现如何,然后根据初始测试中发现的失败模式,添加清晰的指令和示例来提高性能。
工具允许agent与其环境交互,并在工作时拉取新的、额外的上下文。由于工具定义了agent与其信息/动作空间之间的契约,因此工具必须促进效率,这既包括返回token效率高的信息,也包括鼓励高效的agent行为,这一点极其重要。
在《为AI agent编写工具——与AI agent合作》一文中,我们讨论了构建能被LLM良好理解且功能重叠最小的工具。类似于设计良好的代码库中的函数,工具应该是自包含的、对错误具有鲁棒性,并且其预期用途极其清晰。输入参数同样应该具有描述性、无歧义,并发挥模型的固有优势。
我们观察到的最常见的失败模式之一是工具集过于臃肿,覆盖了太多功能,或者导致关于使用哪个工具的决策点不明确。如果人类工程师都无法明确说出在特定情况下应该使用哪个工具,那么就不能期望AI agent做得更好。正如我们稍后将讨论的,为agent策划一个最小可行工具集,也有助于在长时间交互中更可靠地维护和精简上下文。
提供示例,也称为少样本提示(few-shot prompting),是一项众所周知的最佳实践,我们继续强烈推荐。然而,团队常常会将一长串边缘情况塞进提示词中,试图阐明LLM在特定任务中应遵循的每一条可能规则。我们不建议这样做。相反,我们建议努力策划一组多样化、规范性的示例,以有效地描绘agent的预期行为。对于LLM来说,示例就是“一图胜千言”中的“图”。
我们对上下文不同组成部分(系统提示词、工具、示例、消息历史等)的总体指导是:深思熟虑,保持上下文信息丰富但紧凑。现在,让我们深入探讨在运行时动态检索上下文。
在《构建有效的AI agent》一文中,我们强调了基于LLM的工作流与agent之间的区别。自从那篇文章发表以来,我们倾向于一个简单的agent定义:LLM在循环中自主使用工具。
在与客户合作的过程中,我们看到该领域正在趋同于这个简单的范式。随着底层模型变得更有能力,agent的自主性水平可以扩展:更智能的模型允许agent独立地驾驭微妙的问题空间并从错误中恢复。
我们现在看到工程师在设计agent上下文时的思维方式正在发生转变。如今,许多AI原生应用采用某种形式的基于embedding的推理前检索,以呈现重要的上下文供agent推理。随着该领域向更具agent性的方法过渡,我们越来越多地看到团队用“即时”(just in time)上下文策略来增强这些检索系统。
采用“即时”方法构建的agent,不是预先处理所有相关数据,而是维护轻量级的标识符(文件路径、存储的查询、网页链接等),并在运行时使用工具将这些引用动态加载到上下文中。Anthropic的agent编码解决方案Claude Code就使用这种方法对大型数据库执行复杂的数据分析。该模型可以编写有针对性的查询、存储结果,并利用像 head 和 tail 这样的Bash命令来分析大量数据,而无需将完整的数据对象加载到上下文中。这种方法模仿了人类的认知:我们通常不会记住整个信息库,而是引入外部的组织和索引系统,如文件系统、收件箱和书签,以便按需检索相关信息。
除了存储效率之外,这些引用的元数据还提供了一种有效精炼行为的机制,无论是显式提供还是隐式体现。对于一个在文件系统中运行的agent来说,在 tests 文件夹中存在一个名为 test_utils.py 的文件,与在 src/core_logic/ 中存在同名文件,暗示着不同的用途。文件夹层级、命名约定和时间戳都提供了重要的信号,帮助人类和agent理解如何以及何时利用信息。
让agent自主导航和检索数据也实现了渐进式披露(progressive disclosure)——换句话说,允许agent通过探索逐步发现相关的上下文。每次交互都会产生上下文,为下一个决策提供信息:文件大小暗示复杂性;命名约定暗示用途;时间戳可以作为相关性的代理。agent可以一层层地构建理解,只在工作记忆中保留必要的内容,并利用笔记策略进行额外的持久化。这种自我管理的上下文窗口使agent专注于相关的子集,而不是淹没在详尽但可能不相关的信息中。
当然,这里有一个权衡:运行时探索比检索预先计算好的数据要慢。不仅如此,还需要有主见且深思熟虑的工程,以确保LLM拥有正确的工具和启发式方法,以便有效地驾驭其信息环境。如果没有适当的指导,agent可能会因误用工具、追逐死胡同或未能识别关键信息而浪费上下文。
在某些情况下,最高效的agent可能会采用混合策略,预先检索一些数据以提高速度,然后自行决定进行进一步的自主探索。决定“正确”自主水平的边界取决于任务。Claude Code就是一个采用这种混合模型的agent:CLAUDE.md 文件被直接放入初始上下文中,而像 glob 和 grep 这样的原语则允许它导航其环境并即时检索文件,有效地绕过了过时索引和复杂语法树的问题。
混合策略可能更适合内容动态性较低的场景,例如法律或金融工作。随着模型能力的提升,agent设计将趋向于让智能模型智能地行动,而人类策划将逐渐减少。鉴于该领域的快速进步,“做最简单有效的事情”可能仍然是我们对在Claude之上构建agent的团队的最佳建议。
长周期任务要求agent在token数量超过LLM上下文窗口的动作序列中,保持连贯性、上下文和目标导向的行为。对于需要持续工作数十分钟到数小时的任务,例如大型代码库迁移或全面的研究项目,agent需要专门的技术来应对上下文窗口大小的限制。
等待更大的上下文窗口似乎是一个明显的策略。但在可预见的未来,各种大小的上下文窗口都可能受到上下文污染和信息相关性问题的困扰——至少在追求最强agent性能的情况下是如此。为了使agent能够在更长的时间跨度内有效工作,我们开发了几种直接解决这些上下文污染约束的技术:压缩(compaction)、结构化笔记(structured note-taking)和多agent架构(multi-agent architectures)。
压缩
压缩是指将接近上下文窗口限制的对话进行总结,然后用总结重新初始化一个新的上下文窗口的做法。压缩通常是上下文工程中推动更好长期连贯性的第一个杠杆。其核心是以高保真度提炼上下文窗口的内容,使agent能够以最小的性能下降继续运行。
例如,在Claude Code中,我们通过将消息历史传递给模型来总结和压缩最关键细节来实现这一点。模型会保留架构决策、未解决的bug和实现细节,同时丢弃冗余的工具输出或消息。然后,agent可以使用这个压缩后的上下文以及最近访问的五个文件继续工作。用户可以获得连续性,而无需担心上下文窗口的限制。
压缩的艺术在于选择保留什么和丢弃什么,因为过于激进的压缩可能导致丢失微妙但关键的上下文,而这些上下文的重要性可能要到后来才会显现。对于实现压缩系统的工程师,我们建议在复杂的agent轨迹上仔细调整你的提示词。首先最大化召回率,确保你的压缩提示词能捕捉到轨迹中的每一条相关信息,然后通过消除多余内容来提高精确度。
一个容易处理的多余内容示例是清除工具调用及其结果——一旦工具在消息历史深处被调用过,agent为什么还需要再次看到原始结果?最安全、最轻量级的压缩形式之一是工具结果清除,最近作为一项功能在Claude开发者平台上推出。
结构化笔记
结构化笔记,或agent记忆,是一种技术,其中agent定期将笔记持久化到上下文窗口之外的内存中。这些笔记在稍后的时间点被拉回上下文窗口。
这种策略以最小的开销提供了持久记忆。就像Claude Code创建待办事项列表,或者你的自定义agent维护一个 NOTES.md 文件一样,这种简单的模式允许agent在复杂任务中跟踪进度,维护关键的上下文和依赖关系,否则这些信息会在数十次工具调用中丢失。
Claude玩《宝可梦》的演示展示了记忆如何在非编码领域改变agent的能力。该agent在数千个游戏步骤中维护精确的计数——跟踪诸如“在过去的1234步中,我一直在1号道路训练我的宝可梦,皮卡丘已经升了8级,目标是10级”这样的目标。在没有任何关于记忆结构的提示下,它会绘制已探索区域的地图,记住已解锁的关键成就,并维护战斗策略的战略笔记,帮助它了解哪些攻击对不同对手最有效。
在上下文重置后,agent会读取自己的笔记,并继续进行长达数小时的训练序列或地牢探索。这种跨总结步骤的连贯性使得长周期策略成为可能,而如果将所有信息都保留在LLM的上下文窗口中,这是不可能实现的。
作为Sonnet 4.5发布的一部分,我们在Claude开发者平台上以公开测试版的形式发布了一个记忆工具,它通过一个基于文件的系统,使得在上下文窗口之外存储和查阅信息变得更加容易。这允许agent随着时间的推移建立知识库,跨会话维护项目状态,并引用之前的工作,而无需将所有内容都保留在上下文中。
子agent架构
子agent架构提供了另一种绕过上下文限制的方法。不是由一个agent尝试维护整个项目的状态,而是专门的子agent可以用干净的上下文窗口处理聚焦的任务。主agent协调高层计划,而子agent执行深入的技术工作或使用工具查找相关信息。每个子agent可能会进行广泛的探索,使用数万个或更多的token,但只返回其工作的浓缩、精炼的摘要(通常为1000-2000个token)。
这种方法实现了清晰的关注点分离——详细的搜索上下文被隔离在子agent内部,而主导agent则专注于综合和分析结果。这种模式在《我们如何构建我们的多agent研究系统》一文中讨论过,在复杂的研究任务上,它显示出比单agent系统有显著的改进。
这些方法之间的选择取决于任务特征。例如:
即使模型不断改进,在扩展交互中保持连贯性的挑战仍将是构建更有效agent的核心。
上下文工程代表了我们在使用LLM构建应用方面的一个根本性转变。随着模型能力的增强,挑战不再仅仅是精心制作完美的提示词——而是在每一步都深思熟虑地策划哪些信息进入模型有限的注意力预算。无论你是在为长周期任务实现压缩、设计token高效的工具,还是让agent即时探索其环境,指导原则始终如一:找到最小的高信号token集合,以最大化你期望结果的可能性。
我们概述的这些技术将随着模型的改进而继续演变。我们已经看到,更智能的模型需要更少的规范性工程,允许agent以更高的自主性运行。但是,即使能力在扩展,将上下文视为一种宝贵且有限的资源,仍将是构建可靠、有效agent的核心。
立即在Claude开发者平台上开始上下文工程实践,并通过我们的记忆和上下文管理手册获取有用的提示和最佳实践。
由Anthropic的应用AI团队撰写:Prithvi Rajasekaran、Ethan Dixon、Carly Ryan和Jeremy Hadfield,团队成员Rafi Ayub、Hannah Moran、Cal Rueb和Connor Jennings亦有贡献。特别感谢Molly Vorwerck、Stuart Ritchie和Maggie Vo的支持。