🧩 上下文工程

F2 章说过 context window 有限,历史会撑爆它。这是所有长任务 Agent 的核心难题。本章看 OpenCode 如何工程化地管理上下文:compaction(压缩历史)、子 Agent(分流任务)、按模型动态选 system prompt。这是生产 Agent 的"记忆艺术"。

本章目标

  • 理解 compaction 如何压缩历史消息(对应 F2 的记忆管理)
  • 掌握子 Agent 派生机制(task 工具,对应 LG3 的 Send)
  • 看清 system prompt 如何按模型动态选择
  • 理解 overflow 检测和自动 compaction 触发
  • 对比 LG2 的 RemoveMessage,看生产级方案的成熟度

上下文管理:生产 Agent 的核心难题

回顾 F2 章的核心约束图:

Context Window(固定大小) 对话历史 ↑ Agent 每步都在变长 当前输入 system prompt 输出预留
图 OC5.1 · 对话历史不断膨胀,迟早撑爆 context window

一个编码 Agent 可能跑几十上百步(读很多文件、改很多代码、执行很多命令),历史消息可能几十万 token。必须主动管理,否则:① 超出窗口报错;② 费用爆炸;③ 模型被旧信息干扰。OpenCode 用三大手段解决:

🗜️

compaction 压缩

token 溢出时,让专门 agent 总结历史,用摘要替换旧消息。

🔀

子 Agent 分流

把独立子任务交给子 agent,结果只回传摘要,不污染主上下文。

🎯

动态 system prompt

按模型特性选不同提示,注入环境信息,精准控制 agent 行为。

① compaction:历史压缩

这是 OpenCode 处理溢出的核心机制。源码在 session/compaction.ts

📄 session/compaction.ts · 核心接口(精简) typescript
// compaction 模块的核心方法
interface Interface {
  isOverflow(input: { tokens; model }): Effect<boolean>   // 检测是否溢出
  create(input: { sessionID; agent; model; auto }): ...    // 创建压缩任务
  process(input: { messages; sessionID; ... }): ...        // 执行压缩
  prune(input: { sessionID }): ...                         // 清理旧压缩记录
}

export const PRUNE_MINIMUM = 20_000   // 触发清理的最小 token
export const PRUNE_PROTECT = 40_000   // 保护阈值

compaction 的工作原理

compaction 压缩流程 ① 检测溢出:isOverflow(tokens, model) runLoop 每步检查 token 是否超模型窗口 ② 创建压缩任务(用专门的 compaction agent) result === "compact" 时,runLoop 触发 ③ compaction agent 总结历史 → 用摘要替换旧消息 几十条消息 → 一段摘要(保留关键信息) ④ 主 agent 带着精简历史继续工作
图 OC5.2 · compaction 用"专门的 agent"压缩历史,保留关键信息
📄 runLoop 里的 compaction 触发(OC2 回顾) typescript
// runLoop 内(prompt.ts:1149-1168):

// 显式压缩任务
if (task?.type === "compaction") {
  const result = yield* compaction.process({ messages: msgs, ... })
  if (result === "stop") break
  continue
}

// 自动检测溢出 → 触发压缩
if (lastFinished && lastFinished.summary !== true
    && (yield* compaction.isOverflow({ tokens: lastFinished.tokens, model }))) {
  yield* compaction.create({ sessionID, agent, model, auto: true })
  continue    // 压缩后继续循环
}

// handle.process 返回 "compact" 时也触发
if (result === "compact") {
  yield* compaction.create({ sessionID, ..., overflow: !handle.message.finish })
}
💡 compaction agent 是"内部的"

注意 compaction 用的不是主 agent,而是专门的 compaction agentagent.ts:220 定义,hidden)。它的提示词(compaction.txt)专门优化为"忠实总结对话"。用小模型跑(省钱),产出摘要替换旧消息。这是"用 AI 管理 AI 上下文"的精妙设计。

② 子 Agent:分流任务

对应 LG3 的 Send(map-reduce)。OpenCode 的 task 工具派生子 Agent,把独立子任务隔离:

📄 tool/task.ts · 子 Agent 派生(精简) typescript
// task 工具:派生子 agent 执行独立子任务
export const TaskTool = Tool.define("task", Effect.gen(function* () {
  return {
    description: DESCRIPTION,   // task.txt:告诉模型何时派生子任务
    parameters: Schema.Struct({
      description: Schema.String,  // 子任务描述
      agent: Schema.String,        // 用哪个子 agent(explore/general...)
      prompt: Schema.String,       // 给子 agent 的指令
    }),
    execute: (params, ctx) => Effect.gen(function* () {
      // ① 创建子会话
      const childSession = yield* sessions.create({
        parentID: ctx.sessionID,
        agent: params.agent,
        ...
      })
      // ② 派生子 agent 权限(OC4:继承 deny + 禁止递归)
      const childPermission = deriveSubagentSessionPermission(session.permission)
      // ③ 子 agent 独立跑(有自己的上下文,不污染主会话!)
      const result = yield* prompt.loop({
        sessionID: childSession.id,
        ...
      })
      // ④ 只把【结果摘要】回传主 agent(不是完整历史)
      return { output: result.summary }
    }),
  }
}))
主 Agent build 子 Agent(独立上下文) explore:探索代码库 读10个文件(不进主上下文!) 子 Agent(独立上下文) general:通用任务 独立完成(结果摘要回传) 摘要回传 只传结果,不传过程 派生 摘要
图 OC5.3 · 子 Agent 有独立上下文,只回传摘要——保护主上下文不被污染
⚠️ 子 Agent 的价值:上下文隔离

