Hermes 101|05|Context Builder

上下文不是越多越好。Context Builder 决定哪些信息进入模型、以什么顺序进入、如何避免 prompt 膨胀。

Hermes 101|05|Context Builder

很多 Agent 失败并不是因为模型能力不够,而是因为模型看到的上下文不对。

它可能缺少项目约定,所以写出了不符合仓库风格的代码;也可能被过多历史消息淹没,在旧结论和新任务之间摇摆;还可能看到了一个当前不可用的工具,于是计划从第一步就偏离现实。

这就是 Context Builder 的位置。它不是简单把所有材料拼成 prompt,而是在每轮模型调用之前,把身份、规则、会话状态、任务输入、工具能力和外部记忆组织成一个可执行的工作集。

Context Builder 把运行时状态组装成模型输入

读完本文,你应该能回答

  • 上下文为什么不是越多越好?
  • Context Builder 如何决定模型这一轮能看到什么?
  • 系统规则、项目规则、技能、记忆和工具 schema 应该怎样排序?
  • 如何避免旧历史、无关规则或不可用工具污染当前任务?

本篇在系列中的位置

前面已经有 loop、tools 和 session,本篇回答模型调用前的关键问题:这一轮到底把什么交给模型。下一篇会继续看当上下文太长时,Hermes 如何压缩而不是简单丢弃历史。

贯穿案例

贯穿这个系列,可以一直带着同一个任务来读:用户说“帮我修复这个 repo 里的 failing tests”。不同章节会回答同一个任务在运行时的不同问题:入口怎样进入、上下文怎样准备、模型怎样决定下一步、工具怎样执行、状态怎样保存、失败后怎样恢复。

定义

Context Builder 是 Agent Runtime 中负责构造模型输入的层。它决定哪些信息进入上下文、以什么格式进入、在什么时机进入,以及哪些信息必须留在模型视野之外。

最小 Agent 里,context builder 往往只是一段数组拼接:

const request = [
  { role: "system", content: systemPrompt },
  ...history,
  { role: "user", content: userInput }
]

这个实现能跑 demo,但不能支持长期任务。真实 Agent 的输入来自多个来源:系统身份、用户偏好、项目规则、技能说明、工具 schema、会话历史、压缩摘要、检索结果、平台元数据和当前工作目录。Context Builder 的核心价值,是让这些来源形成稳定的层次,而不是互相覆盖。

Hermes 的上下文来源

Hermes 的上下文构造可以分成几类。

第一类是 稳定身份层。例如全局 personality、工具使用规则、安全约束、执行纪律。这些内容通常进入 system prompt,并且需要保持稳定,因为频繁改变 system prompt 会破坏 prompt caching,也会让同一个 session 的行为难以解释。

第二类是 项目上下文层。Hermes 会从工作目录发现项目级 Hermes 配置文件、AGENTS.mdCLAUDE.md、编辑器规则文件等上下文入口。启动时加载根目录上下文;当工具访问子目录时,再按需发现子目录里的 AGENTS.mdCLAUDE.md。这是一种渐进式上下文注入:不把整个仓库规则一次塞进 prompt,而是在路径真正相关时才进入模型视野。

第三类是 能力层。工具 schema、skills 索引、MCP 工具、插件暴露的能力,都会影响模型计划。Context Builder 必须只暴露当前可用的能力,否则模型会把不可执行的动作当成计划基础。

第四类是 会话层。当前消息、历史对话、工具结果、压缩摘要、session metadata、token 统计,决定模型如何接续任务。这里的难点不是“保留越多越好”,而是既要保留决策依据,又要避免旧信息拖累当前任务。

上下文来源不是平铺,而是按优先级和时机进入

Context 冲突矩阵

读这一篇时,最容易混淆的是:不同来源的上下文都像“提示词”,但它们的优先级和风险完全不同。可以用下面这张表判断冲突时应该保留谁、压低谁。

