DeepSeek Harness 快速上手!

一、DeepSeek Harness 介绍

1.1 什么是 DeepSeek Harness

DeepSeek Harness(简称 DSH)是 DeepSeek 开源的一款 AI 智能体开发平台:提供网页界面、会话管理,以及代码执行、文件操作、任务看板、SSH 运维等工具能力,让开发者像使用集成开发环境(IDE)一样与 AI 智能体协作。

1.2 仓库与资源

资源 地址
官方仓库 https://github.com/deepseek-ai/deepseek-harness
npm 包 https://www.npmjs.com/package/@deepseek-ai/dsh
国内 npm 镜像 https://registry.npmmirror.com/@deepseek-ai/dsh
Node 下载镜像 https://npmmirror.com/mirrors/node/

1.3 功能特性

会话式协作

  • 像聊天一样与 AI 协作,支持多会话、历史记录与流式输出
  • 会话中可切换不同的智能体预设与已装插件能力

工具系统:让 AI 真正「动手」

  • 代码执行:在授权范围内调用终端实际运行命令
  • 文件操作:浏览目录、读取/编辑文件

插件生态:按需扩展能力

插件 能力
任务看板 多列看板管理任务,支持定时任务(cron),关闭浏览器后仍由宿主机执行
SSH 运维 远程命令执行、文件传输、端口隧道、集群并发操作
桌面启动器 一键启动 DSH 网页版、创建快捷方式

无界面模式

  • dsh --profile headless "任务" 命令行直接跑任务,便于脚本化与 CI/CD 集成

多模型支持

  • 「设置」中可配置 DeepSeek 等多家模型服务商,随时切换

关注微信公众号:【Java陈序员】,获取开源项目分享、AI副业分享、超200本经典计算机电子书籍等。

二、DeepSeek Harness 安装

2.1 安装 Node.js

DeepSeek Harness 依赖 Node.js 22+(官方要求 ≥ 22.12),需要先装好 Node.js, 同时运行环境还需满足 glibc ≥ 2.28(macOS 无此限制;这一要求同时保证了 DSH 用到的 zstd 压缩接口可用)。

⚠️ CentOS 7 用户请注意:CentOS 7 的 glibc 停留在 2.17, 不支持 Node.js 22+, 直接安装会报 GLIBC_2.28 not found可参考第三章的 Docker 安装方式,用容器绕开系统限制。

安装 Node.js 有两种方式:直接安装(适合只用一个版本)、用 nvm 安装(推荐,方便多版本切换)。

方式一:直接安装

Windows:去 nodejs.org 下载 22.x LTS(长期支持版) 安装包,一路下一步安装即可。

https://nodejs.org

国内下载慢,可改用 npmmirror 镜像下载安装包(msi).

https://npmmirror.com/mirrors/node/

macOS:

  • 去 nodejs.org 或 npmmirror 镜像下载 22.x LTS(长期支持版) 安装包(Apple 芯片选 arm64 版,Intel 选 x64 版),双击安装
  • 或用 Homebrew:brew install node@22

macOS 没有 glibc 概念,不存在 glibc 版本限制,原生安装即可。

Linux(Ubuntu / Debian 等):

# NodeSource 官方源
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt-get install -y nodejs

方式二:使用 nvm 安装(推荐)

nvm 是 Node.js 版本管理器,可以在多个 Node 版本间自由切换,还能配合国内镜像加速下载,开发环境强烈推荐。

第 1 步:安装 nvm

  • Linux / macOS(国内网络推荐 gitee 上的 nvm-cn 一键脚本,下载源已自动指向国内):
bash -c "$(curl -fsSL https://gitee.com/RubyMetric/nvm-cn/raw/main/install.sh)"
source ~/.bashrc    # 或 source ~/.zshrc

能访问 GitHub 的话,也可用官方脚本:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
  • Windows:安装 nvm-windows(官网下载安装包),用法与 Linux/macOS 一致,只是安装命令需写完整版本号,如 nvm install 22.14.0.

第 2 步:配置国内下载源(可选,国内网络建议)

export NVM_NODEJS_ORG_MIRROR=https://npmmirror.com/mirrors/node/
# 想永久生效,把上面这行追加到 ~/.bashrc 或 ~/.zshrc

第 3 步:安装并切换 Node 22

nvm install 22
nvm use 22
nvm alias default 22    # 设为默认版本

nvm 常用命令速查

命令 作用
nvm install 22 安装 22.x 最新版
nvm use 22 切换当前终端使用的版本
nvm alias default 22 设为默认版本(新终端生效)
nvm ls 查看已安装版本
nvm install --lts 安装最新 LTS 版本

