前言¶
在 DSH 或同類 Agent 宿主裏跑模型請求,往往還要經過本機代理或上游網關。常見問題是:同一條代理對某個 API 通、對另一個不通,或者整段窗口裏某條路全掛;客戶端只配一個 HTTP_PROXY 時,失敗只能反覆在同一條死路上重試,既拖慢響應,也不利於排查。
DeepSeek Harness(DSH)社區把能力拆成插件維護。dsh-dual-proxy(維護者 gambn,分類:聯網工具)把「Agent 到模型端點的網絡路徑」當成可管理資源:在多個候選網關、環境變量裏的代理與直連之間自動選路,運行中用真實請求做通道驗證,失敗立刻切到下一條,無需重啓宿主、也無需改客戶端裏的固定代理地址。
下面介紹它的定位、行爲要點,以及作爲 DSH 插件時的安裝與配置。
這是什麼¶
dsh-dual-proxy 的英文簡介是:Agent gateway manager for DSH — online multi-gateway failover and channel health checks。同一套核心提供兩種形態:
- DSH 插件(推薦):隨 DSH 啓停,在「設置 → 插件」裏改配置,可通過
routeHostFetch把宿主進程內的fetch引到本代理; - 獨立進程:全局安裝 CLI,或掛 systemd 用戶服務,非 DSH 的 Agent 與腳本也能用。
npm 包版本爲 0.7.1,許可證 MIT。倉庫:https://github.com/gambn/dsh-dual-proxy;社區目錄頁:https://www.skillhub.cn/plugins/gambn/dsh-dual-proxy(獨立站點,與 DeepSeek / 幻方無官方從屬關係)。
核心功能¶
候選路與選路順序¶
客戶端連到本地監聽(默認 127.0.0.1:7898),由插件在候選之間切換。候選包括:upstreamHost:upstreamPort(或 upstreamUrl)、配置裏的 gateways、啓動環境中的 HTTP(S)_PROXY / ALL_PROXY(去重並排除自身監聽端口),最後補 直連。示意如下:
客戶端 → 127.0.0.1:7898
├── 網關 A(TLS 探測通過)→ 上游代理
├── 網關 B(TLS 探測通過)→ 上游代理
└── 都探測失敗 → 直連
健康檢查與失敗處理¶
- 按
healthIntervalMs對healthUrl發GET,響應碼<500視爲通道可用(401/403 也算端點活着);通過者設爲全局首選,全部失敗則清首選、下次請求重新掃描;healthIntervalMs設爲0可關閉後臺驗證。 - 每 host 偏好緩存(默認 TTL 60 秒,最多 1000 條 LRU):命中可跳過探測,失敗即切換。
- 失敗網關默認冷卻 30 秒,期間排到隊尾;任一路剛失敗會觸發一次健康檢查(1 秒內防抖),不必等下一個週期。
HTTPS CONNECT 與普通 HTTP¶
- CONNECT(443):對候選先做 TLS 握手探測,通過的纔開隧道;隧道建立後只轉發字節,隧道內失敗無法換路。
- 普通 HTTP:請求體先緩衝(上限 8 MB),按順序換路重放;建連用
attemptTimeoutMs,等響應頭用responseTimeoutMs。
重放與安全相關默認¶
自 0.6.0 起,POST / PATCH 在連接建立後失敗默認不再自動換路重放,返回 502;需要舊行爲可打開 retryNonIdempotentAfterSend。可選 retryNonIdempotentWithIdempotencyKey:僅當請求帶非空 Idempotency-Key / X-Idempotency-Key 時,允許發送後重放非冪等請求。
上游代理 URL 可帶 user:pass,連接時發送 Proxy-Authorization: Basic;0.7.0 僅支持 http:// 上游代理,upstreamUrl 傳 https:// 會報錯。日誌只寫主機、網關與原因,不記錄請求內容。
接入 DSH 宿主¶
打開 routeHostFetch 後,進程內所有 fetch(不限於模型調用)會先到本代理再選路;pnpm、git 等子進程不繼承,仍走啓動環境代理。插件禁用或卸載時會還原原來的 undici dispatcher。
安裝與啓用¶
運行要求 Node.js ≥ 22.19.0(undici 8);插件形態還需要 dsh ≥ 0.1.7。
先做插件安裝:
dsh plugin --profile web add dsh-dual-proxy
也可僅安裝獨立 CLI:
npm install -g dsh-dual-proxy
安裝後確認 ~/.dsh/profiles/web/package.json 的 dsh.profile.bundles 含 dsh-dual-proxy(包內 cordis.patch.yml 會參與組合),再重啓 dsh web。若曾跑過獨立進程或 systemd 用戶服務,先釋放默認端口 7898:
systemctl --user disable --now dsh-dual-proxy 2>/dev/null
插件以當前 DSH 進程權限運行;安裝前建議自行查看倉庫源碼與 MIT 許可證。
典型配置(DSH 插件)¶
啓用後在「設置 → 插件」中可改下列字段(節選,默認值以 README 爲準):
| 字段 | 默認 | 說明 |
|---|---|---|
listenHost |
127.0.0.1 |
監聽地址 |
listenPort |
7898 |
監聽端口 |
upstreamHost / upstreamPort |
127.0.0.1 / 7897 |
第一個候選網關 |
upstreamUrl |
空 | 非空時覆蓋 host/port,可含認證 |
gateways |
空 | 額外候選,host:port 逗號分隔 |
routeHostFetch |
false |
bundle patch 裏默認可能爲打開 |
healthUrl |
https://api.deepseek.com |
通道驗證;空則關閉後臺驗證 |
healthIntervalMs |
60000 |
健康檢查間隔;0 關閉 |
fastFailTimeoutMs |
2000 |
緩存/首選路徑的建連超時 |
cooldownMs |
30000 |
失敗網關冷卻 |
attemptTimeoutMs |
5000 |
每次嘗試/探測超時 |
responseTimeoutMs |
60000 |
普通 HTTP 等響應頭上限 |
verifyTls |
true |
443 是否 TLS 探測 |
獨立進程與 Claude Code 啓動器¶
不掛 DSH 時,可直接跑 CLI,例如:
node bin/dsh-dual-proxy.js --listen-port 7898 --upstream-port 7897 \
--gateway 127.0.0.1:12334 --health-url https://api.deepseek.com
Claude Code 爲原生二進制,不能像 DSH 那樣改進程內 fetch;可用包內 claude-dual-proxy 在啓動器裏起代理,再給子進程設 HTTP_PROXY / HTTPS_PROXY:
claude-dual-proxy --listen-port 7896 --gateway 127.0.0.1:12334 -- --resume
systemd 用戶服務模板在倉庫 contrib/。
適用場景與注意¶
適合:本機有多條代理或網關、模型/API 請求需要在線 failover 與通道探測的 DSH web 配置;或非 DSH 腳本希望統一走一個本地入口選路。
邊界(README 已說明):只處理 HTTP/1.1 的 CONNECT 與普通 HTTP;不做透明代理、不接管 UDP;不校驗證書、不做鑑權;默認只綁回環,把 listenHost 改成非迴環會在啓動時告警。全部候選失敗返回 502。
結尾¶
dsh-dual-proxy 把多網關、環境代理與直連握在同一本地入口,用健康檢查與失敗切換減少「單點代理拖死整批請求」的情況,並可選把 DSH 宿主內的 fetch 接入選路邏輯。