Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

上下文工程核心

管理 Agent(智能体) 的“工作记忆“——在有限的 Token 空间内实现信息优先级的精准编排。

前置条件

  • 已完成 简介,理解 Harness Engineering(驾驭工程) 基本概念
  • 已安装 OpenCode CLI 并完成基础配置
  • 已了解 LLM 上下文窗口和 Token 计数的基本概念

文章概述

每个 Agent 的上下文窗口(Context(上下文) Window)容量有限,装不下所有信息。上下文工程就是管理这个有限空间的技术——决定哪些信息保留、哪些丢弃、如何预留空间,直接影响 Agent 的决策准确度。本章围绕三个核心维度展开:压缩(缩减信息量)、缓存(重用已有信息)、预算(分配有限空间),讲解每个维度的实现原理。你会理解 Compaction 自动压缩机制如何选择性保留关键信息、Session 级与跨 Session 缓存的差异、以及 Token 预算在系统指令/用户输入/工具输出之间的分配策略与超限处理机制。

上下文工程与约束系统配合使用:上下文工程确保 Agent “看得到“需要的信息,约束系统确保 Agent “不做“不该做的事。验证护栏则在输出阶段验证结果正确性。学完本节,你应能根据任务特征配置上下文管理参数,理解压缩后信息保真度与性能的权衡关系,并掌握跨会话上下文保持的基本方法。

读完本文,你将能够合理分配 Token 预算以优化上下文利用,理解 Compaction 压缩与缓存机制的工作原理,以及根据任务复杂度调整上下文管理策略。

⏱ 时间有限?先读这些: 上下文压缩原理 → 上下文缓存策略 → Token 预算管理 → 三层协作的决策流程

最小示例

用一个最简单的配置来理解上下文工程:

{
  "compaction": {
    "auto": true,
    "prune": false,
    "reserved": 10000
  }
}

这三行配置说的是:开启自动压缩(auto: true),不裁剪旧工具输出(prune: false),预留 10K Token 的缓冲空间避免压缩过程溢出。reserved 就像一个安全缓冲区——当上下文接近模型窗口上限时,这段预留空间确保压缩过程中不会因超限而失败。

操作系统类比:Context = 工作记忆

理解上下文工程最直观的方式是将其类比为操作系统的内存管理

操作系统概念OpenCode 对应说明
RAM / 工作记忆Context WindowAgent 的有限工作空间
Swap / 页面文件压缩Compaction空间不足时压缩不活跃内容腾出空间
CPU 缓存层级(L1/L2/L3)Caching按层级缓存内容,命中越快成本越低
内存分配(heap/stack/reserved)Token Budget为不同用途预分配有限空间
内存碎片整理上下文压缩消除冗余内容,提高空间利用率
虚拟内存跨 Session 缓存将持久化内容映射到上下文空间

这个类比帮助理解几个关键设计:

  1. 空间有限性:RAM 有限,Agent 的 Context Window 也有限——必须精打细算
  2. 层级缓存:CPU 缓存有 L1/L2/L3 层级,Context 缓存也有 Session 级和跨 Session 级
  3. 压缩换空间:操作系统用 Swap 换内存空间,Context 用 Compaction 换 Token 空间

为什么需要上下文工程

Token 空间有限,信息无限

每个 AI 模型都有固定的上下文窗口上限——Claude 的 200K Token、GPT-4 的 128K Token。这个窗口就是 Agent 的“工作记忆“,所有对话历史、代码片段、工具输出、系统指令都必须塞进这个有限空间。

然而,软件开发的信息量几乎是无限的:

  • 一个中型项目可能有数十万行代码
  • 完整的 API 文档可能超过 10 万字
  • 一次长会话的对话历史可能积累数万 Token
  • MCP(模型上下文协议) 工具返回的查询结果可能非常庞大

核心矛盾:有限的工作记忆 vs 无限的信息需求。上下文工程就是为了解决这个矛盾而诞生的方法论。

上下文质量决定决策质量

Agent 的每一次决策都依赖于当前上下文。上下文不完整,决策就会出错:

