前言¶
給 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、不想動核心代碼的維護者。
使用前注意:
- 插件以當前 dsh 進程的權限運行,安裝前建議檢查倉庫源碼與許可證(MIT)。
tavilyApiKey以明文存儲於~/.dsh/settings.yaml(settings 系統,非憑據保險庫),敏感環境建議通過 profile 的cordis.patch.yml覆蓋。- CDP 實現用 Node 原生
http加手寫 WebSocket 幀(無ws依賴),未啓用 permessage-deflate,與 cloakbrowser 默認配置(關閉壓縮)兼容。 - 版本兼容性跟隨
@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