前言¶
DSH 的子代理(subagent)能让一个会话把任务丢给另一个 agent 并行处理,但执行仍然落在本机。当你的 agent 需要在另一台机器上跑、用那台机器的模型配置、工具和沙箱时,本地子代理帮不上忙。通常的做法是开一个公网端口、配 token、再写一套 WebSocket 协议——这意味着额外的暴露面和一套独立于 DSH 的基础设施。
dsh-remote-subagent 走的是更简单的一条路:复用 DSH 自带的 headless 入口,通过 SSH 的 exec 通道把远端 dsh headless --json 的 JSON 事件流直接读回本地。下面介绍这个插件是什么、怎么装、怎么用,以及它明确的边界。
这是什么¶
这是 DSH(DeepSeek Harness)的一个插件,作者 deepseekv41flash,分类属于工作流,目前在 SkillHub 目录页与 GitHub 上显示 1 个星标,版本 0.1.0,许可证 MIT。
它解决一个问题:本地会话需要让另一台机器上的 DSH 替自己干活,并且能看到那个 agent 的思考、工具调用和工具结果,还能在它跑完之后接着追问。
核心机制是 remote_agent 工具。本地会话通过它把任务派给远端 DSH,远端 agent 用自己的模型配置、工具、沙箱和 session 存储执行,过程中的 JSON 事件通过 SSH 实时流回本地。
本地会话 ── remote_agent 工具 ──SSH──> 远端 dsh headless --json <task>
▲ │
└──── 事件流(thinking / tool_call / tool_result / final)◄──┘
选择 dsh headless --json 而不是自建服务,是因为它有三点好处:
- 远端不需要开公网端口,也不需要 token 或 WebSocket 协议;
- 远端 agent 用它自己的 profile,session 落在远端
$DSH_HOME/sessions,在远端 DSH Web UI 里同样可见; - 事件流本身就是「工作过程」,不需要额外埋点。
安装与启用¶
README 给出的安装命令是:
# 从 npm 安装到当前 profile(bundle 形式)
dsh plugin --profile <profile> add dsh-remote-subagent
# 或在 DSH 插件市场/plugin_manager 里安装 dsh-remote-subagent
依赖会自动安装(ssh2,版本要求 ^1.17.0)。启用后,左侧栏出现「远端代理」图标,模型侧多出 remote_agent 工具。
插件的运行要求写在 package.json 里:Node.js >=20,DSH 引擎 >=0.1.0-rc.6 <0.3.0。远端同样需要 dsh 在 SSH 登录 PATH 上,且 headless profile 可用。
机器从哪来¶
插件不要求你重复配置一份 SSH 清单。它优先读取 dsh-remote 的注册表:
$DSH_HOME/remote-workspaces/machines.json
默认机器的解析顺序是:插件配置 config.machineId → 注册表 currentId → 第一个已保存机器 → config.machine(没有 dsh-remote 的独立部署用这个)。认证支持密码、私钥(含 passphrase)和 SSH agent。
主机密钥采用 TOFU 策略:首次连接把指纹记录到 $DSH_HOME/dsh-remote-subagent/known_hosts.json,之后每次连接必须匹配,不匹配就拒绝。
remote_agent 工具¶
插件暴露一个 remote_agent 工具,支持以下几个 action:
| action | 作用 | 关键参数 |
|---|---|---|
spawn |
起一次新的远端 run(独立远端会话) | task、machine?、cwd? |
wait |
阻塞等 run 结束或超时(默认 30s,上限 120s;超时不影响远端继续跑) | runId、waitSeconds? |
get |
状态 + 最近 N 条过程事件 + 结果 | runId、eventLimit? |
send |
给同一远端会话追加消息(新 run,--session-id 续跑,turn+1) |
runId、task |
list |
最近的 run 列表 | limit? |
cancel |
终止远端进程(按 pid 文件 kill -TERM) |
runId |
machines |
列出可用的远端机器 | — |
两个动作的复用语义需要区分清楚:
spawn永远创建新的远端会话,等于内置 subagent 的 spawn;send复用该 run 所属的同一个远端会话,等于 subagent 的 send_message;- 多次
spawn并发 = 多个互不共享上下文的远端会话;同一会话同一时刻只能跑一个 turn。
run 历史和 sessionId 持久化在本地,DSH 重启后依然可以对同一个 session 继续 send。
面板¶
左侧栏「远端代理」打开主面板:
- 左列:新建任务(选机器 + 任务文本 + 派活)、run 列表(状态点 / 任务摘要 / 机器 / 用时);
- 右列:run 详情(状态、远端 session id、cwd、轮次、事件数、token)、实时事件时间线(1.5s 轮询增量、自动滚底)、结果框、终止 / 刷新、追加消息输入框。
面板背后的数据接口(GitHub 仓库为 client 半,Desktop 走 /api 前缀,Web 走裸路径):
GET /dsh-remote-subagent/runs
GET /dsh-remote-subagent/run?id=<run>&from=<seq>&limit=<n>
POST /dsh-remote-subagent/action {action: spawn|send|cancel, ...}
可选配置¶
插件配置写在所在 profile 的 cordis.patch.yml 的 config: 下,全部可省略:
| 字段 | 默认 | 说明 |
|---|---|---|
machineId |
'' |
默认机器(id/名称/host) |
machinesFile |
'' |
自定义机器注册表路径 |
headlessCommand |
dsh headless |
远端命令前缀 |
cwd |
'' |
远端工作目录(空 = 机器 home) |
maxConcurrent |
4 |
并行 run 上限 |
timeoutSeconds |
900 |
单 run 上限,超时自动终止远端进程 |
maxEvents |
4000 |
每个 run 保留的事件上限 |
connectTimeoutMs |
20000 |
SSH 连接超时 |
典型用法¶
下面是 README 提供的一个完整调用序列,读一次远端健康检查,再追加一条追问:
remote_agent({action:"spawn", task:"在 /opt/app 跑一次只读健康检查:磁盘、内存、监听端口,最后总结"})
→ runId
remote_agent({action:"wait", runId, waitSeconds:120})
remote_agent({action:"get", runId, eventLimit:30})
remote_agent({action:"send", runId, task:"把监听端口按大小排序再列一次"})
先 spawn 拿到 runId,再 wait 等它结束或超时,接着用 get 拉最近若干条过程事件和结果;send 是在上一步的同一个远端会话里追加消息,turn 加一,模型能看到前面的上下文。
数据与回滚¶
插件在本地写入两类数据:
$DSH_HOME/dsh-remote-subagent/runs/<runId>.json:每个 run 的元数据 + 事件 transcript。重启后历史仍在;重启瞬间还在跑的 run 会标记为 failed/interrupted,但 session id 保留,仍可send续跑。$DSH_HOME/dsh-remote-subagent/known_hosts.json:TOFU 主机指纹。
卸载时从 profile 移除 dsh-remote-subagent bundle;需要清数据就删除 $DSH_HOME/dsh-remote-subagent/。插件对远端没有持久改动,只会在 /tmp/dsh-remote-subagent-*.pid 落临时 pid 文件(正常结束自动清理)并占用远端 session 目录。
实测状态¶
README 记载了 v0.1.0(2026-11-04)在一台 Linux 远端(DSH 0.2.0-rc.2,SSH 密码登录)上的实测结果:
spawn用时 11s,产生 23 条事件,turn 1,包含tool_call与tool_result;send续跑同一session-*,turn 2 正确引用上一轮上下文,回答中的数值与 turn 1 一致;- DSH 重启 + 插件热重载后,
send仍能续上同一远端会话(turn 3); cancel之后远端没有残留的dsh headless进程,pid 文件被清理。
README 还说明有离线单测覆盖:机器解析顺序与报错、事件流解析/分页/续跑/取消/持久化、面板路由、SSH 引用与 TOFU 指纹、Client 槽位注册。
已知边界¶
这些限制来自 README,实际使用前需要对照自己的环境确认:
- 远端需要
dsh在 SSH 登录 PATH 上,且 headless profile 可用;远端版本过老、没有--json/--session-id时不可用; - 只支持 POSIX 远端(命令用
sh -c包装),Windows 远端未实现; - 不支持 dsh-remote 的
useSshConfig别名机器与 ProxyJump 跳板,需要用直连条目; - 远端 run 的模型 / 工具 / 沙箱完全由远端 profile 决定,本地不能改;
wait超时不会终止远端 run;运行中不支持插话,需要wait或cancel之后再send;- 事件流只覆盖 headless 单 turn;远端 agent 如果把活丢进后台 job,后续输出不会出现在这个 run 的流里。
适用场景与注意¶
适合的场景是:你有一台专门跑了 DSH 的机器(比如带特定模型配置、特定工具或隔离沙箱的服务器),想让本地会话把任务派过去执行,并且希望在本地面板里看到完整的执行过程。它把执行环境和交互环境拆开,远端不需要暴露任何端口。
需要注意的点:
- 插件安装在当前 DSH profile 里以后,是以当前 dsh 进程的权限运行的。安装第三方插件之前,建议先读一遍源码(GitHub 仓库)并确认许可证——本插件声明为 MIT;
- 它依赖 dsh-remote 的
machines.json作为机器来源,如果已经用 dsh-remote 管理机器,不需要重复配置;没有 dsh-remote 时要改用config.machine; - 「远端会话可追加消息」意味着 session 内容会留在远端,注意远端的存储和清理策略。
小结¶
dsh-remote-subagent 做的事情不复杂:把 dsh headless --json 的 SSH 调用封装成一个 remote_agent 工具,配上事件流回读、run 持久化和面板。它的价值在于让「换一个执行环境」这件事不需要新开服务、不需要改协议,代价是只支持 POSIX 远端,且远端行为完全由远端 profile 决定。
插件目录页:https://www.skillhub.cn/plugins/deepseekv41flash/dsh-remote-subagent
仓库:https://github.com/deepseekv41flash/dsh-remote-subagent