DeepSeek Harness(dsh):安装、无头运行、三模型基准测试

发布日期
2026年8月18日
更新日期
2026年9月16日
作者
Jacob Lloyd —— 项目完成后,在 AI 协助下撰写
阅读时长
约 18 分钟阅读

简单来说: DeepSeek 发布了一个免费、开源的“编程代理”:一个能读取你的项目、编辑文件并替你运行命令的程序,类似 Claude Code。本文展示了我如何在 Linux 电脑上安装它、让它自动启动、将它同时指向 DeepSeek 的云端模型和我自己硬件上的模型,并用 5 个小型真实编程任务对它进行了测试。全部 15 次运行均通过,云端运行只花了几美分,也存在一些尖锐的边角问题。

六秒钟,文件创建,程序运行,答案打印,退出码 0。这就是 DeepSeek Harness(dsh)完成我交给它的第一个任务时的表现。DeepSeek 于 2026 年 8 月 13 日发布了它,作为一款 MIT 许可的编程代理,其构建理念是:一切皆插件,包括模型适配器、工具、沙盒以及代理循环本身。我在同一周安装了它,将它指向 DeepSeek 的云端模型和我自己 GPU 设备上的模型,并让它运行了一套小型任务。以下是所需步骤、成本以及它在哪里出了问题。

简而言之

  • 它是什么:一个 Claude Code 级别的代理(读取和编辑文件、运行 shell 命令、维护计划、生成子代理),以 npm 包形式发布。它有一个运行在 127.0.0.1:3080 的Web UI,以及一个无头模式,该模式打印一个答案后退出,这正是为脚本设计的部分。
  • 成本:软件免费。我的 5 项任务基准测试在峰值费率下,V4-Flash 上约 3 美分,V4-Pro 上约 7 美分,本地模型上则免费。
  • 结果:在版本 0.1.0-rc.7 上,V4-Flash、V4-Pro 和本地 Gemma-4-26B 共 15/15 通过,整套测试耗时 43 到 56 秒。在一项真实杂务(构建并检查一个 290 页网站的链接)中,它还未经要求就发现我的运行手册已过时。
  • 你需要什么:Node.js,外加一个 DeepSeek API 密钥或任何 OpenAI 兼容服务器。我两者都用了。
  • 问题所在:它还是开发者预览版。README 警告说版本之间会有破坏性变更,所以请固定版本并在升级后重新测试。

2026年9月16日更新:上文所述测试均是在8月份使用0.1.0-rc.7版本完成的。此后我又将软件升级至0.1.5-rc.1版本,该版本的README文档还介绍了相关的SDK与ACP配置方式。另外,自2026年9月9日起我已不再在系统中使用另一款用于对比测试的编程代理工具Reasonix;如今相关对比内容仅作为文末的一个简短历史记录留存。

使用流程:从基础到进阶

按照步骤1至3操作,您就能在十分钟左右获得一个可正常使用的代理程序。步骤4与5则能使其能够被其他软件调用。

最终效果如何

我实际使用的其实是无界面模式。只需在项目文件夹内执行相应命令即可:

$ cd ~/scratch/dsh-demo
$ dsh --profile headless "Create fizz.py that prints FizzBuzz for 1..15 and run it; reply with the program output only."

1
2
Fizz
4
Buzz
…
FizzBuzz
$ echo $? 0

这里的三个反引号是 dsh 自带的格式:它将回复内容包裹在 Markdown 代码块中。它不会在启动时所在的文件夹之外写入任何内容(默认的权限模式为 workspace-write)。它仅将最终结果输出到标准输出,同时会保存每次运行的记录,方便日后通过网页界面查看每一次工具调用情况以及消耗的 Token 数量。

最有力的证明其实是一个真正的实际任务,而非简单的演示。我让 dsh 处理某个网站的源代码文件夹,要求它读取项目文档、执行构建与链接检查并生成报告,整个过程无需任何人工编辑或发布操作。仅用了53秒,它就读完了文档、运行了正确的命令,并输出了检查结果:共290页内容、1,752张图片,没有任何损坏的链接,还有构建耗时数据。更厉害的是,它主动指出文档中仍写着“288页”,从而发现了信息上的偏差。现在这类低风险任务我都会放心地交给它处理。

浏览器端的用户界面采用了2026年流行的布局:左侧为会话列表,中间是聊天界面,还有模型设置页面。一个好习惯是:将 API 密钥粘贴到设置页面中,而不要写入配置文件。

