把 DeepSeek Harness 装进口袋

10 阅读6分钟

DSH 这么好玩,但是只能在电脑上玩太可惜了。于是我用 Kuikly 框架做了一个 DeepSeek Harness App——一码三端的跨端原生 App,不是把官方 Web 塞进 WebView,而是按官方 Host 协议跟电脑上的 DeepSeek Harness 说话。

它是什么

DeepSeek Harness 跑在电脑上,界面是 Web。DSH 开源之后,手机端客户端冒出来好几个,我也用 Kuikly 跨端 UI 框架做了一个 DSH App。

DSH 自带的 Web GUI 只监听 127.0.0.1,而且不带认证。出门想用手机连,你不能把 3080 直接打公网——因为它自带 bash 工具,谁连上谁就拿到你电脑的执行权。

社区里早有「手机遥控 DSH」的玩法,大多是套一层浏览器或 WebView。我走另一条:原生界面 + 官方协议。按官方 Host 协议连接电脑上的 Harness,它不是把官方 Web 塞进 WebView,也没自己另起一套聊天后端。

Harness 的 Agent 循环、工具调用、流式事件、插件都还在电脑上跑。App 只做宿主:管连接、生命周期、聊天界面,通过 RPC 和事件流跟 Host 通信。手机上看到的会话、工具卡片、审批,对应电脑上 Harness 的同一套协议。

快速开始

打开 App,首页是「连接 DSH」,先选 扫码连接SSH。两套配置互不干扰,会话缓存也不会混。DeepSeek API Key 配在电脑端 DSH,不要配在手机里。

扫码要同时开着三样:电脑上的 Relay、电脑上的 DSH、手机上的 App。建议电脑开两个终端,都不要关。

先分清两个容易混的地址,后面命令会用到:

  • relay / DSH_RELAY:插件连 Relay 用的地址,电脑本机一般是 http://127.0.0.1:8787

  • publicRelayUrl / PUBLIC_RELAY_URL:写进二维码、给手机用的地址,必须是手机能打开的电脑 IP,例如 http://192.168.1.10:8787

手机不内置公网域名,一律读二维码里的 origin。电脑 3080 始终只听回环,不用打公网。

扫码连接

手机和电脑先连到同一个 Wi-Fi(两边要能互通;有些会隔离终端)。

**1. 启动 Relay(默认 127.0.0.1:8787) **

Relay 在插件仓库的 relay/ 目录,没有单独安装包:

git clone https://github.com/yukiykchen/dsh-scan-remote.git

**cd** dsh-scan-remote/relay

cp .env.example .env

npm ci

npm run build

HOST=127.0.0.1 PORT=8787 npm start

也可以 docker compose up --build。另开窗口确认还活着:

curl http://127.0.0.1:8787/health

Relay 要一直开着。关掉后扫码和隧道都会断。

2. 给 DSH 安装插件

npx @deepseek-ai/dsh plugin --profile web add "github:yukiykchen/dsh-scan-remote#v0.0.1"

已经装过可以跳过。Settings 里没有 Remote Access,多半是插件没装到 web profile,或 Host 不是用这个 profile 启动的。

3. 写入手机能访问的电脑地址,再启动 DSH

ipconfig getifaddr en0    # macOS Wi-Fi;Linux 用 ip addr / hostname -I

把看到的局域网 IP 写进二维码 origin:

**export** PUBLIC_RELAY_URL=http://192.168.1.10:8787   # 换成上一步的电脑 LAN IP

npx @deepseek-ai/dsh web

从 DeepSeek Harness 仓库开发也可以用 pnpm dsh web。已经用过插件时,可以直接改 ~/.dsh-scan-remote/config.jsonpublicRelayUrl,再重启 DSH。改完一定要重启,否则 Settings 里仍是旧码。

浏览器打开本机 DSH:Settings > Remote Access,应看到二维码、倒计时和电脑名。确认码里的地址是当前网段,不是上一张网的 IP。

