kkgace/dsh-web-searxng-search

dsh-web-searxng-search

Self-hosted SearXNG web search provider for DeepSeek Harness (dsh). No API key or vendor account.

待分类deepseekharnesssearch-provider

把自建 SearXNG 接入 DeepSeek Harness 的 web 搜索能力。

English | 中文

把 web_search 工具指向你自己运维的 SearXNG 实例。 无需 API Key、无需厂商账号,查询也不归因到任何账号。

为什么需要它

DeepSeek Harness 自带的搜索 provider 依赖 DeepSeek API,每次搜索都会计费并归因到某个 API Key。 本插件在同一个 ctx.web seam 上注册第二个 provider,并把 seam 切到它——搜索因此跑在你可控的 基础设施上,也不需要任何厂商凭证。

特性

  • 直接实现 ctx.web seam 上的 WebSearchProvider,内置的 web_search 工具照常可用。
  • 自身无运行时依赖;官方 @deepseek-ai/* 包声明为 peer dependency,由宿主提供。
  • 可配置超时、语言、安全搜索级别、分类与引擎白名单。
  • 结果按 URL 去重——元搜索引擎常把同一页面返回多次。
  • 区分「实例返回了 HTML」(未开启 JSON 格式)与「确实无结果」,并给出可执行的错误提示。
  • 注册是一个 effect(ctx.effect),插件卸载与 HMR 都会干净回滚。
  • 14 个离线单测,不依赖网络。

环境要求

组件版本 / 说明
DeepSeek Harness@deepseek-ai/dsh-web 0.1.x
Node.js>= 22.19
SearXNG需开启 JSON 格式(见下)

开启 SearXNG 的 JSON API

插件读取 SearXNG 搜索 API。JSON 输出默认关闭; 未开启时实例会返回 200 + 一个 HTML 页面,插件会将其报告为配置错误,而不是"无结果"。

# settings.yml
search:
  formats:
    - html
    - json

安装前先验证接口:

curl -fsS 'http://localhost:8888/search?q=test&format=json' | head -c 120

安装

# 从 npm
dsh plugin --profile web add dsh-web-searxng-search

# 从 GitHub
dsh plugin --profile web add github:kkgace/dsh-web-searxng-search

# 从本地目录
dsh plugin --profile web add /path/to/dsh-web-searxng-search

然后重启 web 应用:

dsh web

收录之后,也可以在 设置 → 插件市场 里一键安装。

配置

bundle 出厂默认指向 http://localhost:8888。用 profile 覆盖层指向你的实例—— 只 patch 已存在的行,不要 insert 新行:

# ~/.dsh/profiles/web/cordis.patch.yml
- id: web-search-searxng
  config:
    baseURL: 'https://searxng.example.com'

也可以在 dsh 运行的环境里设置 SEARXNG_BASE_URL。

选项类型默认值说明
baseURLstringhttp://localhost:8888实例根地址,末尾不要带 /search。
timeoutMsnumber15000单次请求超时,1000–120000 毫秒。
languagestring—传给实例的界面语言,如 zh-CN。
safeSearch0 | 1 | 20关闭 · 适中 · 严格。
categoriesstring—逗号分隔的 SearXNG 分类,如 general,it。
enginesstring—逗号分隔的引擎名,用于收窄搜索范围。
apiKeystring—仅当实例需要认证时的 Bearer Token。

工作原理

  1. Harness 中一切皆 Cordis 插件,能力以 seam 暴露。web 搜索就是 ctx.web seam。
  2. 插件实现 WebSearchProvider 契约——id、available(): boolean(纯本地、不发网络)、 search(req, signal?)——并在 ctx.effect(...) 内通过 ctx.web.registerSearchProvider(...) 注册。
  3. 只注册还不够:cordis.patch.yml 必须把 web.searchProvider 切到 searxng, 否则 seam 会一直停留在内置 provider 上。
  4. 失败以 WebError(message, code, { cause }) 抛出,由宿主路由处理,而不是静默回退到别的 provider。

开发

npm test        # node --test tests/*.test.mjs

测试会 mock 掉 globalThis.fetch,不碰任何网络。官方 @deepseek-ai/* 包是由宿主提供的 peer dependency;若要在 Harness profile 之外跑测试,让它们能从 node_modules 解析即可。

排错

现象原因 / 处理
web_search 仍走别的 providerweb.searchProvider 没指向 searxng,或改完没有重启 dsh web。
启动报 duplicate loader entry id: web-search-searxngprofile 覆盖层 insert 了一行 bundle 已经插入的行。改用 - id: … + config: 的 patch 形式。
报"无结果"但实例确实有数据实例未开启 JSON 格式。
WEB_PROVIDER_CONFIGURED_UNAVAILABLEavailable() 返回 false——baseURL 不是绝对 http(s) 地址。
WEB_PROVIDER_TIMEOUT实例未在 timeoutMs 内响应。

许可证

MIT