嵌入在聊天应用中的 dsh 网页界面:已完成的会话‘创建并运行 hello.py’显示了上下文注入、思考、写入及 Bash 执行等步骤,最终回复为‘hello from dsh’,下方还有包含轮次、步骤数、延迟及缓存命中率的统计信息;再往下是状态栏,显示‘运行中’,模型下拉菜单中选中了 DeepSeek-V4-Flash,还有开始、重启与停止按钮
dsh 网页界面(拍摄于8月,嵌入在我的聊天应用中)。已完成的会话会展示其执行步骤流程(思考 → 写入 → Bash),以及每轮交互的统计数据。底部的状态栏则是我自己的应用对 systemd 服务及默认模型的控制面板,不属于 dsh 的功能范围。

步骤1:安装(两分钟)

只需安装一个 npm 包即可。我为代理工具专门设置了一个私有的 Node.js 前缀,这样相关文件就不会出现在系统目录中;对于像我这样使用不可修改版 Fedora 桌面的用户来说,这是最稳妥的做法。若要进行全局安装,命令也完全相同:

npm install -g @deepseek-ai/dsh
dsh --version          # 0.1.0-rc.7 when I benchmarked it
dsh web                # starts the UI, prints http://127.0.0.1:3080

打开相应 URL,进入 设置 → 模型,粘贴你的 DeepSeek API 密钥并保存即可。这样便会生成 ~/.dsh/.credentials.yaml 文件(权限为 0600),模型随即即可使用,无需重启。如果你需要编写脚本,该文件其实就是一个标准的 YAML 映射格式(内容类似 DEEPSEEK_API_KEY: sk-…)。我自己的密钥是从其他服务也在使用的环境变量文件中读取的,因此密钥绝不会出现在 shell 历史记录或任何配置文件中。

继续操作前,有两点需要注意:

  • 默认情况下遥测功能处于关闭状态。只要不设置 DSH_TELEMETRY_MODE 变量,该功能便不会启用。我核实过实际提供的配置文件,而非宣传文案:虽然 OTLP 导出器确实存在,但并未被开启。
  • 沙盒环境确实存在,但限制较多。在默认模式下,程序的写入操作仅能作用于启动程序所在的文件夹;读取操作则不受此限制,文档中也明确说明了这一点。因此,执行重要任务时切勿从个人主目录启动该程序,也切勿将其指向包含敏感信息的文件夹。

步骤2:将其作为服务运行

这个网页界面实际上是一个需要长时间运行的 Node.js 进程。我希望它在用户登录后自动启动,且无需终端窗口,同时仅绑定到本地回环接口。使用 systemd 的 --user 单元即可实现这一目的:

# ~/.config/systemd/user/dsh-web.service
[Unit]
Description=DeepSeek Harness web UI (dsh web) on 127.0.0.1:3080
After=network.target

[Service]
WorkingDirectory=%h
Environment=DSH_HOME=%h/.dsh
# Use the path from `which dsh`. systemd does not allow comments at the end of a line.
ExecStart=/usr/local/bin/dsh web --host 127.0.0.1 --port 3080
Restart=on-failure
RestartSec=3

[Install]
WantedBy=default.target
systemctl --user daemon-reload
systemctl --user enable --now dsh-web.service
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:3080/   # 200

WorkingDirectory 用于设置界面的默认工作区根目录,不过用户仍需手动选择一个工作区才能开始输入内容。这样的默认设置挺不错的。命令行工具同样不支持 --host 0.0.0.0 参数;开发者表示目前“有意不提供”绑定到所有网络接口的功能。该界面本身没有登录机制,对此我表示赞同。如果需要从其他机器访问,可以部署带身份验证功能的反向代理,或者通过远程桌面使用本机浏览器——这正是我的做法。

步骤3:将所有模型配置在单个 YAML 文件中,并支持热重载

~/.dsh/settings.yaml 用于设置默认模型以及任何额外的模型提供商。dsh 会在下一次请求前重新读取该文件,因此无需重启或重新登录。我的配置文件内容如下:

agent-default-model:
  provider: deepseek-official
  model: deepseek-v4-flash          # or deepseek-v4-pro

llm-deepseek:
  reasoningEffort: high             # off | low | high | max

