第 4 章:从 Prompt Engineering 到 Context Engineering

本章导读

  • 核心问题:为什么 Agent 的核心不只是 Prompt,而是 Context Engineering。
  • 关键词:Context、Context Window、Context Budget、Just-in-time Context、Context Layer
  • 学习产出:设计 CI 失败分析所需的最小高信号上下文。

1. 本章要解决什么问题

前面三章讨论了 Agent 的基本思想、Workflow 与 Agent 的边界,以及 Claude Code 所体现的 Agentic Coding 模式。

从这一章开始,我们进入全书最重要的主题之一:

Context Engineering。

过去人们谈大语言模型应用,最常说的是 Prompt Engineering。

Prompt Engineering 关注的是:

我应该怎样把指令写得更清楚?

而 Context Engineering 关注的是一个更大的问题:

在模型做出下一次判断之前,应该让它看到哪些信息?

这两个问题看起来相似,但工程含义完全不同。

Prompt Engineering 更像“写一句好指令”。

Context Engineering 更像“设计一个信息系统”。

因为 Agent 在执行复杂任务时,并不是只依赖一段用户输入,而是依赖大量动态变化的上下文:

  • 系统指令;
  • 用户目标;
  • 对话历史;
  • 项目文档;
  • 代码文件;
  • Git Diff;
  • Issue 描述;
  • 工具返回结果;
  • 测试日志;
  • 长期记忆;
  • 临时 Scratchpad;
  • 当前计划;
  • 已完成步骤;
  • 失败原因;
  • 环境约束。

问题在于:

模型的上下文窗口是有限的,注意力也是有限的。

因此,Agent 工程的核心能力之一就是:

在有限 Context Budget 内,选择、组织、压缩和隔离最有价值的信息。

本章要回答:

  • 为什么 Prompt Engineering 不再足够;
  • Anthropic 如何定义 Context Engineering;
  • 为什么 Context 是有限资源;
  • 什么是 Context Window、Context Budget、Context Quality、Context Lifetime;
  • 为什么“更多上下文”不一定更好;
  • 企业 Agent 平台应该如何设计 Context Layer。

2. 对应 Anthropic 文章

本章主要对应 Anthropic Engineering 的文章:

  • Effective Context Engineering for AI Agents

这篇文章提出了一个非常关键的转向:

Building with language models is becoming less about finding the right words and phrases for your prompts, and more about answering the broader question of what configuration of context is most likely to generate the desired behavior.

用中文表达就是:

使用大语言模型,不再只是寻找更好的 Prompt 措辞,而是设计什么样的上下文配置最可能引导模型产生期望行为。

这句话可以看作 Context Engineering 的定义。

3. 原文核心观点

3.1 Context 是模型采样时看到的全部 Token

Anthropic 对 Context 的定义很直接:

Context refers to the set of tokens included when sampling from a large-language model.

也就是说,Context 不是狭义的“背景资料”。

它包括模型在当前调用中看到的一切:

System Prompt
User Message
Assistant Message
Tool Definitions
Tool Results
Retrieved Documents
Memory
Code Snippets
Logs
Examples
Instructions

只要进入模型输入窗口,它就是 Context。

工程解释

在很多系统中,开发者会把“Prompt”和“Context”混在一起。

例如:

String prompt = systemPrompt + userInput + retrievedDocs + toolResults;

这种写法在 Demo 阶段可以工作,但进入复杂 Agent 后会迅速失控。

因为不同上下文有不同特性:

上下文类型 生命周期 作用 风险
System Prompt 长期 定义角色和边界 太长会稀释关键规则
User Task 当前任务 定义目标 描述不清会导致偏航
Tool Result 动态 提供环境反馈 结果过长会污染上下文
Memory 跨会话 提供经验和偏好 过期或错误记忆会误导模型
Code 按需加载 提供真实实现 全量加载成本极高
Logs 临时 提供失败证据 噪声非常多

所以 Context 必须被结构化建模,而不能只是字符串拼接。

3.2 Context 是有限资源

Anthropic 反复强调:

Context is a critical but finite resource.

有限不只是指模型有最大上下文长度。

更重要的是:

即使窗口足够大,模型的有效注意力也是有限的。

上下文越长,模型越容易出现:

  • 忽略关键信息;
  • 被无关内容干扰;
  • 混淆多个约束;
  • 记错前文细节;
  • 把低质量信息当成高质量证据;
  • 在长任务中逐渐偏离目标。

