← 返回文章列表
技术文档 · DeepSeek Harness

dsh 使用教程

版本基准 @deepseek-ai/dsh 0.1.5-rc.2 · 整理于 2026-09-22

版本基准:@deepseek-ai/dsh 0.1.5-rc.2 本文以本机实际安装的包与 profile 为准写成,命令均可直接复制运行。


目录

  1. dsh 是什么
  2. 安装与前置条件
  3. 五分钟快速开始
  4. 目录与文件布局
  5. 启动器 CLI 参考
  6. 四种入口模式
  7. Web GUI 使用指南
  8. 模型与凭据配置
  9. 权限与沙箱
  10. 工具集详解
  11. 上下文注入:AGENTS.md、Skill 与引用
  12. 自定义 profile 与 patch
  13. Agent preset
  14. 环境变量速查
  15. 故障排查
  16. 速查表

1. dsh 是什么

dsh(DeepSeek Harness)是一个编码 Agent 运行时。它不是一个单体程序,而是一个启动器 + 可组合配置树

dsh 启动器
  └── profile($DSH_HOME/profiles/<name>)
        ├── bundle 层 1:@deepseek-ai/dsh-base      ← 共享核心
        ├── bundle 层 2:@deepseek-ai/dsh-web-app   ← 表层(web / headless / sdk / acp)
        ├── profile 自己的 cordis.patch.yml          ← 你的覆盖
        ├── $DSH_HOME/cordis.patch.yml               ← home 级覆盖
        └── --patch 指定的额外覆盖层                  ← 单次调用覆盖

每一层都是 patch(补丁):按 id 定位配置树中的行,覆盖它的整个 config、禁用它,或插入新行。最终组合成一棵 Cordis 插件树并启动。

关键点:


2. 安装与前置条件

2.1 环境要求

要求
Node.js 22.x(本机为 v22.23.2)
平台 macOS / Linux 用 bash 栈;Windows 用 PowerShell 栈(自动切换)
pnpm 在需要 dsh plugin ... add 管理 profile 插件时才需要
网络 访问模型端点;如需代理见 14. 环境变量速查

2.2 安装

# 全局安装(本机即为此方式)
npm install -g @deepseek-ai/dsh

# 验证
dsh --version      # 0.1.5-rc.2
dsh --help

安装后 dsh 位于 Node 的 bin 目录,本机为:

/Users/bo/.nvm/versions/node/v22.23.2/bin/dsh

2.3 从源码运行(开发场景)

在仓库根目录:

pnpm run build          # 生产运行需要已构建的包与前端产物
pnpm dsh <args...>      # 转发所有参数到 TypeScript 入口

Web 表层必须有已构建的前端 dist。源码 checkout 未执行 pnpm run build 时,dsh web 会以构建提示停止。


3. 五分钟快速开始

3.1 交互式:启动 Web GUI

cd ~/my-project          # 运行命令时所在的目录 = 默认 workspace 根目录
dsh web

你会看到类似输出:

dsh web: http://127.0.0.1:3080/?token=...

浏览器会自动打开(SSH 会话与 --no-open 除外),取得签名 cookie 后重定向到干净的根页面。看到页面并能对话即成功。

常用变体:

dsh web --no-open            # 不自动开浏览器,只打印 URL
dsh web --port 8080          # 换端口
dsh web --host 127.0.0.1     # 指定绑定地址(0.0.0.0 会被拒绝)
dsh web --trusted-host app.internal   # 允许额外主机访问 /api

3.2 一次性任务:headless

dsh --profile headless "把 README 里的错别字找出来并修复"

3.3 检查配置树(不启动)

dsh --profile web --dump-config           # 打印组合后的完整配置树
dsh --profile web --dump-default-config   # 不含用户层与 --patch 覆盖
dsh --profile web --help                  # web 应用自己的 flag
dsh --help                                # 启动器自己的 flag

4. 目录与文件布局

Harness 数据根目录的解析优先级:显式配置路径 > $DSH_HOME > ~/.dsh(纯空白的环境变量视为未设置)。

