DeepSeek Harness (dsh) 安装与使用教程


一、dsh 是什么

DeepSeek Harness(命令名 dsh)是 DeepSeek AI 开源的 agent harness(代理框架),核心设计理念是 Everything is a plugin——模型、工具、技能、会话、沙箱、存储、调度、UI 全部以插件形式存在,可以自由替换与重组。

特性说明
开发者DeepSeek AI(开源,GitHub: deepseek-ai/deepseek-harness)
底层框架Cordis(插件化框架,组合/生命周期/服务/事件)
包名@deepseek-ai/dsh(npm)
形态Web UI(默认 http://127.0.0.1:3080)+ headless CLI(一次性任务)
插件分发基于 npm 生态(pnpm 管理),这是它与 [[npm
当前状态技术预览(developer preview)

与 RootStack 的定位

dshAI Agent 工具 体系中的落地工具之一:本地部署、工作区文件读写、命令执行、插件可编程。本章覆盖从安装到自研插件发布的完整链路。

核心概念速览

概念一句话
profile一个”配置档案”:插件层的有序堆叠 + 用户覆盖层
bundle附带配置层的 npm 包(插件组合包)
patch 层YAML 配置覆盖层,按顺序叠加
插件导出 apply(ctx) 的 TS 模块,通过 ctx 注册能力
$DSH_HOME全局状态目录(profiles、共享配置都在这里)

二、安装

2.1 前置要求

依赖要求说明
Node.jsLTS 版本(18/20/22)运行时,npm 随附
npm随 Node.js 附带npx 启动 dsh 用
pnpm需在 PATHdsh plugin 命令转发给 pnpm,必须可用
网络能访问 npm registry国内可配置镜像(见 [[npm
# 检查前置
node -v
npm -v
pnpm -v    # 没有则: npm install -g pnpm

2.2 从 npm 启动(最简方式)

npx @deepseek-ai/dsh web
要点说明
首次运行npx 自动下载 @deepseek-ai/dsh 到缓存并执行
启动结果终端打印访问地址,默认 http://127.0.0.1:3080
固定版本npx @deepseek-ai/dsh@0.x.x web 指定版本
代理环境设置 NODE_USE_ENV_PROXY=1 让 Node 遵循 HTTP_PROXY/HTTPS_PROXY
# 代理环境示例
export HTTP_PROXY=http://127.0.0.1:7890
export HTTPS_PROXY=http://127.0.0.1:7890
export NODE_USE_ENV_PROXY=1
npx @deepseek-ai/dsh web

2.3 从源码运行(开发/插件调试)

git clone https://github.com/deepseek-ai/deepseek-harness.git
cd deepseek-harness
pnpm install
pnpm run build          # 构建产物(frontend 等)
pnpm dsh web            # 源码入口,转发所有参数
场景用哪种
只想用npx @deepseek-ai/dsh web
想开发插件源码 checkout + pnpm dsh
想改 dsh 本身源码 checkout

从源码运行时,dsh 命令在仓库根目录下以 pnpm dsh <args...> 形式执行;所有文档中的 dsh ... 命令对应改为 pnpm dsh ...

2.4 环境变量

变量作用
DSH_HOME全局状态目录(默认 ~/.dsh 或平台惯例路径),profiles 与共享 patch 都在这里
NODE_USE_ENV_PROXY=1让 Node 版本遵循 HTTP_PROXY/HTTPS_PROXY
HTTP_PROXY / HTTPS_PROXY常规代理变量

三、Web UI 使用

3.1 启动与访问

npx @deepseek-ai/dsh web
# 打开 http://127.0.0.1:3080

3.2 配置模型

打开 设置 → 模型

步骤操作
1输入 DeepSeek API 密钥并保存
2模型路由立即可用,无需重启服务器
3其他提供方或自定义 OpenAI 兼容端点:见官方模型配置指南

3.3 选择工作区

步骤操作
1点击 选择工作区
2添加启动 dsh 时所在的项目目录
3选中该目录(选中前会话输入框不可用)

dsh 进程以调用目录为默认文件系统位置;工作区是 agent 可以读写文件的根目录。

3.4 运行任务

在会话输入框发送任务,例如:

Summarize this repository and identify its main packages.
能力说明
文件操作读写工作区文件
命令执行在工作区运行命令
委派拆分子任务
计划维护任务计划
审批超出当前权限策略的操作会先询问你

四、Profile 与 CLI 模式

4.1 Profile 概念

Profile 是 dsh 的”配置档案”:有序的插件 bundle 层 + 用户自己的覆盖层。web 与 headless 是出厂内置的两个 profile。

4.2 命令语法

命令用途
dsh --profile <名>启动指定 profile
dsh --profile headless "job"跑一次持久会话,打印最终答案后退出
dsh web--profile web 的别名
dsh plugin --profile <名> <pnpm参数...>管理该 profile 的插件(转发给 pnpm)
dsh --profile <名> --dump-config只打印各层合并后的配置,不启动
# headless 一次性任务
dsh --profile headless "分析 /tmp/x.log 中的错误模式"
 
# 查看某 profile 的合并配置(验证插件层是否生效)
dsh --profile demo --dump-config

4.3 Profile 目录结构

Profile 位于 $DSH_HOME/profiles/<名>/

文件作用
package.json树外插件依赖(pnpm 管理)+ profile manifest
dsh.profile(package.json 内)manifest,含有序的 bundles 列表
cordis.patch.yml用户自己的 patch 层(每个 bundle 层之后应用)
pnpm-workspace.yamlpnpm 授权配置(如 allowBuilds
{
  "name": "dsh-profile-demo",
  "private": true,
  "dependencies": {
    "dsh-hello-plugin": "link:/path/to/hello-plugin"
  },
  "dsh": {
    "profile": {
      "bundles": [
        "@deepseek-ai/dsh-base",
        "dsh-hello-plugin"
      ]
    }
  }
}

4.4 出厂 bundle

bundle用途
@deepseek-ai/dsh-base基础能力(默认第一个 bundle)
@deepseek-ai/dsh-web-appWeb UI(web profile = base + web-app)
@deepseek-ai/dsh-headlessheadless(headless profile = base + headless)

首次使用 web/headless 会自动从模板初始化;其他名字的 profile 首次使用时以 @deepseek-ai/dsh-base 为基础创建。


五、插件安装与卸载

5.1 命令总览

dsh plugin --profile <名> <args...> 在 profile 目录内转发给 pnpm,因此 pnpm 的所有子命令都可用:

命令作用
dsh plugin --profile demo add <包>安装插件(自动入 bundle 层)
dsh plugin --profile demo remove <包>卸载(同时移除依赖与对应层)
dsh plugin --profile demo update更新
dsh plugin --profile demo why <包>查依赖来源
dsh plugin --profile demo list列出已装包
# 从 GitHub 安装
dsh plugin --profile tui add github:deepseek-harness/turtle-ui
dsh plugin --profile tui remove turtle-ui
dsh --profile tui

5.2 四种安装来源

来源写法说明
npm 包add your-package预构建代码,即装即用
GitHubadd github:user/repo拉源码,需要 prepare 脚本构建
本地目录add ./hello-plugin相对路径锚定调用目录(file:/link: 同理)
tarballadd ./hello-plugin-0.1.0.tgzpnpm pack 产物,无需构建授权

相对路径(.../pluginfile:/link: 形式)以调用目录为锚点:在插件 checkout 目录里执行 add . 安装的是该 checkout,而不是 profile。

5.3 Git 安装的 allowBuilds 授权

从 Git 安装时拉取的是源码,构建依赖包的 prepare 脚本;pnpm ≥10 默认拒绝运行 git 依赖的 prepare,首次 add 会失败:

失败信息会打印:
1. pnpm 的 allowBuilds 提示
2. dsh 的指引: 把打印的包键复制进该 profile 的 pnpm-workspace.yaml
# $DSH_HOME/profiles/<名>/pnpm-workspace.yaml
allowBuilds:
  dsh-hello-plugin: true
分发方式是否需要用户授权说明
npm 发布发布时已构建好 lib/
tarballpnpm pack 产物
GitHub 源码prepare + allowBuilds: true

5.4 层(bundle)自动 reconcile

每次 dsh plugin 成功执行后,dsh.profile.bundles 会与已安装状态自动对齐:

情况结果
依赖声明了 "dsh": {"bundle": {...}}加入层堆叠(update 获得声明也自动激活)
依赖没有 bundle 声明作为普通依赖安装,打一条一次性警告,不激活层
依赖被移除对应层离开堆叠

六、自己制作插件

6.1 第一个插件

插件 = 导出 apply 函数的 TypeScript 模块。框架加载时调用 apply,传入 ctx(上下文对象),你通过 ctx 注册能力。

mkdir -p scratch-plugin/src
// scratch-plugin/src/my-plugin.ts
import type { Context } from '@deepseek-ai/cordis'
 
export const name = 'hello-plugin'
 
export function apply(ctx: Context) {
  // 依赖的服务就绪后这里才会执行
  console.log('[hello-plugin] plugin loaded!')
}
# scratch-plugin/cordis.yml —— 本地插件的 Web 覆盖层
- insert:
    - id: hello
      name: '/absolute/path/to/deepseek-harness/scratch-plugin/src/my-plugin.ts'

插件路径必须是绝对路径。patch 文件只贡献配置,不改变 loader 解析模块时的 profile 目录。

# 从源码 checkout 根目录启动(加载本地插件)
pnpm dsh web --patch ./scratch-plugin/cordis.yml
# 打开 http://127.0.0.1:3080,终端应打印 [hello-plugin] plugin loaded!

6.2 插件的三种形态

形态适用
函数形式(export function apply(ctx)大多数情况,最简
对象形式(export default { name, inject, apply }结构化声明
类形式(class extends Service需要向其他插件提供服务时
// 对象形式
export default {
  name: 'my-plugin',
  inject: ['tools'],
  apply(ctx: Context) {
    // ...
  },
}
// 类形式(提供服务)
import { Service, type Context } from '@deepseek-ai/cordis'
 
export default class MyService extends Service {
  static inject = ['tools']
  constructor(ctx: Context) {
    super(ctx, 'myService')
  }
}

6.3 生命周期与自动清理

通过 ctx 注册的一切(事件监听、工具、定时器)在插件卸载时自动清理,无需手动 removeListener。

需要手动清理的资源(如网络连接)用 ctx.effect()

export function apply(ctx: Context) {
  ctx.effect(() => {
    const timer = setInterval(() => {
      console.log('heartbeat')
    }, 5000)
    return () => clearInterval(timer)   // 卸载时执行
  })
}

6.4 声明服务依赖(inject)

插件需要使用其他服务(toolsllm 等)时声明 inject,框架保证依赖就绪后才加载:

export const name = 'my-tool-plugin'
export const inject = ['tools']
 
export function apply(ctx: Context) {
  ctx.tools.register(/* ... */)
}

6.5 开发一个 Tool

工具注册 DSL 来自 @deepseek-ai/dsh-tools

import type { Context } from '@deepseek-ai/cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'
 
export const name = 'greet-tool'
export const inject = ['tools']
 
export function apply(ctx: Context) {
  ctx.tools.register(defineTool({
    name: 'greet',
    description: 'Greet someone by name.',
    parameters: {
      name: { type: 'string', required: true, description: 'The name to greet' },
    },
    output: {
      schema: { type: 'string' },
      render: (_args, value) => [{ type: 'text', text: value }],
    },
    async execute(args) {
      return `Hello, ${args.name}!`
    },
  }))
}
字段作用
name / description给模型的工具元信息
parameters参数 schema,自动推断并校验 args
output.schema返回值 schema(canonical value)
output.render把返回值转成模型可见内容
execute实际执行逻辑
# 重启开发命令(若未在运行)
pnpm dsh web --patch ./scratch-plugin/cordis.yml
# 在 UI 里问: Use the greet tool to greet Ada.
# 模型调用 greet 并收到 Hello, Ada!

6.6 插件配置

插件可以接受用户配置(config 系统):在插件中声明配置 schema,用户通过 patch 层注入值。配置合并遵循层顺序(见 7.3),适合把 API key、开关、参数外置。


七、打包与安装插件

7.1 Bundle 是什么

Bundle = 附带一个配置层的 npm 包。区别于普通依赖包:它在 manifest 里声明 patch 层,安装后自动加入 profile 的层堆叠。

// hello-plugin/package.json
{
  "name": "dsh-hello-plugin",
  "version": "0.1.0",
  "dependencies": {
    "@deepseek-ai/cordis": "^2.0.0"
  },
  "dsh": {
    "bundle": {
      "patch": "./cordis.patch.yml"
    }
  }
}
包类型是否激活层用途
声明 dsh.bundle插件本体,用户启用
dsh.bundle否(警告)仅供插件 import 的库

7.2 安装本地 checkout 并验证

# 在包含 hello-plugin 的目录中
dsh plugin --profile demo add ./hello-plugin
 
# 验证层(不启动)
dsh --profile demo --dump-config   # 输出中应有 "# == dsh-hello-plugin" 层
 
# 启动
dsh --profile demo
# 卸载:同时移除依赖和对应层
dsh plugin --profile demo remove dsh-hello-plugin

7.3 层顺序(决定配置合并结果)

1. dsh.profile.bundles 里的各 bundle patch(按列表顺序,先是 @deepseek-ai/dsh-base,再按加入顺序)
2. profile 自己的 cordis.patch.yml
3. $DSH_HOME/cordis.patch.yml(机器本地偏好,各 profile 共享)
4. 每个 --patch <路径> overlay(按 argv 顺序)

后面的层覆盖前面的层。改配置时先想清楚”这个值应该放哪一层”:项目配置放 bundle/profile,机器偏好放 $DSH_HOME,临时调试放 --patch


八、提交与发布插件

8.1 三种分发方式对比

方式命令用户侧安装构建责任
发布 npmpnpm publishdsh plugin add your-package作者(发布时构建好 lib/
tarballpnpm packdsh plugin add ./xxx.tgz作者
GitHub 安装打 tagdsh plugin add github:you/repo用户(prepare + allowBuilds)

8.2 发布到 npm(推荐)

# 1. 构建
pnpm run build    # 产出 lib/
 
# 2. 登录
npm login
 
# 3. 发布(lib/ 随包发布)
pnpm publish

8.3 GitHub 源码分发的 prepare 脚本

Git 安装拉的是源码,作者必须提供自包含的 prepare 脚本(pnpm 在 git 安装后运行它构建发布入口):

要求说明
自包含不能假设开发环境上下文(如 monorepo checkout)
示例turtle-ui:prepare 用专用 tsdown 配置直接转译 src/,不依赖项目引用、不做类型检查
用户侧pnpm ≥10 需 allowBuilds: true(见 5.3)
// package.json
{
  "scripts": {
    "prepare": "tsdown src/index.ts --format esm --out-dir lib"
  }
}

8.4 提交到社区

渠道用途
GitHub Discussions提交反馈、bug 报告、功能建议
dsh-plugin topic给插件仓库加该 topic(GitHub Topics)提高发现度
Discord加入 DeepSeek Harness 社区交流
提交清单:
1. 仓库 README 写明安装方式(dsh plugin add 你的包名)
2. package.json 声明 dsh.bundle(patch 层)
3. 提供构建(npm 发布/tarball 预构建 或 prepare 脚本)
4. 仓库加 dsh-plugin topic
5. Discussions 发帖介绍

九、常见问题

问题原因解决
npx 每次下载慢无缓存/网络慢配置 npm 镜像(见 [[npm
端口 3080 被占用其他进程占用改端口或先 lsof -i :3080 查占用
启动报模块解析错误(源码运行)缺少构建产物pnpm run build(文档明确要求先构建再运行)
浏览器 UI 是旧代码存在陈旧 bundle源码模式下重建:pnpm run build(launcher 不检查新鲜度)
git 安装失败并提示 allowBuildspnpm ≥10 拒绝 prepare复制打印的包键到 profile 的 pnpm-workspace.yaml
代理不生效Node 未遵循环境代理NODE_USE_ENV_PROXY=1 后重试
dsh plugin 报 pnpm 不存在pnpm 不在 PATHnpm install -g pnpm
首次 add 失败(新 profile)profile 未初始化dsh plugin --profile <名> add <包> 会自动初始化(base 模板)
包装了但没层manifest 无 dsh.bundle只作为普通依赖,需在 package.json 声明 bundle
Windows 下路径问题绝对路径/分隔符patch 中插件路径用绝对路径,注意反斜杠转义

十、速查表

命令速查

命令作用
npx @deepseek-ai/dsh web启动 Web UI(推荐日常用)
npx @deepseek-ai/dsh@<v> web固定版本启动
dsh --profile headless "job"一次性任务
dsh --profile <名>启动指定 profile
dsh --profile <名> --dump-config查看合并配置
dsh plugin --profile <名> add <包>安装插件(npm/github/./tgz)
dsh plugin --profile <名> remove <包>卸载插件
dsh plugin --profile <名> update更新插件
pnpm dsh web --patch ./x/cordis.yml源码模式 + 本地插件

目录速查

路径内容
$DSH_HOME/profiles/<名>/package.jsonprofile manifest + 插件依赖
$DSH_HOME/profiles/<名>/cordis.patch.ymlprofile 层配置
$DSH_HOME/profiles/<名>/pnpm-workspace.yamlallowBuilds 等授权
$DSH_HOME/cordis.patch.yml机器级共享配置

关联