# A local OpenAI-compatible server (mine is llama.cpp-based on a GPU rig).
llm-pi-ai:
  providers:
    local-rig:
      displayName: Local GPU rig
      apiKeyEnv: LOCAL_RIG_PLACEHOLDER_KEY    # a reference, not a value
      api: openai-completions
      baseURL: http://my-gpu-rig:1234/v1      # your server's address
      defaultContextWindow: 65536
      models:
        - id: unsloth/gemma-4-26B-A4B-it-qat-GGUF/gemma-4-26B-A4B-it-qat-UD-Q4_K_XL
          name: Gemma 4 26B-A4B (rig)

<p有两个细节让我各自花费了十分钟才弄明白:

  • apiKeyEnv 只是一个引用值,绝不能填写实际密钥。 dsh 会从 .credentials.yaml 或环境变量中获取实际密钥。即便是在本地运行的、无需密钥的服务器,也仍需在 .credentials.yaml 中填入某个占位符值,因为与 OpenAI 兼容的客户端要求必须提供 Bearer Token。
  • 提供商 ID(如上例中的 local-rig)一旦被会话引用便不可更改。 若需重命名,只能新增一个提供商条目。

<p由于整个配置都集中在这个文件中,因此“让 dsh 切换为使用本地模型”只需修改两行代码即可完成,任何脚本或其他程序都能轻松实现。我正是利用这一点将简单任务交给免费的本地模型处理,而将复杂难题转交给 V4-Pro 来处理,完全无需改动其他设置。

步骤4:在自己的软件中调用它

官方提供的软件包并不包含终端用户界面(TUI)。虽然 npm 上有一些第三方开发的 TUI 插件,但在八月份时这些插件才发布四天,且其 workspace:* 依赖项存在问题。我可不会在家庭服务器上运行一个未经审核且拥有 shell 访问权限的软件包。因此,当我把 dsh 集成到自己的聊天应用中时,我只使用了官方软件包所提供的功能:

  • 以固定的参数列表运行无界面模式下的任务。我的服务器会执行 dsh --profile headless "…",将任务内容作为唯一的参数传入,且不使用 shell。这样一来,哪怕任务内容包含 ; rm -rf / 这样的命令,它也只会被当作普通文本处理。该软件一次只运行一个任务,并会保留最近执行结果的历史记录。
  • 通过修改 settings.yaml 文件中的 agent-default-model 来切换模型。无需重启服务即可生效。
  • 若需要的话,可将网页版界面嵌入到 iframe 中;该界面不会发送任何会阻止框架加载的头部信息。

有一条规则值得借鉴:务必将所有这些功能置于自己应用的管理员登录机制之后加以保护。毕竟无界面模式下的任务本质上就是任意代码执行,因此对待“运行任务”这一操作的方式应如同对待 shell 命令一样谨慎。

基准测试:5个任务,3种模型,全部通过

这并非严谨的科学实验:我只是挑选了五个适合交给编程助手完成的小任务。每个任务都在全新的工作目录下执行,并通过脚本进行验证:文件是否存在且能运行?测试用例是否顺利通过(且未对测试文件做任何修改)?重命名操作后是否完全没有残留对旧名称的引用?总耗时涵盖了整个流程,包括约7,500个token的系统提示词。Token数量则取自dsh自身的会话日志。

任务V4-FlashV4-ProGemma-4-26B(本地运行)
回复“PONG”(启动后执行一次调用)✅ 2.1秒✅ 2.8秒✅ 13.2秒*
编写并运行FizzBuzz程序✅ 5.3秒 · 使用了2个工具✅ 8.4秒 · 使用了2个工具✅ 4.9秒 · 使用了2个工具
修复两个bug以确保单元测试通过(测试文件未改动)✅ 11.7秒 · 使用了8个工具✅ 15.8秒 · 使用了7个工具✅ 10.4秒 · 使用了8个工具
用150字以内总结一个由6个模块构成的代码库✅ 8.9秒 · 使用了9个工具✅ 10.9秒 · 使用了7个工具✅ 12.1秒 · 使用了7个工具
在3个文件及测试代码中重命名某个函数,并确保一切正常✅ 15.1秒 · 使用了14个工具✅ 18.2秒 · 使用了12个工具✅ 12.2秒 · 使用了11个工具
总耗时43秒56秒53秒
Token消耗情况(输入未命中/缓存读取/输出)42.6k / 136k / 4.5k41.4k / 107k / 3.2k40.5k / 237k / 5.6k
按峰值费率计算的成本(非峰值时段价格减半)约0.027美元约0.072美元0美元(仅消耗电力)