$DSH_HOME/                       默认 ~/.dsh
├── settings.yaml                用户设置文档(热重载,Web 的 Models 页写这里)
├── .credentials.yaml            API 密钥等机密(仅本 OS 用户可读)
├── .anonymous-user-id           匿名遥测 ID(删除该文件即重置身份)
├── AGENTS.md                    用户全局指令(注入到每个会话)
├── cordis.patch.yml             home 级覆盖层(作用于所有 profile)
├── profiles/
│   ├── web/                     首次使用 dsh web 时自动创建
│   │   ├── package.json         dsh.profile.bundles 列表 + patchReload
│   │   ├── cordis.patch.yml     ← 你改这里
│   │   ├── cordis.yml           组合产物,不要手改
│   │   └── node_modules/        树外插件
│   ├── headless/
│   └── node_modules/            所有 profile 共享的插件依赖
├── sessions/                    会话 JSONL 日志(默认 zstd 压缩)
├── storages/                    持久 KV(projection cache 等)
├── skills/                      用户级 skill 根目录
└── .agent-presets/              用户自定义 agent preset 根目录

profile 目录里两个 YAML 的区别:

文件 作用
cordis.patch.yml 你的 patch 层,顶层是 YAML 数组。改这个。
cordis.yml 组合后的树,每次启动由启动器重写。不要手改。

package.json 里的 profile manifest:

{
  "dsh": {
    "profile": {
      "bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app"],
      "patchReload": "live"
    }
  }
}

5. 启动器 CLI 参考

5.1 启动器 flag

Flag 说明
-V, --version 打印版本
--profile &lt;name&gt; 启动 $DSH_HOME/profiles/&lt;name&gt;
--from-default-profile &lt;template&gt; 从随附模板创建新 profile 再启动
--patch &lt;path&gt; 追加一个覆盖层,可重复
--dump-config 打印组合后的树并退出
--dump-default-config 打印不含用户层与 --patch 的树并退出

5.2 应用参数的分界

启动器只解析自己的 flag,第一个不认识的 token 之后全部交给应用

dsh --profile web --port 8080        # --port 属于 web 应用
dsh --profile headless "run tests"   # 位置参数属于 headless 应用
dsh --profile web --help             # web 应用的 help
dsh --help                           # 启动器的 help

5.3 插件管理

dsh plugin --profile web add <package>      # 转发给 profile 目录里的 pnpm
dsh plugin --profile web remove <package>

需要 pnpm 在 PATH 上;否则报 pnpm not found on PATH。 内置 bundle(dsh-basedsh-web-appdsh-headlessdsh-sdk-appdsh-sdk-minimaldsh-acp-app)从 dsh 安装目录解析,无需安装。

5.4 保留名称

desktop 名称保留给 Electron 持有的 profile,CLI 会拒绝针对它的启动、dump 与插件管理。


6. 四种入口模式

命令 用途 首次使用自动初始化
dsh web 浏览器 GUI,多轮交互 ✅ 从模板创建 profiles/web
dsh --profile headless "task" 一次性任务,打印答案后退出
dsh --profile sdk 通过 JSON-RPC stdio 为 SDK client 服务
dsh --profile sdk-minimal 极简独立配置树的 SDK 服务
dsh --profile acp 通过 ACP stdio 为自动化 client 服务
dsh --profile &lt;自定义&gt; 你自己的 profile --from-default-profiledsh plugin 初始化

创建自定义 profile:

dsh --profile rescue --from-default-profile web    # 从 web 模板复制
dsh --profile my-profile --from-default-profile headless

随附的 web / headless / sdk / sdk-minimal / acp profile 在首次使用时会自动创建,不需要手动初始化。


7. Web GUI 使用指南

7.1 界面构成

区域 内容
左侧边栏 构建标识、New Session、Workspace 与 Session 列表、底部 Settings
中间会话区 聊天流、工具调用树、turn 导航轨、Plan/Goal 徽章
输入框 / 命令补全、@ 引用补全、模型选择、权限选择、附件
右侧栏 文档预览(Markdown/代码/HTML/PDF/纯文本)、Workspace 文件树
消息尾部 本轮产出的文件(deliverables)行

7.2 会话与 Workspace

7.3 斜杠命令

在输入框键入 / 打开命令面板:

命令 作用
/model 切换当前会话的模型
/permission 切换当前会话的权限预设
/plan 进入计划模式;/plan &lt;message&gt; 带指令进入;/plan off 退出
/goal 查看/创建/编辑/暂停/恢复/清除持久目标
/compact 立即压缩较早历史(不消耗模型轮次,会报告节省的 token 数)
/export 下载完整会话树(会话 + 子会话 + 附件)为 ZIP
/feedback 提交反馈
/&lt;skill-name&gt; 直接调用某个 skill

命令与其输出留在 UI 中,不进入模型请求(skill 调用除外,它会以 Instructions 卡片形式进入对话)。

7.4 @ 引用

7.5 计划模式(Plan Mode)

进入后 Agent 只探索与设计,不做修改,最终通过 exit_plan_mode 提交完整计划供你评审:

7.6 目标(Goal)

一个会话至多一个当前目标,跨轮次、resume、fork、进程重启存活。

/goal 完成所有文档门禁修复        # 创建并启用自动续行
/goal                             # 查看状态、轮数、上限与下一步命令
/goal edit <objective>            # 改目标,不改 phase
/goal pause  /  /goal resume      # 暂停 / 恢复
/goal clear                       # 清除

自动续行有 Round 上限(默认 256),被阻塞的目标会保留策略代码与说明。

7.7 后台任务

会话头部有后台任务列表。Agent 用 run_in_background: true 启动的工作会出现在这里,可以查看输出与终止。

7.8 设置面板


8. 模型与凭据配置

8.1 两种配置途径

  1. Web 的 Models 页:写入 $DSH_HOME/settings.yaml$DSH_HOME/.credentials.yaml,热重载,无需重启。
  2. 直接编辑 $DSH_HOME/settings.yaml:保存即生效。

8.2 settings.yaml 结构

# 官方 DeepSeek 适配器:覆盖 base 行上的端点与模型列表
llm-deepseek:
  baseURL: https://api.deepseek.com
  models:
    - id: deepseek-flash
      name: DeepSeek-V41-Flash
      contextWindow: 1000000
      inputModalities: [text, image]
      imagePixelBudget: 640000
      imageMaxBytes: 1048576
      systemPromptUpdate: in-history

# pi-ai 多提供方孪生:默认休眠,零路由
llm-pi-ai:
  providers:
    my-provider:
      apiKeyEnv: MY_API_KEY          # 密钥按引用解析,不落盘
      api: openai-completions
      baseURL: https://my-endpoint/v1
      models:
        - id: my-model
          name: my-model

# 新建 Agent 的默认路由
agent-default-model:
  provider: deepseek-official
  model: deepseek-flash

要点:

8.3 凭据优先级

启动环境变量  >  $DSH_HOME/.credentials.yaml  >  项目 .env  >  $DSH_HOME/.env

新保存的值会立即覆盖 .env 中的旧值。密钥在每次请求时按引用解析。

⚠️ 凭据文件权限只保护其他 OS 用户;Agent 的工具进程以你的身份运行,因此该存储无法向 Agent 隔离机密。

8.4 常用环境变量

export DEEPSEEK_API_KEY=sk-...     # 官方适配器与 web 搜索共用
export MY_API_KEY=...              # 自定义 pi-ai provider

9. 权限与沙箱

9.1 三个内置预设

预设 沙箱模式 审批策略
read-only 只读 ask
workspace-write 只能写工作区 ask
danger-full-access 无限制 never

默认是 workspace-write + ask:文件写入限制在工作区内,危险操作前征询许可。

9.2 切换方式

DSH_PERMISSION_MODE=read-only dsh web
DSH_PERMISSION_MODE=danger-full-access dsh web    # 完全权限,需显式确认风险

会话选择可跨重启保留。

9.3 审批行为

9.4 沙箱拒绝后的重试

Agent 遇到沙箱拒绝时,可以用更宽的 sandbox_permissions + 一句 justification 重试一次,由你批准。这是沙箱拒绝的唯一例外通道,不能投机性升级。

9.5 平台差异


10. 工具集详解

dsh-base 提供完整工具集。Web 表层把「按 Agent 的工具行」移到 agent preset 之后,由 preset 决定每个会话看到什么。

10.1 文件与搜索

