DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

s11phere /

s11phere/dsh-web-search-keyless

Verified

DSH 插件:给 ctx.web 换上一个不需要密钥、也不消耗模型回合的搜索 provider

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@8ee754f6

dsh-web-search-keyless

DSH 宿主插件:给 ctx.web 换上一个不需要密钥、也不消耗模型回合的搜索 provider。 Bing RSS 为主,DuckDuckGo Lite 为备,命中失败自动顺延。

为什么

DSH 自带的 dsh-web-search-deepseek 走的是 "Anthropic Messages + 原生 web_search 服务端工具":DeepSeek 没有独立检索端点,所以每搜一次就是一次完整的模型回合,按 token 计费,而且每个 query 文本不同、前缀从第一个差异处断开,缓存几乎必然不命中。 实测一次会话里 93 个 query 就是 93 次官方 API 请求、93 次未命中缓存的输入。

真实检索本来不需要模型参与。本插件把这一层换成两个普通 HTTP GET,成本为零:

引擎 端点 输出
bing https://www.bing.com/search?q=…&format=rss RSS,<item> 里的 title / link / description / pubDate
ddg https://lite.duckduckgo.com/lite/?q=… 表格 HTML,a.result-link + td.result-snippet + span.timestamp

DDG 的 href 是 //duckduckgo.com/l/?uddg=<encoded> 形式的跳转壳,unwrapDdgHref 会解出真实地址。

安装

dsh plugin --profile web add github:s11phere/dsh-web-search-keyless

装完重启 dsh web(新增 bundle 不进热更新),刷新页面。卸载把 add 换成 remove, 同样要重启。

别用 scp 风格的 git@github.com:... —— pnpm 会把它误解析成「包名 git + 版本」, 装出一个叫 git 的空依赖,插件不会生效。用上面的 github:<owner>/<repo> 写法。