用户:修复登录模块的 bug

上下文缺失场景:
- Agent 不知道登录模块在哪里 → 随机搜索,浪费时间
- Agent 不知道之前的修复历史 → 重复已尝试的方案
- Agent 不知道项目规范 → 生成不符合风格的代码

上下文完整场景:
- Agent 精确定位登录模块 → 直接进入修复
- Agent 了解历史上下文 → 避免重复劳动
- Agent 掌握项目规范 → 生成一致风格的代码

上下文工程的目标,就是让 Agent 在任何时刻都拥有做出正确决策所需的信息——不多不少,恰到好处。

上下文工程的三层模型

上下文工程从三个维度管理有限的工作记忆空间:

graph TB
    subgraph 三层模型
        P[压缩层<br/>Compaction] --> C[缓存层<br/>Caching]
        C --> B[预算层<br/>Budget]
    end

    P --> |缩减信息量| P1[选择性保留关键信息]
    C --> |重用已有信息| C1[避免重复传输]
    B --> |分配有限空间| B1[优先级排序]

    style P fill:#4A90D9,color:#fff
    style C fill:#50C878,color:#fff
    style B fill:#FF9F43,color:#fff
    style P1 fill:#E8F4FD,color:#333
    style C1 fill:#E8F8EC,color:#333
    style B1 fill:#FFF4E8,color:#333
层级核心问题解决思路触发时机
压缩层信息太多怎么办?选择性保留,丢弃低价值内容上下文接近上限时
缓存层重复内容怎么处理?一次传输,多次复用每次请求时
预算层空间如何分配?按优先级预分配,动态调整任务开始时

三层之间存在依赖关系:缓存优先(能复用就不重传),预算控制(分配各部分空间),压缩兜底(超限时智能缩减)。

配置映射速查:压缩层对应 compaction 字段(如 compaction.autocompaction.reserved);缓存层对应 caching 字段(如 caching.crossSession);预算层通过 compaction.reserved 控制整体预留空间,推理预算通过 provider.*.models.*.options.thinking.budgetTokens 设置。部分高级配置(如微压缩规则)需要 OpenCode >= v1.17.x 和 OMO >= v4.13.x。没有直接对应配置的概念(如上下文注入),通过 AGENTS.md 或 Skill(技能) 配置实现。

上下文压缩原理

自动压缩机制(Compaction)

当上下文接近窗口上限时,OpenCode 会自动触发 Compaction——一个后台 Agent 会分析当前上下文,生成摘要并选择性保留关键信息。

sequenceDiagram
    participant U as 用户
    participant A as Primary Agent
    participant C as Compaction Agent
    participant M as 模型

    U->>A: 继续对话
    A->>A: 检测上下文接近上限
    A->>C: 触发后台压缩
    C->>M: 分析上下文重要性
    M-->>C: 返回重要性评估
    C->>C: 生成摘要 + 选择性保留
    C-->>A: 返回压缩后的上下文
    A->>M: 使用压缩上下文继续
    M-->>A: 生成响应
    A-->>U: 返回结果

Compaction 的核心原则

  1. 用户指令优先保留 — 用户明确说过的话不能丢
  2. 关键决策记录 — Agent 做出的重要选择必须保留
  3. 错误信息保留 — 失败的尝试是宝贵的学习材料
  4. 代码片段压缩 — 用文件路径 + 摘要替代完整代码
  5. 对话历史摘要 — 多轮对话合并为简洁摘要

微压缩策略

除了自动压缩,OpenCode 还支持细粒度的微压缩配置:

// Requires OpenCode >= v1.17.x, OMO >= v4.13.x
{
  "compaction": {
    "strategy": "selective",
    "rules": [
      {
        "type": "code",
        "action": "summarize",
        "keepSignature": true
      },
      {
        "type": "tool_output",
        "action": "protect",
        "window": "40K"
      },
      {
        "type": "conversation",
        "action": "summarize",
        "keepUserMessages": true
      }
    ]
  }
}

三种压缩动作