工具 能力
read 带行号读取 UTF-8 文件;读取受支持的图片
write 创建或原子替换文件
edit 定向字面量替换
glob 按路径模式发现文件(含隐藏与忽略文件,排除 VCS 元数据)
grep ripgrep 正则内容搜索

10.2 Shell 与后台任务

工具 能力
bash / pwsh 一次性命令,返回 stdout / stderr / 退出码
run_in_background 启动长时间运行的工作
job_output 读取后台任务输出(可等待)
job_list 列出任务及其 kind 与状态
job_kill 终止任务(工作真正停止后才结算)

每次 bash 调用都是全新 shell:cwd、变量、函数不保留,需要跨调用状态请用 workdir 参数或写文件。

10.3 网络

工具 能力
web_search 联网搜索(默认 DeepSeek 路由,60s 超时)
web_fetch 抓取页面正文(匿名 fetch 只接受公开 HTTP(S) 目标;排除活动与隐藏内容)

抓取结果标记为外部不可信数据。抓取无需逐次审批。

10.4 规划与协作

工具 能力
todo_write 结构化任务列表,跨轮次与重开会话持续
ask_user_question 暂停并向你请求确认、选择或缺失信息
present 声明最终交付文件(不复制内容)
subagent 委派给子 Agent(continuable 模式默认后台启动)
subagent_fork 继承当前对话的子 Agent(一次性)
send_message 向可继续的子 Agent 追加消息
list_agents 列出可继续的子 Agent
workflow 运行 JavaScript 编排脚本,扇出到多个 subagent
ralph 面向不可变目标的全新 Agent 迭代循环
goal 读取/创建长期目标
skill 加载 skill 的完整指令

选择建议:

10.5 输出上限与压缩


11. 上下文注入:AGENTS.md、Skill 与引用

11.1 AGENTS.md 指令链

第一次请求会注入一条持久基线:

用户全局:$DSH_HOME/AGENTS.md
项目链:从项目根目录到会话工作目录,每个目录中的候选文件(从宽泛到具体)

11.2 Skill

Skill 是可复用的任务专项指令。两种形态:

<root>/<name>/SKILL.md      # 目录 bundle
<root>/<name>.md            # 平铺文件

不发现嵌套的 **/SKILL.md

Frontmatter:

---
name: my-skill
description: 一句话说明这个 skill 做什么、什么时候用
whenToUse: 可选的更详细触发条件
disable-model-invocation: false   # true = 模型看不到
user-invocable: true              # false = 用户 /命令里看不到
---

正文指令……

扫描根与优先级:

Rank 来源 路径
100 project-dsh &lt;projectRoot&gt;/.dsh/skills
200 project-agents &lt;projectRoot&gt;/.agents/skills
300 custom 配置的 customSkillDirs
400 user-dsh $DSH_HOME/skills
500 user-agents $DSH_AGENTS_HOME~/.agents 下的 skills
600 bundled 配置的 bundledSkillDir

使用: 模型通过 skill 工具自动加载;你也可以在输入框键入 /my-skill 直接调用。

11.3 引用


12. 自定义 profile 与 patch

12.1 patch 的三种条目

cordis.patch.yml 顶层是 YAML 数组,每个条目是以下之一:

(a) 按 id 覆盖配置——替换目标行的整个 config

- id: agent-default-model
  config:
    provider: hw
    model: deepseek-v4.1-flash

(b) 按 id 禁用

- id: session-telemetry-otel
  disabled: true

(c) 插入新行

- insert:
    - id: tool-str-replace-editor
      name: '@deepseek-ai/dsh-tool-str-replace-editor'
      config:
        maxOutputChars: 16000

⚠️ 覆盖会替换整个 config,不做合并。 想保留的设置必须全部重述。 ⚠️ !!js 表达式可用,例如 !!js process.env.MY_VAR ?? 'default'

12.2 层叠顺序(后者覆盖前者)

1. dsh.profile.bundles 中各 bundle 的 patch(按列表顺序)
2. profile 自己的 cordis.patch.yml
3. $DSH_HOME/cordis.patch.yml
4. --patch 指定的覆盖层(按命令行顺序)

每行最后一次写入生效

12.3 实战示例

示例 1:换默认模型

编辑 $DSH_HOME/profiles/web/cordis.patch.yml