*此数值为模型在本地设备上初次加载后的首次调用耗时;后续任务则显示了模型处于“热状态”时的速度。测试所用版本为0.1.0-rc.7,日期为2026年8月18日。价格数据取自当天的DeepSeek定价页面:Flash模式下的价格为每百万token 0.014美元(缓存命中)/0.44美元(未命中)/1.32美元(输出);Pro模式则为每百万token 0.044美元/1.32美元/3.96美元。用于测试的脚本属于临时使用,现已删除,因此我无法确认代码摘要功能是否真的统计了字数。

表格所反映的信息如下:

  • 提示词缓存大幅降低了成本。每个任务都需要处理约7,500个token的系统提示词;但在第一次调用之后,绝大多数Token均通过缓存读取方式获取,其成本仅为未命中情况下的3%左右。正因如此,多步骤任务的成本也维持在较低水平。
  • V4-Pro在达成相同结果时所需的工具调用次数更少(重命名任务中仅需12次调用,而Flash则需14次)。在这组测试中,Flash的速度更快且成本仅为其三分之一,因此我仍将其作为默认选择。
  • 本地运行的模型同样表现出色。Gemma-4-26B属于混合专家型模型,实际激活参数量为40亿,采用Q4量化技术,并通过llama.cpp在两块RTX 5090显卡上运行。该模型顺利完成了所有任务:虽然它读取的缓存Token量较大(达237,000个,而Flash仅为136,000个),但总耗时依然具有竞争力。这也是本地模型首次真正具备胜任此类工作的能力——当然,五个小任务的结果并不能代表它能应对涉及40个文件的代码重构工作。

我最终确定的使用规则是:简单的日常任务或脚本化操作选用Flash模式;需要更少、更精准操作步骤的任务则选择V4-Pro;至于那些重新执行成本较低且无需联网处理的任务,则可直接利用本地模型来完成。

有趣的测试:给我做一个玩具吧

我还想看看它在面对一个开放式创意需求时会如何表现:“制作该网站标志的交互式像素艺术版本。需使用纯原生JS实现,可嵌入任何地方;鼠标悬停时产生某种物理效果,点击则触发酷炫的互动效果。不能依赖任何第三方库,请自行测试。” 它最终生成的成果就是这样的,目前也已上线(后来它还在 像素艺术小工具大比拼 中与其他两个由Kimi生成的版本进行了角逐)。

将鼠标悬停其上,然后点击。 像素会从指针位置散开并又重新聚集起来。点击后,这些像素会碎裂成多个小颗粒,最终各自回到原位。触摸操作同样有效,且符合 prefers-reduced-motion 的设置要求。
像素Logo小部件的四个状态:静止状态、鼠标悬停时像素被挤开并带有蓝色光晕、点击后青色像素云从边缘弹开,最后像素又重新组合成环形及两个“L”的形状
静止 → 鼠标悬停时像素被排斥 → 像素四散 → 重新组合。此过程是在无头模式的Chromium浏览器中捕捉到的。帧率为61 fps,控制台无任何错误提示,且像素确实能重新组合。

过程如下:

  • 第一次尝试(V4-Flash):耗时10分钟,但未生成任何文件。 任务要求可以手绘或通过程序生成位图。该模型选择手绘一个40×40的位图,结果陷入了无限循环:会话日志中满是 ################ 和 .... 这样的内容,直到因超时而被终止。这次尝试仅耗费了约2美分。教训:绝不要让模型自行在“脑中”绘制像素点。
  • 第二次尝试(V4-Flash;任务要求改为“根据几何图形生成栅格图像,不可使用位图”):耗时25分钟,所有内容均成功生成。 该模型共执行了100次运算步骤、201次工具调用,输出了17.2万个令牌(其中12.3万个为推理过程记录),还有1630万个用于缓存读取的令牌。按最高费率计算,此次花费约为49美分。它生成了一个包含399行代码的 ll-pixel-logo.js 文件,该文件包含一个全局API以及若干 data- 参数;此外还生成了演示页面、说明文档、针对该渲染器的Node单元测试。甚至在未被要求的情况下,它还编写了一个 Playwright 脚本,用于以三种尺寸截取演示页面的截图。它在完善说明文档时刚好达到25分钟的时间限制,因此虽然任务已完成,系统仍返回了超时错误。可见退出代码有时也会出现误报或漏报的情况。
  • 生成的图像效果: 那个圆环与两个倾斜的“L”形图案乍看之下像是一个标志,但实际上它们比原版标志更粗且更接近“Z”字形。若要正式使用的话,我得花十分钟来调整其变形参数才行。不过我没这么做;所以你看到的就是未经任何调整的原始效果。
  • 将其嵌入到此处仅需一行代码: 由于该网站的内容安全策略仅允许 script-src 'self' 类型的脚本运行,而这个小部件根本不会发起任何网络请求,因此操作极为简单。任务要求如此,模型也照做了。
  • 后续产生的一个问题: dsh生成的输出文件权限被设为0600。我将其上传至Web服务器后,该脚本在正式环境中返回了403错误。后来我执行了 chmod 644 才解决问题。记住:从 dsh 工作区复制出来的任何文件,都必须检查并修正其权限设置。

