Coding Agent 的上下文并不是一份不断增长的聊天记录。模型每次决策前看到的输入,来自项目指令、Rules、Skill、工具定义、会话历史、外部记忆和运行时事件。它们由不同组件保存,在不同时间进入工作窗口,也由不同机制负责恢复。

如果不先划清组件边界,几个常见问题会混成一团:AGENTS.md 和 Skill 谁优先,MCP 与 Tool Search 是否相同,Hook 算不算上下文,Subagent 是工具还是新会话,compact 后恢复的是历史还是外部材料。

这套系统更接近一台上下文操作系统。模型只处理当前工作集;Harness 负责装配、换页、执行、隔离和验证。

核验日期:2026-07-17。本文讲稳定组件和边界。各产品的版本差异集中在实现图谱中维护。

上下文系统的五类组件

同一个 Markdown 文件可能同时带有说明、脚本入口和资源链接,但在运行时仍可以按职责拆成五类。

组件类别 主要对象 回答的问题
内容源 System prompt、AGENTS.mdCLAUDE.md、Rules、Skill、Memory、文件 有哪些材料可以进入工作集
选择器 层级覆盖、glob、description 路由、Tool Search、检索器 当前任务需要哪些材料
装配器 Context builder、message converter、tool registry 材料以什么顺序和语义进入模型输入
执行器 Tool、MCP server、脚本、Subagent、sandbox 模型选定动作后由谁改变外部世界
生命周期控制 Hook、cache、prune、compact、checkpoint、trace 工作集怎样增长、压缩、恢复和审计
flowchart LR
    subgraph S["内容源"]
        S1["System / Developer"]
        S2["AGENTS / CLAUDE / Rules"]
        S3["Skills / Commands"]
        S4["Files / Memory / History"]
        S5["Tool / MCP schemas"]
    end

    subgraph Q["选择与装配"]
        Q1["Scope / precedence"]
        Q2["Router / retrieval"]
        Q3["Context assembler"]
    end

    subgraph R["模型工作集"]
        R1["Instructions"]
        R2["Tools"]
        R3["Messages"]
    end

    subgraph E["执行与隔离"]
        E1["Local tools"]
        E2["MCP / remote APIs"]
        E3["Subagent context"]
    end

    subgraph L["生命周期"]
        L1["Prompt cache"]
        L2["Prune / compact"]
        L3["Memory / checkpoint"]
        L4["Hooks / trace"]
    end

    S --> Q --> R --> E
    E --> R
    R --> L
    L --> Q

Hook 没有被画进内容源,因为 Hook 本身是事件处理器。它可以生成上下文,也可以只记录日志、修改参数或阻断动作。只有 Hook 的输出被 Context Assembler 接纳时,那部分输出才成为模型上下文。

模型看到的是装配结果

不同 Provider 使用 system、developer、user、assistant、tool 等不同 role,但 Harness 层可以先抽象成三块。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Model Input
├── Instructions
│ ├── Harness baseline
│ ├── Project guidance
│ └── Selected rules / skills / memory
├── Tool definitions
│ ├── Built-in tools
│ ├── MCP tools
│ └── Deferred tools discovered later
└── Conversation items
├── User intent
├── Assistant actions
├── Tool results
├── Loaded skill body
└── Compaction item / summary

某段内容来自 SKILL.md,不代表它必须进入 system role;某个 MCP 工具出现在工具面,也不代表它的说明永远常驻模型上下文。产品可以改变具体消息形态,只要语义和生命周期保持一致。

因此,运行时 trace 只能证明某个版本、某个模型和某种配置下的实现。它不适合直接写成跨版本协议。

持久项目指令

AGENTS.mdCLAUDE.md 和 Project Rules 都属于持久项目指令。它们描述仓库边界、构建命令、目录职责、验证方式和长期约束。

这类文件有三个共同特征:

  • 生命周期通常长于单次任务
  • 作用域由目录层级、文件模式或产品配置决定
  • 内容在任务开始前就应成立,不依赖某个特定工作流是否被调用

它们最适合保存“在这个仓库里一直成立”的规则,例如:

  • 哪些目录可写
  • 使用哪个包管理器
  • 代码修改后运行哪些检查
  • 哪些生成目录不能手工编辑
  • 子目录是否有更具体的约束

大型操作手册、框架教程和只在少数任务中使用的 SOP 不适合常驻。它们会抬高每次请求的固定基线,也会让关键仓库规则埋在大段说明里。

Rules 是条件式指令

Rules 解决的是“哪些指令在什么作用域生效”。选择条件可以是:

  • 无条件应用
  • 当前路径或被读写文件匹配 glob
  • 模型根据 description 判断
  • 用户显式引用
  • 更近目录覆盖更远目录

