搜索与抓取失败时自动切换备用通道,省下调用成本
30/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/21 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
相关生态插件(非 dsh 原生,按其对应运行时安装)
git clone https://github.com/FuriousKinght/dsh-fk-search-tier.git状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
是什么
生态应用
桌面端 / Web 外壳,不以 dsh plugin add 安装
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 14 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🟢 扫描:未发现敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描未发现敏感能力:最多只发网络请求、读取自身元数据或只读文件,未发现执行命令、文件写入或敏感信息读取。
发起外部网络请求
查看扫描证据(共 6 处,展示前 6 条)
- 发起网络请求lib/index.js:67
const resp = await fetch(url, { ...init, signal: ctrl.signal }) - 发起网络请求lib/index.js:335
async fetch(cfg, request, signal, options = {}) { - 发起网络请求lib/index.js:371
async fetch(cfg, request, signal, options = {}) { - 发起网络请求lib/index.js:378
const resp = await fetch(request.url, { - 发起网络请求lib/index.js:626
async fetch(request, signal) { - 发起网络请求lib/index.js:647
const result = await backend.fetch(layerCfg, request, signal, { timeoutMs: c.timeoutMs })
扫描于 2026/11/3(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
两级搜索 failover 插件(Tavily → DeepSeek Search API;Fetch: DeepSeek → 直连)。带额度感知熔断,第一层失败自动切第二层。
README
由 DeepSeek 最新模型翻译生成dsh-fk-search-tier
两级搜索 + 两级抓取 failover —— 搜索先 Tavily 后 DeepSeek Search API;抓取先 DeepSeek Fetch API 后直连兜底。
DeepSeek Harness 插件。不改 DSH 本体,纯 ctx.web provider 注册。
为什么做这个
DSH 默认的 deepseek-official 搜索通道:
- 每次搜索消耗一个完整模型轮次(实测约 9.6K input token)
- 按 token 计费,高峰期成本翻倍
两级方案把成本压到最低:
【搜索】searchProvider: search-tier 第 1 层 Tavily → 免 key 匿名档 / 免费 1000 credits/月 ↓ 429 / 额度耗尽 / 5xx / 超时 / 空结果第 2 层 DeepSeek → 5 元 / 1000 次成功请求(按次,不烧 token)
【抓取】fetchProvider: fetch-tier 第 1 层 DeepSeek Fetch API → 返回干净 Markdown(实测 ~0.3 秒) ↓ 429 / 额度耗尽 / 5xx / 超时第 2 层 直连抓取 → 零成本兜底(HTML → 纯文本)
实测数据(2026-10-17):
| 项目 | 结果 |
展开完整文档(README 剩余 1 节)
dsh-fk-search-tier
两级搜索 + 两级抓取 failover —— 搜索先 Tavily 后 DeepSeek Search API;抓取先 DeepSeek Fetch API 后直连兜底。
DeepSeek Harness 插件。不改 DSH 本体,纯 ctx.web provider 注册。
为什么做这个
DSH 默认的 deepseek-official 搜索通道:
- 每次搜索消耗一个完整模型轮次(实测约 9.6K input token)
- 按 token 计费,高峰期成本翻倍
两级方案把成本压到最低:
【搜索】searchProvider: search-tier 第 1 层 Tavily → 免 key 匿名档 / 免费 1000 credits/月 ↓ 429 / 额度耗尽 / 5xx / 超时 / 空结果第 2 层 DeepSeek → 5 元 / 1000 次成功请求(按次,不烧 token)
【抓取】fetchProvider: fetch-tier 第 1 层 DeepSeek Fetch API → 返回干净 Markdown(实测 ~0.3 秒) ↓ 429 / 额度耗尽 / 5xx / 超时第 2 层 直连抓取 → 零成本兜底(HTML → 纯文本)
实测数据(2026-10-17):
| 项目 | 结果 |
| Tavily keyless 免注册 | ✅ 返回 5 条真实结果 |
| DeepSeek Fetch API | ✅ 0.53s / 931 字符(example.com) |
| DeepSeek Fetch 真实页面 | ✅ 0.27s / 24,740 字符(GitHub 仓库页) |
| 不存在的域名 | HTTP 500(API 的预期行为,触发切层) |
安装
dsh plugin --profile desktop add <本包路径或包名>
⚠️ 必须让 DSH 走 bundle 机制自动加载 patch,不要手工把 cordis.patch.yml 的内容抄进 profile 的 cordis.patch.yml —— 那会绕过加载时序,导致 tool-web: waiting for web。
装完重启 DSH。
配置
⚠️ 先把这件事说清楚:密钥不要写进插件目录
插件目录里的 cordis.patch.yml 是随插件发布的文件。
把 apiKey 写在那里,等于把密钥公开(推 GitHub、发给别人、打包分发都会带上)。
正确做法有两种,任选其一(推荐 A):
A. 用环境变量(推荐)
插件会自动读这两个环境变量,cordis.patch.yml 里留空即可:
| 后端 | 环境变量 |
| DeepSeek Search / Fetch | DEEPSEEK_API_KEY |
| Tavily(可选) | TAVILY_API_KEY |
Windows — PowerShell(当前用户,永久生效):
[Environment]::SetEnvironmentVariable("DEEPSEEK_API_KEY", "sk-你的key", "User")
Windows — 图形界面:
Win + R → sysdm.cpl → 高级 → 环境变量 → 用户变量 → 新建 → 变量名 DEEPSEEK_API_KEY,变量值填你的 key → 确定 → 重启 DSH
改完环境变量必须重启 DSH 才生效 —— 已在运行的进程不会重新读取。
B. 在 profile 层覆盖(密钥放私有文件)
$DSH_HOME/profiles/<profile>/cordis.patch.yml 是你自己的私有文件,不随插件发布。
在文件末尾追加:
覆盖 search-tier 的配置(本文件是私有的,可以写密钥)
- id: search-tier
name: dsh-fk-search-tier
config:
order: [tavily, deepseek]
deepseek:
apiKey: 'sk-你的key' baseURL: https://api.deepseek.com
tavily:
apiKey: 'tvly-你的key' # 可选;没有就走 keyless 匿名档
注意:profile 层的同名 id 会整段覆盖插件自带的配置,所以「想保留的键都要重述一遍」,不能只写 apiKey。
最小配置(零配置也能用)
不配任何密钥也能工作:
- Search:Tavily 的 keyless 匿名档(免注册,实测可用)
- Fetch:直连抓取(零成本兜底)
- id: search-tier
name: dsh-fk-search-tier
config:
order: [tavily, deepseek]
tavily: {}
deepseek: {} # 无 key → 该层自动跳过
代价:没有 DeepSeek 层作为兜底,Tavily 匿名档限流时就没有第二层了。
完整配置项
- id: search-tier
name: dsh-fk-search-tier
config:
── 层级顺序 ──
order: [tavily, deepseek] # 搜索:先 Tavily,再 DeepSeek
fetchOrder: [deepseek-fetch, direct] # 抓取:先 DeepSeek Fetch,再直连
── 第 1 层:Tavily ── tavily: apiKey 留空 → keyless 匿名档;有 key 走账户额度(1000 credits/月) depth: basic # basic=1 credit | advanced=2 credits maxResults: 8
── DeepSeek 官方 API(Search + Fetch)── deepseek: apiKey 留空 → 自动读环境变量 DEEPSEEK_API_KEY;仍然没有 → 该层跳过 baseURL: https://api.deepseek.com maxResults: 8 needContent: false # true 会额外返回网页正文(更慢、更长) fetchMaxBytes: 200000 # Fetch 单页最大字节
── 直连抓取(零成本兜底)── direct: userAgent: '' # 可覆盖默认 UA {}
── 超时 ── timeoutMs: 20000 # 搜索单层超时 fetchTimeoutMs: 30000 # 抓取单层超时(页面通常更大) failOnEmpty: true # 上一层返回 0 条也切下一层
── 熔断 ── breaker: threshold: 3 # 瞬时故障累计几次才开断 burstWindowMs: 300000 # 5 分钟窗口 cooldownMs: 60000 # 瞬时故障冷却 60 秒 quotaCooldownMs: 3600000 # 额度耗尽冷却 1 小时
怎么确认密钥读到了
配好并重启 DSH 后,让 AI 调一次诊断工具:
search_tier_status
返回的 layers 里看 hasKey 字段:
{
"id": "deepseek",
"hasKey": true, ← true 表示密钥读到了 "needsKey": true, "open": false }
hasKey: false 说明密钥没读到,按上面 A / B 检查,并确认已重启 DSH。
排查清单
| 现象 | 原因 | 解决 |
| hasKey: false | 环境变量没设,或设了没重启 DSH | 重设 + 重启 |
| hasKey: true 但报 401 | key 无效或已过期 | 去平台确认 |
| 一直用 Tavily,从不切 DeepSeek | Tavily 正常时不会切(这是设计) | 正常现象 |
| 两层都失败 | 网络问题 / 两边都额度耗尽 | 看错误信息里的 skipped-open |
切换规则
搜索与抓取共用同一套熔断语义(两个独立实例,参数相同)。
| 触发条件 | 行为 | 冷却 |
| 429 / 402 / 文本含 insufficient quota | 该层开断,立即切下一层 | 1 小时 |
| 401 / 403(凭据问题) | 跳过该层(不冷却,配置改了立刻恢复) | 无 |
| 5xx / 超时 / 网络错误 | 窗口内累计 3 次才开断 | 60 秒 |
| 返回 0 条结果(仅搜索) | 本次直接切下一层(不计入熔断) | 无 |
| 该层缺 key(仅 deepseek / deepseek-fetch) | 直接跳过 | 无 |
冷却到期后自动半开:下一次请求放行做探活,成功即闭合。
返回给模型的内容
搜索
严格遵循 DSH 的 ctx.web 契约,只返回 sources(让模型自己读):
{
sources: [
{ url, title, snippet, publishedAt? }
],
truncated: boolean,
content?: string // 仅 Tavily 返回 answer 时才带 }
- Tavily:snippet 取 content 前 500 字符
- DeepSeek:snippet 优先取 summary(600-800 字符长摘要),回退 snippet(100-200 字符)
模型收到的最终文本由 DSH 的 formatSearchOutput 组装成 markdown 来源列表。
抓取
按官方 WebFetchResult 契约:
{
url: string, // 请求的 URL(API 不报告重定向后的最终 URL) statusCode: 200, // 成功即 200(DeepSeek API 不报告目标页面状态)
body: { kind: 'text', content: string },
truncated: false
}
- DeepSeek Fetch:直接用 API 返回的 content(已是 Markdown)
- 直连抓取:fetch 原始 HTML → htmlToText() 转纯文本;非 HTML 原样返回
诊断
注册了一个只读工具 search_tier_status,AI 可直接调用查看:
{
"search": {
"providerId": "search-tier",
"order": ["tavily", "deepseek"],
"lastWinner": "tavily",
"layers": [
{ "id": "tavily", "hasKey": false, "open": false, "lastError": null },
{ "id": "deepseek", "hasKey": true, "open": false, "lastError": null }
],
"breaker": { "tavily": { "open": false, "remainingMs": 0 } }
},
"fetch": {
"providerId": "fetch-tier",
"order": ["deepseek-fetch", "direct"],
"lastWinner": "deepseek-fetch",
"layers": [
{ "id": "deepseek-fetch", "hasKey": true, "open": false, "lastError": null },
{ "id": "direct", "hasKey": true, "open": false, "lastError": null }
]
}
}
自测
node test/selftest.mjs
53 项断言,覆盖:
| 段 | 内容 |
| 一 | 错误分类 classify() |
| 二 | 熔断器(额度 / 瞬时 / 半开) |
| 三 | 搜索 provider 契约 |
| 四 | 真实 Tavily keyless 调用 |
| 五 | 降级逻辑(熔断跳过) |
| 六 | 空结果切层 |
| 七 | Fetch provider 契约与 failover(13 项) |
| 八 | 真实 DeepSeek Fetch API 调用(5 项) |
与 dsh-search-failover 的区别
| | dsh-search-failover | 本插件 |
| 搜索后端数 | 10 个 | 2 个(专注) |
| 抓取 failover | ❌ | ✅ 有(2 层) |
| 支持 DeepSeek 新 Search API | ❌ 无 | ✅ 有 |
| 支持 DeepSeek Fetch API | ❌ 无 | ✅ 有 |
| Tavily keyless | ✅ | ✅ |
| 熔断 | ✅ | ✅ |
| 设置页 | ✅ | ❌(纯配置) |
| 代码量 | ~90 KB | ~26 KB |
如果你的需求就是「Tavily → DeepSeek」两级搜索加重试兜底抓取,本插件更轻。
与官方 dsh-web-deepseek-api 的区别
DSH 0.2.1-rc.2 起官方内置了 DeepSeek Search / Fetch provider。两者不冲突,但定位不同:
| | 官方内置 | 本插件 |
| DeepSeek Search | ✅ | ✅ |
| DeepSeek Fetch | ✅ | ✅ |
| 两级 failover | ❌ 无(README 明确写「不会自动重试或回退至其他提供者」) | ✅ 有 |
| Tavily 免费额度兜底 | ❌ 无 | ✅ 1000 次/月 |
| 消费 summary 长摘要 | ❌ 丢弃(只映射 snippet) | ✅ 优先使用 |
| 热切换 provider | ✅(rc.2 的 Volatile) | ❌ 需重启 |
| 维护方 | 官方 | 自己 |
⚠️ 两者同时存在时可能触发 WEB_PROVIDER_AMBIGUOUS(多个可用 provider 但未显式指定)。
本插件的 patch 显式写了 searchProvider / fetchProvider,所以不会歧义;但如果你在设置页把官方开关打开,要注意读一下最终生效的是哪个。
已知限制
1. Tavily keyless 是匿名档,有速率限制,随时可能被官方关闭
2. DeepSeek Search / Fetch API 均按次计费,各 5 元/1000 次
3. 直连抓取层不解析 JS 渲染的页面(纯 fetch + HTML 转文本)
4. 抓取成功一律报 200 —— DeepSeek API 不报告目标页面状态,这是官方契约的行为
5. 无设置页,改配置需编辑 YAML 并重启
更新记录
v0.2.0(2026-10-20)
密钥不再随插件发布 —— 修掉一个会泄露 API Key 的安全问题
插件目录里的 cordis.patch.yml 是随插件分发的文件。之前把 apiKey 写在那里,等于把密钥公开(推 GitHub、发给别人、打包分发都会带上)。
- cordis.patch.yml 里的 apiKey 一律留空
- 插件新增环境变量支持:DEEPSEEK_API_KEY / TAVILY_API_KEY
- 读取顺序:patch 配置 → 环境变量 → 该层跳过
- README 新增完整的「配置」章节(含 Windows 设置步骤、profile 覆盖法、排查清单)
抓取层新增两级 failover
原来只有搜索有 failover,抓取是单层。现在抓取也两级:
- 第 1 层:DeepSeek Fetch API(返回干净 Markdown)
- 第 2 层:直连抓取(fetch + HTML 转文本,零成本兜底)
额度感知熔断
- 瞬时故障:5 分钟内累计 3 次开断,冷却 60 秒
- 额度耗尽单独识别:冷却 1 小时(避免反复撞额度墙)
- 两层都失败时抛明确错误,不静默返回空
诊断工具
新增 search_tier_status 工具,返回各层状态:是否被熔断、剩余冷却时间、最近错误、上次成功用的是哪层、hasKey 是否读到密钥。
自测
test/selftest.mjs 覆盖切换规则、熔断、错误分类;test/e2e.mjs 走真实调用。
测试里的密钥来源改为「环境变量优先,其次从 DSH 凭据文件动态读取」,不再硬编码本机路径。
License
MIT预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
FuriousKinght/dsh-fk-search-tier
搜索与抓取失败时自动切换备用通道,省下调用成本
相关插件 · 搜索 / 抓取
LLM 知识平台Tencent/WeKnora
概览 ·快速开始 ·新特性 ·功能 ·客户端 ·文档 ·开发
★ 36,379已汉化DSH
72
智能体记忆系统MemTensor/MemOS
MemOS 2.0 Stardust星尘
★ 12,247已汉化DSH
71.3
跨代理记忆库zilliztech/memsearch
跨平台语义记忆,专为 AI 编程智能体打造。
★ 2,799已汉化DSH
70.9
技能语料库EverMind-AI/SkillCorpus
SkillCorpus 能给你什么
★ 695已汉化DSH
69.8
动画花园资源检索yjl9903/AnimeGarden
動漫花園 镜像站 | 动画 BT 资源聚合站 | 动画 BT 资源开放接口
★ 1,391已汉化DSH
69.2
代码图谱记忆syncable-dev/memtrace-public
你的智能体值得拥有结构化记忆。
★ 510已汉化MCP
67.9
这是你的仓库?认领条目