工具入门 · 2026-09-28 实测

DeepSeek Harness 安装与使用指南

DeepSeek Harness(命令 dsh)是 DeepSeek 开源的编程 agent,一条 npm 命令就能装好。有 DeepSeek 官方 key 可直接用;只有 OpenRouter key 时需多做两步。本文基于 0.1.7-rc.2 实测,它仍是开发者预览版。

0.1.7-rc.2
实测版本(npm latest 指向候选版)
24 秒
Web 里完成「加函数 + 补测试」,单次实测
≈$0.004
两个演示任务合计,OpenRouter 账单读数,单次实测
$0.14 / $0.28
v4-flash 输入 / 输出,每百万 token(OpenRouter)
先看这张

手里是哪种 key,决定走哪条路

官方 key 直连;OpenRouter key 要经本地垫片转一道,因为两边格式有两处对不上。

路线 A · DeepSeek 官方 key,直连
dsh→api.deepseek.com
路线 B · OpenRouter key,两处改动
dsh→本地垫片 127.0.0.1:18080→openrouter.ai
① 配置里关掉 thinking ② 垫片把 null 改成 0
Install

安装

一条 npm 命令即可,前提是本机有 Node.js 和 npm(官方要求 Node ^22.19.0 或 >=24,见 GitHub 仓库根目录 package.json 的 engines;我们在 v24.14.1 上验证过)。

npm install -g @deepseek-ai/dsh@latest
dsh --version        # 输出 0.1.7-rc.2 即成功
API Key

配置 API Key

没有 key 什么都跑不了。DeepSeek 官方 key 在 platform.deepseek.com 的 API Keys 页创建,按用量付费;两种填法任选一种:

export DEEPSEEK_API_KEY=<你的 DeepSeek API Key>   # 写进 ~/.zshrc 可长期生效
只有 OpenRouter key(sk-or-v1- 开头)的,直接这样填会失败,走路线 B,见下面「用 OpenRouter key 接入」。
Modes

三种用法

日常用 Web 界面,批量或脚本用 headless。命令行模式以启动时所在目录为工作区,Web 界面在页面上选工作区;用命令行时先 cd 进项目再启动。

用法命令适合
Web 界面dsh web(可加 --port 8080、--no-open)多轮对话、看 diff 和每一步轨迹
命令行一次性dsh headless "任务"脚本、CI、批量任务
程序对接dsh --profile sdk / dsh --profile acp嵌进自己的程序或编辑器

headless 的常用写法:

dsh headless "跑一下测试,总结失败原因"
echo "审查这段改动:$(git diff)" | dsh headless -   # - 表示从 stdin 读任务,stdin 全文就是任务
dsh headless --json "跑一下测试"                  # 输出机器可读的事件流
dsh headless --session-id session-xxxx "接着上次的继续"  # 把 session-xxxx 换成真实会话 id

会话 id 形如 session-<uuid>,在 --json 事件流开头的 session 事件里。续接时必须在原来的目录下执行,否则会报错退出。

答案输出到 stdout,诊断信息到 stderr。其他帮助:dsh --help、dsh web --help、dsh headless --help。

第一次上手

先命令行验证,再上 Web

建议先在一个不怕改坏的小项目里试。我们用一个含 3 个失败测试的 Python 小项目跑过下面的流程。

  1. 进入项目目录:cd ~/你的项目。
  2. 命令行先验证链路通:dsh headless "用一句话介绍这个目录里有哪些文件"。
  3. 让它干活:dsh headless "运行 python3 -m pytest -q,修复导致测试失败的 bug,不要改测试文件,修完再跑一遍"。实测它自己跑测试、改代码、复跑,3 条测试全部通过。
  4. 换 Web 界面:dsh web,关掉「Internal Testing Notice」提示,点「Choose workspace」选项目文件夹。
  5. 在输入框用中文说任务,比如「新增 median 函数并补测试」。我们单次实测用了 24 秒、改 2 个文件,5 条测试全部通过。
  6. 看结果:点「Edited N files」看 diff,点顶部「Trajectory」看它每一步调了什么工具。

单次实测两个任务合计花费约 $0.004(OpenRouter 账单接口读数,模型 deepseek-v4-flash)。

路线 B

用 OpenRouter key 接入

用 OpenRouter key 要多做两步:写一份配置覆盖文件,再跑一个本地垫片。原因是 dsh 按 DeepSeek 自家的 Anthropic 格式发请求,而 OpenRouter 的 Anthropic 兼容接口有两处对不上:

问题报错处理
dsh 开思考模式时不带 budget_tokens,OpenRouter 校验不过INVALID_REQUEST: Invalid Anthropic Messages API request配置里 thinking: disabled
OpenRouter 流式返回里 cache_read_input_tokens 等字段为 null,dsh 要求是数字MALFORMED_RESPONSE: ... invalid cache_read_input_tokens本地垫片把 null 改成 0
代价:关掉 thinking 后模型不做深度推理,简单任务无影响,复杂任务效果会差一些。有官方 key 就不要走这条路。

