使用 surfing-plugin 为 DeepSeek Harness 接入自托管搜索与抓取

前言

DeepSeek Harness(dsh)是 DeepSeek AI 开源的智能体框架,官方仓库把它的架构概括成一句话:一切皆插件。网页访问也不例外。官方文档把这项能力放在 ctx.web 这条可选缝上:一边是 web_search,一边是 web_fetch。模型仍然只提交查询词或 URL,真正去哪儿搜、去哪儿抓,由注册进去的 Provider 决定。

随 Harness 一起提供的搜索后端,是 DeepSeek、Exa、Perplexity 这类需要云端 API 密钥的实现;抓取则另有 HTTP Provider。本地已经跑着 SearXNG、又用 Crawl4AI 做页面抽取的人,往往不想再为智能体单独买一路搜索接口。surfing-plugin 做的就是这件事:把原生工具接到自托管服务上,工具名称、参数、超时、取消和结果截断都还是 DSH 原来的那一套。

需要先说明来源。本文依据的是社区插件目录页与维护者仓库,不是 DeepSeek / 幻方的官方应用商店。目录站点独立运营,和官方仓库没有从属关系。写作时仓库规范名为 cyijun/dsh-surfing-plugin(GitHub 显示 12 星),旧地址 cyijun/surfing-plugin 会重定向过去;目录页安装命令仍写作 github:cyijun/surfing-plugin,下文以目录页原文为准。

这是什么

surfing-plugin 是由 cyijun 维护的 DeepSeek Harness 插件,npm 包名为 dsh-surfing-plugin,当前 package.json 版本为 0.1.0,许可证为 MIT,主要语言是 TypeScript。社区目录把它归在「界面增强」分类下,简介是「SearXNG 搜索与 Crawl4AI 抓取提供方」。从源码看,它并不新增侧边栏或皮肤,而是向 ctx.web 注册两个 Provider:

  • 搜索:surfing-searxng,请求 SearXNG 的 /search
  • 抓取:surfing-crawl4ai,请求 Crawl4AI 的 /crawl

插件依赖 @deepseek-ai/dsh-web,并声明 inject = ['web']。也就是说,它挂在 DSH 已有的网页访问服务上,不另起一套工具名。官方 Web Access 文档也写明:换搜索后端不会改变模型提问查询的方式,换抓取后端不会改变模型提交 URL 的方式。

它要解决的问题很具体:在已经能访问 SearXNG 与 Crawl4AI 的前提下,让 web_search / web_fetch 走这两套自托管服务,而不是默认的云端搜索 Provider。

核心功能

仓库 README 和源码对行为写得很明确,可以分成四块。

1、SearXNG 搜索。 Provider 向 /search 发送表单编码的 POST,并固定 format=json。只保留绝对 HTTP(S) 结果 URL,按 URL 去重,把 titlecontentpublishedDate 映射成 DSH 的 source 字段;如果 SearXNG 返回了非空的 answers,会拼进搜索结果的 contentmaxResults 会在 Provider 和 DSH web 服务两侧都执行。

2、Crawl4AI 抓取。 Provider 只发送最小请求体 { "urls": [url] },不允许模型把浏览器或 crawler 配置注入进去。目标必须是 HTTP(S)。目标站点的非 2xx 状态会作为一次成功的抓取结果返回;Crawl4AI API 本身失败、抓取失败或无法表示的响应,会变成结构化的 WebError。markdown 优先模式默认是 raw,也可以选 fitcitations;后两种在对应字段为空时回退到 raw。没有 markdown 但有 cleaned_htmlhtml 时,返回 HTML。返回给 DSH 前有字符上限,默认 100000

3、随包发布的 cordis.patch.yml 它会做三件事:挂载本插件;把搜索、抓取 Provider 分别固定为 surfing-searxngsurfing-crawl4ai;再插入一个只注册原生 web_fetch@deepseek-ai/dsh-tool-web 行。README 解释了为什么要拆这一行:headless 继续用宿主层的 web_search,Web UI 继续用各 Agent Preset 里的 web_search,避免重复注册。已有的 DeepSeek 搜索 Provider 可以继续挂着,但不会被选中。

4、配置覆盖环境变量。 服务地址既可以写服务根路径,也可以写成完整的 /search/crawl。没有密钥时不发认证头,适合本机无认证部署;有密钥时优先用 apiKeyEnv,字面量 apiKey 会覆盖环境变量。

安装与启用

目录页给出的安装命令是:

dsh plugin add github:cyijun/surfing-plugin

插件以当前 dsh 进程的权限运行,安装时可能执行代码。安装前应检查源代码仓库和许可证。目录页也写了:如需可复现安装,请固定 commit 哈希。

维护者 README 建议装进 web profile,并把 commit 写死。对应写法如下(把 COMMIT_SHA 换成实际哈希):

dsh plugin --profile web add github:cyijun/surfing-plugin#COMMIT_SHA

从 Git 安装会走包里的 prepare 脚本做构建。pnpm 10 及以上默认拦截 Git 依赖的构建脚本。第一次安装被拦住时,把提示里的确切包键写进该 profile 的 pnpm-workspace.yaml,再重试:

allowBuilds:
  dsh-surfing-plugin: true

