feat(search): 原生 provider 层(searxng/智谱/阿里IQS/博查/火山/百度)+ 降级链(契约无改动)

主人定调「先把原生的做进插件,MCP 路线等后端 MCP 完善后再接」。
- 新包 plugins/tools/io/search/:一 provider 一文件 + 共享 http/提取器 + 归一化 Result;域名过滤/去重/排序**归一化后统一做一次**
- 配置 15 键:WEB_SEARCH_PROVIDER(默认 searxng)/_FALLBACK/_MAX_RESULTS + 五家 ×(API_KEY/BASE_URL);WEB_SEARCH_TIMEOUT 语义改为「**每次上游尝试**」(降级链才有意义)
- 硬语义:未注册/未配置的主 provider ⇒ **启动期报错**(不许静默回落);off ⇒ 不注册工具;缺 key 的家不进可用清单;降级链**如实标实际应答的 provider**(变异:拿主力冒充 ⇒ 测试红「provider = zhipu, want bocha」)
- 密钥绝不进日志/响应(有断言);错误分类(鉴权/限流/额度/网络)+ **空结果 ≠ 成功**(变异暴露过一个死分支⇒下移到 searchWith 修掉)
- searxng 真机 e2e 通过(provider=searxng 5 条);**其余五家无 key ⇒ 如实标未实测**;契约无改动(无新端点、工具 schema 不变)
- 注册表留好 B 档接入位(tavily/exa/firecrawl/serper/serpapi),并有「未登记⇒启动报错」的防回归断言
This commit is contained in:
AskaEth committed 2026-10-05 22:38:20 +08:00
1 parent 236b202fda
commit 69a3b73777
24 files changed
+3251 -171

No files matched your search

+16
View File
@@ -0,0 +1,16 @@
// Package search 实现 web-search 工具的「搜索后端(provider)」层:
// 一 provider 一文件、统一窄接口、统一归一化结果
// (DevDocs/design/27-网络搜索与检索提供商.md §4,照 Open WebUI 的 provider 范式,不自创)。
//
// 三条不变量(design/27 §1):
//
// - **能力 ≠ 单一后端**:能力面对模型只有一把工具(`web-search`),后端由配置选定;
// 换 provider 不改工具 schema。
// - **provider 是一等公民、各自独立配置**:未配置的家**不出现**在注册表里(fail-closed),
// 绝不「挂着报错」。
// - **诚实**:provider 报错与空结果必须如实区分(空结果是空结果,不是成功);
// 密钥只从配置读,**绝不进日志/响应/提示词**。
//
// provider 只负责「发命令、取回 JSON、按 spec 归一化」:**不做域名过滤/去重/排序**
// —— 那些统一在归一化之后做一次(见 Finalize)。零新依赖:一律标准库 `net/http`。
package search