Rules 与 Skill 都可能由 Markdown 表达,但语义不同。Rule 约束当前任务,Skill 提供完成某类任务的方法和资源。Rule 通常不应要求模型“调用自己”;Skill 则需要一次激活动作,才能展开正文和资源。

Cursor 的 Project Rules 同时支持 Always、智能选择、文件模式和手动应用。Codex 与 Claude Code 的项目指令更强调目录层级。产品名称不同,底层都是作用域选择器。

Skill 是动态能力包

Skill 的核心不是一段额外提示词,而是一个可渐进展开的能力包:

1
metadata -> workflow body -> references / scripts / assets

metadata 进入轻量目录,帮助模型或用户选择。正文只在激活后进入工作集。参考材料和脚本继续留在外部,直到当前分支需要。

这种结构把“知道有这项能力”和“承担这项能力的全部成本”分开。目录承担召回,正文承担工作流,脚本承担确定性动作,资源承担交付素材。

Skill 的详细加载、热更新和 compact 恢复见《AI Coding Agent 的 Skill 加载机制深度解析》

Tool 与 MCP 属于执行面

Tool 是模型可以请求的动作接口。文件读取、Shell、编辑器操作、浏览器、数据库查询和代码搜索都可以表现为 Tool。

MCP 定义 Host、Client、Server 如何交换 tools、resources 和 prompts。它解决跨进程和跨产品互操作,不替 Harness 决定:

  • 当前是否应该调用
  • 哪个参数需要审批
  • 失败后是否重试
  • 结果怎样裁剪
  • 停止前需要什么验证

一个 MCP tool 进入 Harness 后仍要经过 Tool Registry、权限规则、Hook 和消息转换。协议接通了能力,运行时负责治理能力。

Tool Search 又处在另一层。它延迟的是完整 tool schema,让模型先看到搜索入口或轻量索引,找到相关工具后再展开定义。它与 Skill 都采用渐进披露,但选择对象不同。

Messages 是短期工作轨迹

Messages 保存当前任务发生过什么:用户目标、模型动作、工具结果、文件观察、失败路径和验证证据。

append-only 历史会混入大量过时状态:

  • 已经修正的错误假设
  • 被放弃的方案
  • 长日志和重复文件内容
  • 与当前目标无关的探索
  • 已完成子任务的过程细节

Harness 需要 prune、compact、externalize 和 replay 等策略管理它。对话历史并不是长期事实源。仓库真相仍在文件、git、测试、issue 和外部系统中,必要时应该重新读取。

《Messages 数组与 Prompt Cache:六种操纵策略》专门讨论 message array 的增长和缓存边界。

Memory 保存跨轮次和跨会话状态

Memory 不是一种单一文件格式。按生命周期可拆成四层:

层级 典型内容 读取方式
会话工作记忆 当前目标、最近观察、未完成动作 直接位于工作窗口
Compact 恢复包 摘要、保留尾部、外部状态指针 压缩后重建
项目记忆 构建命令、目录地图、已验证惯例 启动或相关任务时加载
长期知识 历史决策、案例、语义知识、结果反馈 检索后按需换入

项目记忆与项目规则也有边界。Rule 是必须遵守的约束;Memory 是过去观察到、未来可能有用的信息。把记忆写成绝对规则,会让过期经验长期压住新证据。

Subagent 是上下文隔离器

Subagent 表面上像一个 Tool:主 Agent 给出任务,稍后拿回结果。但它创建的是一块独立工作上下文。

sequenceDiagram
    participant P as Parent context
    participant O as Orchestrator
    participant S as Subagent context
    participant W as Workspace / tools

    P->>O: 发送有边界的任务与必要证据
    O->>S: 创建独立上下文
    S->>W: 搜索、读取、执行、验证
    W-->>S: 返回局部证据
    S-->>O: 结构化结果与引用
    O-->>P: 只回灌结论、证据和风险

父上下文不必承担子任务的全部搜索轨迹。隔离的收益来自信息过滤,而不是“多一个人格”。如果任务边界不清、共享状态频繁变化或合并协议缺失,Subagent 只会制造更多同步成本。

Hook 是运行时控制面

Hook 位于 Agent loop 的事件边界,可以观察或干预:

  • session start 和用户输入
  • tool 调用前后
  • permission request
  • compact 前后
  • subagent start/stop
  • stop 与 task completion

Hook 的输出有四种常见去向:

Hook 动作 是否进入模型上下文
写 trace 或发通知 通常不进入
阻断工具或修改参数 改变执行,不一定进入
返回错误观察 作为新观察进入
注入项目状态或恢复材料 明确进入