- id: agent-default-model
  config:
    provider: my-provider
    model: my-model

示例 2:启用会话全文搜索

base 默认 session-query-sqliteopenAt: never(不打开 SQLite)。要开启:

- id: session-query-sqlite
  config:
    path: !!js dshHomePath('session-index.sqlite')
    openAt: first-search

示例 3:单次调用叠加覆盖(不改 profile 文件)

dsh web --patch ./my-overlay.yml

示例 4:启用 Schedule(提醒)overlay

dsh web --patch apps/cli/config/examples/schedule/cordis.yml

启用后模型获得 schedule_create / schedule_list / schedule_delete 工具,提醒以普通 follow-up 消息回到同一会话(不发邮件/短信/推送;会话关闭时提醒保持逾期直到恢复)。

示例 5:最小自定义 profile

$DSH_HOME/profiles/my-profile/package.json

{
  "name": "my-profile",
  "private": true,
  "dsh": {
    "profile": {
      "bundles": ["@deepseek-ai/dsh-base"]
    }
  }
}
dsh --profile my-profile "your task"

12.4 验证 patch

dsh --profile web --dump-config | grep -A4 'agent-default-model'

组合失败会以非零状态退出并打印具体原因。

12.5 硬性约束


13. Agent preset

Web 表层的每个会话从 preset 组合自己的 Agent(工具、提示词段落、skill),而不是共享一套进程级工具集。

13.1 随附 preset

preset 说明
standard 完整编码 Agent(默认)
ptc 含 PTC 模式
cordis 含运行时 Cordis 工具
minimal 固定双工具训练配置

13.2 自定义 preset

$DSH_HOME/.agent-presets/&lt;name&gt;/agent.cordis.yml 编写。最省事的做法是复制一个随附 preset 再改:

cp -r <dsh安装目录>/node_modules/@deepseek-ai/dsh-agent-presets/presets/standard \
      ~/.dsh/.agent-presets/my-preset

配置 roster(在 profile patch 里):

- id: agent-presets
  config:
    default: standard
    includeShippedRoot: true      # 前置随附 preset 为 system 根
    includeUserRoot: true         # 追加 $DSH_HOME/.agent-presets 为 user 根
    roots:
      - path: ~/company-presets
        trust: system

13.3 规则


14. 环境变量速查

14.1 Harness 自身

变量 作用
DSH_HOME 数据根目录,默认 ~/.dsh(纯空白视为未设置)
DSH_PERMISSION_MODE 进程级权限模式:read-only / workspace-write / danger-full-access
DSH_TOOLS_MODE 工具呈现模式:native / ptc / both;未设置用 schema 默认
DSH_TELEMETRY_MODE 遥测模式,默认 FEEDBACK_ONLYDISABLED 关闭捕获
DSH_TELEMETRY_DISABLED 任意非空值(含 0/false)即退出遥测
DSH_TELEMETRY_OTLP_URL 覆盖 OTLP 端点
DSH_AGENTS_HOME 共享 agent 配置根,默认 ~/.agents
DSH_BUNDLED_SKILL_DIR 内置 skill 根目录
DSH_MAX_TOKENS_AS_SUCCESS SDK 部署:token 达限的 subagent 完成是否算成功

14.2 工具进程可见(受管注入)

变量 作用
DSH_WEB_URL 运行中的 Web 服务器 URL
DSH_SESSION_ID 当前会话 ID
DSH_SHELL 当前 shell 栈标识

14.3 代理

标准代理变量在启动时读取一次,应用于 LLM、web 搜索与 HTTP MCP 流量:

export HTTPS_PROXY=http://proxy:8080
export HTTP_PROXY=http://proxy:8080
export NO_PROXY=localhost,127.0.0.1,.internal

14.4 模型密钥

变量 作用
DEEPSEEK_API_KEY 官方适配器 + web 搜索共用
自定义 apiKeyEnv 指定的名字 pi-ai provider 密钥

15. 故障排查