环境要求以仓库 README 和 package.json 为准:

  • Node.js ^22.19.0>=24.0.0
  • DeepSeek Harness >=0.1.0-rc.6 <0.2.0
  • 本机或内网能访问的 SearXNG、Crawl4AI
  • SearXNG 必须在 search.formats 中启用 json;否则请求 format=json 会被拒绝。SearXNG 文档同样指出,很多公开实例默认关掉了 JSON 输出

README 另外写了本地 checkout 安装:

dsh plugin --profile web add .
dsh --profile web --dump-config
dsh --profile web

卸载命令是 dsh plugin --profile web remove dsh-surfing-plugin

关于 npm:README 写的是「发布到 npm 后」再用 dsh plugin --profile web add dsh-surfing-plugin,并提到首次发布前要确认包名仍可注册。本文写作时未能从 npm 注册表确认该包已经上架,因此当前安装路径以 GitHub 命令为准,不要把 npm 包名当成已经可用的安装入口。

配置与用法

先准备两个后端地址。值可以是服务根,也可以是完整端点:

export SEARXNG_URL=http://127.0.0.1:8080
export CRAWL4AI_URL=http://127.0.0.1:11235

# Crawl4AI 当前版本默认启用 Bearer token;无认证部署可以省略。
export CRAWL4AI_API_TOKEN=replace-with-your-token

需要覆盖默认值时,在 $DSH_HOME/profiles/web/cordis.patch.yml 里改本插件那一行。显式配置优先于环境变量。仓库给出的示例如下(中文 README 把语言写成了 zh-CN):

- id: surfing-plugin
  config:
    searxng:
      url: https://search.example.com
      apiKeyEnv: MY_SEARXNG_KEY
      authHeader: X-API-Key
      authScheme: ''
      language: zh-CN
      categories: general,news
      safeSearch: 1
      timeRange: month
    crawl4ai:
      url: https://crawl.example.com
      apiKeyEnv: CRAWL4AI_API_TOKEN
      authHeader: Authorization
      authScheme: Bearer
      markdownMode: raw
      maxContentChars: 100000

常用字段对应关系如下:

  • searxng.url:环境变量 SEARXNG_URL;服务根或 /search
  • searxng.apiKeyEnv:默认读 SEARXNG_API_KEY
  • searxng.language / categories / safeSearch / timeRange:传给 SearXNG 的查询参数;safeSearch 只能是 012timeRange 只能是 daymonthyear
  • crawl4ai.url:环境变量 CRAWL4AI_URL;服务根或 /crawl
  • crawl4ai.apiKeyEnv:默认读 CRAWL4AI_API_TOKEN
  • crawl4ai.markdownModerawfitcitations,默认 raw
  • crawl4ai.maxContentChars:默认 100000

装好并配好后端之后,智能体仍然调用原生的 web_searchweb_fetch,不需要换工具名,也不需要在对话里写插件专用指令。可以用 dsh --profile web --dump-config 核对 patch 是否已经把 searchProvider / fetchProvider 指到 surfing-searxngsurfing-crawl4ai

适用场景与注意事项

比较适合这几类用法:已经自建 SearXNG 和 Crawl4AI,希望 DSH 的网页工具走同一套后端;希望搜索与抓取留在自己控制的网络里,而不是默认的云端搜索 Provider;同时使用 headless 与 Web UI,需要 README 里那种拆开的 web_fetch Consumer,以免重复注册 web_search

使用前有几条边界需要看清楚。

第一,这不是「装上就能搜」的插件。两个后端服务要先能访问;SearXNG 还要打开 JSON 格式。公开 SearXNG 实例经常关掉 JSON,不适合直接拿来当 API。

第二,它不是通用爬虫控制器。Crawl4AI 请求体被故意写死成单个 URL,模型不能指定浏览器参数、抽取策略或并发。抓取策略、浏览器隔离、目标网段和 SSRF 策略都在 Crawl4AI 一侧,公开部署前要按 Crawl4AI 自己的安全说明限制网络和认证。

第三,认证与传输。仓库建议优先用 apiKeyEnv,不要把密钥写进 Git;对非本机服务用 HTTPS;Provider 请求禁止重定向,避免认证头被转到另一个后端。没有密钥时不发认证头。

第四,版本窗口比较窄。当前声明的 DSH 范围是 >=0.1.0-rc.6 <0.2.0。官方仓库仍处于开发者预览,README 写明会有破坏兼容性的变更,升级 Harness 后应再核对本插件是否仍匹配。

第五,也是目录页的安全提示:插件以当前 dsh 进程的权限运行,安装时可能执行代码。Git 安装还会走 prepare 构建。安装前应阅读源码和 MIT 许可证,并尽量固定 commit,避免后续推送静默改变实际执行的代码。

小结

surfing-plugin 把 DSH 原生的 web_searchweb_fetch 接到自托管的 SearXNG 与 Crawl4AI 上,工具协议仍由 Harness 自己的 web 缝负责。目录把它放在「界面增强」里,实际能力是 Provider 替换。安装命令以目录页为准,配置以后端地址和密钥环境变量为主。

目录页:https://deepseek-harness-plugin.com/zh-CN/plugins/surfing-plugin/

GitHub(目录收录地址,会转到现规范名):https://github.com/cyijun/surfing-plugin

GitHub 现规范仓库:https://github.com/cyijun/dsh-surfing-plugin

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

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

小夜