Files
searxng-use-cli/README.md
T
thzxx fb9b2af45f feat(v1.8.0): 稳定性修复 + AI Agent 体验增强
稳定性修复:

- 修复 cache.py SQLite 连接泄漏(contextlib.closing 包装)

- 修复 fetch.py requests stream=True 连接泄漏(try/finally resp.close())

- RETRYABLE_STATUS 新增 403,激活 UA fallback 切换逻辑

- --cache-stats 移至实例解析前,无需实例即可查询

- classify_error 从错误消息提取 HTTP 状态码,正确分类 E_AUTH/E_RATE_LIMIT

- --stream 与 --queries-file 互斥检查,违规报 E_INPUT

- batch 退出码语义统一(0=有结果 / 1=全部错误 / 2=全部空结果)

AI Agent 体验增强:

- 错误码体系完善:E_CONFIG/E_AUTH/E_NETWORK/E_RATE_LIMIT/E_PARSE/E_EMPTY/E_INPUT/E_INTERNAL

- recovery_hint 恢复提示字段,AI Agent 可程序化决策恢复策略

- stream 模式新增 error 事件类型(含 error_code + recovery_hint)

- 进度事件扩展:instance_try/instance_ok/instance_fail

- batch 模式统一 schema(status 字段区分 success/failed)

- JSON 输出含 schema_version 字段确保版本兼容

测试与文档:

- 测试覆盖:330 -> 352

- SKILL.md / README.md 同步更新
2026-08-01 19:02:44 +08:00