动作含义适用场景
summarize生成摘要,丢弃原文对话历史、长文档
protect完整保留,不压缩用户指令、关键决策
truncate截断,只保留开头/结尾超长的工具输出

工具输出保护窗口:最近 40K Token 的工具输出不受压缩影响,确保 Agent 能看到最新的执行结果。

压缩后的信息保真度

压缩是有损的,但损失可控。关键在于区分“必须保留“和“可以压缩“:

必须保留(保真度 100%):
├── 用户明确的指令
├── Agent 的关键决策
├── 错误信息和失败原因
└── 当前任务的核心上下文

可以压缩(保真度 70-90%):
├── 历史对话 → 摘要
├── 完整代码 → 文件路径 + 关键函数签名
├── 工具输出 → 结果摘要
└── 探索过程 → 结论性发现

压缩比 vs 保真度的权衡:更高的压缩比意味着更多的信息损失。OpenCode 默认在压缩比 3:1 时可保持大部分关键信息保真度(经验估算)。

上下文缓存策略

缓存 vs 压缩

缓存和压缩是互补的两种策略:

策略解决的问题核心机制效果
缓存消除重复传输一次发送,多次复用可显著节省 Token 消耗(经验估算)
压缩精简必要内容选择性保留,丢弃冗余可有效延长会话寿命

最佳实践:缓存优先,压缩兜底。先通过缓存消除重复,再通过压缩精简必要内容。

Session 级缓存

Session 级缓存在单个会话内有效,自动管理,无需配置:

graph LR
    subgraph Session 生命周期
        R1[请求 1] --> |缓存系统指令| C1[(缓存)]
        R2[请求 2] --> |命中缓存| C1
        R3[请求 3] --> |命中缓存| C1
    end

    R2 -.-> |节省 Token| S1[系统指令: 2K Token]
    R3 -.-> |节省 Token| S1

    style C1 fill:#50C878,color:#fff

Session 级缓存的内容

  • 系统指令(System Prompt(提示词))— 每个 Session 固定
  • 工具定义(Tool Definitions)— MCP 工具的 JSON Schema
  • 项目上下文(Project Context)— README、CLAUDE.md 等

跨 Session 缓存

跨 Session 缓存需要显式配置,适用于长期项目:

// Requires OpenCode >= v1.17.x, OMO >= v4.13.x
{
  "caching": {
    "crossSession": {
      "enabled": true,
      "persistPath": ".opencode/cache",
      "maxAge": "7d",
      "entries": [
        {
          "type": "project_knowledge",
          "files": ["README.md", "CLAUDE.md", "docs/**/*.md"]
        },
        {
          "type": "tool_definitions",
          "tools": ["filesystem", "git", "mcp-*"]
        }
      ]
    }
  }
}

跨 Session 缓存的生命周期

缓存类型生命周期失效条件
项目知识项目持续期文件内容变更
工具定义工具版本更新配置变更
用户偏好用户修改手动清除

缓存命中率优化

缓存命中率是衡量缓存效果的关键指标:

缓存命中率 = 命中缓存的 Token 数 / 总请求 Token 数

优化目标:命中率通常可达 60% 以上(取决于使用模式)

提升命中率的策略

  1. 固化系统指令 — 使用稳定的 System Prompt,避免频繁修改
  2. 结构化项目知识 — 将常用文档放在固定位置
  3. 合理设置缓存粒度 — 太小命中率低,太大更新成本高
  4. 预热缓存 — Session 开始时主动加载常用内容

Token 预算管理

预算分配策略

Token 预算将有限的上下文窗口划分为四个区域:

graph TB
    subgraph Token 预算分配
        S[系统消息<br/>2-4K Token<br/>固定开销]
        U[用户输入<br/>动态变化<br/>任务描述 + 代码]
        T[工具输出<br/>动态变化<br/>MCP 返回数据]
        R[预留空间<br/>20-30%<br/>Agent 推理缓冲]
    end

    S --> U --> T --> R

    style S fill:#4A90D9,color:#fff
    style U fill:#50C878,color:#fff
    style T fill:#FF9F43,color:#fff
    style R fill:#A66CFF,color:#fff

