scaso01/monster-search
GitHub: scaso01/monster-search
一款自托管的多引擎元搜索工具,通过智能分层和 RRF 融合,让用户用一次查询同时获取 34 个搜索引擎的结果。
Stars: 0 | Forks: 0
# monster-search
[](https://github.com/scaso01/monster-search/actions/workflows/ci.yml)
[](https://www.python.org/downloads/)
[](LICENSE)
提出一个问题,同时获取来自 34 个搜索引擎的答案。覆盖网页、学术、
代码、安全、包、WHOIS、新闻、视频、AI、社区、存档和
购物,全部集成于一个 CLI 和 Python API 之后。
它会首先读取查询内容,仅运行适合该查询的引擎,因此 CVE
标识符会被发送到漏洞数据库,而论文标题则会被发送到
学术搜索引擎。来自各个引擎的结果会被合并到一个排名列表中,
而不是作为单独的堆叠显示。
它与外界交互的所有内容要么是免费的公共 API,要么是你自行托管的
服务。这里没有付费层级,也不需要注册任何账号。

## 快速开始
```
# 安装
git clone https://github.com/scaso01/monster-search.git
cd monster-search
pip install -e ".[dev]"
# 搜索 (默认智能分层 -- 并行运行 tier1 引擎,约 15-60 秒)
monster-search "python asyncio best practices"
# 快速查询 (约 3 秒)
monster-search --engine searxng "python asyncio"
# 深度搜索,包含慢速 AI 引擎 (约 2-5 分钟)
monster-search --deep "supply chain attacks 2026"
# 检查服务健康状态
monster-search --health
```
## 引擎
34 个引擎分为 12 个类别,按 3 个优先级层级执行。
### 引擎列表
| 引擎 | 类别 | 层级 | 来源 | 耗时 |
|--------|----------|------|--------|------|
| SearXNG | 网页通用 | 1 | 自托管 (Docker, :8080) | ~3-4秒 |
| Marginalia | 网页通用 | 1 | 外部 API | ~3秒 |
| mwmbl | 网页通用 | 1 | 外部 API | ~3秒 |
| Perplexity | 网页 AI | 1 | 外部 (cookie 认证) | ~30秒 |
| Synthesizer | 网页 AI | 1 | SearXNG + Crawl4AI + llama-server | ~30-60秒 |
| Vane | 网页 AI | 2 | 自托管 (Docker, :3004) | ~2分钟 |
| Khoj | 网页 AI | 2 | 自托管 (Docker, :42110) | ~2分钟 |
| Fyin | 网页 AI | 2 | 通过 SSH 访问的主机上的 CLI | ~2分钟 |
| Local Deep Researcher | 网页 AI | 3 | 自托管 (Docker, :8300) | ~3-8分钟 |
| arXiv | 学术 | 1 | 外部 API | ~3秒 |
| Semantic Scholar | 学术 | 1 | 外部 API | ~3秒 |
| OpenAlex | 学术 | 1 | 外部 API | ~3秒 |
| Zoekt | 代码 | 1 | 自托管索引 | ~1秒 |
| OSV | 安全 | 1 | 外部 API (osv.dev) | ~2秒 |
| deps.dev | 包 | 1 | 外部 API | ~2秒 |
| Who-Dat | 域名/WHOIS | 1 | 自托管 (Docker, :8083) | ~1秒 |
| News (SearXNG) | 新闻 | 1 | 自托管 (Docker, :8080) | ~5秒 |
| GNews | 新闻 | 1 | 外部 RSS | ~2秒 |
| Archive.org | 存档 | 1 | 外部 API (CDX + catalog) | ~10秒 |
| YouTube | 视频 | 1 | yt-dlp + youtube-transcript-api | ~5-10秒 |
| grep.app | 代码 | 1 | 外部 API | ~3秒 |
| GitHub Code Search | 代码 | 1 | gh CLI 子进程 | ~5秒 |
| GitHub Repos | 代码 | 1 | gh CLI 子进程 | ~3秒 |
| searchcode_repo | 代码 | 选填 | searchcode.com API (需要 --repo) | ~2秒 |
| Hacker News | 社区 | 1 | Algolia API | ~2秒 |
| HuggingFace | AI/ML | 1 | HuggingFace Hub API | ~3秒 |
| Reddit | 社区 | 1 | Reddit Atom feed | ~3秒 |
| CheapShark | 购物 | 1 | CheapShark API | ~2秒 |
| SlickDeals | 购物 | 1 | SlickDeals API | ~3秒 |
| Crawl4AI | 工具 | -- | 自托管 (Docker, :11235) | ~15秒 |
| changedetection.io | 工具 | -- | 自托管 (Docker, :8086) | -- |
**注意事项:**
- 第 1 层级引擎默认在每次查询时运行(始终开启 + 路由控制的专业引擎)。
- 当第 1 层级结果稀少(< 3 个结果)时,第 2 层级引擎会自动提升执行。
- 第 3 层级引擎仅在指定 `--deep` 或进行深度研究查询时运行。
- Crawl4AI 接收 URL(页面提取)而非查询。changedetection.io 监控 URL 变更。
- Meilisearch 作为后台结果缓存运行(不是搜索引擎)。
- 路由控制的引擎(学术、安全、包、代码、WHOIS、存档)仅在查询通过 regex 分类匹配到其类别时才会激活。
### 类别
| 类别 | 引擎 | 触发条件 |
|----------|---------|---------|
| 网页通用 | searxng, marginalia, mwmbl | 始终开启 |
| 网页 AI | perplexity, synthesizer, vane, khoj, fyin, local_researcher | 始终开启 (tier1) / 提升执行 (tier2) / 深度执行 (tier3) |
| 学术 | arxiv, semantic_scholar, openalex | 查询包含 paper/research/arxiv/doi 关键词 |
| 代码 | zoekt, grepapp, github_code, github_repos | 查询包含代码结构 (.py, func, class 等) |
| 安全 | osv | 查询包含 CVE/GHSA/vulnerability 关键词 |
| 包 | deps | 查询包含生态系统前缀 (npm:, pypi:, cargo: 等) |
| 域名/WHOIS | whodat | 查询包含域名或 IP 地址 |
| 新闻 | news, gnews | 查询包含 latest/breaking/headlines 关键词 |
| 存档 | archive_org | 查询包含 wayback/archive/cached 关键词或是 URL |
| 视频 | youtube | 查询包含 video/tutorial/watch 关键词 |
| 社区 | hackernews, reddit | 查询包含 discussion/forum/community 关键词 |
| AI/ML | huggingface | 查询包含 model/dataset/ML 关键词 |
| 购物 | cheapshark, slickdeals | 查询包含 buy/price/deal/discount 关键词 |
## 智能分层执行
默认搜索模式(`monster-search "query"`)采用智能分层:
1. 通过 regex 模式**分类**查询(安全、学术、代码、新闻等)
2. 并行**运行第 1 层级**引擎(始终开启 + 类别匹配的专业引擎)
3. 如果第 1 层级产生的结果少于 3 个,则**自动提升第 2 层级**
4. **第 3 层级**仅在指定 `--deep` 或进行深度研究查询时运行
5. 通过加权 Reciprocal Rank Fusion (RRF) **融合**结果
6. 通过 MinHash LSH 内容相似度进行**去重**
```
Tier 1 (fast, ~15-60s): searxng, marginalia, news, gnews, perplexity,
synthesizer, + router-gated specialists
Tier 2 (medium, ~2 min): vane, khoj, fyin
Tier 3 (slow, ~3-8 min): local_researcher
```
### 熔断器
每个引擎都有一个独立的熔断器。在多次连续失败后,熔断器会打开并在冷却期内跳过该引擎 —— 从而防止一个损坏的服务拖慢整个搜索过程。
### RRF 融合
来自多个引擎的结果使用加权 Reciprocal Rank Fusion 进行合并。每个引擎都有一个质量权重(perplexity: 1.0, searxng: 0.9, marginalia: 0.85 等)。重复的 URL 会与所有相关引擎的元数据合并。
### MinHash 去重
在融合之后,MinHash LSH 步骤会根据片段相似度移除近似重复的内容(Jaccard 阈值 0.5,3-gram shingles)。短文本会回退到基于 URL 的去重。
## CLI 参考
```
monster-search [OPTIONS] QUERY
```
### 核心选项
| 标志 | 描述 |
|------|-------------|
| `--engine NAME` | 运行特定的引擎或类别别名 |
| `--deep` | 包含慢速 AI 引擎 (tier2 + tier3) |
| `--category {general,news,images,science,files}` | SearXNG 类别过滤器 |
| `--time-range {day,week,month,year}` | 时间过滤结果 |
| `--max-results N` | 覆盖默认值 (5) |
| `--json` | 输出 JSON 以便管道传输 |
| `--no-fuse` | 禁用 RRF 融合(传统的首次出现去重) |
| `--model MODEL` | 覆盖 AI 引擎使用的 LLM 模型 |
| `--benchmark` | 使用计时表对引擎进行基准测试 |
| `--health` | 检查服务健康状态 |
### 引擎和类别别名
```
# 单个引擎
monster-search --engine searxng "query"
monster-search --engine marginalia "query"
monster-search --engine perplexity "query"
monster-search --engine synthesizer "query" # alias: --engine synth
monster-search --engine vane "query"
monster-search --engine khoj "query"
monster-search --engine fyin "query"
monster-search --engine local_researcher "query"
monster-search --engine news "topic"
monster-search --engine gnews "topic"
monster-search --engine archive_org "query or URL"
monster-search --engine crawl "https://url" # page extraction (URL only)
monster-search --engine arxiv "transformer"
monster-search --engine semantic_scholar "attention"
monster-search --engine openalex "machine learning"
monster-search --engine osv "pypi:jinja2"
monster-search --engine deps "npm:express"
monster-search --engine whodat "example.com"
monster-search --engine zoekt "func main"
# 类别别名 (并行运行分组引擎并融合结果)
monster-search --engine academic "transformer" # arxiv + semantic_scholar + openalex
monster-search --engine code "func main" # zoekt + grepapp + github_code
monster-search --engine security "pypi:jinja2" # osv
monster-search --engine packages "npm:express" # deps
monster-search --engine whois "example.com" # whodat
monster-search --engine video "rust tutorial" # youtube
monster-search --engine ai_ml "text generation" # huggingface
monster-search --engine shopping "laptop" # searxng shopping + slickdeals + cheapshark
# + deals_rss + priceghost + amazon + newegg
monster-search --engine deals "ssd" # slickdeals + deals_rss + amazon
# 全面扫描
monster-search --engine all "query" # all 34 engines (~2-5 min)
```
别名会并发运行其包含的引擎并合并返回的结果,因此单一的
学术查询会返回根据排名交错排列的 arXiv 和 OpenAlex 结果,
而不是按来源分组:

### URL 变更监控
```
monster-search watch add "https://example.com" --tag news
monster-search watch list
monster-search watch list --tag news
monster-search watch check UUID
monster-search watch diff UUID
monster-search watch remove UUID
```
## Python API
```
from monster_search import (
SearXNGClient, AllEnginesClient, MarginaliaClient,
PerplexityClient, Crawl4AIClient, LocalResearcherClient,
NewsSearchClient, ArchiveOrgClient, VaneClient,
ChangeDetectionClient, Config, check_health,
)
import asyncio
# 快速搜索 (约 3 秒)
results = SearXNGClient().search("python asyncio", max_results=5)
# AI 合成 (约 30 秒)
message, results = PerplexityClient().search("latest frameworks")
# 智能分层搜索 (async,推荐默认)
client = AllEnginesClient()
message, results = asyncio.run(client.smart_search("query"))
# 深度搜索,包含慢速引擎
message, results = asyncio.run(client.smart_search("query", include_slow=True))
# 页面提取 (接收 URL,而非查询)
content, results = Crawl4AIClient().search("https://example.com")
# URL 监控
cd = ChangeDetectionClient()
cd.add_watch("https://github.com/trending", tag="github")
# 健康检查
status = check_health()
```
### SearchResult 模型
每个引擎都会返回 `SearchResult` 对象:
```
@dataclass(frozen=True, slots=True)
class SearchResult:
title: str
url: str
snippet: str
source: str # engine name or "fused"
engine: str | None = None # upstream engine (e.g., "google")
score: float | None = None
published: str | None = None
category: str | None = None
sources: tuple[str, ...] | None = None # engines that found this URL
fused_score: float | None = None # weighted RRF score
```
## 前置条件
**起步阶段无需任何前置条件。** Python 3.12 和 `pip install` 就足够了。下面
“外部 API”表格中的每一个引擎都是免费且无需密钥的,因此新克隆的项目
开箱即可搜索大约二十个引擎。任何你尚未设置的服务都会
报告自身不可用并被跳过,而不会导致搜索失败。
其余的都是你自行托管的。每一项都会增加相应的引擎;但全都不是
强制的。将匹配的 `MONSTER_*_URL` 指向你运行它的位置,
不设置即可保持该引擎处于关闭状态。
| 服务 | 默认端口 | 增加的功能 |
|---------|--------------|------|
| [SearXNG](https://github.com/searxng/searxng) | :8080 | 通用网页和新闻搜索,以及 synthesizer 撰写答案所依据的来源 |
| [Vane](https://github.com/ItzCraworzyy/Perplexica) | :3004 | AI 搜索 (Perplexica 的一个 fork) |
| [Khoj](https://github.com/khoj-ai/khoj) | :42110 | AI 聊天和搜索,匿名模式 |
| [Local Deep Researcher](https://langchain-ai.github.io/langgraph/) | :8300 | 迭代多步研究 |
| [Crawl4AI](https://github.com/unclecode/crawl4ai) | :11235 | 提取 JavaScript 渲染的页面 |
| [changedetection.io](https://github.com/dgtlmoon/changedetection.io) | :8086 | `watch` 子命令 |
| [Who-Dat](https://github.com/MoeClub/whodat) | :8083 | WHOIS 查询 |
| [Zoekt](https://github.com/sourcegraph/zoekt) | :6070 | 跨自有仓库的 regex 代码搜索 |
| [Meilisearch](https://github.com/meilisearch/meilisearch) | :7700 | 缓存,使得重复查询能瞬间返回 |
| 任何 OpenAI 兼容的 LLM | :8080 | Synthesizer 生成的书面回答。[llama-server](https://github.com/ggml-org/llama.cpp), Ollama 和 vLLM 均可工作 |
外部 API(无需容器):
| 服务 | 认证 | 备注 |
|---------|------|-------|
| [Marginalia](https://search.marginalia.nu/) | 无 | 独立的网络索引,遵循 CC-BY-NC-SA 4.0 协议 |
| [Perplexity](https://www.perplexity.ai/) | Session cookie | 大约每月需手动刷新 |
| [arXiv](https://arxiv.org/) | 无 | 预印本搜索 API |
| [Semantic Scholar](https://www.semanticscholar.org/) | 无 | 学术论文搜索 |
| [OpenAlex](https://openalex.org/) | 无 | 开放的学术作品 |
| [OSV.dev](https://osv.dev/) | 无 | 漏洞数据库 |
| [deps.dev](https://deps.dev/) | 无 | 包元数据 |
| [Who-Dat](https://github.com/MoeClub/whodat) | 无 | WHOIS 查询 |
| [GNews](https://news.google.com/) | 无 | Google News RSS |
| [Archive.org](https://archive.org/) | 无 | CDX + 高级搜索 |
其中一个引擎 **fyin** 是一个 CLI 二进制程序而不是服务,因此它会在你
安装它的主机上通过 SSH 运行。在你设置 `MONSTER_SSH_HOST` 之前,它将保持关闭状态。请参阅 [通过 SSH 运行的引擎](#engines-that-run-over-ssh)。
`--health` 会向你展示当前的配置状态。它会对每个
引擎发出真实的查询,而不是仅 ping 端口,因此如果某个引擎做出了响应但返回的
内容不可用,它也会被报告为宕机。在下面的例子中,除了
fyin 之外,一切都已配置完毕,因为 fyin 没有设置 SSH 主机。

## 架构
```
src/monster_search/
├── __init__.py # Public API exports
├── models.py # SearchResult frozen dataclass (sources, fused_score)
├── config.py # Config from MONSTER_* env vars
├── health.py # Container health probes
├── cli.py # CLI entry point (argparse + watch routing)
├── benchmark.py # Engine benchmarking (--benchmark)
├── fusion.py # Weighted RRF with metadata merge
├── _tiered.py # Tiered execution engine (tier1/2/3)
├── _router.py # Regex query classifier (9 categories)
├── _breaker.py # Per-engine circuit breakers
├── _dedup.py # MinHash LSH content deduplication
├── __main__.py # python -m support
└── clients/
├── _pool.py # Connection pool (reusable httpx clients)
├── searxng.py # SearXNG JSON API (sync + async)
├── marginalia.py # Marginalia independent search
├── perplexity_client.py # Perplexity AI synthesis (cookie auth)
├── synthesizer.py # AI synthesis (SearXNG + Crawl4AI + llama-server)
├── local_researcher.py # Local Deep Researcher LangGraph REST
├── crawl4ai_client.py # Crawl4AI page extraction
├── news.py # SearXNG news category, date-sorted
├── gnews.py # Google News RSS
├── archive_org.py # Archive.org CDX + Advanced Search
├── vane.py # Vane AI search (dynamic provider IDs)
├── khoj.py # Khoj AI chat/search (anonymous)
├── fyin.py # Fyin search over SSH
├── arxiv.py # arXiv preprint search
├── semantic_scholar.py # Semantic Scholar papers
├── openalex.py # OpenAlex works
├── osv.py # OSV.dev vulnerabilities
├── deps.py # deps.dev package info
├── whodat.py # Who-Dat WHOIS lookup
├── zoekt.py # Zoekt code search
├── meilisearch_client.py # Meilisearch result cache (background)
├── changedetection_client.py # changedetection.io URL monitoring
└── all_engines.py # Composite: tiered parallel + RRF fusion
```
## 配置
所有设置均通过 `MONSTER_*` 环境变量进行。将 `.env.example` 复制为 `.env`:
```
cp .env.example .env
```
主要变量:
| 变量 | 默认值 | 描述 |
|----------|---------|-------------|
| `MONSTER_SEARXNG_URL` | `http://localhost:8080` | SearXNG 基础 URL |
| `MONSTER_DEFAULT_ENGINE` | `all` | 默认 CLI 引擎 |
| `MONSTER_MAX_RESULTS` | `5` | 每个引擎的结果数 |
| `MONSTER_TIMEOUT` | `15` | HTTP 超时时间 (SearXNG) |
| `MONSTER_PERPLEXITY_SESSION_TOKEN` | -- | Perplexity cookie (每月刷新) |
| `MONSTER_PERPLEXITY_TIMEOUT` | `90` | Perplexity 超时时间 |
| `MONSTER_VANE_URL` | `http://localhost:3004` | Vane AI 搜索 URL |
| `MONSTER_VANE_TIMEOUT` | `300` | Vane 超时时间 |
| `MONSTER_KHOJ_URL` | `http://localhost:42110` | Khoj AI 搜索 URL |
| `MONSTER_KHOJ_TIMEOUT` | `300` | Khoj 超时时间 |
| `MONSTER_ZOEKT_URL` | `http://localhost:6070` | Zoekt 代码搜索 URL |
| `MONSTER_WHODAT_URL` | `http://localhost:8083` | Who-Dat WHOIS URL |
| `MONSTER_MEILISEARCH_URL` | `http://localhost:7700` | Meilisearch 结果缓存 URL |
| `MONSTER_MEILISEARCH_KEY` | -- | Meilisearch API 密钥 |
| `MONSTER_LLAMA_URL` | `http://localhost:8080` | Synthesizer 的 OpenAI 兼容 endpoint |
| `MONSTER_SYNTHESIZER_TIMEOUT` | `120` | Synthesizer 超时时间 |
| `MONSTER_SSH_HOST` | -- | SSH 路由引擎的远程主机(见下文) |
| `MONSTER_FYIN_ENV_FILE` | -- | 在 fyin 之前在该主机上 source 的可选环境变量文件 |
| `MONSTER_FYIN_TIMEOUT` | `300` | Fyin SSH 超时时间 |
| `MONSTER_LOCAL_RESEARCHER_URL` | `http://localhost:8300` | Local Deep Researcher URL |
| `MONSTER_LOCAL_RESEARCHER_TIMEOUT` | `600` | Local Researcher 超时时间 |
| `MONSTER_CRAWL4AI_URL` | `http://localhost:11235` | Crawl4AI URL |
| `MONSTER_CRAWL4AI_TIMEOUT` | `60` | Crawl4AI 超时时间 |
| `MONSTER_ARCHIVE_ORG_TIMEOUT` | `60` | Archive.org 超时时间 |
| `MONSTER_CHANGEDETECTION_URL` | `http://localhost:8086` | changedetection.io URL |
| `MONSTER_CHANGEDETECTION_API_KEY` | -- | changedetection.io API 密钥 |
| `MONSTER_SEMANTIC_SCHOLAR_API_KEY` | -- | 免费密钥;如果没有密钥,该引擎将被跳过 |
| `MONSTER_GREPAPP_ENABLED` | `false` | grep.app 默认关闭(它会在许多网络中触发 429 错误) |
`.env.example` 列出了每一个变量及其真实的默认值。这两者会相互
检查,如果这里的默认值与代码不一致,那就是一个 bug。
### 通过 SSH 运行的引擎
有两个引擎是通过 SSH 在 shell 中运行而不是使用 HTTP 通信的,在
你将 `MONSTER_SSH_HOST` 设置为 `ssh` 接受的值(`user@host`)之前,它们都处于关闭状态:
- **fyin** 需要在该主机上安装 `fyin` 二进制文件。如果未设置主机,它将
报告为禁用状态,而不会在查询时报错。
- **archive.org** 查询默认直接发出。archive.org 会严格限制
某些 VPN 出口 IP 的速率 —— 在 CDX 上持续出现 HTTP 429,有时是 TCP
超时 —— 因此设置主机后会改为通过 `curl` 在那里路由
请求。仅当你自己的出口 IP 是被阻止的 IP 之一时才执行此操作。
此工具中的其他任何操作都不会打开 SSH 连接。
## 测试
```
# 单元测试:所有 HTTP 调用均为 mocked,无需服务。这是 CI 运行的内容。
pytest tests/ -m "not integration"
# 集成测试:向真实服务发起真实请求。
pytest tests/test_integration.py -m integration
# ...不包含每个耗时约两分钟的 AI 引擎。
pytest tests/test_integration.py -m "integration and not slow"
# Lint
pyflakes src/monster_search/ tests/
```
单元测试套件通过 `respx` 模拟 HTTP 且不进行任何网络调用,因此它是
确定的,可以在任何地方安全运行。
集成测试套件用于捕获那些已经悄悄
停止工作的引擎。搜索提供商会毫无预兆地更改 endpoint,而
模拟的测试在发生这种情况时仍会通过,因为 mock 依然返回
旧的数据结构。当所需的服务不可达或未配置时,那里的每个测试
都会自动跳过,因此部分的配置只会产生跳过而不会
导致失败。
## 许可证
MIT 许可证。详情请参阅 [LICENSE](LICENSE)。
标签:Python, 信息检索, 元搜索, 搜索引擎, 无后门, 聚合搜索, 自托管, 请求拦截, 逆向工具