前言¶
DSH 本身是 HTTP(S) 出口,但智能體在運行時常需要更強的出口策略:切換節點、按域名分流、走固定的 Xray 配置。常規做法是在系統層面配代理環境變量,或者把整個 DSH 的請求單獨接出去。前者影響面大、依賴環境;後者容易漏掉 web_fetch 這類只問代理策略層的調用,導致「模型 API 進了代理、網頁抓取還直連」的分裂。
下面介紹 TwinsEarth 維護的 DSH 插件 @twinsearth/dsh-2xray(倉庫 TwinsEarth/DSH-2Xray)。它定位爲 Host-only bundle,在 DSH 進程內承擔 xray-core 的啓動守護和流量接管,不需要額外構建。
這是什麼¶
插件同時扮演兩個角色:xray-core 客戶端的進程管理者,以及 DSH 進程內 HTTP(S) 流量的路由者。它生成 xray-core 客戶端配置,啓動並守護 xray 子進程;在 xray 本地入站確認可用後,把 DSH 進程的全局 HTTP(S) 出口接到該入站;可選地通過零依賴 gRPC 控制面做多節點切換與流量統計。
維護者:TwinsEarth。包名 @twinsearth/dsh-2xray,當前版本 0.8.0,許可證 MIT,要求 Node >= 24.9.0。0.8.0 適配 DSH 0.2.2-rc.1,DSH 0.2.1 及以前需使用 0.7.0。除控制面外無運行時依賴,是一個 Host-only bundle。
核心功能¶
接入方式上,插件調用 @deepseek-ai/dsh-http-proxy 的 installProxyFromEnvironment(),而不是自己裸裝 setGlobalDispatcher()。原因是 DSH 在第一個插件掛載前就已經安裝了策略 dispatcher,web_fetch 只詢問 proxyRouteFor(),裸裝會破壞出口的一致性。
啓動與接管遵循固定順序:寫配置 → 起進程 → TCP 就緒 → 204 功能探測 → 接管 dispatcher。只有探測通過後纔會接管,避免 dispatcher 指向尚未監聽的端口導致整體 ECONNREFUSED。停止時先摘路由,再 terminate,最後等退出。
端口策略是固定端口 + 佔用即失敗,不做靜默換端口。換端口後 DSH 還指向舊端口,表現爲持續連接失敗,用戶無法判斷原因。
子進程優先使用 ctx.subprocess,它在 Windows 上是帶 KILL_ON_JOB_CLOSE 的 Job Object,可以避免 Electron 關閉後遺留孤兒 xray 佔住端口。若沒有 Job Object,進程被強殺時 cordis dispose 可能不會執行。
多節點場景下,插件爲每個節點生成一個 outbound 和一個 balancer,切換節點只改 RoutingService.OverrideBalancerTarget,進程、入站、dispatcher 都不動。控制面用 node:http2 + 手寫 protobuf 實現,不引入 @grpc/grpc-js,目的是減少每個 profile 的依賴和供應鏈面。
重啓策略只針對意外崩潰:退出碼 23(配置錯)不重啓,端口占用不重啓,上游不可達也不重啓,因爲進程本身是健康的。
安裝與啓用¶
插件是 Host-only bundle,無需構建。安裝命令由插件管理器負責,不提供命令行插件添加形式。
npm i @twinsearth/dsh-2xray
安裝後由插件管理器啓用;或者在 DSH 插件頁選擇「從目錄安裝」,指向本地 Bundle 目錄,例如 E:\GPT\dsh-2xray。
接着需要把 xray 可執行文件放到下面任一位置,解析優先級從高到低:
1. 插件自己的 bin/xray(.exe)(隨 bundle 分發時使用)
2. 配置字段 binary.path
3. 環境變量 DSH_XRAY_BIN
4. <DSH_HOME>\xray-proxy\bin\xray.exe(DSH_HOME 默認 %USERPROFILE%\.dsh)
5. 放進 PATH
第三步是編輯 profile 的 cordis.patch.yml(或 bundle 默認配置),填入 server.* 或 nodes[],把 enabled 改成 true,然後重啓 profile。bundle 自帶配置默認 enabled: false,避免安裝即報錯。需要留意的是,bundle 的 cordis.patch.yml 是整塊配置,profile 層覆蓋時必須重述要保留的字段;註冊行的 name 必須等於包名 @twinsearth/dsh-2xray,否則 patch 會按「name mismatch」跳過。
單節點配置示例:
- id: xray-proxy
name: '@twinsearth/dsh-2xray'
config:
enabled: true
server:
address: example.com
port: 443
uuid: 00000000-0000-0000-0000-000000000000
flow: xtls-rprx-vision
serverName: www.example.com
password: REPLACE_WITH_43_CHAR_BASE64URL_X25519_PUBLIC_KEY
shortId: ''
fingerprint: chrome
spiderX: /
inbound:
protocol: http
host: 127.0.0.1
port: 20808
takeover: auto
多節點配置示例:
- id: xray-proxy
name: '@twinsearth/dsh-2xray'
config:
enabled: true
activeNode: hk-01
nodes:
- id: hk-01
address: hk.example.com
port: 443
uuid: 11111111-2222-4333-8444-555555555555
flow: xtls-rprx-vision
serverName: www.example.com
password: REPLACE_WITH_43_CHAR_BASE64URL_X25519_PUBLIC_KEY
shortId: ''
- id: jp-01
address: jp.example.com
port: 443
uuid: 11111111-2222-4333-8444-555555555555
flow: xtls-rprx-vision
serverName: www.example.com
password: REPLACE_WITH_43_CHAR_BASE64URL_X25519_PUBLIC_KEY
shortId: ''
control:
enabled: true
port: 10085
stats: true
nodes[] 與 server.* 二選一,每個節點需要 id/tag 以及 server.* 各字段。activeNode 指定啓動時釘住的 node id 或 outbound tag。control.enabled 爲 true 時纔會開 gRPC 控制面;control.stats 打開 stats 與 policy.system 流量計數。
典型用法¶
默認單節點場景下,最直接的用法是:按上面的示例填好 server.*,保持 inbound.protocol 爲 http,takeover 用默認的 auto。這樣插件會在探測通過後接管 DSH 進程的全局出口,無需手工設置代理環境變量。
啓用 gRPC 控制面後,可以切換節點:啓動順序爲寫配置 → 起進程 → TCP 就緒 → 204 功能探測 → 接管 dispatcher → OverrideBalancerTarget(activeNode) 釘住出口。之後切換節點只改 balancer override,不動進程和入站。插件還提供三個可選的模型工具:xray_status(與 status.json 相同的狀態快照)、xray_switch_node、xray_stats,均由 ctx.inject(['tools']) 可選註冊;工具註冊失敗不影響代理本身工作,避免代理被工具可用性拖累。
關於入站協議,默認 HTTP;SOCKS 只作爲可選附加,因爲 DSH 代理策略明確拒絕 socks5:// URL,SOCKS 只能走內置 dispatcher,且失去 web_fetch 的覆蓋。SOCKS 適合給非 Node 客戶端使用。
功能探測默認請求 http://www.gstatic.com/generate_204,這是唯一能證明 uuid、flow、SNI、REALITY 全鏈路可用的檢查,默認超時 5000ms。
適用場景與注意¶
適合需要在 DSH 內統一管理 xray 出口、做多節點切換、或希望在進程內看到明確狀態和日誌的開發者。如果已經通過系統代理或環境變量較好地解決了出口問題,沒必要額外引入一層。
需要注意的幾點:
- 插件以當前 DSH 進程權限運行,安裝前應檢查源碼與許可證。許可證是 MIT,倉庫提供
LICENSE文件;Xray 二進制自身另有許可說明(見bin/README.md)。 - 版本必須與 DSH 匹配:0.8.0 適配 DSH 0.2.2-rc.1,DSH 0.2.1 及以前使用 0.7.0。
- 端口策略是固定端口,衝突即失敗,需自行確保
inbound.port未被佔用,且與control.port不衝突。 takeover可選auto/force/off。已有代理策略時先試auto,它會保留現有策略;只有在明確需要覆蓋時才用force。noProxy不支持 CIDR,內網後綴按routing.bypassDomains配置。
插件目錄頁在 SkillHub(社區目錄,與 DeepSeek / 幻方無官方從屬關係),源碼和文檔在 GitHub:
- https://www.skillhub.cn/plugins/TwinsEarth/DSH-2Xray
- https://github.com/TwinsEarth/DSH-2Xray