预算配置示例

{
  "compaction": {
    "auto": true,
    "prune": false,
    "reserved": 10000
  }
}

各区域的作用

区域占比内容管理策略
系统消息2-5%System Prompt、工具定义固定,通过缓存优化
用户输入25-30%任务描述、代码上下文按需加载,智能截断
工具输出40-50%MCP 返回、文件内容结果压缩、分页返回
预留空间10-20%Agent 推理、生成响应必须保留,不可侵占

注意:OpenCode 不提供精确到类别的预算分配配置,上表是概念性的预算分配原则。实际控制通过 compaction.reserved 设置整体预留空间,以及 Provider 层的 thinking.budgetTokens 控制推理预算。

预算超限的处理机制

当 Token 使用接近上限时,系统依次触发三级响应:

flowchart TB
    A[Token 使用 > 80%] --> B{触发压缩}
    B --> |成功| C[继续执行]
    B --> |仍超限| D{模型降级}
    D --> |成功| E[使用更便宜模型]
    D --> |仍超限| F{强制截断}
    F --> G[丢弃最早历史]

    C --> H[任务完成]
    E --> H
    G --> H

    style A fill:#FFF4E8,color:#333
    style B fill:#4A90D9,color:#fff
    style D fill:#FF9F43,color:#fff
    style F fill:#DC3545,color:#fff

三级响应详解

级别触发条件动作影响
压缩Token > 80%执行 Compaction有损但保留关键信息
降级Token > 90%切换到更便宜的模型响应质量下降
截断Token > 95%丢弃最早的历史可能丢失重要上下文

配置超限响应

{
  "compaction": {
    "auto": true,
    "prune": false,
    "reserved": 10000
  }
}

OpenCode 的 Compaction 机制在上下文接近窗口上限时自动触发。当 Token 使用量达到模型上下文限制的约 80% 时,系统会启动一个专门的 compaction Agent,对历史消息进行智能摘要压缩,替换掉原始冗长的对话记录。reserved 参数确保压缩过程中有足够的缓冲空间不会溢出。此外,还可以通过 Provider 的 thinking.budgetTokens 控制推理 Token 预算:

{
  "provider": {
    "anthropic": {
      "models": {
        "claude-sonnet-4-20250514": {
          "options": {
            "thinking": {
              "type": "enabled",
              "budgetTokens": 16000
            }
          }
        }
      }
    }
  }
}

三层协作的决策流程

压缩、缓存、预算三层如何协作?以下是完整的决策流程:

flowchart TB
    Start[新请求到达] --> Check{缓存命中?}

    Check --> |是| UseCache[使用缓存内容]
    Check --> |否| LoadContent[加载完整内容]

    UseCache --> Budget{预算检查}
    LoadContent --> Budget

    Budget --> |预算充足| Execute[执行任务]
    Budget --> |预算紧张| Compact{触发压缩?}

    Compact --> |是| DoCompact[执行 Compaction]
    Compact --> |否| Downgrade[模型降级]

    DoCompact --> Recheck{预算足够?}
    Recheck --> |是| Execute
    Recheck --> |否| Downgrade

    Downgrade --> Execute

    Execute --> Response[生成响应]
    Response --> UpdateCache[更新缓存]
    UpdateCache --> End[完成]

    style Start fill:#E8F4FD,color:#333
    style Check fill:#50C878,color:#fff
    style Budget fill:#FF9F43,color:#fff
    style Compact fill:#4A90D9,color:#fff
    style Execute fill:#A66CFF,color:#fff
    style End fill:#E8F8EC,color:#333

决策要点

  1. 缓存优先 — 每次请求先检查缓存,命中则节省 Token
  2. 预算控制 — 加载内容后检查预算,决定是否需要压缩
  3. 压缩兜底 — 预算紧张时触发压缩,而非直接降级
  4. 渐进降级 — 压缩 → 降级 → 截断,逐级响应

上下文工程在 Harness Engineering 中的位置

