前言¶
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 去重,把 title、content、publishedDate 映射成 DSH 的 source 字段;如果 SearXNG 返回了非空的 answers,会拼进搜索结果的 content。maxResults 会在 Provider 和 DSH web 服务两侧都执行。
2、Crawl4AI 抓取。 Provider 只发送最小请求体 { "urls": [url] },不允许模型把浏览器或 crawler 配置注入进去。目标必须是 HTTP(S)。目标站点的非 2xx 状态会作为一次成功的抓取结果返回;Crawl4AI API 本身失败、抓取失败或无法表示的响应,会变成结构化的 WebError。markdown 优先模式默认是 raw,也可以选 fit 或 citations;后两种在对应字段为空时回退到 raw。没有 markdown 但有 cleaned_html 或 html 时,返回 HTML。返回给 DSH 前有字符上限,默认 100000。
3、随包发布的 cordis.patch.yml。 它会做三件事:挂载本插件;把搜索、抓取 Provider 分别固定为 surfing-searxng 和 surfing-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;服务根或/searchsearxng.apiKeyEnv:默认读SEARXNG_API_KEYsearxng.language/categories/safeSearch/timeRange:传给 SearXNG 的查询参数;safeSearch只能是0、1、2,timeRange只能是day、month、yearcrawl4ai.url:环境变量CRAWL4AI_URL;服务根或/crawlcrawl4ai.apiKeyEnv:默认读CRAWL4AI_API_TOKENcrawl4ai.markdownMode:raw、fit或citations,默认rawcrawl4ai.maxContentChars:默认100000
装好并配好后端之后,智能体仍然调用原生的 web_search 和 web_fetch,不需要换工具名,也不需要在对话里写插件专用指令。可以用 dsh --profile web --dump-config 核对 patch 是否已经把 searchProvider / fetchProvider 指到 surfing-searxng 和 surfing-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_search、web_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