dsh-search-failover
v0.3.9
Published
Provider-level web search+fetch pool for DeepSeek Harness: bypass the official LLM search channel (0 model tokens), failover/rotate across Exa/Tavily/Jina/Firecrawl/Serper/SerpApi/SearXNG/DDG/Brave with quota-aware circuit breaking, multi-key rotation, an
Maintainers
Readme
dsh-search-failover
为什么不用官方默认搜索?
DSH 默认通道 deepseek-official 不是专用搜索 API:每次 web_search 都会发起一轮完整 Messages 模型调用,由 DeepSeek 在服务端执行搜索。这意味着:
| | 官方 deepseek-official | 本插件 search-pool |
|---|---|---|
| 检索方式 | 一整轮 LLM 调用 + 服务端 web_search 工具 | 直连 Exa / Tavily / Jina / Firecrawl 等检索端点 |
| 模型 token | 每次搜索都烧(input + output),结果还会回灌上下文 | 0(纯检索,不碰任何 LLM) |
| 计费来源 | DEEPSEEK_API_KEY 余额 | 各引擎自己的免费额度 |
| 抓取 web_fetch | 同样走官方通道 | 同步接管:Jina Reader / Exa Contents / Tavily Extract / Firecrawl Scrape |
| 宕机 / 额度耗尽 | 整条链路挂掉 | 熔断冷却 + 自动下探下一个引擎 / 下一个 Key |
装上即把 searchProvider 与 fetchProvider 都指到 search-pool。卸载后自动回落到官方通道。
✨ 核心特性
- 🛡️ Provider 级透明替换:无侵入接管 DSH
ctx.web的 搜索 + 抓取,保持原生web_search/web_fetch工具签名不变。 - 🔄 双重路由策略:
- 优先顺序 (Failover):按优先级从高到低依次尝试,前一个后端失败或熔断自动下探下一个。
- 加权轮询 (Weighted Rotate):按 1~10 权重将搜索流量平摊到所有健康引擎,最大化榨干各大搜索源的免费额度。
- ⚡ 智能额度感知与熔断器 (Circuit Breaker):
- 遇到额度耗尽(HTTP 402/429/Quota Exceeded)→ 长冷却 (1h),避免无效请求;
- 遇到临时网络抖动(Transient Error)→ 5 分钟内连续 3 次失败触发 短冷却 (60s);
- 冷却到期自动半开探活,成功立即恢复。
- 🤖 AI 自主换源技能 (
web_search_from):- 为 Agent 注入专属换源工具。当 AI 认为默认结果不够理想、信息过时或源单一时,可自主选择
exa/serper/tavily/jina/firecrawl等引擎重新搜索并对比。
- 为 Agent 注入专属换源工具。当 AI 认为默认结果不够理想、信息过时或源单一时,可自主选择
- 🎛️ 现代卡片流 Web GUI 设置面板:
- 在 DSH 设置页一键填写/修改 API Key、切换策略、拖拽排序、测试连通性,保存即实时生效,无需重启进程。
- 密钥安全保存在本地
~/.dsh/settings.yaml,绝不上报。
- 🔑 单引擎多 Key 轮换:同一后端可换行或逗号填多个 Key;Key A 额度耗尽先切 Key B,全部挂了才熔断下探下一个引擎。
- 🔌 全生态适配:
- 搜索:Exa, Serper, Tavily (keyless 匿名档), Jina, SerpApi, Firecrawl, SearXNG (自托管), DuckDuckGo, Brave
- 抓取:Jina Reader (
r.jina.ai) · Exa Contents · Tavily Extract · Firecrawl Scrape
🏗️ 架构概览
┌──────────────────────────────────────────────────────────────┐
│ AI Agent / User Chat │
└──────────────┬────────────────────────────────┬──────────────┘
│ (默认搜索 / 抓取) │ (显式换源)
▼ ▼
┌──────────────────────────────┐ ┌─────────────────────────────┐
│ 原生 web_search / web_fetch │ │ web_search_from (增强工具) │
└──────────────┬───────────────┘ └──────────────┬──────────────┘
│ │
▼ ▼
┌──────────────────────────────────────────────────────────────┐
│ SearchPoolProvider (search-pool) │
│ │
│ [调度决策] │
│ ├── 指定源 (source): 直连指定引擎, 不走池 │
│ ├── Failover: 按 priority 升序依次尝试 │
│ └── Rotate: 按 weight 展开加权轮转 │
│ │
│ [熔断与健康守护] │
│ ├── CircuitBreaker 监控各后端健康度 │
│ └── 额度耗尽(1h 冷却) / 瞬时错误(60s 冷却) / 探活恢复 │
└──────────────────────────────┬───────────────────────────────┘
│
┌──────────┬──────────┬─────┴────┬──────────┬──────────┬──────────┐
▼ ▼ ▼ ▼ ▼ ▼ ▼
┌─────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌─────────┐┌─────┐ ┌─────────┐
│ Exa │ │Serper│ │Tavily│ │ Jina │ │Firecrawl││Serp-│ │ SearXNG │
│ │ │ .dev │ │(Anon)│ │ AI │ │ .dev ││ Api │ │ (Local) │
└─────┘ └──────┘ └──────┘ └──────┘ └─────────┘└─────┘ └─────────┘🎛️ 设置面板实机预览
- 实时密钥填写:随时填写或更新各引擎 API Key(支持多行多 Key),点击保存立即热生效。行内「↗」直达各引擎申请页。
- 网页抓取接管:
web_fetch同步走搜索池(Jina Reader / Exa / Tavily / Firecrawl),享受同一套熔断与多 Key。 - 一键测试连接 (▶ 测试):对指定后端发起 1 条测试搜索,毫秒级反馈连通状态与响应耗时。
- 动态优先级调整 (↑ / ↓):通过按钮调整引擎在 Failover 链中的优先级。
- 轮询权重调节:在轮询分摊模式下,为不同引擎设置 1~10 权重值。
- 添加自定义后端:无需改写代码或配置文件,直接在界面添加 SearXNG 实例或新后端。
- 额度余量透视:行内直接显示支持额度查询的后端(如 SerpApi)的套餐类型、剩余次数及重置日期。
🚀 快速开始
1. 安装插件
在你的 DSH 项目或 Web Profile 下安装:
# 方式 A: 从 npm 安装 (推荐)
dsh plugin --profile web add dsh-search-failover
# 方式 B: 本地克隆软链调试 (开发者)
git clone https://github.com/Walvez/dsh-search-failover.git
dsh plugin --profile web add link:$(pwd)/dsh-search-failover2. 启用配置
在 cordis.patch.yml 中声明挂载与默认后端配置:
- id: search-pool
name: dsh-search-failover
config:
strategy: failover # failover (优先顺序) | rotate (轮询分摊)
maxResults: 8 # 默认返回条数上限
timeoutMs: 15000 # 单个请求超时时间 (ms)
backends:
- id: exa
kind: exa
apiKeyEnv: EXA_API_KEY # 从 ~/.dsh/.env 读取
priority: 1
- id: serper
kind: serper
apiKeyEnv: SERPER_API_KEY
priority: 2
- id: tavily
kind: tavily
apiKeyEnv: TAVILY_API_KEY
priority: 3
- id: jina
kind: jina
apiKeyEnv: JINA_API_KEY
priority: 4
- id: firecrawl
kind: firecrawl
apiKeyEnv: FIRECRAWL_API_KEY
priority: 5
- id: serpapi
kind: serpapi
apiKeyEnv: SERPAPI_API_KEY
priority: 6
- id: searxng
kind: searxng
baseURL: http://127.0.0.1:8080
priority: 7
circuit:
threshold: 3 # 连续错误阈值
burstWindowMs: 300000 # 统计时间窗口 (5 分钟)
cooldownMs: 60000 # 瞬时错误冷却时间 (1 分钟)
quotaCooldownMs: 3600000 # 额度耗尽冷却时间 (1 小时)3. 启动 DSH Web
dsh web打开 Web GUI (默认 http://127.0.0.1:3080),进入 设置 → 搜索池 即可在界面直接管理所有 Key。
📊 后端引擎支持与额度参考
| 引擎标识 (kind) | 搜索 | 抓取 | 官方免费额度 (核实) | 密钥 | 申请页 |
|---|:---:|:---:|---|---|---|
| exa | ✓ | ✓ | 注册送 $20,每月赠 $10 | 必须 | dashboard.exa.ai |
| serper | ✓ | ✗ | 注册赠送 2,500 次 | 必须 | serper.dev |
| tavily | ✓ | ✓ | 每月 1,000 credits;无 key 走匿名档 | 可选 | app.tavily.com |
| jina | ✓ | ✓ | 免费注册 Key;s.jina.ai 搜索 / r.jina.ai 抓取 | 必须 | jina.ai |
| firecrawl | ✓ | ✓ | 每月 1,000 credits | 必须 | firecrawl.dev |
| serpapi | ✓ | ✗ | 每月 250 次,支持实时额度查询 | 必须 | serpapi.com |
| searxng | ✓ | ✗ | 自托管无限 | 无 | docs.searxng.org |
| brave | ✓ | ✗ | 需绑卡 | 必须 | brave.com/search/api |
| ddg | ✓ | ✗ | 完全免费 | 无 | — |
同一后端可换行或逗号填多个 Key。Key A 额度耗尽先切 Key B,全部挂了才熔断下探下一个引擎。
🤖 AI 自主换源工具 (web_search_from)
当 Agent 认为默认搜索结果不理想时,可以主动调用由本插件注册的 web_search_from 工具:
工具参数
{
"name": "web_search_from",
"description": "用指定的搜索后端(引擎)搜索当前信息并返回该源原始结果。可用于多源对比或换引擎重试。",
"parameters": {
"query": { "type": "string", "description": "搜索关键词" },
"source": { "type": "string", "description": "指定后端类型 (例如 exa, serper, tavily, jina, firecrawl, searxng 等)" },
"maxResults": { "type": "number", "description": "返回结果数量上限 (默认 8)" }
}
}Agent 典型工作流
- Agent 执行
web_search(query="最新技术动态")走默认搜索池; - 发现结果大多是旧闻或不相关,Agent 主动调用
web_search_from(query="最新技术动态", source="serper")从 Google 实时索引获取结果; - 对比各源信息,输出最准确、最及时的回答。
🧪 单元测试
项目包含完善的单元测试套件(覆盖熔断器状态机、加权轮询、优先级排序、多源容灾、自愈探活等):
# 运行单元测试
npm test
# 运行真实网络冒烟测试
EXA_API_KEY=your_key node scripts/smoke.mjs exa serper tavily📄 开源许可证
本项目基于 MIT License 开源。
欢迎提交 Issue 和 Pull Request 共同改进!
