使用DeepSeek Harness有感
1. DSH 是什么?
“harness” 的本义是“马具”,即缰绳、马鞍、挽具那一整套。给马套上马具,不是为了束缚它,而是为了让它“能被人驾驭着去干活”。DeepSeek Harness 这个名字起得很准:它给大模型套上两层东西:
(1) 赋能层:文件读写、Shell、网页搜索、子代理、后台任务、长目标跟踪......让模型从“会说话”变成“能干活”;
(2)约束层:文件沙箱、审批策略、只读/可写边界,让“能干活”不至于变成“敢乱来”。
DSH 不是聊天软件,也不是某一个 CLI 助手。它是一套可插拔的 agent 运行框架,即官方把框架做成了 npm 上的一个启动器 + 几十个插件包,你想让 agent 长什么样,就用配置把它“拼”出来。这一点和 Claude Code、Codex CLI 这类「成品工具」有本质区别——DSH 更像是一个组装平台。
他的安装也很简单,一行命令(需要 Node 22+,本文环境实测 22.23.2):
npm install -g @deepseek-ai/dsh
装完之后直接 dsh web ,浏览器里就会打开一个可以对话、可以干活、可以管理会话的界面(默认 http://127.0.0.1:3080)。
2. 亮点:
2.1 一切皆插件:Cordis 上的“乐高式”Agent
DSH 的底层是 DeepSeek 自己的依赖注入框架 Cordis(@deepseek-ai/cordis)。你 agent 的每一个能力如Shell 工具、文件工具、网页搜索、计划模式、上下文压缩、Goal 跟踪、子代理、工作流都是一行插件配置。
我从随包发布的标准模式预设文件里摘一段真实的:
- id: tool-bash
name: '@deepseek-ai/dsh-tool-bash'
disabled: !!js process.platform === 'win32'
- id: tool-pwsh
name: '@deepseek-ai/dsh-tool-pwsh'
disabled: !!js process.platform !== 'win32'
注意看:配置里可以内嵌 “!!js” 表达式。Windows 上自动禁用 bash 工具、启用 PowerShell 工具,靠的不是代码分支,而是配置表达式。同样,标准预设里的网页工具默认关掉了抓取能力:
- id: tool-web
name: '@deepseek-ai/dsh-tool-web'
config:
fetch: false
searchTimeoutMs: 60000
更有意思的是它的分层设计:配置注释里明确区分 host plane(主机面)与 agent plane(代理面)。工具注册表、沙箱与审批栈、会话持久化、模型路由这些进程级单例归主机面;每个会话自己的状态归代理面;预设之间用 realm(领域)做隔离,保证同一个进程里挂多个预设互不冲突。这套面与领域的划分,是 DSH 架构上最见功底的地方,也是它敢让一切皆插件而不乱套的原因。
2.2 Profile + Patch:不 fork 代码就能魔改
这是 DSH 最反直觉、也最实用的设计:你的定制不是一个仓库,而是一摞“补丁层”。
配置树从一个空根开始,按顺序叠加:
空根
└─ bundle 补丁层(dsh.profile.bundles 按序,如 dsh-base → dsh-web-app)
└─ profile 自己的 cordis.patch.yml
└─ home 级 $DSH_HOME/cordis.patch.yml
└─ --patch 指定的覆盖层(可叠加多个)
实测中,`web` profile 的清单长这样(`$DSH_HOME/profiles/web/package.json`):
{
"name": "dsh-profile-web",
"private": true,
"dependencies": {},
"dsh": { "profile": { "bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app"] } }
}
想给 agent 开网页抓取、关掉用不上的 Ralph 循环?不用改任何源码,写一个 patch 文件:
# my-patch.yml —— 追加在 profile 层之后的覆盖层
- id: tool-web
name: '@deepseek-ai/dsh-tool-web'
config:
fetch: true # 标准预设默认 false,这里打开网页抓取
- id: tool-ralph
name: '@deepseek-ai/dsh-tool-ralph'
disabled: true # 用不到 Ralph 迭代循环,直接关掉
dsh --profile web --patch ./my-patch.yml
而且官方给了两个“体检”命令,合并后的配置树不启动就能看:
dsh --dump-config # 完整合并树(含用户层与 --patch)
dsh --dump-default-config # 只看 bundle 层(不含用户层)
配置即产物、覆盖即定制、可 dump 可 diff——这种“乐高 + 补丁”的哲学,是我认为 DSH 相比成品 CLI 工具最大的差异化亮点。
2.3 三种入口,一个内核:web / headless / 自定义 profile
dsh 只是个启动器,它只解析自己的 flag,第一个不认识 token 之后的所有参数原样透传给被启动的应用。所以:
| 命令 | 作用 |
|
dsh web |
启动浏览器 UI(等价 --profile web) |
|
dsh --profile headless "跑一遍测试并总结失败原因" |
无头模式:跑一个全新持久化会话,打印最终答案就退出 |
|
dsh --profile tui --resume <会话ID> |
启动自定义 profile 并把 `--resume` 交给终端应用 |
|
dsh plugin --profile tui add <包名> |
把插件管理转发给 profile 目录下的 pnpm |
|
dsh web --help |
注意:这是 web 应用的帮助,不是启动器的 `--help` |
`headless` 模式对 CI 极友好:任务进、答案出,会话还照常持久化。启动器与应用参数分离的设计让每个前端应用都能定义自己的参数体系,互不污染。
2.4 代理编排全家桶:子代理 / 工作流 / Ralph / Goal
DSH 内置了四套层层递进的编排机制,全在“标准模式”预设里:
- subagent / subagent_fork:派子代理干活。`fork` 会继承当前会话的完整上下文;子代理是可续聊的后台对话(`send_message` 继续给它派活),跑完会自动通知主代理。
- workflow:用一段 JavaScript 脚本编排**大规模 fan-out——`agent()` 派单、`pipeline()` 流水线、`parallel()` 并发汇聚,还带 JSON Schema 校验子代理的返回。
- Ralph:每轮用一个全新上下文**的子代理干活,以共享工作区作为持久记忆,适合“带遗忘”的迭代式攻坚。
- Goal:把一个长目标注册为跨轮次持久目标,自动续跑多轮直到完成或明确受阻;会话恢复/分叉后还能“续弦”。
再配上 todo 清单、后台任务(`run_in_background` + `job_output`/`job_kill`)、Skills 技能目录、Plan Mode(先出计划、批准后再动手)和 ask-user(关键决策问你)——这是一套相当完整的“自主干活”工具链。
2.5 沙箱与审批:给自主性套上缰绳
回到 harness 的本义。DSH 的沙箱是“分层”的:文件策略从只读、工作区可写,到危险全访问逐级放宽;命令执行在 Windows 下跑 PowerShell 约束语言模式;审批策略可以设为 `ask`——敏感操作弹出确认,用户批准才放行。
有个细节很能体现官方态度:Windows 沙箱里禁止子进程通过命名管道捕获输出,这个限制直接导致 Node 的 `child_process.spawn` 默认用法会报 EPERM。官方没把这事藏起来,而是在文档里写成了明确的“边界”:要么改用 `stdio: 'inherit'`,要么逐次申请更宽的权限。把限制写成有文档的边界,而不是让用户撞墙猜——这是我给 DSH 加分的一条。
2.6 会话持久化、Token 计量与上下文压缩
每个会话都落盘在 `$DSH_HOME/sessions/<路径哈希>/session.jsonl.zstd`(zstd 压缩的 JSONL,实测路径),随时可以回看、恢复、分叉。内置 Token 计量器按会话折叠统计上下文消耗;上下文超限时,`compaction-basic` 负责压缩历史,工具结果裁剪器按真实阈值裁剪(实测默认:超 8192 字符截断,保留头部 4096 + 尾部 1024)。
2.7 模型无关:路由是配置,可换
模型不是写死在代码里的。实测 `$DSH_HOME/settings.yaml` 里长这样:
agent-default-model:
provider: deepseek-official
model: deepseek-v4-pro
reasoningEffort: max
更有意思的是子代理的 provider 也是插件:标准预设里赫然躺着 `codex` 和 `claude-code` 两个 provider 行,默认 disabled,想去掉 `disabled` 就能让子代理用别的产品跑。框架的开放度可见一斑。
3. 上手:从零到跑通(Windows 实测)
3.1 安装与首次启动
npm install -g @deepseek-ai/dsh
dsh --version
dsh web # 浏览器打开 http://127.0.0.1:3080
`web` 和 `headless` 两个 profile 首次使用时会从内置模板自动初始化;其他 profile 需要经由 `dsh plugin` 创建。`$DSH_HOME` 默认是 `~/.dsh`(Windows 为 `C:\Users\<你>\.dsh`),里面装着 profiles、sessions、settings.yaml 和 `.credentials.yaml`(凭据文件,别提交到 git)。
3.2 无头模式一句话任务
dsh --profile headless "把本仓库的测试跑一遍,用中文总结失败原因并给出修复建议"
跑完打印最终答案退出,适合脚本化和 CI。
3.3 装插件、建自定义 profile
dsh plugin --profile tui add <某个 dsh 插件包>
dsh --profile tui --resume <会话ID>
`plugin` 子命令本质是把参数转发给 profile 目录下的 pnpm——所以机器上要有 pnpm。
3.4 无侵入定制:patch 层
见 2.2 的 `my-patch.yml` 例子。改完用 `dsh --profile web --patch ./my-patch.yml` 启动,用 `--dump-config` 验证合并结果,不满意就删文件,零残留。
3.5 预设、设置与凭据
Web UI 里可以选 agent 预设。随包附赠四个:标准模式(官方描述:功能完整的编码 Agent,支持文件编辑、Shell、文件与网页检索、Skills、计划、目标、子代理和工作流)、minimal(最小)、code、cordis(带 Cordis 开发技能)。日常用标准模式就够了;要裁剪/加料,就在它的基础上做 patch。
3.6 开发者工作流(想改 DSH 本身的话)
仓库根目录 `pnpm run build`,之后用 `pnpm dsh <args>` 走 TypeScript 入口;前端产物改动需要重新构建并刷新页面,客户端插件的热更新还要求 `pnpm run dev:web` 同时在跑。这套开发循环体验一般,详见 4.6。
4. 缺点与坑:不吹不黑
4.1 仍是 RC 版
`0.1.0-rc.6`,连 1.0 都没到。CLI 语法、内部插件接口都有继续变化的可能,生产环境用它要有追版本的觉悟。
4.2 文档碎片化,门槛偏高
官方 CLI 的 README 只有几十行,大量细节散落在几十个插件包各自的 README 配置文件注释里。想真正吃透 host plane、agent plane、realm 这些概念,得去读配置注释和源码。网上虽已出现不少教程(如
orcarouter 的 DSH 使用教程(https://www.orcarouter.ai/zh-CN/blog/deepseek-dsh-usage)、zoahdev 的 17 章实战手册(https://github.com/zoahdev/deepseek-harness-handbook)、
命令速查手册(https://www.ai-indeed.com/encyclopedia/29697.html)
),但多为第三方出品,质量参差。
4.3 学习曲线陡
对只想问个问题的用户,Cordis、patch 层、`!!js` 表达式这些概念纯属噪音;DSH 的定位明显是给工程师的框架,不是给大众的消费品。
4.4 依赖树庞大
实测安装目录下 `node_modules` 三万余个文件。安装慢、占空间,且 `dsh plugin` 强依赖 pnpm,环境要求(Node 22+、pnpm)比竞品多。
4.5 Windows 二等公民
bash 工具在 Windows 被配置直接禁用;沙箱下 PowerShell 跑约束语言模式,部分 .NET 静态调用、COM、反射用不了;子进程管道捕获输出直接 EPERM。边界虽然写清了,但跨平台体验一致性确实打折(Linux/macOS 用户无此烦恼,可参考 [Windows 下的 DSH 运行指南](https://www.orcarouter.ai/blog/deepseek-harness-windows-tui))。
4.6 Web UI 的开发热更条件苛刻
改前端要重建 + 刷新;`dev:web` watcher 不在跑,客户端插件的 HMR 就不生效。普通用户无所谓,想给 DSH 写前端插件的开发者会感受到摩擦。
4.7 配置即代码的双刃剑
YAML 里嵌 `!!js` 表达式非常灵活,但 patch 文件本质上已经是代码,团队协作时同样需要 review 纪律;而灵活性和风险的边界,官方文档并没有给出太多护栏。
4.8 单机定位,协作靠社区
开箱即用是单机本地会话;多用户共享、远程接管(如 [ZOL 这篇远程教程](https://news.zol.com.cn/1234/12348966.html))都要自己搭。另外 npm 上已出现多个仿名第三方包(还有 [Rust 重写版](https://github.com/xizheyin/deepseek-harness-rs)),生态活跃是好事,但安装时务必认准 `@deepseek-ai/dsh`。
5. 结语:Harness 的真正含义
回到开头。写这篇文章的 agent,此刻就“套”在这副马具里:它有文件沙箱和审批策略的缰绳,也有子代理、工作流、Goal 的挽具;它读的每一个文件、执行的每一条命令,都在 2.5 节描述的那套边界内完成。
DeepSeek Harness 目前不是最易用的,也不是最成熟的——RC 版本、陡峭的学习曲线、碎片化的文档都是实打实的代价。但它的架构方向是清醒的:agent 不该是黑盒成品,而应该是可组装、可审计、可约束的工程对象。如果你喜欢终端、享受拆解框架、想造一个“自己的 Claude Code”,DSH 是当前开源生态里最值得动手的那一个;如果你只想开箱即用地让 AI 改 bug,那么它的缺点会让你先于它的亮点被记住。
马具的意义,从来不是让马停下,而是让马跑得更远——DSH 想做的那副马具,至少已经能让我写完这篇关于它自己的文章了。
更多推荐

所有评论(0)