
字节笔记本
2026年10月6日 · 约 6 分钟读完
DeepSeek Harness 怎么守住运行时不变式
DeepSeek Harness(缩写 dsh)是 DeepSeek AI 在 GitHub 上开源的 agent harness,MIT 协议,目前处于开发者预览阶段。它的架构口号是「一切皆插件」,底层由 Cordis 框架驱动。框架跑得越久,越多的问题不是抛在接线上,而是藏在运行状态里:某个事件被重复消费,某段可变数据被改出了不一致,某个本该一直在线的服务被悄悄卸掉。dsh-invariants 包给出的答案,是把运行时不变式检查做成一个可配置的注册表服务,挂在每个插件都拿得到的 ctx.invariants 上。它是 support 组的支持包,不在 agent loop 主干上,也不属于核心能力接缝,但整个仓库的包都按同一套约定向它注册检查。

一、检查对象:事件流与可变数据,别的不算数
这套机制先划清了检查的边界:不变式只允许断言两类东西,权威事件流或者可变数据,绝不检查某个服务或方法是否存在。理由很直接:存在性断言接近同义反复,服务注册上了不代表行为正确;而事件与状态是系统真实发生过的证据,围绕它们写出的断言才是可执行的契约。每个检查由拥有这段事件或数据的包自己发布,用自己确切的 npm 包名注册,权利与责任都落在包自己头上,注册表本身不导入任何产品包。
二、选择机制:正则过滤,启动时一次说清
interface Config {
/** 全局开关,默认 true */
readonly enabled?: boolean
/** 允许列表:包名命中至少一条才入选,空列表放行全部 */
readonly package_allowlist?: string[]
/** 阻止列表:在允许列表之后再排除一轮 */
readonly package_blocklist?: string[]
}一个包被选中的条件是:服务已启用,允许列表为空或至少一条模式匹配它的完整 npm 名称,且没有任何阻止列表模式命中;阻止列表匹配优先于允许列表。条目一律用 new RegExp(source) 编译,模式不带 ^ 和 $ 就不锚定,/pattern/flags 这种字面量语法不被解析。校验放在服务启动时:空白条目、首尾带空白的条目、重复条目和无效正则都会直接抛错,而不是被静默跳过。有效模式允许暂时匹配不到任何已加载的包,后续加载和 HMR 热替换的行为因此保持确定;过滤器在服务生命周期内固定不变,中途不换规则。
三、子 fiber 里跑安装器,失败带包名归因
通过过滤的安装器在一个专属的子 Cordis fiber 中执行,installer.inject 声明这个 fiber 能访问哪些服务,注册会等安装器同步或异步执行完毕才宣告成功。安装器拿到两样东西:子上下文 ctx,和一个绑定到注册包名的 fail 函数。fail(message) 抛出 InvariantError,它是 Error 的子类,带稳定的 code: 'INVARIANT'、所属包名,以及形如 invariant violated by "": 的消息前缀。任何违规都能准确归因到发布它的包,排查时不必在全仓库里猜是谁的断言炸了。

四、包名保留:谁注册谁负责
ctx.invariants.register(packageName, installer) 为完整 npm 包名保留唯一一个活跃注册,返回绑定到 effect 的 disposer。关键在于:即使过滤器让安装器保持不活跃,这个保留依然成立,两个插件因此绝不可能静默地认领同一个包名;重复、空白或含空白字符的名称直接抛异常。安装器一旦失败,子 fiber 会被原子地 dispose,包名保留同步释放。返回的 disposer 同时挂在注册表与配套插件两侧,卸载任何一边都会清掉监听器、trace 状态和保留项,配套插件因此可以安全重载并再次注册同一个名字,不留残余状态。
五、配套插件约定,外加一台机器守门
每个工作区包都拥有一个 ./invariant 配套插件,发布与注册是穷尽式的,但刻意不合成断言:只有当包真的拥有可观察事件或某种可变数据关系时,插件才安装检查;否则它导出一个空安装器,起始注释以 No runtime invariant: 开头,针对该包解释为什么没有可检查项。光有约定还不够,pnpm run verify-package-invariants 会机械地拒绝五类问题:「生成文件」标记、无解释的空安装器、遗漏或忽略 fail 报告器的非空安装器、错误的注册名称,以及不完整的导出、发布、依赖或打包接线。约定是否被遵守,不由评审时的自觉决定,由 CI 决定。
六、可以搬走的三条经验
对任何想把运行时检查做扎实的项目,这套设计有三处值得直接借鉴。第一,失败要归因:错误对象带上包名和稳定错误码,报错信息直接定位到发布方。第二,确定性优先于灵活:过滤器启动时定死,校验宁可抛错也不静默跳过,换来可预测的热更新行为。第三,约定要有机器守:穷尽式注册加机械校验脚本,让「忘了写检查」和「写了假检查」都过不了 CI。仓库在 GitHub 的 deepseek-ai/deepseek-harness,装好 Node.js 之后执行 npx @deepseek-ai/dsh web 就能在本地起一个 Web UI,感兴趣可以对照源码读它的 invariant 插件目录。