冲突场景 应该优先相信 应该压低或隔离 原因
用户当前请求 vs 旧会话摘要 用户当前请求 旧摘要 当前 turn 是最新意图,旧摘要只提供背景
项目规则 vs 通用编码习惯 项目规则 通用习惯 Agent 应该服从当前 repo 的约定
Tool result vs 模型猜测 Tool result 猜测 工具结果是可观察事实
Skill 流程 vs 当前错误信息 当前错误信息 Skill 中过时步骤 Skill 是经验,不是不可变规则
可用工具列表 vs 记忆里的旧工具 当前工具列表 旧记忆 模型只能调用本轮真实暴露的工具

这张表的意义不是让 Context Builder 做“文本排序”,而是让它在进入模型前先完成一次语义分层:哪些是硬约束,哪些是背景,哪些只是候选建议。

组装顺序比内容更多

Context Builder 的一个常见误区,是只关注“放什么”,不关注“放在哪里”。

对模型来说,顺序和边界会改变语义。系统规则、项目规则、用户当前请求、工具结果、历史摘要如果混在同一段文本里,模型很难判断哪条信息优先级更高。Hermes 的设计倾向于把不同来源放在清晰的段落中,并让关键约束出现在稳定位置。

可迁移伪实现:Context Builder

下面的伪代码是机制抽象,不对应 Hermes 的真实 API 或文件结构。

一个工程化的 Context Builder 可以抽象成这样:

type ContextSource =
  | { kind: "identity"; priority: 100; content: string }
  | { kind: "project"; priority: 80; content: string }
  | { kind: "skill"; priority: 70; content: string }
  | { kind: "memory"; priority: 60; content: string }
  | { kind: "session"; priority: 50; messages: Message[] }
  | { kind: "tool_schema"; priority: 40; tools: ToolSchema[] }

async function buildProviderRequest(input: UserInput): Promise<ModelRequest> {
  const sources = await collectContextSources(input)
  const scanned = sources.filter(passPromptInjectionScan)
  const bounded = applyTokenBudgets(scanned)

  return {
    system: renderSystemSections(bounded),
    messages: renderConversation(input.session, bounded),
    tools: renderAvailableToolSchemas(bounded)
  }
}

这里有三个边界很关键。

首先,Context Builder 不应该信任所有文本。项目上下文文件可能来自外部仓库,网页内容可能包含 prompt injection,工具结果也可能把恶意指令带回上下文。进入 prompt 之前要做扫描、截断和标注。

其次,Context Builder 不应该破坏消息角色结构。工具调用和工具结果有 provider 规定的对应关系,不能为了压缩或拼接方便把它们变成普通段落。

最后,Context Builder 不应该把“长期记忆”和“当前工作集”混为一谈。记忆是可检索资产;工作集是本轮模型真正需要看的内容。把所有记忆常驻 prompt,会把个性化变成上下文污染。

渐进式发现

Hermes 的子目录上下文发现体现了一个重要原则:上下文应当跟随行动路径,而不是跟随仓库体积。

当 Agent 读取 backend/src/main.py 时,系统会检查相关目录上是否存在 AGENTS.mdCLAUDE.md,并把发现的规则随工具结果注入给模型。这样做有两个收益。

第一,系统 prompt 保持相对稳定,有利于缓存和可预测性。第二,模型只在接触某个区域时看到该区域规则,减少无关约束干扰。

这类设计也解释了为什么 Context Builder 不是一个纯字符串函数。它需要知道工具调用路径、当前工作目录、session 来源、平台、模型上下文长度和可用工具集合。

产品边界

Context Builder 决定 Agent 的“注意力界面”。如果它过于保守,模型缺少必要材料;如果它过于贪婪,模型会被噪声拖慢,并且成本上升。

好的 Context Builder 不是追求最大上下文,而是追求 最小充分上下文:让模型看到完成当前任务需要的事实、规则、工具和状态,同时保留边界、来源和优先级。

小结

Hermes 的 Context Builder 说明了一件事:Agent 的智能不只来自模型,也来自模型调用前的输入组织。上下文工程的核心不是“塞更多资料”,而是持续回答一个工程问题:这轮行动,模型到底需要看到什么。