Anthropic 提到类似 context rot 的现象:随着上下文 token 增加,模型从上下文中准确召回信息的能力会下降。

工程解释

很多人以为更大的 context window 可以解决所有问题。

但事实是:

更大的窗口 ≠ 更好的上下文。

如果把一个大型代码库、完整日志、全部对话历史和大量文档都塞进去,模型不一定更聪明,反而可能更混乱。

因此 Context Engineering 的目标不是最大化 token 数,而是最大化 token 的信息价值。

可以用一句话概括:

不要问“还能塞多少”,要问“哪些 token 对下一步决策最有用”。

3.3 Context Engineering 是优化 token utility

Anthropic 把 Context Engineering 描述为:

在 LLM 固有限制下,优化这些 token 的效用,以稳定产生期望结果。

这意味着每个 token 都有机会成本。

如果上下文窗口中放入了 2000 token 的无关日志,就可能挤掉:

  • 关键错误栈;
  • 用户真实目标;
  • 项目约束;
  • 最近工具结果;
  • 重要代码片段。

Context Engineering 要解决的不是“信息是否相关”这么简单,而是:

在当前阶段,哪类信息最值得占用上下文预算?

工程解释

可以把 Context Window 想象成 CPU Cache。

不是所有数据都应该进 Cache。

你需要考虑:

  • 当前任务要访问什么;
  • 哪些数据最可能被用到;
  • 哪些数据可以延迟加载;
  • 哪些数据可以压缩;
  • 哪些数据应该留在外部存储中。

同样,Agent 的 Context Window 也应该只保留高价值信息。

3.4 Agent 需要 Just-in-time Context

Anthropic 在文章中提到,随着应用从预先检索走向更 agentic 的方式,越来越多系统采用 “just in time” context 策略。

也就是说,不是在任务开始前把所有可能相关的数据都加载进来,而是:

保留轻量引用
  ↓
让 Agent 在需要时通过工具加载具体内容

这些轻量引用可以是:

  • 文件路径;
  • 数据库查询名;
  • Web 链接;
  • Issue ID;
  • Git commit hash;
  • 日志位置;
  • 文档索引;
  • 向量检索结果 ID。

例如 Coding Agent 不需要一开始读取整个代码库,而是先知道:

README.md
pom.xml
src/main/java/com/example/order/OrderService.java
src/test/java/com/example/order/OrderServiceTest.java

当它需要理解某个类时,再调用工具读取具体文件。

工程解释

Just-in-time Context 的核心是:

上下文窗口中保留“索引”和“线索”,而不是保留所有原始数据。

这对企业 Agent 非常重要。

因为企业系统中的数据规模远远超过任何上下文窗口:

  • 代码库可能有百万行;
  • 日志可能有数 GB;
  • Confluence 文档可能有几千页;
  • Jira Issue 可能有多年历史;
  • 数据库表可能有上亿行。

Agent 不可能一次性读取所有内容。

它必须像工程师一样:

先定位方向
再打开相关文件
再查看关键片段
再根据发现继续深入

3.5 长任务需要 Compaction、Note-taking 和 Sub-agent

对于长时间任务,Anthropic 提到几类技术:

  • Compaction;
  • Structured note-taking;
  • Sub-agent architectures。

这些技术后面章节会展开,这里先建立整体认识。

Compaction

Compaction 是把接近窗口上限的对话或任务历史压缩成高保真摘要,然后用摘要开启新的上下文窗口。

它解决的问题是:

上下文窗口不够长,但任务还没完成。

Structured Note-taking

Structured note-taking 是让 Agent 把重要发现写到外部笔记或状态文件中,而不是全部保存在对话上下文里。

它解决的问题是:

重要状态需要跨窗口、跨会话保存。

Sub-agent Architectures

Sub-agent 架构让多个子 Agent 在各自干净的上下文中探索问题,然后只把压缩后的结论返回给主 Agent。

它解决的问题是:

单个 Agent 的上下文无法同时容纳所有探索路径。

工程解释

这些技术本质上都在做同一件事:

把完整信息留在外部,把高价值摘要放进上下文。

这也是企业 Agent 平台 Context Layer 的核心职责。

4. 工程视角重新解释

从软件工程角度看,Context Engineering 不是 Prompt 技巧,而是 Agent Runtime 的核心子系统。

它至少包含四类能力:

Context Collection
Context Selection
Context Compression
Context Isolation

4.1 Context Collection:收集上下文

首先,系统要知道上下文来自哪里。