4. 手机扫码

Android 试用包在 github.com/yukiykchen/… 下载 dsh-mobile-*.apk。iOS 用 Xcode 打开 iosApp/iosApp.xcworkspace 装到真机。

  1. 打开 App,选 扫码连接

  2. 扫描电脑二维码

  3. 配对成功后点 连接已配对电脑

扫完后经 Relay 建密封隧道。电脑 3080 继续只听回环;Key 留在电脑上;Relay 只转发密文,看不到对话。跨网段的话,把 Relay 部署到手机能打开的地址即可,协议是两端出站连 Relay,不依赖把 Host 端口映射出去。

SSH

已经有私钥、或不走 Relay 时用这条。只做本地端口转发,不通过 SSH 执行远程命令,同样不暴露 3080。SSH 不需要 Relay。

电脑先启动 DSH:

npx @deepseek-ai/dsh web --port 3080

推荐给手机用的 SSH 用户配 Ed25519 公钥:

ssh-keygen -t ed25519

ssh-copy-id your-user@your-computer

Windows OpenSSH 把 .pub 追加到 %USERPROFILE%\.ssh\authorized_keys

手机和电脑不在同一局域网时,可以两边都加入 Tailscale / ZeroTier,App 里填虚拟地址,例如 100.86.12.34

在 App 里填 SSH 主机、端口、用户名、远程 DSH 端口,导入私钥。首次连接会出示主机指纹,确认后用于后续校验;指纹变了要重新确认。

电脑侧细节以 github.com/yukiykchen/… 为准;连上之后的 RPC 和事件见 App 仓库 github.com/yukiykchen/…

原理与安全

image.png

原理一句话:手机和电脑各自出站连 Relay,用二维码里的密钥建 sealed-tunnel-v1;插件在电脑本机把隧道接到 127.0.0.1:3080。Host 零改动,bash 工具和信任围栏仍在电脑上。

App 怎么对接上远程 DSH

  1. Host 生成 32 字节主密钥,HKDF 派生 claimToken(info:dsh-claim-v1)。

  2. Host POST /pair/session,Relay 只拿到 SHA-256(claimToken),拿不到密钥本身。

  3. 二维码是 {PUBLIC_RELAY_URL}/app/#/pair?id=...&key=...# 后面的密钥不会发给 Relay。

  4. App POST /pair/claim-device,Host POST /pair/confirm

  5. App 拿 access ticket,再 WSS /client-tunnel(ticket 只走 Authorization 头)。

  6. 连上之后,App 在手机本机拉一个 loopback 网关,后面的 JSON-RPC 和 events.mux 与官方 Host 协议对齐,不另起聊天后端。

会话列表、发消息、模型切换、工具卡片、审批,走的是官方 Host 的 POST /api/{method} 和 WebSocket events.mux / events.host。方法名不自造。远程就绪顺序是:先开两条 WS,再 host.describe,再拉 workspace.list / session.list。mux 断线会重放漏掉的 session/event,重连后再拉一次 session.history

细节以 github.com/yukiykchen/… 为准。扫码配对和密封隧道不属于 Host 协议,在 github.com/yukiykchen/… 里。

三点必须说在最后

  1. DSH 还在 preview。 官方会有破坏性变更,协议没有版本协商。别当稳定基础设施,跟着升级是预期成本。这个 App 也是开发和验证中的实验项目,不要当生产客户端。

  2. 不要轻易装来历不明的 DSH 插件。 插件能起子进程、读写文件、在 GUI 里挂页面,装一个约等于给这台电脑装常驻软件。本插件 MIT,衍生自 april-jk/dsh-mobile-pluginapril-jk/dsh-relay,源码看得见更放心。

  3. 永远不要把 dsh 的 3080 直接暴露公网。 局域网 Relay 适合同一可互通网段;跨网段就自持一台 HTTPS Relay,不要把配对二维码发到聊天里。

觉得有用,欢迎 star / 提 issue / 提 PR。