这也解释了为什么 compact 后可能迅速重新膨胀。压缩器刚清掉旧历史,PostCompact Hook、项目记忆和 hot paths 又把大段材料回灌,窗口仍然会很重。恢复层需要预算、去重和外部指针。

Plugin 是分发单元

Plugin 可以打包 Skill、Hook、MCP server、Subagent、Rule 和资源,但它本身通常不定义统一的上下文加载算法。

安装一个 Plugin 不等于包中所有内容都进入 prompt:

  • Skill 仍走目录和按需正文
  • MCP tool 仍走工具注册、权限和可能的延迟发现
  • Hook 仍在对应事件触发
  • Subagent 仍创建隔离上下文
  • 静态 Rule 才可能成为常驻或条件式指令

把 Plugin 画成能力分发层,比把它画成另一种 Skill 更准确。

两条正交坐标

上下文组件可以用“存活多久”和“何时激活”两条坐标定位。

对象 典型存活时间 典型激活方式
Harness baseline 产品版本级 每次会话
项目指令 仓库级 启动和目录作用域
Rules 仓库或用户级 always、路径、智能或手动
Skill metadata 安装级 catalog 装配
Skill body 任务或会话级 显式或模型调用
Tool schema 会话级或动态 注册或 Tool Search
Tool result 当前任务轨迹 工具执行
Compact summary 会话后半段 达到阈值或手动触发
项目记忆 跨会话 启动、检索或恢复
Subagent context 子任务级 编排器创建

“文件是不是 Markdown”无法说明它的运行时位置。成本和可靠性取决于作用域、选择器、装配位置、恢复规则和可观测性。

一次 Agent Turn 的装配顺序

不同产品的消息 role 和内部函数不同,但端到端过程可以稳定描述。

flowchart TD
    A["读取 Harness 基线与项目作用域"] --> B["建立 Rules / Skills / Tools 目录"]
    B --> C["接收用户目标"]
    C --> D["选择相关 Rules、Skill、Memory 与文件"]
    D --> E["装配 instructions + tools + messages"]
    E --> F["模型选择下一步动作"]
    F --> G{"动作类型"}
    G -->|local tool| H["权限 / Hook / Sandbox"]
    G -->|MCP| I["Host / Client / Server"]
    G -->|subagent| J["创建隔离上下文"]
    H --> K["执行结果"]
    I --> K
    J --> K
    K --> L["追加观察与验证证据"]
    L --> M{"工作集是否接近阈值"}
    M -->|否| F
    M -->|是| N["prune / compact / externalize"]
    N --> O["恢复项目指令、记忆指针和必要能力"]
    O --> F

装配顺序并不等于优先级。更晚进入消息尾部的内容可能位置更近,但 system 或 developer 指令通常有更高协议优先级;项目内更近目录的指令也可能覆盖根目录规则。内容冲突时需要同时检查协议 role、目录作用域、产品规则和时间新旧。

组件冲突的判断顺序

上下文冲突适合按四步定位。

  1. 先确认对象层级。模型限制、API 行为、Harness 配置和项目指令不能互相代替。
  2. 再确认作用域。全局、仓库、子目录、当前文件和当前 Skill 的适用范围不同。
  3. 检查时间状态。长期规则、当前计划、旧记忆和最新工具结果的新旧程度不同。
  4. 再检查协议优先级与执行门禁。高优先级指令仍可能被权限或 sandbox 拦截。

旧的配置文件全景常把文件按名字分类。更稳定的办法是按时间状态分类:

  • 存量知识:长期文档、历史决策、案例和术语
  • 当前对齐:项目指令、架构边界、工作约定
  • 迭代状态:plan、task、diff、测试结果、阻塞点
  • 运行时观察:工具输出、日志、浏览器状态、权限结果

同一个文件可以在不同阶段迁移。例如 plan 完成后不应继续作为当前指令常驻,它应该沉淀为决策记录或被删除。

设计检查表

评审一个 Agent Harness 时,“支持哪些文件”只够回答入口问题。还需要检查:

  • 目录如何发现,重名如何覆盖
  • catalog 是否有预算和截断告警
  • 自动路由失败能否追踪
  • Skill 正文和 Tool schema 在哪里展开
  • 动态变化是否破坏稳定缓存前缀
  • prune 与 full compact 是否分开
  • compact 后哪些外部材料自动恢复
  • Subagent 回灌的是结论还是完整轨迹
  • Hook 能否阻断、改参数或注入上下文
  • Plugin 的来源、权限和更新是否受治理
  • trace 能否证明一次动作为什么发生

这些问题共同决定上下文系统是否可维护。文件格式只是最外层接口。

系列文章

参考资料