上下文工程是 Harness Engineering 框架的核心支柱之一:

graph TB
    subgraph Harness Engineering 双引擎
        CE[上下文工程<br/>确保 Agent 看得到]
        CS[约束系统<br/>确保 Agent 不做错]
    end

    CE --> VH[验证护栏<br/>确保输出正确]
    CS --> VH

    VH --> Result[高质量交付]

    style CE fill:#4A90D9,color:#fff
    style CS fill:#50C878,color:#fff
    style VH fill:#FF9F43,color:#fff
    style Result fill:#A66CFF,color:#fff

三者的协作关系

组件职责作用阶段
上下文工程提供决策所需信息输入阶段
约束系统限制危险操作执行阶段
验证护栏验证输出正确性输出阶段

上下文工程确保 Agent 拥有做出正确决策的信息基础;约束系统防止 Agent 执行危险操作;验证护栏在输出阶段进行最终检验。三者形成完整的质量保障闭环。

配置示例汇总

基础上下文管理配置

{
  "context": {
    "compaction": {
      "enabled": true,
      "threshold": 0.8,
      "strategy": "selective"
    },
    "caching": {
      "sessionLevel": true,
      "crossSession": false
    },
    "budget": {
      "total": 200000,
      "reserved": 0.25
    }
  }
}

高级上下文管理配置

{
  "context": {
    "compaction": {
      "enabled": true,
      "threshold": 0.75,
      "strategy": "selective",
      "rules": [
        {
          "type": "code",
          "action": "summarize",
          "keepSignature": true
        },
        {
          "type": "tool_output",
          "action": "protect",
          "window": "40K"
        },
        {
          "type": "conversation",
          "action": "summarize",
          "keepUserMessages": true
        }
      ]
    },
    "caching": {
      "sessionLevel": true,
      "crossSession": {
        "enabled": true,
        "persistPath": ".opencode/cache",
        "maxAge": "7d",
        "entries": [
          {
            "type": "project_knowledge",
            "files": ["README.md", "CLAUDE.md", "docs/**/*.md"]
          }
        ]
      }
    },
    "budget": {
      "total": 200000,
      "allocation": {
        "system": 4000,
        "user": 50000,
        "tools": 80000,
        "reserved": 66000
      },
      "overrunHandling": {
        "compression": {
          "threshold": 0.8,
          "priority": 1
        },
        "modelDowngrade": {
          "threshold": 0.9,
          "fallbackModel": "claude-haiku",
          "priority": 2
        },
        "truncation": {
          "threshold": 0.95,
          "strategy": "fifo",
          "priority": 3
        }
      }
    }
  }
}

上下文工程安全风险分析

上下文工程管理 Agent 的“工作记忆“,安全性直接影响决策质量和数据安全。主要风险包括上下文注入攻击、压缩导致安全信息丢失、缓存污染/泄露、以及 Token 预算不足导致安全检查被跳过。

更详细的风险分析、配置示例和安全检查 → 安全总览

安全检查清单

上下文工程的安全检查(Prompt 注入检测、缓存加密、Token 预算安全预留)与完整安全策略 → 安全总览

小结

上下文工程是 AI Agent 的“记忆管理“方法论,核心解决有限 Token 空间与无限信息需求之间的矛盾。三层模型——压缩、缓存、预算——从不同维度管理上下文:

  • 压缩层:选择性保留关键信息,丢弃低价值内容
  • 缓存层:一次传输重复内容,避免浪费 Token
  • 预算层:预分配空间,优先保障关键区域

三层协作的决策流程遵循“缓存优先、预算控制、压缩兜底“的原则。在实际配置中,需要根据任务特征调整参数,在 Token 节省和信息保真度之间找到最佳平衡点。


常见反模式

反模式一:过度压缩导致信息丢失

现象:将 Compaction 的压缩比调到极限,会话中保存的历史信息被大幅摘要化。Agent 在后续任务中反复遗漏关键细节,需要频繁重新解释上下文。

原因:追求极致的 Token 节省,低估了压缩对信息保真度的影响。成本优化的优先级高于任务质量。

