Agent Engineering 101|09|Context Builder

Context Builder 是每轮模型调用前的工作集构造层。它把 system prompt、session branch、dynamic messages 和 tool schemas 组合成模型请求。

Agent Engineering 101|09|Context Builder

核心结论

配套代码仓库: github.com/llm-101/mini-agent-harness

读完本文,你应该能回答

  • Context Builder 和 prompt 拼接有什么区别?
  • system prompt、session branch、tool results、skills 如何组成工作集?
  • 为什么“全塞进去”不是上下文工程?
  • 不同任务阶段应该选择哪些上下文?

本篇在系列中的位置

  • 上一篇:08 Tool Runtime 产生了可回灌的工具结果。
  • 本篇:本文解释每轮模型调用前,Harness 如何选择模型能看到的工作集。
  • 下一篇:10 Compaction 会处理上下文超过预算后的连续性问题。

贯穿例子

本系列会反复使用同一个任务来连接各章:

用户说:“帮我修复这个 repo 里的 failing tests。”

在这个任务里,Context Builder 决定下一轮模型应该看到哪些测试输出、哪些文件片段、哪些历史决策、哪些 skill 约束。读者要关注的是:上下文不是越多越好,而是为了做对下一步而选择当前工作集。

  • Context Builder 把状态事实源转换为本轮模型可见的工作集。它不是记忆本身,而是 context assembly 的边界。
  • 如果在模型调用前到处临时拼 prompt,系统会失去上下文顺序、来源、预算和可测试性。
  • mini-agent-harness 中,Context Builder 是每轮调用前的选择器:它决定模型这一轮真正需要看到什么。

定义

Context Builder 把状态事实源转换为本轮模型可见的工作集。它不是记忆本身,而是 context assembly 的边界。

为什么要单独看这一层?

模型上下文窗口有限,任务相关信息却不断增长。Context Builder 的价值,是把“所有历史”变成“这一轮必须使用的工作集”。

Context Builder

边界

这一层的职责可以拆成几个稳定部分:

  • System Prompt:稳定运行时指令
  • Project Context:AGENTS.md / README.md / .cursorrules 注入
  • Session Branch:active branch 消息
  • Dynamic Messages:临时注入的上下文
  • Tool Schemas:本轮可用工具列表
  • Metadata:messageCount 与 toolCount

这一层的边界可以用一个问题检验:如果它的内部实现变化,模型适配、工具执行、状态存储和产品外壳是否都不需要跟着重写?如果答案是否定的,说明这个边界还没有真正收束变化。

代码锚点

本篇主要对应这些模块:

  • src/context/context-builder.ts
  • src/core/context-files.ts
  • src/core/harness.ts

阅读代码时建议先看类型,再看运行路径。

类型定义告诉你这一层暴露什么 contract;运行路径告诉你这个 contract 在 Agent 执行中何时被消费、何时被写回、何时被产品层看见。

运行流程

Runtime Context Assembly

一次典型执行可以概括为:

  1. Load State:session branch
  2. Inject Project:context files
  3. Attach Skills:system suffix
  4. Attach Tools:schemas
  5. Build Request:NormalizedModelRequest
  • Order:上下文顺序
  • Budget:token 成本
  • Source:上下文来源

这里最容易被忽略的是“中间态”。生产级 Agent 不是只关心最终答案;它还要在运行过程中展示进度、捕获错误、记录 usage、允许取消,并把可恢复状态写回 session。

读者抓手:工作集选择矩阵

候选内容 什么时候应该进入上下文 什么时候不该进入
system prompt 每轮都需要 几乎不应省略
最近 user/assistant messages 当前任务连续性依赖时 与当前分支无关时
tool results 下一步判断依赖真实结果时 已被 summary 准确覆盖时
skill instructions 任务类型匹配时 只会增加噪音时
long history 需要追踪旧决策时 超出预算且已可压缩时
dynamic project context 修改代码/文件时 闲聊或纯解释任务时

Context Builder 的核心判断不是“能塞多少”,而是“这一轮模型为了做对下一步,必须看到什么”。

可迁移伪实现:上下文构造

下面的伪代码是机制抽象,不对应真实 API 或文件结构。它只用来说明这一层的控制点:

const messages = [...dynamicMessages, ...sessionMessages];
return {
  systemPrompt,
  messages,
  tools,
  metadata: { messageCount: messages.length, toolCount: tools.length }
};

这个草图的价值在于说明控制点,而不是提供可复制的库代码。

真正的工程实现还要处理错误、取消、并发、token 预算、日志、权限、序列化和 provider 差异。

工程原则

将这一层从 Agent 系统中拆出来,通常带来四个直接收益。

第一,可替换。

外部系统、模型 provider、工具集合或产品外壳变化时,核心运行时不必整体重写。

第二,可观测。

边界清晰后,事件、trace、usage、错误和状态迁移都有稳定落点。

第三,可恢复。

只要状态写入 session,运行时就可以在进程重启、工具失败或长任务中断后继续推理。

第四,可治理。

权限、脱敏、审批、路径保护和执行策略可以放在稳定 hook 或 runtime boundary 上,而不是只靠 prompt 约束。

和 Agent Harness 的关系

Agent = Model + Harness 这个公式的重点,不是把模型之外的所有东西都称为“工程杂活”。

相反,它提示我们:模型之外存在一套必须被设计的运行时系统。

Context Builder 就是这套系统中的一个切面。它不替代模型能力,也不替代产品体验;它让模型能力可以被组织成可执行、可观察、可恢复、可治理的任务流程。

小结

Context Builder 的核心价值,是把一类容易扩散的复杂性收束到明确边界中。

mini-agent-harness 中,这个边界被刻意写得较小,方便阅读和教学。但它对应的问题并不小:只要一个 Agent 要长期运行、调用工具、管理上下文、支持 UI、保存状态并处理失败,这个边界就会出现。

下一步可以继续沿着系列计划,把这些边界组合成完整 Agent Harness:模型边界、工具边界、状态边界、上下文边界、扩展边界和产品外壳边界。