如果主 Agent 自己探索代码库,要读 10 个文件,每个文件几百行——主上下文瞬间爆炸。用子 Agent:探索在子上下文里发生,主 Agent 只收到一段摘要。这是上下文管理的结构性方案,比 compaction(事后压缩)更主动。对应 LG3 的 Send,但目标是上下文隔离而非并行加速。

③ 动态 system prompt

不同模型(Claude/GPT/Gemini)特性不同,最优提示也不同。OpenCode 按模型动态选择 system prompt:

📄 session/system.ts:26 · 按模型选 prompt typescript
export function provider(model: Provider.Model) {
  if (model.api.id.includes("gpt-4") || ...o1...o3) return [PROMPT_BEAST]  // GPT-4/o系列
  if (model.api.id.includes("gpt")) {
    if (model.api.id.includes("codex")) return [PROMPT_CODEX]               // Codex
    return [PROMPT_GPT]                                                     // 其他 GPT
  }
  if (model.api.id.includes("gemini-")) return [PROMPT_GEMINI]              // Gemini
  if (model.api.id.includes("claude")) return [PROMPT_ANTHROPIC]            // Claude
  if (...kimi...) return [PROMPT_KIMI]
  return [PROMPT_DEFAULT]                                                   // 兜底
}

对应的提示文件在 session/prompt/(anthropic.txt 105行、gpt.txt 107行、gemini.txt 155行 等)。每个都是针对该模型特性精心调优的指令。

system prompt 的完整组装

OC2 看到 runLoop 这样组装 system(prompt.ts:1256-1268):

📄 system prompt 四部分(OC2 回顾) typescript
// 并发获取四部分(Effect.all)
const [skills, env, instructions, mcpInstructions, modelMsgs] = yield* Effect.all([
  sys.skills(agent),          // ① 可用 skill 列表
  sys.environment(model),     // ② 环境信息(工作目录/git/平台/日期)
  instruction.system(),       // ③ AGENTS.md/CLAUDE.md 等指令文件
  sys.mcp(agent, ...),        // ④ MCP server 指令
  MessageV2.toModelMessagesEffect(msgs, model),
])
const system = [
  ...env,                     // 环境信息
  ...instructions,            // 项目指令
  ...(mcpInstructions ? [mcpInstructions] : []),  // MCP
  ...(skills ? [skills] : []),                     // skills
]
// 外层还会加 provider(model) 选的模型专属提示

其他内置 Agent

Agent用途hidden
build默认主 agent,全部权限
plan规划模式,禁用编辑工具,只写 .opencode/plans
explore代码库探索子 agent,只读 + bash/webfetch
general通用子 agent
compaction上下文压缩(用小模型)
title生成会话标题
summary生成会话摘要

这体现了"多 Agent 协作":不同任务用不同特化的 agent,各自有独立上下文和权限。

与框架对照

OpenCode 概念框架对应
compaction 历史压缩LG2 RemoveMessage 裁剪(更初级)
isOverflow 溢出检测需自己实现(框架不管)
compaction agent 总结需自己写总结节点
task 子 agent 派生LG3 Send(map-reduce)/ 子图
子 agent 上下文隔离子图的独立 state
按模型选 system promptLC2 ChatPromptTemplate(但通常固定)
动态注入 environment需自己组装(工作目录/git 等)
多内置 agent 协作多图/supervisor 模式
🧭 上下文工程是"产品级"的分水岭

教学框架的 Agent 通常不管上下文长度——演示用,历史短。但真实产品跑长任务,上下文工程是核心能力:compaction、子 agent、智能裁剪。OpenCode 在这方面做得很完整——这也是它比"玩具 Agent"强大的关键。学完本章你应理解:会写 Agent 循环只是入门,会管理上下文才是产品级

小结

下一章 · 本教程终章 ★

最后一章 OC6 · 概念对照表——本教程的收官!用一张大表把所有概念两两对照:基础理论 ↔ LangChain ↔ LangGraph ↔ OpenCode。这是你复习和查阅的终极参考,也是验证"是否真正理解"的试金石。