做 Agent 产品时,最容易被低估的不是模型,也不是工具,而是两者之间那层持续变化的 Context。

我们经常把它叫作“提示词”,仿佛它只是后台的一大段文本。但一旦 Agent 开始读取仓库、调用 Bash、等待审批、使用 Browser、压缩历史,这个称呼就不再准确。它实际上是一套运行时界面:决定哪些事实可见、哪些能力可用,以及模型如何理解刚刚发生的事情。

看不见的 Context 会制造什么问题

如果用户只能看到最终回复,那么很多故障会变得难以区分:

  • 模型不知道某条规则,还是知道但没有遵守?
  • 工具没有进入本轮 Context,还是模型选择了不调用?
  • 历史被压缩后丢失了目标,还是 provider 本身出现了退化?
  • Token 突然上升,是附件、工具 schema,还是重复的工具输出?

这些问题不能只靠“再改一版 prompt”解决。首先要让运行输入成为可观察的对象。

Context 是每次调用前构建出来的

在 ActSpace 中,Context 不是某个模块持有的长字符串。每次模型调用前,Runtime 都会根据当前 session 和 Turn 重新组装:

  1. 系统规则、人格和项目级 AGENTS.md
  2. 已持久化的会话事件。
  3. 当前对模型可见的工具定义。
  4. 附件、图片与工具 observation。
  5. 用户这一次刚刚提交的输入。

这种方式有一个很实际的好处:Context 查看器可以复用相同的 producer,而不是另写一套“看起来差不多”的解释逻辑。

可见性也是产品控制面

不是所有工具都需要永久出现在模型面前。

以 Browser 为例,普通编码任务如果每轮都附上完整浏览器命令,会占用 Token,也会增加误调用概率。因此 ActSpace 在新 Turn 中只暴露一个入口;当模型确认确实需要网页操作后,下一次请求才展开完整工具组。

这不是单纯的性能优化。它把“当前有哪些能力”变成了可以按场景控制的产品决策。

为缓存安排稳定顺序

Context 还影响成本。支持 prompt caching 的模型会从稳定前缀中获益,所以我们尽量把变化慢、复用高的规则放在前面,把当前时间、工具结果和最新用户输入放在后面。

排序不能为了缓存而破坏语义,但在语义等价的前提下,稳定性本身就是 Harness 应该维护的性质。

ActSpace 会把 input、output、cache read 和费用记录到每轮用量中。缓存不再是 provider 控制台里的一个抽象百分比,而是能和具体会话、具体 Turn 对上的运行事实。

压缩不是把旧内容变短

长会话最终会接近模型的上下文窗口。最粗糙的做法是把旧消息全部总结一次,但这很容易丢掉约束、文件路径、失败原因和用户已经确认的选择。

更可靠的压缩应保留后续执行真正依赖的状态:

  • 目标和完成标准。
  • 已经做过的修改与验证结果。
  • 仍未解决的风险。
  • 关键工具输出与证据来源。
  • 用户明确否决或批准的方向。

工具输出也需要单独治理。只留下摘要可能把一个关键报错稀释掉;完整保留又会快速吞掉窗口。ActSpace 的方向是保留可识别的原始前缀,再追加结构化摘要。

把 Context 当成界面之后

一旦 Context 被当成界面,许多工程取舍会自然变得清楚:

  • 它需要稳定的数据来源,而不是散落的字符串拼接。
  • 它需要可视化与检查入口。
  • 它的变化需要和 Turn、工具状态一起被观测。
  • 它需要测试,尤其是压缩、恢复和能力披露边界。
  • 它也需要设计:层级、命名和成本反馈都会影响用户是否信任 Agent。

模型的能力仍然重要。但在真实产品里,模型每一次能否做对事情,往往取决于我们有没有给它一个清楚、准确、可控制的运行空间。