图:显式状态驱动 harness 概念架构
Coding Agent 的执行过程包含两类工作:一类是理解问题、修改代码和验证结果,另一类是决定读取哪些文件、加载哪些工具、如何分配子任务,以及哪些状态需要保留。前一类依赖模型能力,后一类取决于 harness——围绕模型构建的运行框架,负责状态、上下文、工具、权限和执行反馈。
当文件内容、搜索结果、工具调用和任务决策都累积在同一段对话中,持久状态与当前上下文就被绑定在一起。模型分配(model routing)需要传递历史,compaction 需要压缩历史,session 重启又可能丢失仍有价值的信息。这些问题看似独立,实际都涉及同一个设计选择:对话历史是否应该同时承担状态存储与模型输入的职责?
一种替代方案是显式状态(explicit state):文件、日志、任务、规则和执行结果分别保存,harness 根据当前任务选择信息,再组装模型上下文。Jev 这样的决策模型可以参与 context selection、model routing 和工具选择,但持久化、权限执行和最终验证仍由运行系统负责。这一分工将高频决策从对话流程中分离出来,使其可以被单独评估和优化。[1]
Model routing 的成本取决于上下文重处理
Jev 是决策模型,不负责代码生成
TypeSafe 将 Jev 定位为面向软件决策的模型。应用提供状态、上下文和预定义问题,Jev 返回程序可以直接处理的 typed output。官方文档定义了三种主要原语:[2][3]
- Choice:从预定义选项中选择,例如决定某个 context chunk 应采用
hide、short、long还是full。 - Score:对有序等级给出概率分布,返回概率加权的等级分数。
- Noul:表示二元命题为真的概率,取值为 0 到 1,与
null无关。接近 0.5 表示判断不确定;Noul 没有额外独立的confidence字段。
typed output 便于验证、记录和执行:类型检查可以拒绝非法枚举,概率阈值可以触发人工确认,历史决策也能用于评估。但类型约束只保证输出格式,不保证判断正确,也不保证概率在特定任务上经过充分校准。危险命令被分类为 allow,依然属于决策错误。
这种能力适合构建独立的决策层:Jev 输出选择与评分,代码模型、工具和确定性程序完成执行。需要验证的不只是单次选择是否正确,还包括决策开销能否被后续收益覆盖,以及错误选择发生后系统能否恢复。typed output 提供了接口基础,但不直接保证整个 harness 的效率。
Prompt caching 倾向于稳定前缀,但不限制状态组织方式
如果暂时忽略缓存收益,模型每轮需要的是完成当前任务所必需的信息,而不一定是完整的历史记录。缓存机制改变的是复用与重建上下文的相对成本,并没有改变任务本身的信息需求。
在常见的 causal attention 实现中,历史 token 的 key/value 可以复用,减少重复计算。API 层的 prompt caching 则通过计费和延迟体现前缀复用的收益。两者相关,但底层 KV cache 与 API 的缓存策略并不是同一个概念。
以 Anthropic 文档为例,缓存前缀按照 tools → system → messages 的顺序组织,命中要求对应前缀内容一致。修改靠前的工具定义会影响后续部分的缓存复用。cache read 有价格折扣,仍然需要计费。[4]
这使稳定前缀和 append-only transcript 成为常见选择,但并不排除其他架构。系统可以保留稳定规则,仅重建动态部分,也可以通过 compaction 压缩历史,或从外部状态中检索信息。缓存复用是一项优化约束,不是必须保留完整对话历史的理由。
较低的 token 单价不一定降低任务总成本
考虑一个简化的 routing 场景:假设 frontier model 的输入、输出价格分别为每百万 token 5、25 美元,低成本模型分别为 3、15 美元。这组价格仅用于分析成本结构,不代表当前 API 报价。[1,第 3—4 页]
设已有上下文为 X,执行阶段的生成量为 Y,新读取的文件和命令输出为 Z,均以百万 token 为单位。假定两条路径的 Y、Z 相同,且 frontier model 会完整读取子任务的 Y + Z。排除两条路径共有的初始成本后:
- frontier model 直接执行:C₁ = 25Y + 5Z。
- frontier model 将任务分配给低成本模型,再读取其结果:C₂ = 3X + 15Y + 3Z + 5(Y + Z) = 3X + 20Y + 8Z。
第二条路径增加了两部分开销:低成本模型加载 X,以及 frontier model 重新处理 Y 与 Z。代入 X = 0.65、Y = 0.12、Z = 0.23,两条路径的成本分别为 4.15 和 6.19 美元,routing 路径高出约 49%。这是特定假设下的计算结果,并非实际 session 的测量值。
由此可得,只有 3X + 3Z < 5Y 时,第二条路径的成本更低。已有上下文越长、任务读取的信息越多,输出单价的优势越可能被上下文加载与重处理开销抵消。
这一算例没有完整建模 cache read/write、多轮交互、失败重试及模型能力差异,因此不能据此否定 routing。它说明,routing 应比较完整执行路径的成本,而不能只比较 token 单价。
相应的优化是为子任务构建范围明确、信息完整的上下文,并要求返回结论、证据位置和验证结果,避免直接传递整个 session。复杂修改仍可能要求主模型检查关键代码;省略必要证据会增加错误和返工概率。
显式状态支持按任务组装上下文
Context chunk 保留原始信息及其不同表示
要减少跨模型调用中的状态传递,首先需要让状态能够独立存取。用户目标、文件内容、tool output、diff、任务状态和规则可以保存为有类型的 context chunk,模型上下文则由当前任务需要的 chunk 组成。持久状态负责保留信息,上下文负责呈现信息,两者不必具有相同的范围和生命周期。[1,第 6—9 页]
从实现角度看,chunk 至少需要 ID、类型、来源、代码版本、时间、敏感级别、有效条件和原始内容引用。短摘要与长摘要是同一份原始信息的不同表示,应保留可追溯关系。决策依据可记录为简短的审计说明,不需要依赖模型不可见的内部推理过程。
例如,前一个任务产生了大量搜索结果,当前任务只涉及认证模块。系统可以仅加载其中相关的 chunk,其余内容继续保存在外部状态中,供后续检索。
假设一次搜索返回 2400 行内容,其中只有 12 条命中与当前问题相关,context assembly 可以只加载这 12 条。任务变化后,同一组结果也可能不再进入上下文。这里调整的是信息的 visibility,而不是直接删除信息;这些数字只是说明选择过程,不代表实测压缩率。[1,第 7 页]
| Visibility | 上下文中的表示 | 适用情况 |
|---|---|---|
hide | 不加载内容,保留外部索引 | 与当前任务无关,或已被新结果替代 |
short | 简短结论与证据引用 | 需要结果,不需要完整过程 |
long | 关键过程、限制与异常 | 需要判断结果的适用条件 |
full | 完整内容或必要的源内容区间 | 精确修改、错误定位、证据复核 |
这属于 query-aware compression:根据当前问题决定保留哪些信息,而不是通过一次通用 compaction 生成供所有后续任务使用的摘要。它仍可能遗漏相关内容,因此原始信息必须可恢复,模型也需要能够在证据不足时继续检索。
session 重启同样可以与状态清空分离:重建当前上下文,同时恢复仍有效的目标、证据和任务结果。恢复前需要检查代码版本、权限和依赖变化,避免复用已失效的状态。
相关性评分不能替代硬约束
仅按模型评分选择 chunk,可能遗漏必须遵守的规则。例如,“该目录禁止直接访问数据库”即使与当前函数的语义相似度较低,也不应被过滤。
context assembly 可以分两步完成:先通过确定性规则加载任务目标、权限和目录约束,再在剩余 token budget 内按相关性选择证据。模型可以调整证据的排序与表示,但不能覆盖这些硬约束。
重建上下文还涉及检索、评分、摘要生成和 cache write。若每轮对全部历史 chunk 调用决策模型,调度开销可能超过输入 token 的节省。较合理的实现是先根据目录、符号、任务依赖和版本缩小候选集,再对候选 chunk 评分,并缓存仍有效的结果。
因此,是否重建上下文需要比较检索、决策、推理、预期重试和延迟的总成本。上下文长度只是其中一个变量,不能独立代表系统效率。
Tool schema、Skill 与指令采用按需加载
工具发现与工具调用对信息量的要求不同。发现阶段只需要知道某种能力是否存在,调用阶段才需要完整参数。因此可以采用 tiered disclosure:先提供简短的能力描述,再按需加载 tool schema,复杂用法则通过文档补充。这样既保留工具的可发现性,又避免全部参数定义持续占用上下文。[1,第 8 页]
Anthropic 的 tool search 提供了一个现有实现。设置 defer_loading: true 后,相关工具不会进入初始模型上下文;搜索返回工具引用,API 再将其展开为完整定义。[5]
这里需要区分 API payload 与模型上下文。延迟加载 schema,并不意味着可以省略 API 请求中的工具注册。 这一 API 仍要求每次请求提供完整工具定义,也没有承诺自动移除已经加载的 schema。按需发现解决了初始加载问题,但何时保留、移除或重新加载工具定义,仍属于 harness 的上下文生命周期管理。
指令也可以采用条件加载。conditional instructions 将规则与任务范围关联:处理前端文件时加载界面规范,进入计费目录时加载相应注意事项,条件不再满足时停止注入。全局安全规则则始终保留。与单次读取不同,条件应在每轮 context assembly 时重新判断,避免相关规则在 compaction 后丢失。
实现时还需要定义跨目录规则的合并方式、冲突优先级,以及任务范围变化后的重新匹配机制。
进一步可以将 Skill 设计为具有生命周期的行为单元,即 Structured Skills:条件满足时加载指令、工具行为或检查 Hook,退出时卸载。这不只是组织提示词,还要求运行系统提供行为注册、作用域管理和清理机制。原生 harness 可以控制这些接口;插件能否实现同样的设计,取决于宿主开放的控制能力。
内置工具也适用这一方式。集成 ast-grep 这类结构化搜索工具时,需要提供正确的查询方法和结果处理逻辑,而不是只注册一个命令。工具可以预装,schema、说明和运行状态则按任务加载。内置能力的数量与每轮上下文的大小可以分别管理。
Sub-agent 共享检索结果,但需要版本一致性
代码审查、测试建议和变更说明可能依赖相同的文件、符号和 diff。前置检索结果满足各任务需要时,可以共享同一组证据,再由不同 sub-agent 独立分析。[1,第 10—11 页]
这里复用的是检索和状态准备结果,不是跨模型共享 KV cache。各模型仍有独立的输入计费、缓存边界,以及任务特有的检索开销。
read-only 任务虽然没有写冲突,也不自动具备一致性。主 Agent 修改代码时,后台审查可能同时读到旧文件和新日志。任务应绑定同一个 snapshot 或工作区版本,结果携带版本标识;基准版本发生变化后,再判断是否需要重新执行。
写任务还需要隔离工作区、锁或冲突检测机制。任务去重应同时考虑目标、范围、输入版本和验收条件,不能只匹配任务描述,否则可能跳过代码修改后必要的复查。
通过实验验证效率与安全性
Token 分布需要以实际 workload 为准
一组示意估算将文件读取占比设为总 token 的 30%—40%、搜索为 10%—18%、代码编辑为 4%—10%。这些数字没有来自统一的实测数据,只能用于提出假设:读取与检索可能是重要的优化对象,不能作为生产系统的容量基准。[1,第 5、12 页]
FastContext v3 曾报告另一组结果:在 GPT-5.4-high 与 Mini-SWE-Agent 执行 SWE-bench Multilingual 的 300 条轨迹中,读取与搜索占 tool-use turns 的 56.2%,占主 Agent 总 token 的 46.5%。这一结果适用于特定模型、Agent 和 benchmark,不能直接推广到其他 Coding Agent。[6]
该论文在 2026 年 6 月 30 日的 v4 中标注撤回,原因涉及产品知识产权问题,并需重新批准。撤回原因没有直接否定数据,但这组数据也缺少独立验证,因此不适合用于估算生产收益。[7]
实际优化应基于目标系统的任务负载:统计 tool output 长度、证据重复读取次数、缓存命中率和任务验收结果。仓库规模、任务类型及工具接口的差异,都可能改变成本分布。
先确定数据访问策略,再执行 routing
routing 除了考虑任务难度和价格,还必须包含数据敏感度。但敏感度判断本身也受访问策略限制:不能先将文件发送到未经批准的外部模型,再由该模型判断能否访问。[1,第 9—10 页]
合理的顺序是先依据仓库策略、目录标签、数据分类和本地检查确定访问范围,再从允许的模型中选择成本与质量合适的候选。任务描述只能用于预判,实际 tool call 仍需在执行前检查。
权限控制不能只匹配命令名。执行脚本还需检查内容、参数、工作目录、网络访问和读写范围。模型可辅助识别风险,但拒绝规则、最小权限、沙箱和必要的人工审批应独立执行,不依赖模型给出的概率。
仓库内容与 tool output 也可能包含 prompt injection。信息被存储、摘要或转交给 sub-agent,不会改变其信任级别。chunk 应保留来源与信任属性,检索和状态恢复也不能将外部内容转换成高权限指令。
敏感任务可以被限制在特定模型或部署环境中,但模型来源和价格本身不能证明其符合保密要求。部署位置、数据保留、合同条款、访问控制和组织审批仍需分别核对;缓存、摘要、状态存储与审计日志也应遵守同一套数据策略。
分阶段引入新策略,并保留 baseline
完整的 multi-agent 系统不是验证这套设计的前提。可以分三个阶段推进,让每次改动都能与已有方案比较。
第一阶段,建立 baseline。 固定代表性任务和验收测试,记录成功率、实际费用、完成时间、缓存命中、tool output 长度及失败原因。成本比较必须包含任务结果,不能将未完成任务的低开销计为优化收益。
第二阶段,建立外部状态。 为文件、搜索结果、日志和 diff 保存可追溯记录,保留稳定规则,并在每轮请求中检索相关信息。重点检查关键证据遗漏、过期文件引用,以及失败后恢复原始信息的能力。
第三阶段,引入决策模型。 先将 Jev 用于低风险的候选排序,再测试缓存选择与 sub-agent routing。新策略可以先在 shadow mode 下运行,即仅记录建议而不影响实际动作,与当前策略对比后逐步启用,同时保留确定性的 fallback。
评估指标至少包括任务通过率、每个成功任务的总成本、完成延迟、证据遗漏率、过期引用、错误 routing 带来的返工,以及权限检查的拦截和误放行情况。对于输出波动明显的任务,应重复运行或采用配对实验;单次运行不足以区分策略收益与模型波动。
conditional instructions 和共享后台任务可以随后加入,每次只改变一个主要因素,以便区分检索、缓存、模型选择与运行预算各自的影响。
Context engineering 与模型能力是不同的优化维度
《Recursive Language Models》展示了另一种外部状态思路:Alex L. Zhang、Tim Kraska 和 Omar Khattab 将长输入放入外部环境,由模型通过程序检查片段,并递归调用模型处理局部内容。[8]
RLM 关注长上下文推理,Jev harness 则需要同时处理状态管理、权限、工具和 routing。两者都不要求把完整状态持续放在模型上下文中,但这个共同点不足以证明它们具有相同的实现路径或效果。
上下文组织和模型能力是两个独立的优化维度。正确的上下文不能弥补模型能力缺口,更强的模型也不能消除过期证据或错误权限配置带来的问题。harness 的目标不是替代模型升级,而是减少无关输入、重复读取和不可审计的状态传递。
显式状态驱动的设计最终可以归结为一个可测试目标:将任务、证据、规则和执行结果保存为可追溯状态,按需组装上下文,在任务质量和权限边界不变的前提下,降低重复读取、重试和延迟。是否达到这一目标,需要在同一组真实任务上与 baseline 比较。
参考资料
[1] 《Jev Engineering for Coding Agents》,2026 年 9 月,12 页。成本算例见第 3—4 页,状态与调度思路见第 6—10 页,材料边界见第 12 页。
[2] TypeSafe,〈Introducing System One and Jev〉,署名 Diogo Almeida。该页面介绍 Jev 的产品定位,不包含本文所述 Coding Agent harness 的端到端评估。typesafe.ai/blog/introd…
[3] TypeSafe 官方原语文档:Choice、Score、Noul。docs.typesafe.ai/primitives/… ;docs.typesafe.ai/primitives/… ;docs.typesafe.ai/primitives/…
[4] Anthropic,〈Prompt caching〉。页面持续更新,本文只引用前缀顺序、匹配和失效机制,不将页面上的当前价格视为历史价格快照。platform.claude.com/docs/en/bui…
[5] Anthropic,〈Tool search tool〉。用于核对延迟加载、工具引用展开及 API 工具注册要求。platform.claude.com/docs/en/age…
[6] 〈FastContext: Training Efficient Repository Explorer for Coding Agents〉,arXiv:2606.14066,v3,2026-06-18。统计适用于该版本记载的实验范围;本文未复现实验。arxiv.org/html/2606.1…
[7] 同上,v4 撤回记录,2026-06-30。arxiv.org/abs/2606.14…
[8] Alex L. Zhang、Tim Kraska、Omar Khattab,〈Recursive Language Models〉,arXiv:2512.24601,v1,2025-12-31。arxiv.org/html/2512.2…