企业研发 Agent 的上下文来源可能包括:

用户输入
Issue / Ticket
README / AGENTS.md
源码文件
Git Diff
Git History
构建日志
测试结果
数据库 Schema
API 文档
团队规范
历史 Memory
工具返回结果

这些来源不能都由一个方法硬编码,而应该由 ContextProvider 插件化提供。

4.2 Context Selection:选择上下文

收集到候选上下文后,还要决定哪些进入模型。

选择依据包括:

  • 与当前任务的相关性;
  • 与下一步决策的关系;
  • 信息新鲜度;
  • 来源可信度;
  • token 成本;
  • 权限;
  • 是否已经被更好摘要覆盖。

这就是第 6 章要详细讨论的 Context Selection。

4.3 Context Compression:压缩上下文

当上下文过长时,需要压缩。

但压缩不是简单总结。

不同内容需要不同压缩方式:

内容 压缩方式
长对话 保留目标、决策、未完成事项
测试日志 保留失败测试、错误类型、关键栈
代码文件 保留结构、符号、关键方法
文档 保留结论、约束、引用链接
工具结果 保留可执行下一步和证据

这就是第 7 章要讨论的 Context Compression。

4.4 Context Isolation:隔离上下文

不是所有上下文都应该共享。

例如:

  • Subagent 的探索细节不一定要给主 Agent;
  • 一个用户的偏好不能泄露给另一个用户;
  • 一个项目的内部代码不能进入另一个项目;
  • 临时推理草稿不一定进入长期 Memory;
  • 高权限工具结果不一定能被低权限 Agent 看到。

这就是第 8 章要讨论的 Context Isolation。

5. 核心概念

5.1 Context Window

Context Window 是模型单次调用可以看到的 token 范围。

它包含:

输入消息
系统指令
工具定义
工具结果
历史对话
检索文档
记忆

Context Window 是物理限制。

但更重要的是有效注意力限制。

5.2 Context Budget

Context Budget 是系统为一次模型调用分配的上下文预算。

例如一个模型支持 200K tokens,但系统可能只允许一次调用使用 40K tokens。

原因包括:

  • 控制成本;
  • 降低延迟;
  • 减少噪声;
  • 保留输出空间;
  • 提高稳定性。

在企业平台中,Context Budget 应该是一等对象。

5.3 Context Quality

Context Quality 指上下文是否能有效帮助模型做出正确决策。

高质量上下文通常具备:

  • 相关;
  • 准确;
  • 新鲜;
  • 有来源;
  • 结构清晰;
  • 不与其他信息冲突;
  • 能直接支持下一步行动。

低质量上下文可能是:

  • 过期文档;
  • 无关日志;
  • 重复内容;
  • 错误记忆;
  • 没有来源的总结;
  • 太长的工具输出;
  • 与当前任务无关的历史对话。

5.4 Context Lifetime

不同上下文有不同生命周期。

上下文 生命周期
System Prompt 长期
用户任务 当前任务
当前计划 当前阶段
工具结果 当前步骤或当前阶段
错误日志 当前排障过程
项目规范 项目级长期
用户偏好 用户级长期
临时 Scratchpad 短期,通常不持久化

Context Engineering 必须考虑生命周期。

否则系统会把临时信息当长期事实,或者把长期规则当一次性噪声。

6. 架构图 / 流程图

Context Layer 架构
图 4-1 Context Layer 架构 这张图展示 Context Layer 如何收集、过滤、排序、压缩、隔离并渲染上下文。 Mermaid 源文件

6.1 从 Prompt Engineering 到 Context Engineering

从 Prompt Engineering 到 Context Engineering
图 4-2 从 Prompt Engineering 到 Context Engineering Mermaid 源文件

6.2 Context Layer 的基本结构

Context Layer 的基本结构
图 4-3 Context Layer 的基本结构 Mermaid 源文件

6.3 Just-in-time Context

Just-in-time Context
图 4-4 Just-in-time Context Mermaid 源文件

7. Java / Spring Boot 落地方案

企业 Agent 平台应该把 Context 作为独立模块,而不是让每个 Agent 自己拼接 Prompt。

建议建立:

agent-context
  ContextManager
  ContextProvider
  ContextCandidate
  ContextSelector
  ContextCompressor
  ContextBudget
  ContextWindow

7.1 ContextChunk

首先定义最小上下文单元:

public record ContextChunk(
    String id,
    ContextType type,
    String source,
    String content,
    int priority,
    int tokenEstimate,
    Instant createdAt,
    Map<String, Object> metadata
) {}

