KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA
01 · 九个可比槽位:把「Agent Harness」拆成可比较的零件 — keel 龙骨
四门解析课各讲了一家 harness,但每家的术语、切分方式、甚至「什么叫主循环」都不一样。要把五家(四家已有解析课 + E 平台)放进同一个坐标系,第一步是把「Agent Harness」这个含混的词拆成九个互相独立、每家都必然要回答的槽位(slot)。本课的四门前置解析课中,五家核心事实均有源码级出处;E 平台 为公司内部平台,只在各槽位做定性参与,无公开源码级证据。
四门解析课各讲了一家 harness,但每家的术语、切分方式、甚至「什么叫主循环」都不一样。要把五家(四家已有解析课 + E 平台)放进同一个坐标系,第一步是把「Agent Harness」这个含混的词拆成九个互相独立、每家都必然要回答的槽位(slot)。本课的四门前置解析课中,五家核心事实均有源码级出处;E 平台 为公司内部平台,只在各槽位做定性参与,无公开源码级证据。
九个槽位不是产品功能清单,而是机制切分:任何一家把 agent 跑起来的系统,都必须在每一格给出一个答案——哪怕答案是「我们没有这一层」。
槽位的入选标准有两条:一是独立性——任意两格之间不允许「改了一格必然改另一格」的强耦合(有依赖关系的格子会标注);二是不可回避性——跳过任何一格,系统要么跑不起来,要么在运行时以事故的形式替你补上答案(没有结果预算的系统迟早被一次并行 grep 打爆上下文)。九格按「从宿主到智能」排列:前三格是骨架(进程、循环、工具),中三格是内脏(安全、上下文、会话),后三格是生态(扩展、渠道、记忆)。每格先给一句引导,再放五家的一句话答案;引号内的机制名与常量值都出自四门解析课,可按代码地图回查。
一、进程模型与宿主形态(process model & hosting)
| 家 | 一句话答案 |
|---|---|
| Claude Code | 单进程 REPL(REPL.tsx 896KB 与 print.ts 215KB 共享同一个 query()),子 agent 是同进程 async generator;只有 daemon、远程桥、BYOC 执行器三类才起真子进程 |
| DeepSeek (dsh) | 单进程 Node 运行时 + vendored Cordis 响应式插件内核;浏览器 UI 是独立的 59 个 client 包,PTC 程序跑在专用子进程里 |
| Hermes | 一个 Python 内核(AIAgent)套七张壳:CLI/TUI、消息网关、HTTP API、ACP、cron、batch、dashboard;容器里是 s6-overlay 监督树 |
| OpenClaw | 单例 Gateway 本地控制平面:文件锁 + 崩溃熔断保证一个 operator 一个控制面,CLI、渠道、插件全部连到这一个进程 |
| E 平台 | HTTP 与执行彻底解耦的云原生多进程:HTTP 落 ARQ 队列由 worker 执行,多租户 workspace scope(定性,无公开源码级证据) |
这一槽的分歧是九格里最大的:单进程(Claude Code、dsh)、多宿主进程树(Hermes)、单例常驻(OpenClaw)、HTTP/worker 分离(E 平台)是四种真正不同的工程立场,各自决定了后面八格的形状。注意两个「单进程」也不相同:Claude Code 的单进程是连 UI 一起(vendored Ink 在同一进程里渲染),dsh 的单进程是内核单进程 + UI 外置(client 59 包跑在浏览器)——后者是向平台形态过渡的单进程。
二、主循环与停止条件(agent loop & stop conditions)
| 家 | 一句话答案 |
|---|---|
| Claude Code | query() 壳 + queryLoop() 心,跨迭代状态是显式九字段 State;10 个终止 reason 与 7 个继续 transition 全部字面量化,maxTurns 只是其中一条出口 |
| DeepSeek (dsh) | while (await this.turn()) {} 一行驱动 turn/step 双层循环,无 maxSteps;停止只靠 concludesTurn、preStep reject、abort、error 四机制 |
| Hermes | 循环条件是三个变量的合取:max_iterations(默认 90)× IterationBudget.remaining × 宽限一轮标志;退出原因是贯穿全流程的诊断字符串 |
| OpenClaw | 无 maxTurns:硬边界只有 48 小时墙钟超时 + 六种循环检测器(warning 10 / critical 20)+ critical 二次命中硬终止 |
| E 平台 | AgentRunner 驱动至模型自然收尾,或协作式取消(stop_triggered → RunCancelledEvent);未见轮次上限的公开证据(定性) |
这一格是「任务长度假设」的显影:给交互式编码工具配 90 轮上限很安全,给常驻助理配同样的上限就是事故。Claude Code 的枚举路线还有一层别家没有的收益——transition 字段让测试可以直接断言「这轮走的是哪条恢复路径」,而不必翻消息内容。
三、工具并发与结果预算(tool concurrency & result budget)
| 家 | 一句话答案 |
|---|---|
| Claude Code | isConcurrencySafe 分批、写工具严格串行、并行批 contextModifier 延迟到批次末按序提交;结果预算三级(50K 字符 / 100K token / 单消息聚合 200K),超限落盘回喂 2000 字节预览 |
| DeepSeek (dsh) | dispatch 可重叠执行,但提交严格按 model order(slots + committed 游标),上限默认 10;abort 时为未启动调用补合成错误结果保 replay 合法 |
| Hermes | 8 路并发 worker,配起始顺序门(120s)与授权门(360s)两道超时;单工具结果上限超大落临时文件 |
| OpenClaw | 任一工具声明 sequential 就整批串行(保守判据);结果截断两级——单条固定 8000 字符 + 按上下文预算的第二级 |
| E 平台 | DynamicTool 惰性加载 + embedding 查找,控制暴露给模型的工具面大小(定性,无公开源码级证据) |
四家的共同不变量是「结果体积必须有上界」,分歧在上界挂在哪:Claude Code 挂在常量组(50K/100K/200K),dsh 挂在提交顺序不变量上(顺序本身就是 replay 的前提),OpenClaw 挂在两级截断(第一级保线格式、第二级保上下文预算),Hermes 挂在超时门(防的是饿死而非爆炸)。
四、权限与执行安全(permission & execution safety)
| 家 | 一句话答案 |
|---|---|
| Claude Code | 5 外部模式 + 四级(实为十步)规则链,deny 优先、放行最后;Bash 有 23 项专项检查;沙箱可用时才把「整把工具 ask」换成命令级检查 |
| DeepSeek (dsh) | 沙箱三后端 fail-closed(bwrap/landlock、seatbelt、windows-acl)+ 拒绝方言按后端归一 + 单向升级阶梯:模型只能申请放宽,永远不能自己放宽 |
| Hermes | 审批三模式 manual / smart / off,决策 once / session / always / deny;hardline 命令永不可绕;判词「唯一安全边界是操作系统」 |
| OpenClaw | 四层策略只能收紧不能放宽(Profile × allow/deny × 会话权限模式 × exec 审批),safe-bin 校验的是 argv 不只是 bin 名,审批是两阶段(先注册再解析) |
| E 平台 | 平台侧统一审批,工具可见性与执行权限由 workspace scope 决定(定性,无公开源码级证据) |
五、上下文与压缩(context & compaction)
| 家 | 一句话答案 |
|---|---|
| Claude Code | 五级压缩各司其职、顺序固定:结果预算落盘 → snip → microcompact → contextCollapse → autocompact,真正的摘要由 fork 出来的模型调用完成(maxTurns 1、skipCacheWrite) |
| DeepSeek (dsh) | 压缩是往 append-only 日志里写一条 surface replace 事件——历史不改写,被遮蔽节点仍可查,消息历史是派生结果 |
| Hermes | 压缩交接不可执行(compaction_handoff_not_actionable)也是退出原因之一;程序化工具调用经 refund() 退还不占迭代预算 |
| OpenClaw | 压缩两档 default / safeguard(配了 provider 直接提升为 safeguard);硬要求保留 tool-call / toolResult 配对切割 |
| E 平台 | 上下文压缩阈值约 75%,越线触发压缩(定性,无公开源码级证据) |
六、会话持久化与恢复(session persistence & resume)
| 家 | 一句话答案 |
|---|---|
| Claude Code | append-only JSONL transcript,读取设 50MB 闸门;rewind 靠文件历史快照,上限 100 个 |
| DeepSeek (dsh) | append-only 事件流是唯一真相(59 种事件类型),surface 投影派生消息;fork / resume / replay 消费同一条事件流 |
| Hermes | SQLite SessionDB + FTS5 全文检索(CJK 走独立 trigram 表),恢复有过大硬闸 SessionResumeTooLargeError |
| OpenClaw | 状态目录双 schema 版本(state 9 / agent 17)各自迁移;审计库只存元数据、保留 30 天 |
| E 平台 | Redis Stream 存流式事件,客户端按 offset 断线续传、可重放(定性,无公开源码级证据) |
恢复能力的分水岭在「事件流是不是真相」:dsh 与 E 平台 的恢复是重放(replay),Claude Code 与 Hermes 的恢复是重读(reload),OpenClaw 居中——transcript 是事实来源,但续跑有 TranscriptNotContinuableError 这类前置校验(最后一条是 assistant 就拒绝继续,防悬空 tool call)。
七、扩展与插件(extension & plugin)
| 家 | 一句话答案 |
|---|---|
| Claude Code | 扩展面刻意最小:agent markdown 定义 + MCP 工具 + 27 个 hook 事件;构建期用 feature() 裁剪,不设运行时插件总线 |
| DeepSeek (dsh) | vendored Cordis 响应式插件(inject epoch 指纹驱动挂卸),54 类 307 个子包,装配靠 YAML 补丁而非代码 |
| Hermes | plugin.yaml + entry-points 懒发现,36 个 provider 与 22 个渠道全部是插件;内核只认识协议与注册表 |
| OpenClaw | bundled 插件与第三方守同一条 SDK 边界 + 双重声明(package.json 清单分离)+ 官方目录 Ed25519 阈值签名 |
| E 平台 | 平台内置工具注册与 DynamicTool 机制,扩展形态未公开(定性,无公开源码级证据) |
八、多渠道与多用户(channels & multi-user)
| 家 | 一句话答案 |
|---|---|
| Claude Code | 无渠道层:单 operator 交互式终端是第一公民,非交互模式复用同一个 query() |
| DeepSeek (dsh) | api/ 九包把运行时暴露成 HTTP/JSON 给桌面与 Web 客户端;多会话经 preset 与 agent-preset-registry 区分 |
| Hermes | BasePlatformAdapter 抽象 + 22 个渠道插件,命令定义单一来源扇出到 CLI 与各渠道 |
| OpenClaw | 20+ 渠道收敛成统一 inbound envelope,路由 binding → agent;多用户是归因不是隔离——群聊共享同一 transcript |
| E 平台 | 多宿主产品面(Agent Chat / LLM Chat / Workflow / ChatFlow)+ 多租户 workspace 隔离(定性,无公开源码级证据) |
这一格与第一格强耦合:没有常驻进程就没有渠道(Claude Code),HTTP/worker 解耦天然适合多租户(E 平台)。Hermes 与 OpenClaw 都有渠道层,差别在扩展哲学——前者跑一次发现才知道有哪些渠道,后者靠 manifest 不执行代码就能算出「有哪些渠道、哪些已就绪」。
九、记忆与自改进(memory & self-improvement)
| 家 | 一句话答案 |
|---|---|
| Claude Code | CLAUDE.md 四层层级 + 相关记忆每轮 5 槽位注入;无自改进闭环,一切沉淀靠人工维护记忆文件 |
| DeepSeek (dsh) | 无自改进闭环;技能经 skill 插件与 preset 静态挂载,改进发生在发版而非运行时 |
| Hermes | 唯一做了完整 self-improving 闭环的:skill_manage 工具 + 后台复盘 fork(白名单仅 memory + skill,预算 16 轮)+ curator(只 archive 不 delete)+ usage 遥测 |
| OpenClaw | 五层记忆(Instructions / Curated core / Episodic / Prospective / Review)+ DREAMS.md dreaming;记忆插件是单槽位 |
| E 平台 | 以 workspace scope 组织租户内上下文;未见自改进闭环的公开证据(定性,无公开源码级证据) |
这一格的谱系是「从无到全」:Claude Code 把沉淀交给人工维护的 CLAUDE.md,dsh 把改进放进发版节奏,OpenClaw 有记忆但写入者是系统流程(dreaming)而非模型自主决策,Hermes 让模型自己写自己要长期执行的技能——风险与能力在同一处增长,所以它的 curator 不变量(只 archive 不 delete)不是附赠品,而是闭环的前置条件。
代码地图
| 机制 | 位置 | 要点 |
|---|---|---|
| 单进程与 UI 边界 | claude-code-harness/course/01-entry-and-layering.md | REPL 与 print 共享同一 query();三类真子进程清单 |
| 显式 State 与 transition | claude-code-harness/course/02-the-agent-loop.md | 10 终止 reason / 7 继续 transition;hasAttemptedReactiveCompact 防无限循环 |
| 工具并发分批 | claude-code-harness/course/03-tool-runtime.md | isConcurrencySafe 保守默认;并行批 contextModifier 延迟提交 |
| 权限裁决链 | claude-code-harness/course/04-permission-and-safety.md | deny 优先放行最后;1e/1f/1g 三步 bypass 模式也绕不过 |
| 五级压缩顺序 | claude-code-harness/course/05-context-management.md | 预算→snip→micro→collapse→auto 的固定顺序与递归护栏 |
| fork 与工具池保序 | claude-code-harness/course/06-subagent-mcp-and-session.md | 内置在前保序去重防 cache breakpoint 击穿 |
| Cordis epoch 指纹 | deepseek-harness/course/01-cordis-kernel.md | 依赖集合变化压缩成一次字符串比较驱动插件挂卸 |
| 插件全景与接缝 | deepseek-harness/course/02-plugin-landscape.md | 54 类 307 包;「契约包 + 实现包」通用形状 |
| 无 maxSteps 循环 | deepseek-harness/course/03-agent-loop.md | 四种停止机制;abort 补合成结果保 replay |
| append-only 事件流 | deepseek-harness/course/04-session-event-log.md | 日志唯一真相、surface 投影、ignorable 兼容机制 |
| 沙箱 fail-closed | deepseek-harness/course/06-sandbox-and-providers.md | 三后端 + 拒绝方言归一 + 单向升级阶梯 |
| 七种运行宿主 | hermes-harness/course/01-positioning-and-hosts.md | 同一 AIAgent 七种进程模型;s6 监督树 |
| 90 轮预算 | hermes-harness/course/02-conversation-loop.md | 三变量循环条件 + 15 个退出原因字面量 |
| 审批链 | hermes-harness/course/03-tools-and-approval.md | manual/smart/off;hardline 永不可绕;YOLO 导入期冻结 |
| self-improving 闭环 | hermes-harness/course/04-skills-and-memory.md | 复盘 fork 白名单 memory+skill;curator 只 archive |
| OS 边界判词 | hermes-harness/course/05-providers-channels-and-security.md | SECURITY.md:唯一边界是操作系统,进程内只是纵深 |
| 单例 Gateway | openclaw-harness/course/01-positioning-and-gateway.md | 文件锁 + 崩溃熔断;锁目录带 uid 后缀 |
| 循环检测 | openclaw-harness/course/02-agent-loop-and-guardrails.md | 六检测器 + critical 二次命中终止;48h 超时 |
| 四层执行策略 | openclaw-harness/course/03-tools-and-exec-safety.md | Profile × allow/deny × 权限模式 × 审批只能收紧 |
| envelope 与路由 | openclaw-harness/course/04-channels-and-routing.md | inbound envelope + binding→agent;多用户是归因 |
| 插件边界与记忆 | openclaw-harness/course/05-plugins-memory-and-deploy.md | bundled 同边界 + Ed25519 阈值签名 + 五层记忆单槽位 |
| 会话库与检索 | hermes-harness/course/04-skills-and-memory.md | SQLite SessionDB + FTS5;CJK 走 trigram 表 |
| preset 装配 | deepseek-harness/course/05-presets-and-code-mode.md | 四种 preset 是四份 YAML 补丁而非四套代码 |
| 续跑前置校验 | openclaw-harness/course/02-agent-loop-and-guardrails.md | 末条是 assistant 抛 TranscriptNotContinuableError |
| E 平台 事实来源 | 无公开源码(内部平台) | 全部标注「定性对比」:ARQ 队列 / Redis Stream / DynamicTool / 75% 压缩阈值 / workspace scope |
关键取舍
九槽位是机制切分,不是功能清单,所以「没有这一层」也是有效答案。
Claude Code 在「多渠道」格的答案是空白,dsh 在「自改进」格的答案是空白——这两个空白本身就是信息:渠道层缺失意味着产品假设单 operator,自改进缺失意味着把改进放在发版节奏里。用功能清单对比例产品会漏掉这类「以缺席表态」的设计。
槽位之间有硬依赖,不能各格独立打分。
进程模型决定了会话形态(单例 Gateway ⇒ 状态有唯一属主),会话形态又决定了多用户的上限(OpenClaw 只能归因不能隔离);停止条件的立场决定了循环检测要不要存在(无 maxSteps ⇒ 必须把「卡住」做成可判定问题)。按单格「谁最好」打分会得到系统性错误的结论。
停止条件是五家分歧最大的一格,本质是对任务长度的假设不同。
Claude Code 假设任务以「轮」为单位(显式枚举每个出口),dsh 与 OpenClaw 假设任务可能任意长(去掉计数器、改用语义边界),Hermes 折中(90 轮 + 预算 + 宽限),E 平台 把终止权交给用户侧的协作式取消。这一格的选择会向下辐射到工具并发、压缩与恢复的所有设计。
E 平台 只做定性参与,是本坐标系刻意保留的局限。
E 平台 没有 source-level 证据,它的每一格答案都只描述机制形态(队列解耦、offset 续播、阈值压缩),不描述参数与实现细节。在「九槽位」里让它入座的价值是补上「平台化企业部署」这一形态——四家解析课覆盖的形态里没有这一档。
同一槽位内的参数差异往往比机制差异更能暴露立场。
同为「有上限」:Claude Code 的上限是类型系统强制每个出口给 reason,Hermes 的上限是 90 轮 + 宽限一轮,dsh 的 maxParallel 与 OpenClaw 的并发上限默认都是 10 但语义完全不同(一个保提交顺序、一个保副作用顺序)。读对比时先看机制、再看默认值,最后看默认值是否可覆盖。
自测题
- 把 Claude Code 的「显式 State + 10 reason」与 dsh 的「无 maxSteps 四机制」放在同一格里。请说明:如果给 dsh 补一个 maxSteps 计数器,它的哪些现有机制(提示:
concludesTurn、abort 补写)会变得多余或冲突? - OpenClaw 的多用户是「归因不是隔离」,E 平台 是「多租户 workspace」。请从进程模型一格推导:为什么单例 Gateway 架构做进程内多租户隔离的成本特别高?
- 五家的工具并发上限有 8(Hermes)、10(Claude Code、dsh)与「任一 sequential 整批串行」(OpenClaw)三种形状。请指出哪两家在保同一种不变量(提交/副作用顺序),哪一家的保守程度本质上不取决于数字。
- 九槽位里哪一格最能区分「个人工具」与「平台」?请用至少三家的证据论证,并说明为什么「权限与执行安全」不是最佳答案。
- E 平台 的 Redis Stream offset 续播与 dsh 的 append-only 事件流在「可重放」上目标一致。请说明两者服务对象(客户端 vs 重建逻辑)的差异,以及为什么前者可以不带
ignorable这类兼容标记(推断)。