装完 Node.js 统一验证:

node -v    # 期望 v22.x

2.2 安装 DeepSeek Harness

运行环境就绪后,直接全局安装 DeepSeek Harness:

npm install -g --registry=https://registry.npmmirror.com @deepseek-ai/dsh

安装成功后,可通过查看 DeepSeek Harness 版本验证:

dsh --version

2.3 启动与访问

直接在终端中输入并运行:

dsh web

启动成功后,本地浏览器输入访问:

http://127.0.0.1:3080

首次启动会提示需要添加一个 DeepSeek 的 API Key.

也可以稍后配置,到「设置」页面配置 AI 模型。

模型配置好,添加一个本地目录下的工作空间后,即可开始使用。

三、DeepSeek Harness Docker 安装

3.1 安装 Docker(以 CentOS 7 为例)

Docker 20.10 是最后一个支持 CentOS 7 的版本:

yum install -y yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install -y docker-ce docker-ce-cli containerd.io
systemctl enable --now docker
docker --version    # 确认 <= 20.10.x

命令说明

命令 作用
yum install -y yum-utils 安装 yum-config-manager 工具
yum-config-manager --add-repo ... 添加 Docker 官方 yum 源
yum install -y docker-ce docker-ce-cli containerd.io 安装 Docker 引擎、命令行工具与 containerd
systemctl enable --now docker 设置开机自启并立即启动
docker --version 验证版本(CentOS 7 应为 20.10.x)

国内网络提示:官方 yum 源在 download.docker.com, 添加源或下载超时的话,改用国内镜像源(阿里云 / 清华):

yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum clean all
yum install -y docker-ce docker-ce-cli containerd.io

建议顺手配置国内镜像加速:

mkdir -p /etc/docker
cat > /etc/docker/daemon.json <<'EOF'
{ "registry-mirrors": ["https://docker.m.daocloud.io"] }
EOF
systemctl restart docker

3.2 Dockerfile

下面这份 Dockerfile 集成了全部踩坑修复,一句话概括:

Node 22 + Nginx 反代 + 浏览器兼容补丁 + 内置 pnpm = 一条命令部署

# syntax=docker/dockerfile:1
# DeepSeek Harness (DSH) 网页版 — 内置 Nginx 反向代理
# 国内源:基础镜像 DaoCloud / apt 阿里云 / npm npmmirror

ARG NODE_IMAGE=docker.m.daocloud.io/library/node:22-slim

FROM ${NODE_IMAGE}

ARG APT_MIRROR=mirrors.aliyun.com
ARG NPM_REGISTRY=https://registry.npmmirror.com
ARG DSH_VERSION=0.1.0-rc.7

ENV DSH_HOME=/data/dsh \
    NODE_ENV=production \
    npm_config_registry=${NPM_REGISTRY}

# 1. 创建非 root 用户,安装 DSH + pnpm(npm 包,无需编译源码)
RUN groupadd --system dsh \
    && useradd --system --gid dsh --home-dir /home/dsh --create-home dsh \
    && npm config set registry "${NPM_REGISTRY}" \
    && npm install -g --no-fund --no-audit --loglevel=error \
         --registry="${NPM_REGISTRY}" "@deepseek-ai/dsh@${DSH_VERSION}" \
    && npm install -g --no-fund --no-audit --loglevel=error \
         --registry="${NPM_REGISTRY}" pnpm \
    && printf 'registry=%s\n' "${NPM_REGISTRY}" > /usr/local/etc/npmrc \
    && mkdir -p "${DSH_HOME}" \
    && chown -R dsh:dsh "${DSH_HOME}" /home/dsh