上下文类型:

public enum ContextType {
    SYSTEM_INSTRUCTION,
    USER_TASK,
    CONVERSATION,
    PROJECT_DOC,
    CODE,
    GIT_DIFF,
    ISSUE,
    TOOL_RESULT,
    MEMORY,
    SCRATCHPAD,
    ENVIRONMENT
}

7.2 ContextProvider

不同来源通过 Provider 接入:

public interface ContextProvider {
    boolean supports(ContextRequest request);
    List<ContextChunk> provide(ContextRequest request);
}

请求对象:

public record ContextRequest(
    String taskId,
    String userId,
    String repositoryId,
    String objective,
    AgentPhase phase,
    Map<String, Object> metadata
) {}

常见 Provider:

ProjectDocContextProvider
RepositoryContextProvider
IssueContextProvider
GitDiffContextProvider
ToolResultContextProvider
MemoryContextProvider
EnvironmentContextProvider

7.3 ContextBudget

public record ContextBudget(
    int maxInputTokens,
    int reservedOutputTokens,
    Map<ContextType, Integer> typeBudgets
) {
    public int availableInputTokens() {
        return maxInputTokens - reservedOutputTokens;
    }
}

示例预算:

System Instruction: 2K
User Task: 2K
Project Docs: 6K
Code: 16K
Tool Results: 8K
Memory: 4K
Reserved Output: 4K

预算不是固定值,而应根据任务阶段动态调整。

例如 Explore 阶段可以给代码和文档更多预算;Verify 阶段可以给测试输出更多预算。

7.4 ContextManager

public class ContextManager {

    private final List<ContextProvider> providers;
    private final ContextSelector selector;
    private final ContextCompressor compressor;
    private final TokenEstimator tokenEstimator;

    public ContextWindow build(ContextRequest request, ContextBudget budget) {
        List<ContextChunk> candidates = providers.stream()
            .filter(provider -> provider.supports(request))
            .flatMap(provider -> provider.provide(request).stream())
            .toList();

        List<ContextChunk> selected = selector.select(candidates, request, budget);

        List<ContextChunk> compressed = compressor.compressIfNeeded(selected, budget);

        return ContextWindow.of(compressed, tokenEstimator.estimate(compressed));
    }
}

7.5 ContextWindow

public record ContextWindow(
    List<ContextChunk> chunks,
    int totalTokens
) {
    public static ContextWindow of(List<ContextChunk> chunks, int totalTokens) {
        return new ContextWindow(chunks, totalTokens);
    }
}

最终交给模型前,可以渲染为结构化消息:

<System Instructions>
...

<User Task>
...

<Project Context>
...

<Relevant Code>
...

<Tool Observations>
...

<Memory>
...

注意:渲染顺序也属于 Context Engineering。

重要信息不应该随机拼接。

8. 与其他框架对比

8.1 与传统 RAG

传统 RAG 通常是:

用户问题
  ↓
向量检索
  ↓
拼接文档
  ↓
生成答案

Context Engineering 更广。

它包括:

  • RAG;
  • 工具结果;
  • 对话历史;
  • Memory;
  • 代码上下文;
  • 任务状态;
  • 压缩;
  • 隔离;
  • 预算;
  • 生命周期。

所以不能把 Context Engineering 简化成 RAG。

RAG 只是 Context Engineering 的一个子能力。

8.2 与 LangChain / LangGraph

LangChain 提供很多文档加载、检索和链式编排组件。

LangGraph 提供状态图和 Agent 编排能力。

但无论使用什么框架,仍然需要回答:

哪些上下文进入模型?
何时进入?
保留多久?
如何压缩?
是否允许共享?
如何解释选择结果?

这些问题不能完全交给框架默认行为。

8.3 与 Claude Code

Claude Code 是 Context Engineering 的典型案例。

它不会一次性读取整个仓库,而是通过:

  • 文件引用;
  • 搜索;
  • 命令输出;
  • 测试反馈;
  • 项目知识文件;
  • 压缩机制;
  • 多轮工具调用;

动态构建上下文。

这正是企业研发 Agent 应该学习的方向。

9. 常见误区

9.1 误区一:Context Engineering 等于写更长 Prompt

不是。

Context Engineering 是关于信息选择、组织和生命周期的系统设计。

Prompt 只是其中一部分。

9.2 误区二:上下文越多越好

不是。