319 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SearXNG CLI 技能包
[![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
一个面向 AI Agent 的网络搜索与网页抓取技能包。AI 通过终端调用 CLI 脚本即可获得"搜索网络"和"抓取网页"两项核心能力,无需 API Key,路由通过用户自建的 SearXNG 实例完成。
**这不是给人用的工具,而是给 AI 用的技能。** 任何能执行终端命令的 AI AgentHermes、Claude Code、Codex、OpenCode、Cursor、Trae 等)均可直接调用。
## 为什么需要这个技能
AI Agent 在以下场景中需要实时网络信息:
- 查询最新新闻、文档、技术资料
- 验证事实、获取实时数据
- 抓取网页内容进行阅读和分析
传统方案依赖付费搜索 API(Google、Bing)或专有爬虫服务。本技能通过用户自建的 SearXNG 实例(隐私元搜索引擎,聚合 70+ 搜索服务)实现零成本、零 API Key、隐私可控的网络搜索能力。
## AI 如何使用
### 搜索网络
```bash
python scripts/search.py -q "搜索词" -i https://your-searxng-instance
```
AI 调用后,stdout 输出 JSON 格式搜索结果,AI 可解析并使用:
```json
{
"query": "搜索词",
"results": [
{"title": "...", "url": "https://...", "content": "摘要...", "engine": "google", "score": 1.0}
],
"suggestions": ["相关建议词"],
"answers": ["直接答案(如有)"]
}
```
### 抓取网页
```bash
python scripts/fetch.py -u "https://example.com" --extract markdown
```
AI 调用后,stdout 输出网页正文(text/html/markdown 三种格式),AI 可直接阅读分析。
### 输入输出约定(AI 必读)
| 通道 | 内容 | 说明 |
|------|------|------|
| stdout | 数据 | JSON/CSV/文本,AI 解析的唯一来源 |
| stderr | 日志 | 进度、警告、错误,AI 可忽略或用于调试 |
| exit 0 | 成功 | 有结果 |
| exit 1 | 失败 | 致命错误(所有实例不可用、参数错误等) |
| exit 2 | 空结果 | 搜索成功但无结果 |
**错误处理**`--format json` 模式下,错误以 JSON 输出到 stdout(非 stderr),格式为 `{"error": "...", "error_code": "E_NETWORK", "recovery_hint": "...", "exit_code": 1, "query": "..."}`AI 可程序化捕获并按 `recovery_hint` 采取恢复行动。
**错误码体系**`error_code` + `recovery_hint` 字段):
| 错误码 | 含义 | recovery_hint(节选) |
|--------|------|----------------------|
| `E_CONFIG` | 配置错误(无实例) | 设置 `-i`/`SEARXNG_INSTANCE`/配置文件 |
| `E_AUTH` | 认证失败(401/403) | 检查凭证、token 过期与权限 |
| `E_NETWORK` | 网络错误(连接失败、5xx) | 重试退避、切换实例、检查代理 |
| `E_RATE_LIMIT` | 限流(429) | 等待重试、降低频率、分散负载 |
| `E_PARSE` | 解析错误 | 切换实例、切换 `--method` |
| `E_EMPTY` | 空结果(exit 2) | 调整查询词、扩大 `--time-range`/`--categories` |
| `E_INPUT` | 输入错误(参数/文件) | 检查语法、标志组合、文件路径 |
| `E_INTERNAL` | 内部错误 | 用 `--verbose` 重跑并报告 |
### 流式输出与进度事件(AI 高级用法)
**`--stream`**JSON Lines 流式输出,每条结果一行 JSON,AI 可增量处理:
```
{"type": "result", "result": {"title": "...", "url": "..."}}
{"type": "done", "schema_version": "1.0", "count": 10, "query": "..."}
```
搜索失败时输出 error 事件(含 `recovery_hint`):
```
{"type": "error", "error": "...", "error_code": "E_AUTH", "recovery_hint": "Verify credentials...", "query": "..."}
```
注意:`--stream` 仅在单查询 + `--format json` 下有效;与 `--queries-file` 或非 json 格式同用会立即报 `E_INPUT`
**`--progress`**:进度事件流(JSON Lines 到 stderr),AI 可实时跟踪执行:
```
{"event": "start", "query": "...", "instances": 2}
{"event": "instance_try", "url": "https://inst1.example.com", "attempt": 1}
{"event": "instance_ok", "url": "https://inst1.example.com", "latency": 0.342, "results": 10}
{"event": "instance_fail", "url": "https://inst2.example.com", "error": "HTTP 503", "error_code": "E_NETWORK"}
{"event": "cache_hit", "query": "...", "ttl": 30}
{"event": "fetch_ok", "url": "...", "chars": 12345}
{"event": "done", "results": 10, "query": "..."}
```
**`--dump-schema`**:输出当前版本的 JSON Schema 到 stdout 并退出,AI 可程序化发现字段名与类型,无需解析文档。
```bash
# AI 推荐用法:流式输出 + 进度事件
python scripts/search.py -q "research" -i https://your-instance --stream --progress
```
## 部署
### 前置条件
- Python 3.8+3.11+ 开箱即用;3.8-3.10 使用 `searxng.toml` 配置需 `pip install tomli`
- 一个 SearXNG 实例 URL(自建或受信任的实例)
### 安装
```bash
git clone https://git.metona.cn/MetonaTeam/searxng-use-cli.git
```
无需安装依赖。`search.py` 仅使用 Python 标准库,开箱即用。
可选安装:
```bash
# 提升 fetch.py 抓取质量(HTTP 连接池 + HTML 解析)
pip install requests beautifulsoup4
# Python 3.8-3.10 使用 searxng.toml 配置文件时需要(3.11+ 内置 tomllib
pip install tomli
```
### 配置实例
AI Agent 无需每次传入实例 URL 和认证信息,支持通过配置文件一次性设置:
1. **CLI 参数**`-i https://your-instance`(最高优先级)
2. **环境变量**`export SEARXNG_INSTANCE="https://your-instance"`
3. **配置文件**`./searxng.toml``~/.config/searxng-cli/searxng.toml`
```toml
# searxng.toml
[searxng]
instance = "https://your-searxng.example.com"
# 私有实例认证(可选,二选一):
auth_basic = "user:password" # Basic 认证
# auth_bearer = "sk-token-123" # Bearer Token(与 auth_basic 同时设置时 bearer 优先)
```
**认证优先级**(从高到低):`--auth-*` CLI 参数 > `--auth-*-file` 文件 > `searxng.toml` 配置 > 环境变量
> **安全提醒**:配置文件中的明文密码有泄露风险。生产环境推荐使用 `--auth-basic-file ~/.searxng_auth` 或环境变量。
## 参数参考
### search.py — 网络搜索
```bash
python scripts/search.py -q "查询词" -i https://your-instance \
[--format json|brief|urls|csv] \
[--engines google,bing,brave] \
[--time-range day|month|year|none] \
[--language zh-CN] \
[--sort-by score|date|engine|none] \
[--no-dedup] \
[--max-results 10] \
[--fetch 3] \
[--cache-ttl 30] \
[--queries-file queries.txt] \
[--include-domain example.com] \
[--exclude-domain spam.com] \
[--proxy http://corp:8080] \
[--auth-bearer-file ~/.token] \
[--verify] \
[--stream] \
[--progress] \
[--verbose|-v] [--quiet]
```
| 参数 | 说明 | 默认值 |
|------|------|--------|
| `-q / --query` | 搜索词(必填,除非用 `--verify`/`--queries-file`/`--clear-cache`/`--cache-stats` | — |
| `-i / --instance` | SearXNG 实例 URL,逗号分隔实现故障转移 | — |
| `-f / --format` | 输出格式:json/brief/urls/csv | json |
| `--engines` | 搜索引擎列表 | google,bing,brave,duckduckgo,startpage,wikipedia,wikidata |
| `-t / --time-range` | 时间范围:day/month/year/none | year |
| `-s / --safesearch` | 安全搜索:0/1/2 | 0(关闭) |
| `-l / --language` | 语言代码 | — |
| `-p / --pageno` | 页码 | 1 |
| `--sort-by` | 排序:score/date/engine/none | score(降序) |
| `--no-dedup` | 禁用跨引擎去重 | 默认开启去重 |
| `--max-results` | 限制结果数(去重+排序后截取) | 不限 |
| `--fetch N` | 自动抓取前 N 个结果的网页正文 | 0(不抓取) |
| `--cache-ttl` | 缓存分钟数 | 0(不缓存) |
| `--queries-file` | 批量查询文件(每行一个查询) | — |
| `--include-domain` | 域名白名单 | — |
| `--exclude-domain` | 域名黑名单 | — |
| `--proxy` | 代理 URL | — |
| `--auth-bearer-file` | Bearer Token 文件 | — |
| `--auth-basic-file` | Basic Auth 文件 | — |
| `--verify` | 实例健康检查模式 | — |
| `--config` | 指定配置文件 | 自动发现 |
| `--stream` | JSON Lines 流式输出(每条结果一行) | 关闭 |
| `--progress` | 进度事件(JSON Lines 到 stderr | 关闭 |
| `-v / --verbose` | 调试日志 | — |
| `--quiet` | 仅输出警告和错误 | — |
### fetch.py — 网页抓取
```bash
python scripts/fetch.py -u https://example.com \
--extract text|html|markdown \
[--encoding gbk] \
[--max-size 5242880] \
[--timeout 15] \
[--retries 3] \
[--no-redirect] \
[--proxy http://corp:8080] \
[--auth-bearer-file ~/.token]
```
| 参数 | 说明 | 默认值 |
|------|------|--------|
| `-u / --url` | 目标 URL(必填) | — |
| `-e / --extract` | 提取模式:text/html/markdown | text |
| `--encoding` | 强制字符编码 | 自动检测 |
| `--max-size` | 最大字节数 | 不限 |
| `--timeout` | 超时秒数 | 15 |
| `--retries` | 重试次数 | 3 |
| `--no-redirect` | 不跟随重定向 | 跟随 |
| `--proxy` | 代理 URL | — |
| `--auth-bearer-file` | Bearer Token 文件 | — |
| `--auth-basic-file` | Basic Auth 文件 | — |
## 能力清单
**搜索**
- 多实例故障转移 + 并行探测
- 指数退避重试(429/5xx/连接错误)
- 跨引擎去重(忽略 utm_*/gclid 等跟踪参数)
- 结果排序(score/date/engine
- 域名白名单/黑名单
- 批量查询(`--queries-file`
- 实例健康检查(`--verify`
**输出**
- JSON(默认,含完整元数据)
- brief(标题+URL+摘要)
- urls(纯 URL 列表)
- CSV(表格导出)
- 结构化 JSON 错误输出
**网页抓取**
- text:提取纯文本
- html:原始 HTML
- markdown:增强 Markdown 转换(GFM 表格、代码块、引用块、嵌套列表、定义列表)
**缓存**
- SQLite 缓存(`--cache-ttl`),相同查询在 TTL 内跳过网络
- `--clear-cache` / `--cache-stats` 管理缓存
**网络**
- 代理支持(`--proxy`
- 认证(Bearer/Basic,支持 CLI/文件/配置文件/环境变量四级优先级)
- `searxng.toml` 配置 `auth_basic` / `auth_bearer` 字段,AI Agent 一次配置即可
- 凭证文件权限警告(POSIX
**工程**
- 共享 `common.py`(统一重试/字符集/认证/日志)
- 结构化日志(`--verbose` / `--quiet`
- 结构化错误码 + `recovery_hint` 恢复建议(`E_NETWORK` / `E_AUTH` / `E_RATE_LIMIT` 等)
- JSON 输出含 `schema_version` 字段,`--dump-schema` 输出 JSON Schema 文档
- JSON Lines 流式输出(`--stream`,含 `error` 事件类型)
- 进度事件(`--progress`,含 `instance_try`/`instance_ok`/`instance_fail`JSON Lines 到 stderr
- batch 模式统一 schema`status` 字段区分成功/失败)
- 352 个单元+集成测试
## 跨 Agent 兼容性
本技能与 Agent 无关——任何能执行终端命令的 AI 均可使用:
| Agent | 调用方式 |
|-------|---------|
| Hermes | `python scripts/search.py -q "..." -i https://your-instance` |
| Claude Code | 同上,通过终端工具调用 |
| Codex (OpenAI) | 同上 |
| OpenCode | 同上 |
| Cursor | 同上 |
| Trae | 同上 |
设计要点:
- 零外部依赖(`search.py` 仅标准库)
- 脚本自注入目录到 `sys.path`,可从任意工作目录运行
- stdout 纯数据,stderr 纯日志
- 无 Agent 专属 API 调用,纯 CLI,跨平台可移植
## 测试
```bash
pip install pytest
pytest -q
```
352 个测试覆盖:缓存操作、认证解析、域名过滤、Markdown 转换、搜索逻辑、集成流程、日志配置、HTML 回退、自动抓取、健康检查、输出格式化、实例解析、并行搜索、CLI 端到端、错误码分类、流式输出、进度事件、配置文件认证、schema_version、recovery_hint、batch 统一 schema、--dump-schema。
## 项目结构
```
├── scripts/
│ ├── search.py # 搜索(多实例故障转移/缓存/批量/域名过滤)
│ ├── fetch.py # 网页抓取(text/markdown 提取)
│ ├── common.py # 共享工具(认证/重试/字符集/日志)
│ ├── cache.py # SQLite 结果缓存
│ └── _config.py # 版本号 + User-Agent
├── tests/ # pytest 单元+集成测试
├── SKILL.md # 完整技能文档(Agent 技能描述)
├── pytest.ini # 测试配置
└── README.md
```
## 许可证
MIT