dsh-websearch-keyless:讓 DSH 原生 web_search 無需 API Key

前言

DeepSeek Harness(DSH)裏,智能體通過 web_search 做聯網檢索。若 profile 沒有可用的搜索 provider,會回退到 @deepseek-ai/dsh-web-search-deepseek,經 DeepSeek 對話 API 完成搜索。DeepSeek API Key 缺失或無效時,每次搜索都會失敗,例如:

DeepSeek API error (HTTP 401): Authentication Fails, your api key: ****d09c is invalid

社區裏也有直接讀 DuckDuckGo HTML、Bing 等公開端點的無 Key 插件,往往只能拿到較薄的摘要、缺少第一方元數據。下面介紹維護者 lovehin 的 dsh-websearch-keyless:對齊 OpenCode WebSearch 服務裏三種可無 Key 調用的後端,註冊爲 ctx.web 的搜索 provider,無需註冊、無需配置即可接管 web_search(web_fetch 仍走內置 HTTP provider)。

這是什麼

插件以 bundle 形式發佈,自帶 cordis.patch.yml,安裝後自動把 web 服務的 searchProvider 指到 opencode-keyless。

核心功能

三路後端與降級

按優先級依次嘗試,某一端失敗、超時或無結果時落到下一個:

順序 後端 端點 無 Key 信號
1 Tavily POST https://api.tavily.com/search X-Tavily-Access-Mode: keyless
2 TinyFish POST https://agent.tinyfish.ai/mcp X-TinyFish-Access-Mode: keyless
3 Exa POST https://mcp.exa.ai/mcp 無 key 參數

實現集中在 lib/providers.js(純 CJS、零依賴)與 lib/index.js(Cordis 插件,向 ctx.web 註冊 WebSearchProvider)。available() 恆爲 true;全部後端均失敗時映射爲 seam 錯誤碼 WEB_PROVIDER_ERROR。

與同類無 Key 插件的差異(README 自述)

  • 調用與 OpenCode 相同的第一方搜索 API 的 keyless 模式,標題與正文片段更完整,而非 scraped 結果頁 markup。
  • 三個獨立 provider,單點限流不會拖垮整條搜索鏈。
  • 兩個源文件、零依賴、無構建步驟、不聲明 DSH peer dependencies。

兼容性說明

README 寫明在 DSH 0.2.1-rc.3 上做過測試;manifest deliberately 不聲明 @deepseek-ai/* peer 與 engines.dsh,避免版本範圍不匹配導致啓動時被跳過。

安裝與啓用

將 <profile> 換成你實際啓動的 profile:desktop 對應桌面應用,web 對應 dsh web。

npx -y @deepseek-ai/dsh plugin --profile <profile> add github:lovehin/dsh-websearch-keyless

插件管理器會同時寫入 dependencies 與 dsh.profile.bundles;作爲 bundle,其 cordis.patch.yml 會自動生效,不必手改 profile 的 patch 層。重啓 DSH 或 reload profile 後 web_search 即可使用。

確認配置是否生效:

npx -y @deepseek-ai/dsh --profile <profile> --dump-config | grep -A3 "^- id: web"

期望看到類似:

- id: web
  name: '@deepseek-ai/dsh-web'
  config:
    searchProvider: opencode-keyless
    fetchProvider: http

手動安裝(CLI 被應用託管拒絕時)

若 profile 由 Electron 獨佔管理(例如提示 profile "desktop" is managed exclusively by the Electron application),需將插件放到 ~/.dsh/local-plugins/dsh-websearch-keyless、在 profile 的 node_modules 做 symlink,並在 package.json 的 dependencies 與 cordis.patch.yml 中手工寫入 bundle 條目;patch 中必須同時設置 searchProvider: opencode-keyless 與 fetchProvider: http(見下文 Gotchas)。逐步命令見 GitHub README 的 Manual install 小節。

典型用法與驗證

DSH 側無需額外配置項:安裝 bundle 並 reload 後,Harness 內對 web_search 的調用會走 opencode-keyless provider。

倉庫自帶無依賴測試(在插件源碼根目錄執行):

npm test              # 離線:解析、降級與插件契約(14 個測試)
npm run test:live     # live:探測三個真實端點

npm test 不需要網絡,CI 在 Node 20、22、24 上運行。test:live 會訪問第三方共享端點,適合作爲人工冒煙而非 CI 門禁。

適用場景與注意

適合誰:希望在 DSH 裏用原生 web_search,但不想維護 Tavily / Exa 等 API Key,且能接受 keyless 共享配額、偶發零結果或限流的用戶。

運行權限:插件以當前 DSH 進程權限出站訪問上述 HTTPS 端點;安裝前請自行審閱 源碼 與 MIT 許可證。

三個常見坑(Gotchas)

  1. fetchProvider 必須寫全。 對 id: web 的 patch 替換整個 config 對象,不會 deep-merge。只改 searchProvider 會丟掉默認的 fetchProvider: http,web_fetch 可能報:multiple usable web providers are registered (deepseek-fetch-api, http); configure one explicitly。

  2. 空的 cordis.patch.yml 可能是字面量 []。 直接 append 會變成第二份 YAML 文檔,解析失敗。需先刪掉 [] 再追加塊。

  3. 不要給插件加 @deepseek-ai/* peer。 範圍不覆蓋當前 DSH 版本時,啓動會 skip bundle 並提示 incompatible。

故障對照(節選)

現象 可能原因
WEB_PROVIDER_CONFIGURED_MISSING 配置了 searchProvider: opencode-keyless 但插件未加載 — 檢查 dependencies、bundles 與 node_modules 解析
all keyless search backends failed 三路均失敗 — 無外網、代理或共享配額;可試 npm run test:live
搜索無結果 keyless 配額共享,生僻 query 可能 legitimately 爲零 — 可改寫 query

卸載:

npx -y @deepseek-ai/dsh plugin --profile <profile> remove dsh-websearch-keyless

結尾

dsh-websearch-keyless 把 OpenCode 同款的 Tavily、TinyFish、Exa keyless 鏈路搬進 DSH,用 bundle 一鍵切換 searchProvider,在零 Key、零構建的前提下恢復 web_search。社區索引見 SkillHub 插件頁,實現與安裝細節以 GitHub 倉庫 README 爲準。

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

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

小夜