更多上下文可能带来更多噪声。

高质量 Agent 追求的是:

最小高信号上下文

而不是最大上下文。

9.3 误区三:有了大上下文模型就不需要 Context Engineering

不是。

更大的窗口会缓解限制,但不会消除:

  • 注意力稀释;
  • 信息冲突;
  • 上下文污染;
  • 成本和延迟;
  • 权限边界;
  • 生命周期管理。

9.4 误区四:RAG 就是 Context Engineering

不是。

RAG 解决检索问题,Context Engineering 解决完整上下文配置问题。

9.5 误区五:工具结果可以原样塞回模型

不应该。

工具结果往往包含大量噪声。

例如测试日志中真正重要的可能只有:

失败测试名
异常类型
关键栈帧
失败断言
相关文件路径

其余内容应该压缩或保留在外部引用中。

10. 贯穿案例:CI 失败分析 Agent

CI 失败分析最能体现 Context Engineering 的价值。

对于 build #4312,候选上下文非常多:

完整 CI 日志
失败摘要
Git Diff
最近提交
AGENTS.md
README.md
失败测试文件
状态机实现
历史类似失败
用户权限
可用工具定义

错误做法是把完整日志、完整代码库和全部历史提交一次性塞进模型。这样不仅成本高,还会让关键错误栈被大量噪声淹没。

正确做法是只把当前决策需要的高信号上下文放入 Context Window:

用户目标:分析 build #4312,且只读
CI 失败摘要:失败测试、异常、关键栈帧
Git Diff 摘要:OrderStatus 新增 PENDING_REVIEW
项目规则:修改状态枚举需同步状态机
引用:完整日志和相关文件路径按需读取

这就是本章所说的“最小高信号上下文”。

CI 失败分析 Agent 的 Context Layer 不只是 RAG,而是持续管理任务目标、工具结果、项目知识、代码片段、Memory 和权限边界。

11. 本章小结

本章讨论了从 Prompt Engineering 到 Context Engineering 的转向。

核心结论有六点:

  1. Prompt Engineering 关注指令怎么写,Context Engineering 关注模型在当前步骤应该看到什么。
  2. Context 是模型采样时看到的全部 token,包括指令、历史、工具结果、文档、代码和记忆。
  3. Context 是有限资源,限制不仅来自窗口大小,也来自模型有效注意力。
  4. 好的 Context Engineering 追求最小高信号上下文,而不是最大上下文。
  5. Agent 需要 Just-in-time Context,通过工具按需加载信息,而不是一次性塞入全部数据。
  6. 企业 Agent 平台应该把 Context Layer 作为独立基础设施设计。

一句话总结本章:

Agent 的能力不只取决于模型有多聪明,还取决于每一步给模型看的上下文是否正确。

12. 实践任务

任务 1:梳理上下文来源

选择一个你熟悉的 AI Agent 场景,例如:

  • CI 失败分析;
  • 自动生成单元测试;
  • 技术方案调研;
  • Issue 自动总结;
  • 代码评审助手。

列出它需要的上下文来源:

上下文来源 类型 是否必须 何时加载 生命周期 风险
Issue 描述 USER_TASK 启动时 当前任务 描述不完整
CI 日志 TOOL_RESULT 按需 当前阶段 噪声多
README PROJECT_DOC 启动时 项目级 可能过期

任务 2:设计 ContextChunk

用 Java 实现本章中的 ContextChunk,并补充:

  • 权限字段;
  • 置信度字段;
  • 过期时间;
  • 来源 URL 或文件路径;
  • 是否允许进入长期 Memory。

任务 3:设计 Context Budget

为“CI 失败分析 Agent”设计一次模型调用的预算:

总输入预算:32000 tokens
保留输出预算:4000 tokens

请分配给:

  • System Instruction;
  • User Task;
  • Project Docs;
  • CI Error Summary;
  • Relevant Code;
  • Git Diff;
  • Memory;
  • Tool Results。

任务 4:实现 Just-in-time Context 策略

设计一个流程:

初始上下文只包含 CI 摘要、错误类型、相关文件路径。
如果 Agent 需要具体代码,再调用 read_file。
如果 Agent 需要完整日志,再调用 read_log_segment。
如果 Agent 需要历史提交,再调用 git_history。

要求说明:

  • 哪些信息一开始进入上下文;
  • 哪些信息只保留引用;
  • 哪些工具负责按需加载;
  • 工具结果如何压缩后再进入上下文。

results matching ""

    No results matching ""