dshbase

博客 · 分析

DeepSeek Harness 从里到外,再来一场三模型实测

2026 年 8 月 25 日 · dshbase · 给安装者与 Agent 开发者的深度拆解

Agent 圈有句简洁的公式——Agent = Model + Harness。8 月 13 日 DeepSeek 把 Harness 这半开源了,再配上自家模型,就是一个完整的 Agent 体系。真正有意思的不是绕来绕去的功能列表,而是架构上的赌注。正如项目首页那句大字:一切皆插件——模型接入、文件系统、沙箱、会话日志,甚至连驱动 agent 运转的主循环都是插件。

DeepSeek Harness GitHub README:everything is a plugin,由 Cordis 驱动,developer preview,一条命令启动

系统的形状

跑 dsh 分成两个运行区加一个命令行入口。Node Host 装载 agent 核心、能力 Provider、执行策略和本地状态;Browser 负责界面,通过 Web Host(HTTP、API、转发事件)把操作送进 Node Host。命令行模式不启动 Browser,任务由 Headless runner 直接送入同一套 agent 核心。两个入口共享模型、工具、会话与主循环——替换模型或文件系统 Provider 时,入口一处都不用改。

DeepSeek Harness 架构:Browser 与 CLI 入口汇入同一个 Cordis 插件树 agent 核心

组合由 ProfileBundle 管理:Bundle 是一组搭好的插件,Profile 决定这次启用哪些,用户还能叠自己的配置。最终交给 Cordis Loader,把配置变成一棵正在运行的插件树,按每个插件声明的依赖来挂载。

Cordis 怎么托住一切皆插件

Cordis 是底下的依赖与生命周期框架。每个插件声明自己需要哪些服务、提供什么。一个需要文件系统服务的文件工具就等着;服务一登记,Cordis 就调用它的 apply。服务被替换或卸载时,Cordis 先清理依赖它的插件,等新实现就绪再重新激活。每个插件有一个 Fiber 记录其 pending 状态、注册的服务和清理函数——依赖不满足就不运行,也没有插件会留下过期的注册。

插件之间两种连接方式:长期能力走服务("我现在依赖哪项能力"),到点才介入的行为走事件("这件事发生时谁想参与")。主循环虽在执行路径中央,对 Cordis 来说仍是一个普通插件——这正是"主循环也是插件"的真实含义:没有一块永远不能替换的巨大核心,只有一组关系明确的插件。

当一个事件可能被多个监听器响应时,Cordis 提供五种事件分发模式:

  • emit — 发通知,不等待异步结果(状态变化通知)
  • bail — 同步逐个询问,拿到有效结果就停(客户端同步决策)
  • waterfall — 按序传递,允许中途截住(包裹模型请求或工具执行)
  • parallel — 并发执行并等待全部完成(互不依赖的异步任务)
  • serial — 异步逐个询问,拿到有效结果就停(按序决策)

Capability Seam,用文件系统说清楚

dsh 把任何可替换能力拆成三个角色:Service Definition 规定大家能调用什么;Provider 完成实际工作;Consumer 把这项能力交给上层。合起来叫 Capability Seamtool-fs 调用 resolve() 拿到引用,之后只把这个引用传给 readText()/writeText()——引用怎么映射到真实文件(本地 realpath、远程绝对路径、E2B 路径),完全是 Provider 内部的事。换文件系统,tool-fs 仍按同一接口工作,模型看到的仍是 readeditwrite

一条消息对主循环做了什么

用户任务落进 Inbox;主循环写下 turn/start,一个 turn 开始。step = 一次模型请求 + 它调用的工具;turn = 零到多个 step。每个 step 前 agent/pre-step 让插件检查输入——压缩可缩短历史,其他插件可补充、改写或拒绝。到 agent/turn-stopping,有插件可再注入一条消息让模型多走一步;没人要求继续,主循环才写 turn/end

运行中收到的消息按意图分流:"先别改配置"这类补充去 next-step(当前 turn 继续);另发的新问题去 next-turn(排到下一轮)。dsh 不是靠语义判断,而是看发送方怎么送——followup() 进 next-turn,steer()inject() 进 next-step。

日志原则很硬,值得重申:凡是进入模型请求的内容,都必须能从 Session 日志重建。用户说过什么、模型答过什么、工具返回了什么、用了哪套系统提示和工具定义,全都有记录。日志只追加;压缩生成替代内容而非改写旧记录。空的 assistant 消息(如输出上限)作为事实留在日志,但不进入下一次请求的历史。

工具策略:给所有工具一套安全层

价值来自工具,风险也一般来自这里。工具调用落地前,tools/pre-execute 的监听器放行、询问或拒绝;单调守卫只能拒绝或弃权,所以已形成的拒绝不会被更宽松的策略翻回放行。需要审批却没服务、或没通过,注册表都生成拒绝结果。通过后才进工具本身;tools/execute 可统一注入超时、重试和指标;后处理插件检查/整理结果;随后只读的 tools/result 先发通知,agent-loop 再把 tool/result 写进 Session 日志交给模型。Bash、网页搜索和子 agent 各管各的业务,权限、超时和结果记录则不必在每个工具里重写。

实测:同一个 bug,三种组合

作者手头有个真实应用和真实痛点:卡片列表页初始化卡顿,因为约 10 个接口每个都压在 3 秒上下。同一个提示词发给三套——"排查为什么会这么慢并修复"

Codex、DeepSeek V4 Flash、V4 Pro 修复同一 bug 的对比

Codex 约 9 分钟搞定:把多个接口合并成一个详情接口、一次返回所需数据,往返次数大减,周额度消耗约 2%。新接口仍需 ~1.3s——方案最贴合预期、完成度最高,但单接口延迟还有优化空间。

V4 Flash + Harness 约 20 分钟:没合并接口,而是逐个把现有接口优化到 800ms 以下,花费 0.82 元——方案和预期不同,但性能改善实打实。

V4 Pro + Harness 是意外:两轮、约 20 分钟、1.33 元。第一轮提议合并+详情接口,页面却基本没变化;第二轮又跑了 20 分钟,仍无有效产出。最高配的模型反而干得最差——这种结果会让人忍不住去查,自己拿到的发版是不是本来该发的那版。

结论

DeepSeek Harness 真正有价值的是它的可组合运行时——也许将来 agent 能按任务类型自主挑合适的插件来跑。但也正是这种可组合性让它更难跑稳:要选对插件和配置,要处理它们之间的依赖,出问题还得翻比较杂的日志(好在已有运行轨迹,排查方便)。而且它仍是 developer preview,官方明确提示后续可能有破坏性变更。把它当作一份正在演进的工程样本:对在做 agent 的团队是可读的参考,但不要急着把它当底座搬进生产。

全部文章 →