犀牛鸟 2026 研究笔记 estelledc.github.io

案例 #1784:SearXNG 可行动错误信息

对齐 写作标准 · 错误语义可参考 case-1828 构造期 fail
PR:#1784 | 5 文件 +187/-4 | 2026-06-24 合入

结论先行

设置页 Test Connection 对联网搜索做探针查询时,若 SearXNG 返回 0 条结果,旧逻辑统一提示 「检查 API Key」 — 对 无 Key 的 SearXNG 完全误导。本 PR 新增 EmptyTestResultsError:SearXNG 解析响应里的 unresponsive_engines,在错误里展示 google (timeout) 等;Bing/Google 等仍走 API Key 提示。

适合谁读:改 web_search 集成、设置页 test connection、#1248 POST 错误码 设计。

Ch12 Agentic RAG · case-1774(三层 API)· case-1754(可执行 API 契约)。


1. 问题现象(What)

1.1 运维场景

  1. 管理员配置 SearXNG 为 Agent 联网搜索后端
  2. 点击 Test Connection
  3. HTTP 成功但 results 为空
修复前 toast 修复后(有 unresponsive_engines)
笼统「检查 API Key」 searxng returned 0 results: unresponsive engines: google (timeout), bing (blocked); check upstream...
同上 无 diagnostics 时提示 JSON format / URL / 上游连通

1.2 修复前 / 修复后

Provider 0 results 时消息
SearXNG API Key实例/JSON/上游引擎
DuckDuckGo 网络/代理提示(PR 新增分支)
Bing/Google 等 verify API key(不变)

2. 定位步骤

rg "Test Connection|test connection|EmptyTest" internal/
rg "unresponsive_engines|UnresponsiveEngines" internal/infrastructure/web_search/
rg "EmptyTestResultsError" internal/

阅读顺序

  1. web_search/test_errors.goNEW 消息路由
  2. web_search/searxng.go — 存 lastUnresponsive + EmptyResultDiagnostics()
  3. handler/web_search_provider.go — 调用 test 流程
  4. test_errors_test.go — 断言 不含 API key(SearXNG)

3. 根因分析(Why)

3.1 类比

SearXNG 像 总机转接:WeKnora 拨通总机(HTTP 200),但 分机(google/bing)全忙。旧 UI 却提示「你是不是 没办电话卡(API Key)」— 问错问题,运维浪费一小时查 Key。

3.2 数据流

flowchart LR
    UI[设置 Test Connection] --> H[web_search_provider handler]
    H --> P[SearxngProvider.Search]
    P --> SX[SearXNG HTTP JSON]
    SX --> R{results 空?}
    R -->|是| E[EmptyTestResultsError]
    E --> D[EmptyResultDiagnostics<br/>unresponsive_engines]
    D --> T[Toast 可行动文案]

3.3 根因


4. 解决方案(How)

4.1 接口:emptyResultDiagnostics

type emptyResultDiagnostics interface {
    EmptyResultDiagnostics() string
}

SearxngProvider 实现;Search 时:

p.lastUnresponsive = data.UnresponsiveEngines

4.2 EmptyTestResultsError

func EmptyTestResultsError(providerType string, provider any) error {
    switch types.WebSearchProviderType(providerType) {
    case types.WebSearchProviderTypeSearxng:
        if detail := provider.(emptyResultDiagnostics).EmptyResultDiagnostics(); detail != "" {
            return fmt.Errorf("searxng returned 0 results: %s", detail)
        }
        return fmt.Errorf("searxng returned 0 results; verify ... JSON format ...")
    default:
        return fmt.Errorf("search returned 0 results, please verify your API key ...")
    }
}

4.3 formatUnresponsiveEngines

[["google","timeout"],["bing","blocked"]] 格式化为 google (timeout), bing (blocked)

4.4 逐文件表(5 文件)

文件 ± 说明
test_errors.go +58 NEW 路由
test_errors_test.go +74 SearXNG 无 API key 断言
searxng.go +14/-2 lastUnresponsive + Diagnostics
searxng_test.go +38 Search empty 场景
web_search_provider.go +3/-2 接 EmptyTestResultsError

4.5 验证

go test ./internal/infrastructure/web_search/... -run 'TestEmptyTestResultsError|TestFormatUnresponsive' -v

Staging:可达 SearXNG 但上游引擎全挂 → toast 含 unresponsive engines;Bing 错 Key → 仍 Key 提示。


5. Review 与合入

PR 四段式

What Why How Test
0 results 误报 API Key 未读 SearXNG diagnostics EmptyTestResultsError + 接口 go test + 手动 test connection

维护者 checklist


6. 与 #1248

模式 1784 #1248 feedback POST
错误分类 按 provider type 按业务:重复点赞 / message 不存在
用户文案 可行动(查 JSON/上游) 可行动(刷新/联系管理员)
实现 小文件 test_errors.go 可仿 feedback_errors.go

7. 可复用模式


8. 常见误区

错误认知:HTTP 200 就是 test 成功。
正确:业务 0 results 仍应 fail with reason。

错误认知:所有搜索后端都要 API Key。
正确:SearXNG 自建 无 Key — 错误提示必须分型。

错误认知:改 handler 文案就够。
正确:diagnostics 在 Search 响应解析 时捕获。

错误认知:unresponsive_engines 只给日志。
正确:Test Connection 是 运维 UI,应进 toast。


9. 思考点

  1. Agent 运行时 Search 失败是否也应带 unresponsive_engines?与 test 路径差异?
  2. 设计 #1248 的 feedback_already_submitted 错误 JSON 形状。
  3. case-1828 SSRF 校验 SearXNG URL — 与 1784 运维提示如何同一文档?

章末自检


延伸阅读