Agent Harness 架构到底需要些什么?

发布时间:2026/8/18 9:51:45
Agent Harness 架构到底需要些什么? 1. 模型不是瓶颈harness 才是同一个模型放进不同的 harness成绩能差多少CORE-Bench 上Claude Opus 4.5 跑在通用 CORE-Agent 脚手架上是 42%换进 Claude Code 的 harness 变 78%把评测 harness 自己的 bug 一起修掉还能摸到 95%。模型一个参数没动36 到 53 个百分点的差距全来自壳——模型不是瓶颈harness 才是。要开 agent 开发先回答一个问题Agent Harness 架构到底需要些什么这个问题会一路影响你后面的每个决策。单独看任何一家你只能看到一种取舍把 Claude Code、Codex、DeepSeek Harness后面叫 dsh三家摆在一起才能看出公共规律。Claude Code 是应用层治理Codex 是内核级沙箱dsh 是一切皆插件——三种哲学各自押注了 harness 的一个侧面。2. Claude\CodeX\DSH三种哲学Claude Code 应用层治理钩子驱动。Anthropic 把控制点放在应用层。官方文档列出的生命周期钩子有二十多个版本不同数目在 24 到 30 之间浮动SessionStart、UserPromptSubmit、PreToolUse、PostToolUse、Stop、SessionEnd……覆盖了循环的每一个确定性节点CLAUDE.md 从企业策略、用户级、项目级、本地到子目录按需加载地分层权限落在工具级每个工具调用都能被审批或钩子拦截。它的逻辑是harness 应当能「在任何时刻插进干预」。Codex 内核级沙箱硬边界优先。OpenAI 把安全重心压进内核。Linux 上用 LandlockseccompmacOS 用 SeatbeltWindows 用受限令牌还单独编了一个 sandbox 二进制来包命令——沙箱策略和主程序分开。它的逻辑是边界要在内核层关死模型和用户的手滑都绕不过去。dsh 一切皆插件可重组运行时。DeepSeek 站在 Cordis 上模型、工具、会话、沙箱、Agent Loop、调度、UI 全是插件没有特权内核。它的逻辑是harness 不该有不可替换的部分——连循环本身都能换。一张表把三家摆开Claude CodeCodexdsh哲学应用层治理钩子驱动内核级沙箱硬边界优先一切皆插件可重组运行时开源闭源开源 CLIApache 2.0开源MIT端形态CLI 桌面端 IDE 插件CLI 桌面端 Cloud IDE 插件CLIweb / headless boot profile扩展机制钩子 / skills / subagents / 插件市场 / MCPskills AGENTS.md 并行 subagents 插件插件Cordis16 seams沙箱应用层 OS 沙箱 工具级权限审批内核级Seatbelt / Landlockseccomp平台链 seambwrap / landlock / seatbelt / windows-acl 审批模型绑定默认 Claude 系可配置切换默认 GPT-Codex 系模型无关适配器即插件两处我按规矩标注一下。Claude Code 桌面端最早是 Chat / Cowork / Code 三个 Tab2026 年 7 月起 Chat 和 Cowork 合并成单视图Code 保持独立。dsh 的「40 多家模型厂商」是发布报道口径我以官方 README 的「模型无关、模型适配器即插件」为准厂商清单没逐家核实。dsh · 一切皆插件Codex · 内核级沙箱Claude Code · 应用层治理应用层治理20 生命周期钩子CLAUDE.md 分层 · 工具级权限内核级沙箱Seatbelt · LandlockseccompAGENTS.md · skills一切皆插件Cordis 16 seams无特权内核 · 模型无关同一个问题harness 需要哪些件Agent Loop / 工具 / 安全 / 会话 / 多 Agent / 扩展 / 模型适配三家的标签压成一句话Claude Code 管「何时干预」Codex 管「哪里隔绝」dsh 管「什么可换」。三个词不打架它们回答的是 harness 的三个不同问题。3. Agent Loop循环怎么组织循环是 harness 的心脏。模型不主动做事它只回应请求——请求怎么来、上下文怎么喂、结果怎么回就是循环的全部工作。dsh 的循环我拆过直接给源码级的细节。ReactLoopAgentpackages/core/agent-loop/src/agent.ts:64把工作切成两个单位turn轮次和step步骤。一个 step 是一次模型请求加上它调用的工具一个 turn 包含零个或多个 step。状态机三条turn():246开循环领 stepstep():332构建请求、流式收回复、派发工具调用buildRequest:407组装请求时还能被 waterfall 改写——连「模型这次调谁、用什么参数」都是可插拔的。消息进来走Inboxpackages/core/agent/src/inbox.ts:25双队列next-turn/next-stepclaim():71领走整批输入。我压成一句话循环不直接读「消息数组」循环读队列。输入、注入、中断都变成队列操作状态机只关心「队列里还有没有活」。这一条换来的是分叉、恢复、回放全挂在同一事件流上循环本身保持得很薄。Claude Code 的循环我从官方文档看一次会话组织成 plan → execute → verify 的 agentic loop循环外面挂着生命周期钩子可以在每个确定性节点插进干预——正好呼应它「应用层治理」的哲学。2026 上半年它给循环加了一串「无人值守」旋钮/loop 按时间重跑、/goal 按条件验收、/schedule 定时触发。这些本质上是给同一个循环装不同的停机条件。Codex 的循环据官方文档是 plan mode / steer mode 两档——一个先规划再动手一个让你在循环里持续转向。它跟 Claude Code 一样循环本身是产品内部件用户只看到暴露出来的模式不看到循环内部。4. 工具与流水线模型怎么接触世界循环是心脏工具是手脚。模型只输出 tool-call真正做事的是工具——所以工具怎么被审批、怎么被执行、结果怎么回写是 harness 的「税务系统」每一笔调用都要过一道关。dsh 在这条接缝上放了一条完整的执行流水线六个阶段显式写在代码里。prepareExecutionpackages/core/tools/src/index.ts:1463跑 pre-execute waterfall然后审批询问、单调守卫dispatch:1569执行timeout/retry 包在外面postExecute:1742跑 post-execute waterfall最后applyFinalContent:1649应用内容变换tools/result通知最终结果。两个细节值钱。一是守卫和审批分开——守卫是已注册的所有者策略不能重新排序ctx.approval是一次性的人机询问缺了回答方一律按 denyfail-closed。二是 PTC程序化工具调用不绕过安全——code preset 里模型生成一段 TypeScript 程序组合多步操作但它复用同一个TOOL_RUNTIME_SCHEDULERpackages/core/tools/src/code-mode.ts:481每个子调用照样走scheduler.prepare():545。批处理也关进同一条流水线不是给模型开后门。Claude Code 的「流水线」是分散的工具级权限审批ask / allow / deny加上 PreToolUse / PostToolUse 钩子做拦截和记录PermissionRequest 钩子还能自动应答权限询问。它没有一条显式的六阶段流水线但同样保证了「工具调用前有一道闸、调用后有记录」——这道闸藏在钩子和权限模型里。Codex 据官方文档把把关拆成两层approval_policy 三档read-only / workspace-write / danger-full-access管「允不允许」内核沙箱管「做不做得到」。工具调用先过审批再被沙箱包一层。对要搭 harness 的人工具流水线至少要有 pre 和 post 两道口。pre 管拦截、审批、改写输入post 管记录、校验、改写结果。dsh 的六阶段是完整版但最小可用的 harness 有 pre post 就能活——流水线可以短不能没有。5. 安全边界沙箱与权限安全是三家里分歧最大的一节也是哲学最鲜明的一节。Codex 押内核级。Linux 上用 Landlockseccomp——Landlock 是内核 LSM管文件系统访问seccomp 过滤系统调用。策略在单独的 sandbox 二进制里主程序只把策略 JSON 传给它它应用规则后 exec 目标命令。沙箱策略硬编码 Landlock ABI V5内核不支持就直接 panic——宁可跑不了也不裸奔。macOS 走 SeatbeltWindows 走受限令牌。它的哲学边界关在内核层谁都没法绕过。Claude Code 押应用层。权限落在工具级每个工具调用可以问、可以配、可以拦OS 沙箱macOS Seatbelt 等做最后物理防线。它的哲学边界可以「随时插进干预」——PermissionRequest 钩子能在权限弹窗出现前自动应答PreToolUse 钩子能直接拒绝某个工具。防的是「误放行」靠的是人可配置。dsh 把沙箱做成接缝。SandboxProvider.confinepackages/sandbox/sandbox/src/index.ts:158是抽象服务传入 argv 和策略返回被包过的 argv。真正的执行走平台链——bwrap、landlock、seatbelt、windows-acl按平台挑一个全部 fail-closed源码注释写得明白「silent unconfined passthrough is forbidden」。审批是独立三档read-only、workspace-write、danger-full-access。它的哲学边界本身可替换。对要搭 harness 的人先定你的安全哲学再动手。要防「模型绕过你」——选内核级像 Codex要防「人误放行」——选应用层加审批像 Claude Code要边界可移植、多平台一鱼多吃——把沙箱做成接缝像 dsh。三条路没有绝对优劣但不选一条的代价是边界不可审计。6. 会话与可观测性dsh 把这件事焊成了运行时不变式。它的会话不是「消息列表」是一条 append-only 的SessionEvent事件流packages/core/session/src/types.ts:404每条事件带seqseq就是log.lengthindex.ts:604的 append 里写死。事件按角色分三类边界turn/start 这类标记、表面真正进模型历史的 user/assistant/tool 消息、仅日志chunk、usage 这类为保真和回放存在的。设计原则一句话模型可见即已记录。每次 llm 请求invariant 检查请求的消息数组和deriveMessages()index.ts:726从日志算出来的是否一致不一致直接 failpackages/core/agent-loop/src/invariant.ts:21-54。不是约定是断言。分叉是日志的纯函数index.ts:1081按 boundary seq 切子会话回放、恢复全是同一事件流的不同读法——日志是唯一真相其它全是投影。Claude Code 把会话可观测性做成产品功能checkpoint 存节点、/rewind 回退、/resume 恢复、stream-logs 看流式日志、/export 导出。对用户够用但它不是架构不变式——没有一条断言保证「模型见到的必须能从历史重建」。Codex 据官方文档把会话存在~/.codex/sessions/跨端可恢复/compact 压缩。同样是产品功能不是架构不变式。对要搭 harness 的人这是我最想让你抄的一条dsh 的「模型可见即已记录」不用抄成断言但要抄成习惯。你至少得能回答一个问题模型上次请求见过什么答不出debug 无从谈起agent 跑错只能重启。会话状态当数据库管还是当运行时内存管是自建 harness 的分水岭。7. 多 Agent 与编排单 agent 有天花板上下文会污染能力会饱和一个循环干不了所有事。多 Agent 不是锦上添花是 harness 的必备件。dsh 把「子 Agent 从哪来」做成一个接缝。SubagentProviderpackages/subagent/subagent/src/types.ts:285定义了什么是一次委派注册了五类实现spawn新建子 AgentinheritsParentContextfalse孩子从零开始:41、fork继承父的已完成轮次前缀从父的上下文续着干:48、acp进程外 ACP 子 Agent:146、claude-code、codex。最后两个最值得说——dsh 能把一轮委派丢给 Claude Code 或 Codex 的进程当后端。这是官方记录在案的仓库的 feature note2026-08-04-claude-code-and-codex-subagent-backends.md写了两个 provider 分别调 Claude Agent SDK 和 Codex 的 app-server每次调用起一个全新产品进程父会话只收最终答案。这句话的意思比表面大harness 之间不是互斥的是可以互相嵌套的——你的主 harness 可以把脏活外包给别的 harness。更「换循环」的是 workflow 引擎。runtime.ts:90把一段 workflow 脚本用vm.Script编译进 worker thread脚本里能调agent()、parallel():401各 thunk 并行非致命错误归 null、pipeline():428逐项过阶段、无跨阶段屏障。Ralph 更极端内置固定脚本RALPH_SCRIPTtool-ralph/src/index.ts:90每轮派一个全新结构化子 Agent 攻一个目标子 Agent 只能填数据不能改循环requireFreshProvider:220强制子 Agent 必须是干净上下文standard preset 里配了maxRounds: 64。Claude Code 的多 Agent 是原生子代理加 Task 工具description 是「招工启事」isolation: worktree 防改动污染子代理对主会话无记忆。Codex 据官方文档是并行 subagentsmulti_agent 打开后有 spawn_agent / wait_agent / close_agent内置 default / worker / explorer 三种 agent 模板。对要搭 harness 的人最关键的一个旋钮是子 Agent 继承不继承父上下文。spawn从零适合独立任务fork继承前缀适合续着上下文干。这个二元选择决定了你多 Agent 编排的语义——dsh 用一个inheritsParentContext布尔值把它显式化了别让它在你的架构里变成隐含假设。8. 可扩展性从哪下手扩展harness 没有扩展点就是死壳。但「扩展」的深度三家差着数量级。Claude Code 的扩展入口五个我在 003 拆过按「加载时机 × 强制程度」两轴排开CLAUDE.md常驻、建议、Rules路径约束、建议、Skills按需加载、建议、Hooks确定性、强制、Subagents隔离上下文。再加插件市场和 MCP。关键区别一句话CLAUDE.md 和 Skills 是建议模型可以忽略Hooks 是强制脚本执行不由模型自觉。不能靠自觉的底线只能写 hook。Codex 的扩展点是 skills AGENTS.md 并行 subagents 插件企业版 MCP。它最有价值的一点是 AGENTS.md 的开放标准属性——同一份指令文件能被多个工具读Codex 能配置读 CLAUDE.md 做 fallback反过来 Claude Code 也能引用 AGENTS.md。这对「工具间迁移」是实打实的解绑。dsh 的扩展深度到顶一切皆插件。架构文档画了 16 个以上 seamllm/fs/shell/subprocess/sandbox/approval/codeRuntime/subagents/workflowEngine/lsp/web/compaction……每个 seam 由 Service Definition / Provider / Consumer 三件套定义换掉 Provider 就改变整个产品。连 Agent Loop 都能换——这是它和主流工具的核心差异主流在工具层给你扩展点它在每一层都给你扩展点。对要搭 harness 的人扩展哲学 你允许别人从哪下手改。三个层级你要哪个固定点插脚本钩子最省事、按需加载流程skills最常用、换任意零件插件最自由。扩展点深度和架构复杂度成正比——dsh 的 16 seams 背后是 Cordis 的插件生命周期管理这层复杂度不是白来的。9. 合起来Agent Harness 架构到底需要些什么到这里三家拆完。harness 架构没有标准答案但有公共要素——缺一样就是短板。三家用完全不同的哲学去实现最后都长出了同一组东西这组东西就是答案。Agent Harness① Agent Loop驱动模型② 上下文管理注入 / 压缩 / 丢弃③ 工具流水线pre / 审批 / post④ 安全边界沙箱 / 权限⑤ 会话可观测可回放 / 可恢复⑥ 多 Agent子代理 / 编排⑦ 可扩展性钩子 / 插件 / skills⑧ 模型适配模型无关八样要素每样给你「为什么必须有」和「三家怎么权衡」。① Agent Loop。为什么必须有模型不主动循环是唯一驱动没有循环就没有 agent。三家权衡Claude Code 把循环藏在产品后面只露出 plan / execute / verifyCodex 用 plan / steer 两档模式dsh 把循环本身做成插件ReactLoopAgent 可换。落点循环至少要有 turn / step 两级边界才有地方挂超时、压缩、中断。② 上下文管理。为什么必须有模型窗口有限注入什么、压缩什么、丢弃什么决定成败。三家权衡Claude Code 用 CLAUDE.md 分层加 /compact /clear /rewindCodex 用 AGENTS.md 加项目文档dsh 用 buildRequest waterfall 改写请求加 system-prompt 组装。落点上下文是你最常调的旋钮先想清楚注入点在哪。③ 工具流水线。为什么必须有模型只输出 tool-call真正做事的是工具没有流水线就是裸奔。三家权衡dsh 六阶段显式设计Claude Code 把把关藏进钩子和权限模型Codex 用审批加沙箱两层。落点至少要有 pre拦截 / 审批和 post记录 / 校验两道口。④ 安全边界。为什么必须有模型不可信边界是最后防线。三家权衡Codex 内核级Landlock seccomp、Claude Code 应用层工具权限 OS 沙箱、dsh 平台链 seambwrap / landlock / seatbelt / windows-acl。落点先定边界关在哪一层——内核级防绕过应用层防误放行。⑤ 会话 / 可观测性。为什么必须有agent 跑错没法 debug 等于没法用。三家权衡dsh 把会话当数据库append-only 日志 不变式Claude Code / Codex 当产品功能checkpoint / resume。落点至少做到「模型每次请求都能从历史重建」。⑥ 多 Agent。为什么必须有单 agent 上下文会污染、能力会饱和。三家权衡Claude Code 原生子代理加 Task 工具Codex 并行 subagentsdsh SubagentProvider 五实现甚至能接 Claude Code / Codex 当后端。落点先想清楚子 Agent 继承不继承父上下文。⑦ 可扩展性。为什么必须有没有扩展点harness 就是死壳。三家权衡Claude Code 钩子 / skills / 插件市场Codex skills / AGENTS.md / 插件dsh 一切皆插件。落点扩展哲学 允许从哪下手改——固定点插脚本还是换任意零件。⑧ 模型适配。为什么必须有没有适配层harness 锁死一家模型而模型是这行贬值最快的东西。三家权衡Claude Code 默认 Claude 系、可配置切换Codex 默认自家、可配置dsh 模型无关、适配器即插件。落点模型适配层越薄越稳别把模型名写死在业务逻辑里。这八样是我从三家身上抽出来的公共要素。你可能要反驳多 Agent 是必备的吗极简的 harness 用不到。我的回答是——可以暂时没有但架构上要留口子。dsh 的 SubagentProvider 是个接缝minimal preset 只是把接缝关上了不是没有。「缺一样是短板」说的是结构上留不留位置不是这版功能开不开。10. 结论不用从零造先定两个哲学拆完三家给要开 agent 开发的人一个总判断不用从零造三家的取舍就是现成教材。你不需要重新发明 Agent Loop、工具流水线、会话日志——这三家已经用不同的哲学把每个要素都实现了一遍你要做的是抄不是造。但抄之前先定两个哲学。第一个是安全哲学边界关在哪一层。要防模型绕过学 Codex 内核级要防人误放行学 Claude Code 应用层要多平台一鱼多吃学 dsh 把沙箱做成接缝。这一条不定你后面所有设计都是打补丁。第二个是扩展哲学允许从哪下手改。只想要固定点插脚本学 Claude Code 的钩子想要流程按需加载学 Codex 的 skills想要连循环都能换学 dsh 的插件化。扩展深度和复杂度成正比别上来就选最深的。这两条想清楚再去对照第九节那张清单一项项查你的 harness 缺什么。现在留一个开放题给你评论区可以吵现在做 agent到底该自己搭 harness还是用现成的我的判断是如果目的不是学架构别从零造——用现成的把省下的时间投到你的工具流水线和安全边界上但如果你就是想掌控所有旋钮dsh 的插件化是最接近「从零」的现成起点。如果你认同「公共要素」这个框架点个赞——这套图纸值得被更多要开 agent 开发的人看见。接来下我会安排自己动手实现一个agent harness帮助你深入去了解agent harness的搭建。