# 2. 安装 Nginx + 浏览器兼容补丁 + 反代配置 + 入口脚本
RUN sed -i "s|deb.debian.org|${APT_MIRROR}|g" \
      /etc/apt/sources.list.d/debian.sources /etc/apt/sources.list 2>/dev/null || true \
    && apt-get update \
    && apt-get install -y --no-install-recommends nginx-full \
    && rm -rf /var/lib/apt/lists/* \
    && mkdir -p /usr/share/nginx/html \
    && printf '%s\n' \
      '/* DSH 浏览器兼容补丁 */' \
      'if (!crypto.randomUUID) {' \
      '  crypto.randomUUID = function () {' \
      '    var b = crypto.getRandomValues(new Uint8Array(16));' \
      '    b[6] = (b[6] & 0x0f) | 0x40;' \
      '    b[8] = (b[8] & 0x3f) | 0x80;' \
      '    var h = Array.prototype.map.call(b, function (v) { return ("0" + v.toString(16)).slice(-2); });' \
      '    return h.slice(0, 4).join("") + "-" + h.slice(4, 6).join("") + "-" + h.slice(6, 8).join("") + "-" + h.slice(8, 10).join("") + "-" + h.slice(10).join("");' \
      '  };' \
      '}' \
      'if (!AbortSignal.any) {' \
      '  AbortSignal.any = function (signals) {' \
      '    var controller = new AbortController();' \
      '    var list = Array.prototype.slice.call(signals || []);' \
      '    if (list.length === 0) { return controller.signal; }' \
      '    var aborted = false;' \
      '    var onAbort = function (ev) {' \
      '      if (aborted) { return; }' \
      '      aborted = true;' \
      '      var src = ev && ev.target ? ev.target : null;' \
      '      var reason = src && src.reason !== undefined ? src.reason : new DOMException("Aborted", "AbortError");' \
      '      controller.abort(reason);' \
      '    };' \
      '    for (var i = 0; i < list.length; i++) {' \
      '      var s = list[i];' \
      '      if (s && s.aborted) { controller.abort(s.reason || new DOMException("Aborted", "AbortError")); return controller.signal; }' \
      '      if (s && typeof s.addEventListener === "function") { s.addEventListener("abort", onAbort, { once: true }); }' \
      '    }' \
      '    return controller.signal;' \
      '  };' \
      '}' \
    > /usr/share/nginx/html/polyfills.js \
    && printf '%s\n' \
      'server {' \
      '    listen 3080;' \
      '    server_name _;' \
      '    client_max_body_size 200m;' \
      '    location = /polyfills.js {' \
      '        root /usr/share/nginx/html;' \
      '    }' \
      '    location / {' \
      '        proxy_pass http://127.0.0.1:3081;' \
      '        proxy_http_version 1.1;' \
      '        proxy_set_header Upgrade $http_upgrade;' \
      '        proxy_set_header Connection "upgrade";' \
      '        proxy_set_header Host 127.0.0.1:3081;' \
      '        proxy_set_header Origin "";' \
      '        proxy_set_header X-Real-IP $remote_addr;' \
      '        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;' \
      '        proxy_set_header X-Forwarded-Proto $scheme;' \
      '        proxy_read_timeout 3600s;' \
      '        proxy_send_timeout 3600s;' \
      '        proxy_set_header Accept-Encoding "";' \
      '        sub_filter_once off;' \
      '        sub_filter "</head>" "<script src=\"/polyfills.js\"></script></head>";' \
      '    }' \
      '}' \
    > /etc/nginx/conf.d/dsh.conf \
    && rm -f /etc/nginx/sites-enabled/default \
    && printf '%s\n' \
      '#!/bin/sh' \
      'set -e' \
      '# 自动修正数据目录属主:命名卷/本地目录挂载都适用(bind mount 会保留宿主属主)' \
      'if [ "$(stat -c %u "$DSH_HOME")" != "$(id -u dsh)" ]; then chown -R dsh:dsh "$DSH_HOME"; fi' \
      'nginx -g "daemon off;" &' \
      'exec su -s /bin/sh dsh -c "exec /usr/local/bin/dsh web --port 3081"' \
    > /usr/local/bin/dsh-entrypoint.sh \
    && chmod +x /usr/local/bin/dsh-entrypoint.sh

USER root
WORKDIR /home/dsh

VOLUME ["/data/dsh"]
EXPOSE 3080

HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
  CMD node -e "require('net').connect(3081,'127.0.0.1').on('connect',()=>process.exit(0)).on('error',()=>process.exit(1))"

ENTRYPOINT ["/usr/local/bin/dsh-entrypoint.sh"]

几个关键设计

设计 解决什么问题
基础镜像 node:22-slim Node ≥ 22.12 + 自带新 glibc, 与 CentOS 7 无关
npm 安装而非源码编译 @deepseek-ai/dsh 是成品包,无需 pnpm 构建
内置 pnpm 容器内直接 dsh plugin 装插件
非 root 用户运行 DSH 能执行代码,禁止以 root 运行
Nginx 反代 0.0.0.0:3080 → 127.0.0.1:3081 DSH 只监听回环地址,需要对外入口
端口错开(DSH 用 3081) Linux 上同端口通配/回环绑定会冲突(EADDRINUSE)
Host 改写 + Origin 剥离 通过 DSH 的「浏览器信任围栏」,否则 API 返回 403
兼容补丁注入 老浏览器 / 明文 HTTP 下补齐 crypto.randomUUIDAbortSignal.any

3.3 构建与启动

# 把上面的 Dockerfile 保存到目录里,然后:
mkdir -p /opt/dsh && cd /opt/dsh

# 构建(首次几分钟)
docker build -t dsh:0.1.0-rc.7 .      

# 运行容器
docker run -d --name dsh \
  -p 3080:3080 \
  -v dsh-data:/data/dsh \
  --restart unless-stopped \
  dsh:0.1.0-rc.7

# 验证
curl -s http://127.0.0.1:3080/ -o /dev/null -w "%{http_code}\n"   # 期望 200

💡 挂载方式说明

  • -v dsh-data:/data/dsh:命名卷(推荐),首次创建自动继承镜像内属主
  • -v /opt/dsh/data:/data/dsh:本地目录(bind mount), 宿主机目录属主通常是 root——镜像入口脚本每次启动会自动检查并修正 /data/dsh 属主,两种方式都不会再遇到 EACCES 权限问题

容器启动成功后,浏览器访问:

http://服务器IP:3080

到「设置」配置模型 API 密钥,数据持久化在 dsh-data 卷中,重启容器不会丢失。

3.4 安装插件

# 进入容器装插件(务必用 dsh 用户,不要用 root, 否则会改乱卷内文件属主)
docker exec -it -u dsh dsh sh -c "dsh plugin --profile web add @linxin666/dsh-web-ui-all"
docker restart dsh

插件装在数据卷里(/data/dsh/profiles/web/node_modules), 容器重建后仍然保留;而 pnpm 是构建镜像时装进镜像的,如果你的镜像是没有内置 pnpm 的旧版,重建容器后 pnpm 会丢失,需要先补装一次(npm install -g pnpm)。用本文 Dockerfile 构建的最新镜像已内置 pnpm, 重建后无需补装。

安装插件遇到的问题:

⚠️ EACCES: permission denied:说明卷里有 root 属主文件(多半是之前用 root 身份跑过容器命令,重建镜像不会清空数据卷,旧权限会保留),先修属主再安装:

docker exec -u root dsh chown -R dsh:dsh /data/dsh
# 容器已退出的用:docker run --rm -it -v dsh-data:/data/dsh --entrypoint sh -u root dsh:0.1.0-rc.7 -c "chown -R dsh:dsh /data/dsh"
# 数据不重要想彻底重来:docker rm -f dsh && docker volume rm dsh-data, 再重新 docker run

⚠️ ERR_PNPM_IGNORED_BUILDS(pnpm 拦截构建脚本)时:这是 pnpm 10 的安全机制,交互式批准即可(空格勾选 → 回车确认,再重装):

docker exec -it -u dsh dsh sh -c "cd /data/dsh/profiles/web && pnpm approve-builds"
docker exec -it -u dsh dsh sh -c "dsh plugin --profile web add <插件包名>"

非交互备选把被拦的包名写进 profile 的 pnpm-workspace.yaml 再重装:

docker exec -it -u dsh dsh sh -c 'cat > /data/dsh/profiles/web/pnpm-workspace.yaml <<EOF
onlyBuiltDependencies:
  - node-pty
  - ssh2
EOF'
docker exec -it -u dsh dsh sh -c "dsh plugin --profile web add <插件包名>"

3.5 遇到的问题与解决

  • 问题 1:在 CentOS 7 中安装 Node.js 后运行出现 GLIBC / CXXABI not found
node: /lib64/libc.so.6: version `GLIBC_2.28' not found

原因:CentOS 7 的 glibc 2.17 跑不动新版 Node (要求 ≥ 2.28)
解决:改用 Docker 部署,临时方案可用官方为 glibc 2.17 编译的 x64-glibc-217 构建,但版本上限 Node 22 且无 zstd, 不满足 DeepSeek Harness 的使用需求

  • 问题 2:createZstdDecompress not found
The requested module 'node:zlib' does not provide an export named 'createZstdDecompress'

原因:zstd 压缩接口是 Node 22.4.0 才加入的,旧版 Node 或 glibc-217 老构建没有
解决:使用最新的 node:22-slim 镜像

  • 问题 3:EADDRINUSE (端口被占)
Error: listen EADDRINUSE: address already in use 127.0.0.1:3080

原因:Linux 下先监听 0.0.0.0:3080 后,再绑定 127.0.0.1:3080 会冲突(防端口劫持机制)
解决:Nginx 占对外 3080, DeepSeek Harness 改绑内部端口 3081

  • 问题 4:crypto.randomUUID is not a function

原因:浏览器只在「安全上下文」(HTTPS 或 localhost)提供该接口,明文 HTTP 访问局域网 IP 时没有
解决:Nginx 注入兼容补丁(polyfill), 用同样允许的 crypto.getRandomValues 实现 UUID v4

  • 问题 5:AbortSignal.any is not a function

原因AbortSignal.any 是较新的网页接口(Web API), Chrome/Edge 116 之前、Firefox 123 之前不支持
解决:兼容补丁(polyfill)补齐,或直接升级浏览器

  • 问题 6:/api/host.listDirectory: HTTP 403

原因:DSH 的「浏览器信任围栏」要求接口请求的 Host 必须是回环地址,且 Origin 的 host 必须等于 Host——这是防 DNS 重绑定(DNS rebinding)和跨站请求的安全设计,反代透传了 Host: IP:3080, 被判不可信
解决:Nginx 反代改写 Host 127.0.0.1:3081、剥离 Origin

四、DeepSeek Harness 使用

4.1 快速上手

第一步:配置模型 API 密钥

打开网页界面后,进入「设置」页面:选择模型服务商(如 DeepSeek)、填入 API 密钥,保存后即可开始对话。

  • 配置保存在 $DSH_HOME(Docker 部署时即 /data/dsh, 位于 dsh-data 卷),重启容器/进程不会丢失
  • 之后随时可在设置里更换模型或补充其他服务商。

第二步:新建会话,开始对话

  • 在左侧会话列表点「新建会话」,输入框支持多行,回车或点发送即可开始
  • 会话支持选择不同的智能体预设(preset)与已装插件能力
  • 回复流式输出,可随时停止、继续,历史会话左侧随时切换回来

会话记录持久化在 $DSH_HOME 下的 sessions/storages/ 等目录。

工具系统:让 AI 真正「动手」

DSH 的核心价值是工具调用——会话中 AI 不只是给建议,还会在授权范围内执行代码、读写文件:

  • 代码执行:把任务交给 DeepSeek Harness, 它会调用终端工具实际运行,而不是只给一段代码
  • 文件操作:浏览目录、读取/编辑文件(即文中提到的 host.listDirectory 等接口能力)
  • ⚠️ 这些能力意味着 AI 能操作宿主机的文件系统,务必只在可信环境使用

4.2 插件模块:按需扩展能力

DeepSeek Harness 具有强大的插件生态 —— 可以说"只有你想不到,没有它装不了":无论是任务看板、SSH 运维还是定时自动化,一条 dsh plugin 命令搞定,能力无限扩展,装完重启即用。

安装插件:插件本质是 npm 包,统一用 dsh plugin --profile web <pnpm参数> 管理(需要先装 pnpm).

# 安装 pnpm
npm install -g pnpm

#  安装插件(自动加入层列表)
dsh plugin --profile web add <插件包名>      

# 卸载插件
dsh plugin --profile web remove <插件包名>    

# 装完重启 dsh web 生效
dsh web
  • 找插件包名:npm search --registry=https://registry.npmmirror.com <关键词>;
  • Docker 部署时用第三章的方式:docker exec -it -u dsh dsh sh -c "dsh plugin --profile web add <插件包名>", 装完重启容器。

例如安装 @linxin666/dsh-web-ui-all 插件:

dsh plugin --profile web add @linxin666/dsh-web-ui-all

docker exec -it -u dsh dsh sh -c "dsh plugin --profile web add @linxin666/dsh-web-ui-all"

安装成功后侧边栏会出现插件入口,常用的有:

插件模块 能做什么
任务看板 多列看板管理任务,支持定时任务(cron),关闭浏览器后仍由宿主机继续执行
SSH 运维 配置远程主机,执行命令、传输文件、端口隧道、集群并发操作
桌面启动器 一键启动 DSH 网页版、创建快捷方式

4.3 常用命令速查

操作 命令
启动网页界面 dsh web
无界面直接跑任务 dsh --profile headless "写一个 hello world"
安装插件 dsh plugin --profile web add <包名>
卸载插件 dsh plugin --profile web remove <包名>
查看帮助 dsh --help

五、结语

本文从 DeepSeek Harness 是什么讲起,带你走完了 Windows、macOS、Linux 的常规安装、老系统的 Docker 部署,再到部署后的简单使用,并把实际踩过的 6 个坑和对应解法全部附上,希望能帮你少走弯路。

DeepSeek Harness 的价值在于:把「和 AI 对话」变成「让 AI 动手」——安装只是开始,把日常的开发、运维任务交给智能体,才是真正的生产力。

最后再提醒一句:DeepSeek Harness 能执行代码,请只在可信环境使用,不要暴露到公网

如果你在安装或使用中遇到问题,欢迎留言交流,我们一起排查。

posted @ 2026-08-24 09:19  Java陈序员  阅读(11)  评论(0)    收藏  举报