注意事项

  • 这只是一个开发者预览版,README里也明确说明了这一点。我在 rc.6 发布三天后安装了 0.1.0-rc.7。配置文件、设置项以及插件结构都可能发生变化。因此,在自动化脚本中请固定使用的版本号,并在每次升级后重新执行冒烟测试。
  • 在无头模式下,程序直到完成前都不会输出任何信息。没有任何内容被输出到标准输出,因此耗时较长的任务看起来像是卡住了。您可以查看会话日志(路径为 ~/.dsh/sessions/…/session.jsonl.zstd,该文件使用 zstd 压缩并采用 JSONL 格式),或者通过网页界面进行监控。退出代码为 0 仅表示“任务轮次已完成”,并不代表“任务成功执行”;因此请务必检查实际结果。
  • 在无头模式下没有 --model 参数。默认使用的模型由 settings.yaml 文件指定;您可以在该文件中修改它(配置会热重载),或者通过网页界面进行调整。
  • 对于无需密钥的本地服务器,需要设置一个占位符凭证;另外,提供程序 ID 是永久性的。详情请参见第 3 步。
  • 网页界面使用的是绝对路径(如 /assets/…、/api),因此如果您想在自己的反向代理下以子路径形式使用它,就必须对路径进行重写。更好的做法是直接将其嵌入到您的应用中,或者为其分配独立的主机名。
  • 网页界面的语言设置取决于您的浏览器。随附的 index.html 文件中指定了 lang="zh-CN",打开后首先会弹出一个“内部测试通知”对话框。点击“继续”后,后续内容便以英文显示。
  • 安装过程中会执行 postinstall 脚本(涉及 node-pty、koffi、protobufjs 等模块),npm 也会对此发出警告。我并未发现任何恶意行为,不过这些脚本实际上是在您的系统环境中编译原生代码;这也是建议使用私有目录而非系统默认目录的另一个原因。
  • Node.js 版本要求: rc.7 需要 Node 22.19 或更高版本、亦或是 Node 24;较旧的 LTS 版本则无法运行该版本。请务必查阅您所安装版本的 README 说明。

历史记录:dsh与Reasonix的对比

今年8月,我同时使用了dsh和Reasonix——后者是一款第三方终端智能代理。两者的分工很明确:当我需要与智能代理交互时,我会使用基于文本界面的Reasonix;而其他软件则调用dsh来完成任务。我在2026年9月9日便不再使用Reasonix,如今dsh已成为我的主要编程辅助工具。如果要在二者之间做选择的话,关键区别在于:dsh具备“一条命令、一个响应、一个退出码”的无界面模式,便于编写脚本;而基于文本界面的工具则默认需要有人在键盘前操作。

这对我意味着什么

无头模式正是供其他软件调用的编程代理所需的运作方式:一条命令、一个响应、一个退出码,还有可供审计的日志记录。通过 YAML 配置模型的方式则让调用脚本能够自行决定哪个模型最适合当前任务。如果你已经在本地运行了模型服务器,不妨试试同样的五个任务。所需的成本仅仅是区区 10 美分的 API 费用以及一个临时文件夹而已。

相关项目:DeepSeek Everywhere(将 DeepSeek 集成到 Claude Code 及相应的代理栈中)、将 Kimi K3 用作编程代理(同样的五个任务,9月份在 dsh 环境下重新执行)、bench-llm 及其后续产品 CrucibleForge(比本文更全面地对本地模型进行基准测试),以及 Reasonix(我在使用 dsh 之前的终端代理工具,现已停用)。


← 更多AI 与本地 LLM