第 1 步:写配置覆盖 ~/.dsh/cordis.patch.yml

对所有 profile 生效,删掉这个文件即恢复默认;没跑过 dsh 的先执行 mkdir -p ~/.dsh。

- id: llm-deepseek
  config:
    baseURL: http://127.0.0.1:18080/api   # 指向本地垫片
    thinking: disabled
    models:
      - id: deepseek/deepseek-v4-flash
        name: DeepSeek-V4-Flash (OpenRouter)
        contextWindow: 1048576
        maxTokens: 131072
        inputModalities: [text]
      - id: deepseek/deepseek-v4-pro
        name: DeepSeek-V4-Pro (OpenRouter)
        contextWindow: 1024000   # OpenRouter 上 Pro 的上游上限
        maxTokens: 384000
        inputModalities: [text]
- id: agent-default-model
  config:
    provider: deepseek-official
    model: deepseek/deepseek-v4-flash

第 2 步:保存垫片 ~/.dsh/openrouter-shim.mjs

import http from 'node:http';

const PORT = Number(process.argv[2] ?? 18080);
const UPSTREAM = 'https://openrouter.ai';
const fixNulls = (s) => s.replace(/"(cache_creation_input_tokens|cache_read_input_tokens)":null/g, '"$1":0');

http.createServer(async (req, res) => {
  try {
    const chunks = [];
    for await (const c of req) chunks.push(c);
    const body = Buffer.concat(chunks);
    const headers = { ...req.headers };
    delete headers.host;
    delete headers['content-length'];
    delete headers['accept-encoding'];
    const up = await fetch(UPSTREAM + req.url, { method: req.method, headers, body: body.length ? body : undefined });
    res.writeHead(up.status, { 'content-type': up.headers.get('content-type') ?? 'application/json' });
    if (!up.body) return res.end();
    const decoder = new TextDecoder();
    let pending = '';
    for await (const chunk of up.body) {
      pending += decoder.decode(chunk, { stream: true });
      const cut = pending.lastIndexOf('\n') + 1; // 只改整行,避免字段被切开
      if (cut > 0) {
        res.write(fixNulls(pending.slice(0, cut)));
        pending = pending.slice(cut);
      }
    }
    res.end(fixNulls(pending + decoder.decode()));
  } catch (err) {
    console.error(new Date().toISOString(), req.url, err.message);
    if (!res.headersSent) res.writeHead(502, { 'content-type': 'application/json' });
    res.end(JSON.stringify({ type: 'error', error: { type: 'api_error', message: `shim: ${err.message}` } }));
  }
}).listen(PORT, '127.0.0.1', () => console.error(`openrouter-shim listening on 127.0.0.1:${PORT}`));

第 3 步:每次使用前启动

重启电脑后垫片要重新开:

node ~/.dsh/openrouter-shim.mjs &                  # 先起垫片
export DEEPSEEK_API_KEY=<你的 OpenRouter Key>       # sk-or-v1- 开头
cd ~/你的项目 && dsh web                           # 或 dsh headless "任务"

成功标志:启动后 Web 界面模型栏显示 DeepSeek-V4-Flash (OpenRouter)。OpenRouter 上 deepseek-v4-flash 的标价是输入 $0.14、输出 $0.28 / 百万 token(2026-09-28 从 OpenRouter models 接口读取)。

FAQ

常见问题

现象原因怎么办
浏览器打开 127.0.0.1:3080 返回 401Web 界面需要访问 token用终端打印的完整地址(带 ?token=...)打开
dsh tui 报 profile "tui" does not exist0.1.7-rc.2 没有随附终端界面,网上教程常写错终端里用 dsh headless
点「Choose workspace」页面没反应它弹的是 macOS 系统自带的选文件夹窗口,常被浏览器挡在后面切到那个窗口选好再点 Choose;别反复点,每点一次弹一个
它改了别的目录里的文件,或找不到项目文件命令行模式的工作区就是启动时所在目录先 cd 进项目再启动
报 no API key for provider route没配 key见「配置 API Key」
用 OpenRouter key 报 INVALID_REQUEST 或 MALFORMED_RESPONSE格式不兼容见「用 OpenRouter key 接入」,并确认垫片在跑
想接着上次的会话继续—dsh headless --session-id session-xxxx "继续";id 在 --json 事件流开头的 session 事件里,必须在原目录下执行
安全须知

用之前记住这几条

高别随便装第三方插件插件跑在 dsh 进程内、不受沙箱约束,能拿到 dsh 持有的凭据,装一个插件就等于执行一个陌生 npm 包。stdio 类 MCP 另起进程、环境变量会先清洗,但仍以你的用户权限读写文件和联网。
中沙箱只管文件读写官方原话是不限制网络、进程、设备和凭据。
中key 别贴进聊天或文档已经贴过的,到对应平台后台轮换或调低额度。
提示开发者预览版官方说明会有破坏性变更。升级前先备份 ~/.dsh,升级后本文的命令和配置可能失效。
提示有遥测要关就设 export DSH_TELEMETRY_DISABLED=1。