dsh-web-fetch:CDP 渲染 + Tavily 提取,雙源網頁抓取插件

前言

給 DSH 智能體補網頁抓取能力時,常遇到兩個問題。一是頁面類型不同:SPA 和 JS 重度頁面必須經過真實瀏覽器渲染才能拿到內容,而普通文章頁用提取 API 更快,往往要維護兩套方案。二是 DSH 的 ctx.web.registerSearchProvider 在同一能力上註冊多個提供者時會拋 WEB_PROVIDER_AMBIGUOUS,模型沒有選擇權。

dsh-web-fetch(作者 runfali,MIT 許可,分類:聯網工具)同時處理這兩個問題:把 CDP 瀏覽器渲染和 Tavily Extract 封裝成兩個獨立的 LLM 工具,由模型按上下文自主選擇。下面介紹它的設計、安裝和使用。

它是什麼

一句話定位:DeepSeek Harness 的雙源網頁內容抓取插件。每個數據源註冊爲一個獨立的 DSH 工具,各自帶 description 和 schema,LLM 根據上下文挑選,而不是依賴寫死的規則。

兩個工具的分工:

工具 適用場景 做法
web_fetch_cdp JS 重度頁面、SPA、需要真實渲染的站點 經 CDP 連接遠程 Chrome / cloakbrowser,返回渲染後內容
web_fetch_tavily 快速提取、無需瀏覽器 調用 Tavily Extract API

核心特性

雙源獨立註冊,規避多提供者限制

每個數據源是獨立的 DSH 工具,模型可以自主選擇。兩個工具可獨立啓用/禁用,禁用的工具對 LLM 完全隱藏。

零侵入、零額外依賴

這是一個 Cordis bundle 插件,不需要修改 DSH 核心,全部通過 ctx.tools.register 和 settings.installSection 實現(要求 dsh ≥ 0.1.2-alpha)。依賴只有三個包:@deepseek-ai/dsh-settings、@deepseek-ai/dsh-tools、@deepseek-ai/schemastery。

配置熱重載

設置界面是 UI 卡片加 ~/.dsh/settings.yaml 熱重載,改配置不用重啓。lib/client.js 內置中英文(zh/en)界面,React 實現。

併發安全與策略可插拔

工具聲明 isConcurrencySafe: true,支持 AbortSignal。新增數據源只需實現 FetchStrategy 契約(1 個文件),再在 src/index.js 註冊 1 行。

安裝與啓用

運行要求:Node.js >= 22,DSH >= 0.1.0-rc.7。先在插件目錄執行 pnpm install,再註冊插件,最後重啓 DSH:

cd /data/dsh-workspace/dsh-web-fetch
pnpm install

dsh plugin --profile web add /data/dsh-workspace/dsh-web-fetch
# 發佈後也可用:
# dsh plugin --profile web add dsh-web-fetch

# systemd 環境:
sudo systemctl restart dsh

pnpm install 這一步不能省:Cordis 加載器只從插件目錄解析依賴,跳過它會報 ERR_MODULE_NOT_FOUND: @deepseek-ai/schemastery。

配置

打開 Settings → Plugin Config → 通用 Web 內容獲取(web-fetch),頂部是 CDP / Tavily 的啓用複選框,下面是兩組配置項:

  • CDP 組:CDP Endpoint(默認 http://10.200.0.5:9222)、Timeout ms(60000)、Extra wait after load ms(2000)
  • Tavily 組:Endpoint(https://api.tavily.com/extract)、API Key(留空即禁用)、Timeout ms(30000)

保存後寫入 ~/.dsh/settings.yaml 的 web-fetch: 下並熱重載。也可以用 profile 覆蓋,編輯 ~/.dsh/profiles/web/cordis.patch.yml:

- id: web-fetch
  config:
    cdpEnabled: true
    cdpEndpoint: 'http://10.200.0.5:9222'
    cdpTimeoutMs: 60000
    cdpWaitMs: 2000
    tavilyEnabled: false
    tavilyEndpoint: 'https://api.tavily.com/extract'
    tavilyApiKey: ''
    tavilyTimeoutMs: 30000

注意:覆蓋 config 會替換整個配置塊,必須包含全部鍵。

典型用法

重啓後 LLM 會自動看到這兩個工具,不需要額外指令。手動測試:

User: 用 web_fetch_tavily 提取 https://example.com 的正文
User: 用 web_fetch_cdp 抓取 https://example.com 這個需要渲染的頁面

工具輸出結構如下:

{
  "sources": [{ "url": "...", "title": "...", "snippet": "...", "content": "...", "provider": "cdp|tavily" }],
  "truncated": false
}

新增數據源

在 src/strategies/my.js 實現 FetchStrategy 契約:

export function makeMyStrategy(config) {
  return {
    id: "my",
    title: "My Fetcher",
    available() { return Boolean(config.apiKey) }, // 輕量檢查,不做 I/O
    async fetch(req, signal) {
      return { sources: [{ url, title, snippet, content, provider: "my" }], truncated: false }
    },
  }
}

再在 src/index.js 註冊一行:

import { makeMyStrategy } from "./strategies/my.js"
ctx.tools.register(makeToolDef("my", makeMyStrategy, "myEnabled", current))

如需新配置項,可選地在 lib/client.js 的 Config 和 FIELD_VIEWS 中補充字段。路由和核心邏輯不用改。

測試

倉庫自帶離線單測,不調用真實瀏覽器或 Tavily:

node tests/test-cdp-unit.mjs   # 21 個測試
node tests/test-tavily-unit.mjs # 9 個測試

適用場景與注意事項

適合兩類人:需要同時覆蓋渲染型頁面和輕量提取的 DSH 智能體開發者;想以插件方式擴展 DSH、不想動核心代碼的維護者。

使用前注意:

  1. 插件以當前 dsh 進程的權限運行,安裝前建議檢查倉庫源碼與許可證(MIT)。
  2. tavilyApiKey 以明文存儲於 ~/.dsh/settings.yaml(settings 系統,非憑據保險庫),敏感環境建議通過 profile 的 cordis.patch.yml 覆蓋。
  3. CDP 實現用 Node 原生 http 加手寫 WebSocket 幀(無 ws 依賴),未啓用 permessage-deflate,與 cloakbrowser 默認配置(關閉壓縮)兼容。
  4. 版本兼容性跟隨 @deepseek-ai/dsh-settings / dsh-tools / schemastery。

經過上面的步驟,DSH 就多了一組可插拔的雙源抓取工具:模型自主選擇渲染或提取,擴展新源只需一個文件加一行註冊。倉庫與目錄頁:

  • GitHub:https://github.com/runfali/dsh-web-fetch
  • 社區插件目錄收錄頁:https://www.skillhub.cn/plugins/runfali/dsh-web-fetch
羽毛球分组比赛记分
小程序二维码

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

小夜