对策:保留合理的预留空间(reserved: 10000),区分“必须保留“和“可以压缩“的内容类型——用户指令、关键决策用 protect 动作保护,历史对话和工具输出用 summarize 压缩。

反模式二:忽视缓存预热

现象:每次新会话 Agent 都要从零扫描项目结构、重新加载文档,前几轮交互效率极低,大量的 Token 消耗在重复加载稳定信息上。

原因:未启用跨 Session 缓存,或认为缓存配置过于复杂不值得做。

对策:配置 crossSession 缓存,将 README.md、AGENTS.md 等稳定的项目知识加入缓存白名单;Session 启动时通过 Skill 主动加载常用上下文,预热缓存。

反模式三:Token 预算分配失衡

现象:系统指令和工具定义占用了过多的 Token 预算,留给 Agent 推理空间的不足。任务进行到一半频繁触发截断,重要决策因空间不足被丢弃。

原因:将大量参考文档直接注入系统消息而非使用 Skill 按需加载。

对策:精简 system prompt 至核心指令;将冗长的参考文档放入 Skill 的 reference/ 目录按需加载而非直接注入系统消息;使用 thinking.budgetTokens 合理分配推理预算。

常见错误与陷阱

场景一:上下文注入攻击

场景:Agent 通过 WebFetch 工具读取了一个包含恶意指令的网页。网页中的隐藏指令加载到上下文后,Agent 的后续行为被劫持,执行了非预期的操作。

后果:Agent 行为被污染,可能泄露项目信息或执行危险命令。

预防:对 WebFetch 返回内容进行安全过滤,隔离用户输入和系统指令的边界;Subagent 默认只读权限限制攻击面;在安全敏感场景中禁用 WebFetch 工具。

场景二:跨 Session 缓存污染

场景:跨 Session 缓存将过期项目知识缓存了 30 天。项目在此期间重构了 API,但 Agent 在不同 Session 中持续使用过时的 API 信息生成代码。

后果:大量代码基于过时假设编写,需要返工,浪费数小时。

预防:设置合理的缓存过期时间(maxAge: 7d);配置文件变更触发的缓存失效机制;关键项目知识变更后手动清除缓存。

场景三:压缩丢失关键决策记录

场景:Agent 在长会话中经过多轮讨论做了一个重要架构决策。Compaction 触发后,将包含该决策的对话摘要化,后续 Agent 不再记得这个约束。

后果:Agent 做出与之前决策相矛盾的设计,架构一致性被破坏。

预防:将关键决策写入外部持久化文件(如 AGENTS.md 或项目决策记录),而非仅依赖上下文;在压缩规则中将“决策“类型设为 protect 动作,确保不被摘要化。

适用场景与限制

上下文工程最有效的场景:长会话的复杂任务(代码重构、多文件修改)、大型代码库的日常开发、需要频繁切换上下文的项目、跨 Session 的持续开发工作。在这些场景中,合理的上下文管理能显著提升 Agent 决策的准确性和一致性,缓存机制可节省 60% 以上的 Token 消耗。

上下文工程不太有效的场景:单轮查询(如代码解释、文档查询)、极小的项目(不足 10 个文件)、Token 预算充足的简单任务。在这些场景中,上下文管理带来的收益有限,默认配置即可满足需求。

高效使用上下文工程需要满足的前提条件:对模型上下文窗口大小有准确了解;能区分“必须保留“和“可以压缩“的信息类型;有稳定的项目知识结构和文档组织;定期检查缓存命中率以优化配置;有应对上下文注入攻击的安全意识。


学习检查清单

完成本章学习后,请确认你能够:

  • 解释上下文工程三层模型(压缩、缓存、预算)的核心职责
  • 描述 Compaction 自动压缩机制的触发时机和保留原则
  • 区分 Session 级缓存与跨 Session 缓存的应用场景
  • 配置 Token 预算分配策略并说明四个区域的作用
  • 说明上下文工程与约束系统、验证护栏的协作关系

关联章节