AI Coding Agent 的 Agent Harness 是什么?从 Model、Harness、Tools 到 JSON State 深入解析 2026 Agent 架构
DeepSeek 专篇写过一家产品的宿主。本篇只拆通用四层:Model、Harness、Tools、JSON State。模型填参数。宿主跑循环。工具过 Schema。状态能回放。
阅读前速览
| 层 | 锁什么 | 谁执行 |
|---|---|---|
| Model | tool_use / arguments | 模型填 JSON,不跑副作用 |
| Harness | 循环 / 权限 / 压缩 | 宿主装配上下文再执行 |
| Tools | inputSchema | Schema 过门,宿主再调 |
| State | session / turn / JSONL | 能重建,才算有状态 |
四层都是对象。Prompt 不是架构。
Harness 是环,不是模型
2026 的 Coding Agent 看起来像「一个模型在改仓库」。拆开以后是四张对象。模型只产出下一次动作的 JSON。真正装上下文、过 Schema、评权限、跑工具、写回结果、在窗口将满时压缩历史的,是 Harness。没有这一环,模型只是聊天。Claude Code 官方把同一件事写成循环:收提示,评估,执行工具,再评估,直到没有工具调用。Codex 把连续性写进 Thread 和会话记录。Cursor 同样是宿主循环,不是模型自己碰磁盘。
- Model:只填
lookup_order和A-1042。看不见套接字,也不 spawn 进程。 - Harness:系统提示、工具表、权限、压缩、预算、
max_turns。这些是宿主状态,不是模型权重。 - Tools 与 State:工具有 Schema。会话有可检查的 JSON。聊天文本不是状态。
内置工具怎么填 JSON,见 AI Coding Agent 与 JSON 工具调用。MCP 那一跳,见 Coding Agent 如何调用 MCP。Schema 为什么是门,见 AI 为什么需要 JSON Schema。某一家产品的插件宿主,见 DeepSeek Harness 专篇。本篇不再讲那一家,只写四层怎么叠。
第一层:Model 只填 JSON
模型看见的是宿主给的工具表和到目前为止的消息。它的输出是文本,或一段工具调用,或两者。虚构查单,不要贴真实密钥:
{
"type": "tool_use",
"id": "call_3c91",
"name": "lookup_order",
"input": { "order_id": "A-1042" }
}
这一段不是 HTTP,也不是 MCP 的 tools/call。它是模型对宿主说「请查 A-1042」。宿主校验形状,再决定执行还是拦住。把模型当成执行器,会漏掉中间那一跳。
第二层:Harness 跑循环
一次会话是状态机,不是单次补全。官方循环可以收成一张对象:不可变的是模型名和工具表;可变的是消息数、待执行工具、预算。轮次从 2 走到 8,是宿主在计数,不是模型在记日记:
{
"session_id": "sess_7f2a",
"turn": 2,
"max_turns": 8,
"immutable": {
"model": "coding-agent",
"tools": ["lookup_order", "Read", "Bash"]
},
"mutable": {
"messages": 6,
"pending_tool": "lookup_order",
"budget_tokens": 128000
}
}
Claude Code 的一轮:模型产出带工具的回复,宿主执行,把 tool_result 写回,再问模型。没有工具调用时循环结束,并交出用量和 session_id。钩子可以在执行前拦截。Codex 在审批之后选沙箱,再执行。权限怎么写成规则,见 Coding Agent 权限模型。Harness 调用权限,并不等于权限。
第三层:Tools 过 Schema
工具表是模型的菜单。每一行必须有名字、说明、一份 JSON Schema。宽 object 等于请模型发明键。查单不要带退款字段:
{
"name": "lookup_order",
"description": "Look up an order by ID. Confirm before any refund.",
"inputSchema": {
"type": "object",
"properties": {
"order_id": { "type": "string", "pattern": "^[A-Z]-\\d{4}$" }
},
"required": ["order_id"],
"additionalProperties": false
}
}
过门之后,宿主执行,再把结果写成对象喂回去。模型读的是回写,不是终端滚动条。失败也要是对象,不要只丢一句散文:
{
"type": "tool_result",
"tool_use_id": "call_3c91",
"content": "{\"order_id\":\"A-1042\",\"status\":\"paid\"}"
}
第四层:JSON State 能回放
状态不是「刚才聊了什么」。状态是消息、工具结果、会话编号、压缩边界。Codex 把会话追加进 JSONL,resume 从记录重建。一行就该能指出是哪一次查单:
{"ts":"2026-09-28T01:12:04.221Z","type":"tool_result","id":"call_3c91","name":"lookup_order","ok":true,"order_id":"A-1042"}
上下文会满。Claude Code 在接近上限时自动压缩,流里会出现 compact_boundary。早期细节可能被摘要吃掉。项目根的 CLAUDE.md 会再注入,所以稳定规则写进文件,不要只写在第一轮提示里。压缩是状态变迁,不是静默丢记忆:
{
"type": "system",
"subtype": "compact_boundary",
"session_id": "sess_7f2a"
}
五步把 Harness 收成对象
不要从「换一个更强的模型」开始。按对象写:
- 先列工具表。每条工具有 Schema。
additionalProperties: false。没有 Schema 的工具不要交给模型。 - 写出循环的停止条件。
max_turns或预算。开口径任务不要裸跑。 - 权限写成规则。只读查单 allow。写盘 ask。退款 deny。不要把「请自动批准」当默认。
- 状态落成 JSON。至少留下 tool_use、tool_result、session_id。能按 id 对上,才算接通。
- 压缩当事件。看到 compact 就知道摘要替换了旧消息。必须留下的规则放磁盘文件。
Schema 怎么当门,见 Agents API + JSON Schema。本篇只要求:四层都有对象,而且由宿主执行副作用。
复盘 Agent,先摊开四份 JSON
一次翻车,多半是工具表、权限、状态没对齐,不是模型「不够聪明」。
- 把
inputSchema和input格式化,看缺字段和多余键。 - 用 JSONPath 提取 抽出
$.name、$.input.order_id、$.session_id。 - 一次成功回写和一次被拒 JSON Diff。先改 Schema 和规则,再改提示。
- 核对
call_3c91在 tool_use 和 tool_result 是否同一 id。 - 会话 JSONL、令牌、仓库路径不要贴进公共格式化站。JSONSort 在浏览器本地跑。
四份对象都能按 Schema 重建,你才是在收架构,不是在收「它好像会改文件」。
常见误区
- 把 Harness 当成新模型。模型换代。环、门、状态应该先稳定。评测错位从这里开始。
- 以为更长的 system prompt 就是架构。提示会被压缩吃掉。工具表、权限、会话记录不会。
- 跳过 Schema,直接执行。Harness 管循环,不替你免除二次校验。宽 object 会把发明键送进副作用。
- 把聊天窗口当成状态。窗口是渲染。状态是 JSON。resume 读的是记录,不是截图。
- 压缩当无事发生。官方会发边界事件。嵌套规则可能要重新读文件才会回来。
- 用某一家产品的插件词当通用词。dsh、Capability Seam 是专篇对象。通用四层是 Model / Harness / Tools / State。
FAQ
Harness 和 Agent Framework 是一回事吗?
不是同一层。Framework 常在业务仓库里编排节点。Harness 是宿主循环:装上下文、过门、执行、落状态。你可以在 Harness 上写业务 Agent,不要把两层糊在一起。
模型会自己改文件吗?
不会。模型只填工具 JSON。读写、Shell、MCP 都由宿主执行。没有宿主,就没有仓库变更。
JSON State 必须是 JSONL 吗?
不必。Codex 用会话 JSONL 做权威记录。Claude Code 用会话文本和事件流。要求是能按 id 重建模型当时看见的对象,不是文件后缀。
压缩会丢掉 Schema 吗?
工具定义通常作为稳定前缀再注入。丢掉的是早期对话细节。必须留下的规则写进项目文件,不要只写在第一句用户消息里。
换模型要重写 Harness 吗?
不该。模型适配器可换。工具 Schema、权限表、状态形状应该先稳住。换模型是换填 JSON 的那一层,不是换四层架构。
结论
Coding Agent 的架构不是「一个更大的模型」。是 Model 填 JSON,Harness 跑循环,Tools 过 Schema,State 能回放。
先写清 A-1042 会进哪一个工具、哪一轮、哪一份状态记录。能指到四层对象,才算有 Harness。模型会换。这四层应该先稳定。
延伸阅读
- DeepSeek Harness 改变了什么 一家产品的宿主,不是通用四层
- Coding Agent 如何调用 MCP 宿主发 JSON-RPC,模型只填参数
- Coding Agent 为什么需要权限控制 Shell / Git / 文件系统三道门
- AI Coding Agent 如何用 JSON 调工具 内置工具的 JSON,还没拆环
- Agents API + JSON Schema 实战 稳定、可验证、可执行
- 为什么 AI 需要 JSON Schema Schema / Function Calling / Structured Output
- JSONSort 本地工具箱 格式化、校验、Diff
- 全部文章 更多 JSON 与 AI 开发笔记
更新记录: 首次发布