症状 原因与处理
EPERM: operation not permitted, open '.../cordis.yml' $DSH_HOME 不可写。检查目录权限,或设置可写的 DSH_HOME
pnpm not found on PATH 安装 pnpm,或不用 dsh plugin(内置 bundle 无需安装)
Web 启动提示需要构建 源码 checkout 未跑 pnpm run build
浏览器没自动打开 SSH 会话或 --no-open 会抑制交接;手动打开打印的 URL
--host 0.0.0.0 被拒绝 出于安全不支持绑定所有网卡;用默认 loopback + --trusted-host
LAN 地址变了但 URL 没变 LAN 地址只在启动时采样一次,重启 GUI 重新公告
审批请求一直失败 没有可用的应答者;ask 策略下会 fail closed(拒绝)
工具报沙箱拒绝 这是策略拒绝,不是 bug。Agent 可用更宽权限 + justification 重试一次
模型无响应 / 401 检查 $DSH_HOME/settings.yaml 的 provider 配置与 $DSH_HOME/.credentials.yaml
会话搜不到内容 全文搜索默认关闭(openAt: never),侧边栏只匹配标题与 workspace 名
改了 patch 没生效 确认改的是 cordis.patch.yml 而不是 cordis.ymlpatchReload: startup 的 profile 需要重启
自定义 provider 没出现在模型选择器 llm-pi-ai: 分节为空时零路由;确认 provider 配置已写入 settings.yaml
想重置匿名遥测身份 删除 $DSH_HOME/.anonymous-user-id
想彻底关闭遥测 DSH_TELEMETRY_MODE=DISABLED 或任意非空 DSH_TELEMETRY_DISABLED

16. 速查表

# ── 启动 ────────────────────────────────────────────────
dsh web                                  # 浏览器 GUI(默认 127.0.0.1:3080)
dsh web --no-open --port 8080            # 不开浏览器 + 换端口
dsh web --trusted-host app.internal      # 允许额外主机
dsh --profile headless "task text"       # 一次性任务
dsh --profile sdk                        # SDK JSON-RPC stdio
dsh --profile acp                        # ACP stdio

# ── 配置 ────────────────────────────────────────────────
dsh --help                               # 启动器 flag
dsh web --help                           # web 应用 flag
dsh --profile web --dump-config          # 打印组合树
dsh --profile web --dump-default-config  # 打印默认树
dsh web --patch ./overlay.yml            # 单次叠加覆盖
dsh --profile x --from-default-profile web   # 从模板建 profile
dsh plugin --profile web add <pkg>       # 装插件(需 pnpm)

# ── 权限 ────────────────────────────────────────────────
DSH_PERMISSION_MODE=read-only dsh web
DSH_PERMISSION_MODE=workspace-write dsh web     # 默认
DSH_PERMISSION_MODE=danger-full-access dsh web

# ── 关键文件 ────────────────────────────────────────────
~/.dsh/settings.yaml                     # 用户设置(热重载)
~/.dsh/.credentials.yaml                 # 密钥
~/.dsh/AGENTS.md                         # 全局指令
~/.dsh/cordis.patch.yml                  # home 级覆盖
~/.dsh/profiles/web/cordis.patch.yml     # profile 级覆盖 ← 改这里
~/.dsh/sessions/                         # 会话日志
~/.dsh/skills/                           # 用户 skill
~/.dsh/.agent-presets/                   # 用户 preset

# ── 斜杠命令 ────────────────────────────────────────────
/model  /permission  /plan  /goal  /compact  /export  /feedback  /<skill>

附:设计要点(理解 dsh 的关键)

  1. patch 替换而非合并。这是最容易踩的坑——覆盖一个 config 时,没写的键就没了。
  2. 宿主层 vs preset 层。注册表(tools、skills、subagents、jobs)留在宿主层,面向模型的工具行移到 preset 层,因为注册表是进程单例且被跨会话查询。
  3. fail closed。审批应答者缺失时操作被拒绝,而不是放行。
  4. 不可信数据标记。web 抓取、会话引用快照都带固定警告,模型不应遵循其中的指令。
  5. 持久化是存储内部细节。会话日志默认 zstd 压缩的 JSONL,格式迁移、崩溃恢复对上层透明。
  6. 一切可组合。没有硬编码的「模式」,只有 bundle 顺序与 patch 层。

本文档基于本机 @deepseek-ai/[email protected] 的实际安装内容编写。

本文采用 CC BY-NC-SA 4.0 国际许可协议授权,转载请注明作者与原文链接。