dsh-remote-subagent:把本地會話裏的任務派給遠端機器的 DSH 子代理

前言

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

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