也可以 dsh plugin --profile web add <本地目录>,但本包不依赖任何 @deepseek-ai/* 裸导入(见下),所以跨盘、跨 profile 都不会出链接问题。

为什么没有任何 @deepseek-ai/* 导入

以 link: / github: 装进 profile 时,Node 按插件的真实路径解析裸导入, @deepseek-ai/* 不在本包的祖先目录链上,因此 import { WebError } from '@deepseek-ai/dsh-web' 会直接 ERR_MODULE_NOT_FOUND(同 dsh-paper-reader 对 defineTool 的处理)。本包因此只依赖 node: 与自己的 ./backends.js: lib/host.js 里带一个形状对齐 seam 契约的本地 WebError(message + code + cause)。 唯一代价是宿主 dsh-tools 只对 instanceof HarnessError 的错误暴露结构化错误码, 所以本 provider 的失败以文本形式到达模型 —— 消息里逐条列出了每个引擎的失败原因。

生效方式

cordis.patch.yml 随包发布,包含两条:注册 loader 入口,以及把 web.searchProvider 指到 keyless。放在包里是为了让安装保持原子——profile 开了 patchReload: live,若把 provider 选择单独写进 profile 配置,保存瞬间宿主就会去解析 一个尚未注册的 provider,重启前 web_search 会一直报 WEB_PROVIDER_CONFIGURED_MISSING。

profile 自己的 cordis.patch.yml 在 bundle 之后应用,随时可以覆盖回去:

- id: web
  name: '@deepseek-ai/dsh-web'
  config:
    searchProvider: deepseek-official   # 换回 DeepSeek 官方搜索

配置

字段 默认 含义
id keyless 注册到 seam 的 provider id,供 web.searchProvider 引用
engines ['bing','ddg'] 引擎尝试顺序;前一个抛错、返回零条或结果全部无关才换下一个
timeoutMs 15000 单个引擎的超时
userAgent 桌面 Chrome UA Bing/DDG 对空 UA 会返回空结果集,别清空
relevanceGuard true 丢掉与 query 无关的结果;关掉就退回"静默转发降级结果",只建议排查解析问题时临时用
fallbackProvider deepseek-official 免费引擎全部失败后改用的已注册 provider;空字符串关闭回退
minIntervalMs 800 同一引擎两次请求的最小间隔(并行 query 会排队)
cooldownMs 300000 引擎遇到 403/429/传输失败后的冷却时长
debug false 打印命中的引擎、丢弃条数与冷却/回退事件
- id: dsh-web-search-keyless
  name: 'dsh-web-search-keyless'
  config:
    engines: ['bing']
    timeoutMs: 10000
    minIntervalMs: 1500
    debug: true

request.maxResults 会作为 count 传给 Bing;截断本身由 seam 负责,provider 一律 返回 truncated: false。全部引擎失败才抛 WebError('WEB_PROVIDER_ERROR'),错误文本里 带每个引擎的失败原因(超时 / HTTP 状态 / 零结果 / 未知引擎 / 结果无关 / 冷却中)。

免费优先、失败才付费的回退

免费引擎全部失败(连接失败 / 403 / 零结果 / 结果全被判为无关 / 冷却中)之后, provider 会调用 fallbackProvider 指定的另一个已注册 provider —— 默认就是 DSH 自带的 deepseek-official。所以正常的常见查询依然零成本,只有冷门调研才会花钱,而且花的那次 会照常写 web/deepseek-search-llm-request 审计事件。

三个设计决定:

  • 复用注册表,不抄实现。回退是直接调用 ctx.web 里已注册的那个 provider,而不是 把"Anthropic Messages + 原生 web_search"再实现一遍:密钥解析、错误语义、审计事件 都只有一份,不会漂移。代价是 searchProviders 在 dsh-web 的类型里是 private (运行时是个普通 Map),因此代码里一律按"拿不到就不回退"处理 —— DSH 改了内部结构, 本插件只是退回纯免费行为,不会抛错。
  • 回退结果不过相关度闸门。付费路径的服务器端检索本身做了相关度,而且它实测不带 snippet,用为免费引擎设计的规则去判它只会误杀。
  • 失败仍然是一次失败。连回退也失败时,抛出的错误里同时列出免费引擎和回退的失败 原因,不会静默降级成空结果。

代价是延迟:最坏情况是 Bing 超时 + DDG 超时之后才轮到付费搜索。工具侧 tool-web.searchTimeoutMs 默认 60s,通常够用;要提高回退命中率可以调小 timeoutMs(引擎失败得越快,越早进入付费路径)。

效果与付费路径的差异(实测)

这不是付费搜索的等价替代。 差异分三层,都有实测支撑:

  1. 元数据反而更全。付费路径(DeepSeek 原生搜索)经本仓库实测的 200 条结果里 0 条带摘要、0 条带日期(web_search_result 的 snippet 来自引用片段 cited_text,实际很少命中),模型只拿到标题 + URL。本插件每条都带标题、摘要、 发布日期,模型据此更容易判断该不该 web_fetch。

  2. 长尾查询会静默降级。Bing 对冷门查询会返回 HTTP 200、channel 标题正确回显 query,然后给出完全无关的热门内容。实测(真实查询,节流 9s/次):

    query 结果
    PyMuPDF latest version 6 条,全部相关
    docling picture caption matching nearest caption below layout model 8 条,全部相关
    Nougat OCR arXiv PDF math LaTeX formula accuracy 8 条,全部相关
    PDFFigures 2.0 mining figures from research papers… 失败(Bing 返回 8 条无关内容)
    FigureSeer parsing result-figures research papers ECCV 2016… 失败(同上)
    CERMINE figure caption zone classification SVM… 失败(同上)

    同一批 query 走付费路径时,返回的是 dl.acm / Springer 论文页、github.com/CeON/CERMINE 源码、docs.rs 文档这一级的深链——冷门方法名、论文标题这类调研,付费路径明显更强。 所以 relevanceGuard 默认开着:与其让模型自信引用垃圾,不如让这次搜索明确失败。

  3. 降级是客户端信誉问题,不是查询语义。同一时刻直接抓 Bing 的 HTML 结果页 (/search?q=…,不走 RSS)返回的同样是无关内容(实测给出 "Assistant Principal jobs in Georgia"),说明两个接口都在被反爬降级。短时间高频请求会显著加剧:一次约 170 个请求的压测之后,DDG 从可用变成 403、再变成连接超时,Bing 的长尾查询全面降级。 因此本插件默认串行 + 最小间隔 + 冷却,且失败后不回落到付费路径。

结论:命名实体、常见库/项目类查询,免费路径够用且更快;冷门方法名、论文标题、 细分算法调研,建议要么接一个为程序化调用设计的检索 API(Tavily / Brave / Exa / Perplexity——本插件的 provider 接口与之同形,改 backends.js 即可),要么在 profile 里 把 web.searchProvider 临时切回 deepseek-official。

已知取舍

  • 质量:Bing RSS / DDG Lite 是检索结果,不是摘要;没有 content 字段,只有 sources[]。模型拿到的是 URL + 标题 + 摘要,需要细节就自己 web_fetch。
  • 可用性:两个引擎都是公开页面,可能被限流或改版。任一失败会顺延到下一个, 两个都失败就是一次工具错误——不再回落到付费路径,这是有意的。
  • 条款:Bing RSS 的版权声明限定 "personal, non-commercial use within an RSS aggregator"。多租户或商用请换成有正式 API 的检索后端,见上一节。

测试

node --test                    # 纯离线:解析器 + 相关度闸门 + 节流/冷却 + 注册
DSH_KEYLESS_LIVE=1 node --test # 额外打真实端点,验证引擎出结果
—/ 5

No ratings yet

Verified DSH bundle

Commit 8ee754f64267

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout