前言¶
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)。
这是什么¶
- 名称:dsh-websearch-keyless(npm 包名同目录)
- 分类:联网工具(SkillHub 社区目录:lovehin/dsh-websearch-keyless)
- 源码:GitHub - lovehin/dsh-websearch-keyless
- 许可证:MIT;当前 package 版本 0.1.0;要求 Node >= 20.3.0
插件以 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)¶
-
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。 -
空的
cordis.patch.yml可能是字面量[]。 直接 append 会变成第二份 YAML 文档,解析失败。需先删掉[]再追加块。 -
不要给插件加
@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 为准。