关于 Web Search
Web Search 是面向 Agent 的本地命令行工具和技能,可免 API 密钥搜索多个引擎、抓取网页并提取 Markdown。适合需要自托管检索的场景;项目不提供 MCP 服务。
主要功能
- 01免密搜索多个引擎
- 02搜索结果去重与排序
- 03抓取网页并提取 Markdown
- 04分页读取缓存页面
- 05搜索 arXiv 和 GitHub
适用场景
- 01无需搜索 API 密钥查找网页
- 02在上下文限制内阅读长页面
- 03搜索论文和代码仓库
- 04通过自托管 SearXNG 搜索
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
6收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| site | any | 否 | 限制为单个主机(例如,"docs.python.org")。 |
| query | string | 是 | 搜索查询,例如 "rust ownership model" 或 "site:nature.com crispr"。 |
| detail | string | 否 | "concise"(默认)会省略每条结果的引擎和评分,以节省令牌; "detailed" 会包含这些信息。 |
| country | any | 否 | ISO 3166-1 alpha-2 国家/地区代码(例如,"us");省略则使用引擎默认值。 |
| language | any | 否 | ISO 639-1 语言代码(例如,"en");省略则使用引擎默认值。 |
| freshness | string | 否 | 以下之一:"any"、"day"、"week"、"month"、"year"(尽力提供近期内容)。 |
| safesearch | string | 否 | 以下之一:"off"、"moderate"、"strict"。 |
| max_results | integer | 否 | 要返回的结果数量(默认 8)。研究时可调高,快速查询时可调低;0 表示不设上限(返回引擎提供的所有结果)。 |
详细介绍
websearch-skill
面向 AI Agent 的开源多引擎网页搜索与内容提取工具。内部各层通过有版本控制的 JSON Schema 契约进行通信。
状态:早期阶段。 首次公开发布于 2026-06-22;当前版本见
CHANGELOG.md。现已提供:无密钥搜索、Markdown 提取、五个 Agent 命令、可自托管的 SearXNG,以及通过两个环境变量启用并锁定的 NordVPN 出口代理。这些功能均有测试套件覆盖。没有 MCP 服务;请直接使用 CLI,或安装此技能(见下方“没有 MCP”)。严格反机器人检测层和本地重排仍在路线图中。使用敏感数据前,请固定版本并在沙盒中测试。
它是什么
面向 AI Agent 的可自托管网页搜索和页面阅读工具,无需 API 密钥或付费搜索服务。它会查询多个引擎,合并并去重结果,然后将页面抓取为干净的 Markdown。CLI 在本地运行,并将查询直接发送到已配置的引擎。
核心命令:
init读取设置文件,启动本地 SearXNG(若启用该层,也会启动 Tor),并报告可用功能。web_search查找页面:跨引擎返回经过排序和去重的结果,每个结果都带有可复用的handle。web_fetch阅读页面:返回干净的 Markdown,并用围栏标记为不可信内容;支持分页,因此长页面不会溢出上下文。web_open从缓存中继续阅读已抓取文档的后续页面,无需再次访问网络。
其他无密钥命令:
arxiv搜索 arXiv 论文并返回结构化元数据(作者、摘要、类别、摘要和 PDF 链接)。github搜索 GitHub 仓库并返回可供排序的类型化字段(星标数、语言、主题)。tor启动本地 Tor 并通过它路由所有流量,从而访问.onion地址,并通过--onion搜索 Tor 索引。默认关闭;见下方的 Tor 部分。
一个运行时,一次调用
整个工具包是一个包含单个 CLI websearch 的 Python 包。没有 Node 服务、没有 npm 运行时、没有自带守护进程,也无需编排;唯一要求是 uv,它会自行获取兼容的 Python。安装部分中的 npx skills add 命令会将技能文件夹复制到 Agent 中;之后不会再运行任何 Node 程序。
Agent 只需一次调用即可启动所有功能:
websearch init
init 会读取设置文件,在本地 SearXNG 尚未运行时启动它;若启用了 Tor 层,也会启动 Tor;随后运行自检并报告功能和后续操作。无需预先探测,也无须遵循特定顺序:无论是在全新的机器上,还是所有服务都已启动的机器上,同一次调用都适用。
SearXNG 是工具包代为管理的可选额外搜索引擎目录:init(或 websearch searxng up)会克隆它,将其安装到自己的虚拟环境中,并作为独立的本地 Python 进程运行。绝不需要 Docker;docker/searxng/ 仅供更偏好容器的主机使用。
开箱即用的引擎,无需密钥
默认引擎是无需密钥的 ddgs 元搜索库,覆盖 Google、Brave、DuckDuckGo、Yandex、Yahoo、Startpage、Mojeek、Wikipedia 和 Grokipedia。每次查询都会使用有响应的提供商。面向 Agent 的 web-search 命令无需账户、服务或引擎标志。较底层的 search 命令可通过 --ddgs-backends google,brave,mojeek 限定提供商。提供商的可用性因网络而异;websearch doctor 会逐一报告各提供商的状态。
若要获得更广泛、更可靠的搜索,你可以运行自己的 SearXNG(约 280 个引擎、使用自己的服务器,仍然无需密钥);路由器会将其与 ddgs 结果融合,并消除它们共享引擎造成的相关性。websearch searxng up 可在任何装有 git 和 Python 的机器上完成设置并启动;在 Docker 主机上,docker/searxng/ 是经过整理的配置,其中包含一个探测工具,可启用所有能在你的连接上响应的引擎。请参阅下文的自托管 SearXNG。公共 SearXNG 实例不会被设为默认选项:大多数实例会禁用 JSON API 并限制自动化客户端的请求频率,因此依赖它们会导致全新安装无法正常工作。
本项目采用 MIT 许可证。可选集成包括自托管 SearXNG、需要密钥的引擎(Brave、Exa、Tavily)以及付费出口适配器。
下方的对比表比较了结果质量、延迟、成本、隐私和检索限制。软件层免费且可自托管,支持多引擎搜索、去重和 Markdown 提取。受保护的网站可能需要计划中的付费出口适配器;住宅代理和 CAPTCHA 求解没有可靠的免费替代方案。
层级状态
| 层级 | 功能 | 状态 |
|---|---|---|
| Layer 1:搜索 | 多引擎路由器(通过无需密钥的 ddgs 使用多个引擎,可选自托管 SearXNG)、规范化、去重、消除相关性的 RRF 融合 | 已构建 |
| Layer 2A:抓取 + 提取 | 分层抓取(httpx、curl_cffi 模拟)、使用 Trafilatura 将内容提取为 Markdown + 元数据 | 已构建 |
| Layer 2B:格式化 + 存储 | 分页 Markdown + JSON 伴随文件、渐进式披露索引/解析器、MinHash 去重、临时 SQLite-FTS5 存储 | 已构建 |
| Layer 3:Agent I/O | 整合的 web_search/web_fetch/web_open、不可信内容隔离、SKILL.md | 已构建 |
| 额外工具 | 无需密钥的 arxiv(论文搜索)和 github(代码仓库搜索),基于同一 Envelope 独立运行 | 已构建 |
| 诊断 | websearch doctor:对可选层、每个引擎、工具以及两个抓取层进行逐项能力自测 | 已构建 |
| 初始化 | websearch init:读取设置文件、启动 SearXNG 和 Tor、运行诊断并报告能力状态 | 已构建 |
| Tor | websearch tor:无需 Docker 的本地 Tor、洋葱网络搜索(Ahmia、SearXNG 的 onions 类别)和 .onion 抓取;通过现有代理进行链式连接,而不是替换现有代理 | 已构建 |
契约以 JSON Schema 2020-12 冻结:[email protected]、[email protected]、[email protected]、[email protected]、[email protected]、[email protected]、[email protected]、[email protected]、[email protected]、[email protected]、[email protected]、[email protected]、[email protected]、[email protected]。每个响应都封装在一个 Envelope { contract_version, ok, data, error, meta } 中。
第 1 层:搜索
搜索会规范化请求,将其发送给每个已配置的 EngineAdapter,对 URL 进行规范化和去重,并使用加权倒数排名融合(RRF,k=60)合并排名。默认的免密钥选项是 ddgs,这是一个元搜索库,支持 Google、Brave、DuckDuckGo、Yandex、Yahoo、Startpage、Mojeek、Wikipedia 和 Grokipedia。在较低层级的 search 命令中,--ddgs-backends 用于选择提供商子集,--engines 用于选择 ddgs 和 SearXNG 适配器。面向 Agent 的 web-search 命令使用默认值。设置 WEBSEARCH_SEARXNG_URL 可添加可自托管的 SearXNG 实例。Brave、Exa 和 Tavily 等需密钥的引擎计划后续支持。
ddgs 是一个免密钥的 Python 库,在进程内运行。SearXNG 是独立的可自托管服务,拥有更大的引擎目录。搜索可以使用任一适配器,也可以组合使用两者。SearXNG 只提供搜索结果;页面抓取和提取仍由第 2A 层负责。
去相关处理可防止重复的上游数据扭曲排名。SearXNG 和 ddgs 都会使用 Google 和 Bing 等爬虫,因此简单合并结果可能会对同一来源重复计数。结果会按 correlation_group 分组;每组根据其最佳排名贡献一个 RRF 项,且共识加分只使用不同分组的数量。SearXNG 和 ddgs 达成一致算作一票独立意见;SearXNG 和神经索引达成一致则算作两票。应用去相关处理时,响应中会包含一条警告。
每条结果都会记录返回该结果的引擎,以及该结果在各引擎中的排名。
第 2A 层:抓取 + 提取
抓取和提取使用独立的接口,可以分别替换。
抓取首先使用 httpx,仅在检测到反机器人挑战时才使用 curl_cffi 的浏览器模拟功能重试。对于 404、限流、身份验证失败,以及法律限制和地理封锁,不会重试,因为相同的网络地址不太可能改变结果。检测会先检查响应标头,然后检查 Cloudflare、DataDome、PerimeterX、Akamai 和 Imperva 的已知正文标记。每种状态都会检查 Imperva 正文标记,因为其封锁可能返回 HTTP 200。浏览器和隐匿层级(Crawl4AI、nodriver)已纳入接口约定,但不包含在基础安装中。
提取默认使用 Trafilatura,这是一种启发式提取器。根据 2026 年 5 月的 WCXB 基准测试,启发式提取器在质量和成本方面都优于神经提取器(神经提取的成本高出数十到数百倍),而 Trafilatura 在 CPU 上约 100 毫秒即可达到约 0.79 的 F1;文章页面的 F1 通常在 0.93 左右饱和。适配器会先用 lxml 解析一次原始 HTML,以恢复原始的 schema.org JSON-LD 块和 og:type(Trafilatura 会将 JSON-LD 合并到元数据中,且不会公开原始块),再运行 Trafilatura 提取 Markdown 正文、纯文本和元数据,随后计算:
- 基于运行时信号(文本密度、字数饱和度、段落数、链接密度的倒数、JSON-LD 是否存在、标题是否简洁)的启发式
quality_score(0..1),并对软 404 和空壳页面进行硬性否决;低于约 0.80 的页面可作为回退候选。 - 由 JSON-LD
@type、og:type,再到 URL 形态依次确定的低成本page_type。
神经提取引擎(crawl4ai、jina_readerlm 等)已列在接口约定的枚举中,但仍为可选项。默认依赖闭包较为宽松:Apache-2.0(trafilatura)以及 MIT/BSD/MPL 依赖项。
提取不会截断 content_markdown。--max-bytes 用于限制下载的响应大小,--max-bytes 0 则会禁用此传输限制。值为 0 时也会禁用 --max-results、--page-size-tokens 和 --per-page,但仍受提供商限制约束,例如 GitHub 每页最多返回 100 条结果,arXiv 每次请求最多返回 2,000 条结果。
Layer 2B:格式化 + 存储
这一层为 Agent 格式化结果,并存储完整页面以供后续访问。
格式化会将 Layer 1 和 Layer 2A 中与供应商无关的结果,渲染为布局稳定的 Markdown 文档,以及包含相同数据的 JSON 伴随文件。结果按相关性排序,并根据配置的 token 预算分页。首先进行近似重复项去重:先按字节精确匹配(规范化 SHA-256),再通过纯 Python MinHash 对词语 4-gram 分片进行处理(128 次置换,Jaccard 相似度 0.9),并使用并查集聚类。每个簇中保留得分最高的页面,其余页面列在 dropped_duplicates 中。默认阈值会合并镜像和转载副本等近乎相同的页面,同时保留仅主题相似的页面。对于包含大量模板文本的语料库,可降低 jaccard_threshold。该实现不依赖 datasketch。渐进式披露会控制内联内容的多少:
auto(默认)在页面符合 token 预算时内联完整正文,否则切换到索引(预览加稳定的id)。- **
index始终显示预览和解析提示;full**始终内联完整内容。
可选的 anthropic_search_result_blocks 视图与 Anthropic search_result 内容块一一对应(source 为不带包装的字符串,至少包含一个非空文本块,引用要么全部提供,要么全部不提供)。默认关闭,并与规范响应格式分开。
伴随文件和存储会在所有模式下保留完整正文。body_char_budget 会将内容从渲染后的 Markdown 视图移至解析器,并添加查找提示;不会修改存储的内容。--no-truncate 会将完整正文保留为内联内容。
存储通过 PageIndex 接口(add / search / get / resolve_index)索引抓取的页面。每个查询的结果集仍以普通 Python 对象形式保留;只有抓取的页面会进入索引。默认适配器使用 SQLite FTS5 和 BM25,且无需第三方包。如果本地 SQLite 构建不支持 FTS5,则会回退到纯 Python BM25 索引,响应格式不变。添加操作会根据 URL 和内容哈希实现幂等;查询会在传入 FTS5 前进行转义;指定文件路径即可启用持久化。可选的向量或 Rust 后端也可以实现相同的接口。
Layer 3:Agent 输入 / 输出
Layer 3 提供 web_search(查找)、web_fetch(读取 URL)和 web_open(翻阅已抓取的文档)。每个工具都返回相同的 Envelope。CLI 和可移植的 SKILL.md 使用相同的实现。该技能遵循 Agent Skills 格式,可安装在 Claude Code、Codex、OpenCode 和其他兼容的 Agent 中。
命令使用便于阅读的 handle(site~shorthash,例如 en.wikipedia.org~3a1f9c2b5e6f)来引用页面。web_fetch 会将完整页面索引到 Layer 2B 存储中,并返回一个符合 token 预算的页面;web_open 会从该存储中读取后续页面,而不会再次抓取 URL。由于每条命令都会在新进程中运行,默认情况下,存储会保存在 env 文件旁边的文件中,或 XDG 缓存目录中。--persist-path off 会将其保留在内存中。分页不会丢弃内容;完整正文仍可按页访问。较低层的 search / fetch / open 命令仍可用于调试和组合调用。
抓取的页面文本不可信,因此 web_fetch 和 web_open 会用围栏包裹每个页面(参见 Security)。围栏内的内容会作为工具输出返回,并与用户指令分开。
额外的免密钥工具
有两个独立工具可处理常规网页搜索难以覆盖的信息源。它们都无需密钥,并使用相同的 Envelope:
arxiv通过官方 Atom API 搜索 arXiv,并返回结构化论文信息(标题、作者、摘要、类别,以及摘要和 PDF 链接)。它支持按字段定向搜索(--field title|author|abstract),并可按日期或相关性排序;它使用 GET,因此可受益于 arXiv 的缓存,并会在 2026 年的限流情况下退避。github通过未经身份验证的 REST API 搜索 GitHub 仓库,并返回类型化字段(完整名称、星标数、复刻数、语言、主题、更新时间)。未经身份验证的搜索每分钟约有 10 次请求限额;请求受限时会返回rate_limited错误。代码搜索需要令牌,不包含在免密钥路径中。
uv run websearch arxiv "diffusion models for protein design" --max-results 5 --sort-by submittedDate
uv run websearch github "vector database" --language Rust --sort stars --per-page 10
没有专门的 Reddit 或 X 工具,因为截至 2026 年,两者都没有符合其服务条款的免密钥搜索 API(截至 2026 年 5 月,Reddit 的匿名 JSON 端点会返回 403;X 则要求付费 API 或已登录的账号)。请使用开放网页的站点过滤器:
uv run websearch web-search "rust async" --site reddit.com
uv run websearch web-search "frontier model release" --site x.com
不再提供 MCP(自 0.3.0 起)
版本 0.3.0 移除了 MCP 服务。该服务是一个长期运行的进程,会在启动时读取配置并缓存其引擎集。更改代理、可自托管的 SearXNG、引擎选择或 env 文件后,都需要重启客户端。CLI 命令会启动新进程,并在每次调用时读取配置。websearch init 会处理设置并报告最终功能。
对于现有的 websearch mcp 安装,请使用 npx skills add hec-ovi/websearch-skill 安装技能;它会通过 Agent 的 shell 提供这些命令。
安装
选择适合你使用方式的方案。所有功能都无需密钥,但需要联网;唯一的硬性要求是 uv。各运行环境的完整安装说明(Claude Code、Codex、OpenCode、Cursor、Hermes、OpenClaw,以及 PyPI 发布)请参阅 docs/INSTALL.md。
作为 CLI 工具使用,无需安装(uvx 会构建临时环境并运行它):
uvx websearch-skill web-search "your query"
# or straight from git, for an unreleased commit:
uvx --from git+https://github.com/hec-ovi/websearch-skill websearch web-search "your query"
作为 Agent 技能使用,通过 skills CLI 支持 40 多种 Agent(它会将 skills/web-search/ 目录安装到检测到的每个 Agent 中):
npx skills add hec-ovi/websearch-skill # all detected agents
npx skills add hec-ovi/websearch-skill -a claude-code -a codex -s web-search
作为 Claude Code 插件使用:
/plugin marketplace add hec-ovi/websearch-skill
/plugin install web-search@websearch-skill
从源代码安装(开发环境,原生使用 uv):
git clone https://github.com/hec-ovi/websearch-skill
cd websearch-skill
uv sync
uv run websearch web-search "your query"
快速入门
无需任何设置即可搜索:默认使用免密钥的 ddgs 元搜索。面向 Agent 的 web-search(第 3 层)无需引擎标志。较低层级的 search(第 1 层)用于调试和高级用法,也是唯一接受 --engines、--ddgs-backends 和 --no-ddgs 的命令:
# Layer 1: search (keyless, multi-engine via ddgs)
uv run websearch search "rust ownership" --json
# force specific keyless engines (search command only, not web-search)
uv run websearch search "rust ownership" --ddgs-backends google,brave,mojeek
# add a self-hosted SearXNG (see docker/searxng/) as a second, broader engine
export WEBSEARCH_SEARXNG_URL=http://127.0.0.1:8888
uv run websearch search "rust ownership" --engines searxng,ddgs
# Layer 2A: fetch + extract one page to clean Markdown
uv run websearch fetch "https://en.wikipedia.org/wiki/Rust_(programming_language)" --json
# Layer 2B: open several pages into one paginated, deduplicated Markdown document,
# and full-text search the passages across them
uv run websearch open \
"https://en.wikipedia.org/wiki/Rust_(programming_language)" \
"https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html" \
--search "ownership borrow checker"
# Layer 3: the fenced, handle-keyed agent interface
uv run websearch web-search "rust ownership" --json
uv run websearch web-fetch "https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html" \
--page-size-tokens 4000
# page through the rest of a fetched doc by its handle, from cache (no refetch, no flags:
# the page index is on disk by default, so a later command resolves the same handle)
uv run websearch web-open "doc.rust-lang.org~<hash>" --page 2
# extra keyless tools: arXiv papers and GitHub repos
uv run websearch arxiv "mixture of experts scaling laws" --max-results 5
uv run websearch github "llm agent framework" --language Python --sort stars
# Tor (off by default): start it, then search the onion indexes and read .onion pages
uv run websearch tor up
uv run websearch web-search "hidden wiki" --onion
uv run websearch web-fetch "http://2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion/"
# initialize local services and report available capabilities
uv run websearch init
# check configured capabilities and providers
uv run websearch doctor
默认情况下,每个命令都会输出简洁易读的内容,也可以通过 --json 输出原始 JSON Envelope(成功时退出码为 0,请求级错误时为 1)。对于 fetch 命令,--output-format {markdown,text,json} 用于选择易读输出所显示的正文格式(text 会输出纯文本呈现);--quiet 则只输出提取的正文,便于通过管道传递。对于 open 命令,--mode {auto,index,full} 用于控制渐进式披露;--no-truncate 会内嵌所有完整正文;--search QUERY 会对已打开的页面执行 BM25 段落搜索;--anthropic-blocks 会将 Anthropic 的 search_result 视图添加到 sidecar。面向 Agent 的 web-search 接受 --max-results、--detail、--freshness、--site、--language、--country、--safesearch、--offset 和 --searxng-url;引擎选择标志(--engines、--ddgs-backends、--no-ddgs)仅适用于较低层级的 search 命令,并可与 --searxng-url(或 WEBSEARCH_SEARXNG_URL)搭配使用。完整标志列表请参阅 uv run websearch <command> --help。
fetch --json 响应示例如下:
{
"contract_version": "1.0.0",
"ok": true,
"data": {
"source": { "final_url": "https://...", "status": 200, "fetched_via": "http", "blocked": false },
"result": {
"title": "Rust (programming language)",
"page_type": "article",
"quality_score": 0.91,
"word_count": 8123,
"content_markdown": "# Rust ...",
"metadata": { "og_type": "article" }
}
},
"error": null,
"meta": { "layer": "extract", "backend": "http", "elapsed_ms": 412 }
}
作为库使用:
from websearch.layer1_search import build_router, SearchRequest
router = build_router(searxng_url="http://127.0.0.1:8888", enable_ddgs=True)
envelope = router.search(SearchRequest(query="rust ownership", count=10))
for r in envelope.data["results"]:
print(r["fused_score"], r["url"], [s["engine"] for s in r["sources"]])
以相同方式使用第 2B 层(格式化 + 存储)。run 会返回一个 Envelope;其 data 是 JSON FormatPayload,因此可以通过常规字典访问方式获取 markdown 和完整 sidecar:
from websearch.layer2_format import (
FormatRequest, ResultInput, build_format_pipeline,
build_page_index, StoreConfig, PageInput, SearchPageRequest,
)
env = build_format_pipeline().run(
FormatRequest(
query="rust ownership",
results=[ResultInput(url="https://x.test/a", title="A", score=0.9, body_markdown="# A ...")],
)
)
document = env.data["markdown"] # the layout-stable document
sidecar = env.data["sidecar"] # identical data with full page bodies
# an ephemeral page index for passage search and resolve-by-id
index = build_page_index(StoreConfig()) # in-memory SQLite FTS5 (BM25)
index.add([PageInput(url="https://x.test/a", markdown="# A ...")])
hits = index.search(SearchPageRequest(query="borrow checker"))
可选层(默认全部关闭)
基础安装会通过直接连接搜索无需密钥的引擎。四项可选设置可分别启用 VPN 验证、代理路由、Tor 或自托管 SearXNG。websearch doctor 会验证每项已配置的设置:
| 层 | 开关 | 添加的功能 |
|---|---|---|
| VPN | WEBSEARCH_VPN=nordvpn 或 any | 声明出站流量应通过隧道传输,因此 doctor 会验证这一点,而不是自行假定。它本身不会路由任何流量:隧道由你的 VPN 应用负责 |
| 出站代理 | NORDVPN_USER + NORDVPN_PASS,或 WEBSEARCH_PROXY=<url> | 为两个进程中离开此机器的所有路径使用同一个代理:CLI 自身的请求,以及本地 SearXNG 向其查询的引擎发出的请求。仅提供这两个 NordVPN 凭据就会启用代理,并将出站流量锁定到该代理;websearch proxy setup 会引导你完成设置,websearch proxy use <city> 用于选择出口,WEBSEARCH_PROXY=off 则改为直接连接 |
| Tor | WEBSEARCH_TOR=on | 所有路径都会经过本地 Tor,.onion 地址变为可访问,且 --onion 会搜索洋葱索引。websearch tor up 会启动 Tor 并为你设置此项 |
| SearXNG | WEBSEARCH_SEARXNG_URL=<url> | 自托管元搜索实例会加入 Layer-1 并行搜索。websearch searxng up 会启动一个实例并为你设置此项,可使用或不使用 Docker |
设置的存放位置
已导出的变量始终优先;单次运行时,--vpn / --proxy / --tor / --searxng-url 的优先级最高。否则,设置取自第一个定义了这些设置的文件:
WEBSEARCH_ENV_FILE,如果你将它指向某个文件(挂载配置目录的容器会这样做)。- 工作目录中的
.env,适用于自行维护配置的项目(复制.env.example)。 $XDG_CONFIG_HOME/websearch/.env,通常是~/.config/websearch/.env。此设置适用于你运行命令的任何位置,也是searxng up和tor up记录其启动内容的位置。
任何已设置的值都不会被覆盖,因此文件只能补全缺失的设置;两个文件都位于仓库之外或已被 git 忽略,这样 NordVPN 服务凭据就不会进入 shell 历史记录。websearch init 会显示它读取的文件和查找过的文件。
自托管 SearXNG
SearXNG 是可选的;无需密钥的 ddgs 引擎不依赖它也能工作。自托管的 SearXNG 能添加更多引擎,无需依赖公共实例或 API 密钥。websearch doctor 可以将其结果与 ddgs 的结果进行比较,从而区分是解析器故障,还是服务提供商屏蔽了你的 IP。
根据 Docker 是否可用选择设置方式。
不使用 Docker(适用于任何环境,包括 Agent 沙盒):
websearch searxng up # clone, install, start detached, wire it in
websearch web-search "your query" # now fuses SearXNG + ddgs
websearch searxng status # where it lives, whether it answers
websearch searxng down # stop it
首次运行 up 时会克隆上游 SearXNG,并在其旁边构建 virtualenv,大约需要 15 到 30 秒以及几百 MB;之后只需启动即可。所有内容都存放在一个状态目录中(WEBSEARCH_SEARXNG_HOME,默认位于 WEBSEARCH_ENV_FILE 旁边或 XDG 缓存目录中),并会自动将 WEBSEARCH_SEARXNG_URL 写入你的 env 文件,因此下次搜索时会自动使用,无需进行其他操作。服务器会在独立会话中启动,而不是作为命令的子进程,这样即使 Agent CLI 终止它运行的每个 shell 命令的进程组,服务器也能继续运行。WEBSEARCH_SEARXNG_PORT 可以将端口从 8888 改为其他端口。websearch init 会在完成所有设置时自动执行这一步。
使用 Docker:
./docker/searxng/searxng.sh up # generates a per-machine secret, waits for health
export WEBSEARCH_SEARXNG_URL=http://127.0.0.1:8888
uv run websearch web-search "your query"
只需一个容器,无需在主机上安装任何内容,还可以通过你的出口代理路由 SearXNG 自身的引擎请求。SearXNG 内置约 280 个引擎,但大多数默认未启用,因此默认实例对一般查询只会使用其中约六个引擎作答(而且在家庭网络连接下,Brave 和 Startpage 会返回 CAPTCHA)。searxng.sh engines 会通过你的网络连接探测每个引擎,并启用能正常响应的引擎,同时记录跳过每个引擎的原因。在此处测得:一般查询的结果从 2 个引擎返回的 26 条增加到 21 到 29 个引擎返回的 155 到 240 条,耗时 3 到 4 秒。
容器以只读方式挂载配置,将运行时状态存储在 Docker 卷中,移除所有功能权限,并默认绑定到环回地址。不会提交任何机密信息。默认引擎列表中排除了种子追踪器和影子图书馆,但仍可按名称查询。若要将其公开到 localhost 以外,请参阅 docker/searxng/。
两种方式都会绑定到环回地址、启用 JSON API,并通过你的出口代理路由实例自身的引擎请求。区别在于引擎列表:不使用 Docker 的方式采用上游默认设置(此处启用了 278 个引擎中的 83 个),而 Docker 方案的探测会启用通过你的网络连接能正常响应的所有引擎(同一台机器、同一天测得 213 个中的 279 个)。有 Docker 时请使用 Docker;没有时请使用 websearch searxng up。
出口代理
NordVPN 服务凭据就是全部设置:只要环境变量(或设置文件)中包含 NORDVPN_USER 和 NORDVPN_PASS,所有网络流量都会通过 NordVPN 的 SOCKS5 代理,出口流量也会被锁定到该代理。无需应用,也无需其他开关。这是 Nord Account 控制面板中“Set up NordVPN manually”下显示的服务凭据,而不是你的账户登录信息。websearch proxy 可以自动完成设置,无需你查找文件:
websearch proxy setup # creates the settings file and prints its path, with both keys empty
websearch proxy locations # the exits NordVPN runs: Netherlands, Sweden, nine US cities
websearch proxy use dallas # writes NORDVPN_HOST, restarts a running SearXNG onto that exit
websearch proxy status # what is set, what is missing, and where the traffic actually comes out
请自行在名为 setup 的文件中填写两行凭据;不会有任何程序读取或打印它们。status 会通过代理向 NordVPN 查询连接显示的位置,因此如果选择未生效,显示的城市就会与预期不符。单条命令也可以接受 --location dallas,让该命令单独使用一个出口节点。
WEBSEARCH_PROXY 可用于选择其他代理,或关闭代理:
export WEBSEARCH_PROXY=socks5h://user:pass@host:1080 # any proxy URL (http:// works too)
export WEBSEARCH_PROXY=nordvpn # the NordVPN shorthand, explicitly
export WEBSEARCH_PROXY=off # direct connection, even with credentials set
锁定
配置代理后,出站流量会自动锁定:没有任何流量会绕过代理离开这台机器。没有代理的路径会被拒绝,并返回 error.code: "egress_locked",而不会回退到直接连接:这适用于两个抓取层级、搜索引擎、本地 SearXNG 的引擎请求、SearXNG 和 Tor 的安装,以及 doctor --baseline。如果搜索发现本地 SearXNG 正在绕过代理运行,就会在查询前将其重启,并切换到当前出口。环回和局域网目标不受影响,因为它们不会离开这台机器。
锁定存在的原因正是为了防止回退:问题会发生在代理不可用的那一天,而不是你正盯着它看的那一天。
websearch proxy lock # WEBSEARCH_EGRESS_LOCK=on: locked even with the proxy off
websearch proxy unlock # WEBSEARCH_EGRESS_LOCK=off: a missing proxy may go direct
WEBSEARCH_EGRESS_LOCK 是可显式设置任一方向的覆盖开关。它设为 on 时,必须先解除锁定,才能执行 websearch proxy off。
每个网络命令也都接受 --proxy <url|nordvpn|off>,可在本次运行中覆盖该变量,因此 --proxy off 无需取消设置任何内容,就能建立直接连接。优先使用 socks5h:// 而不是 socks5://:它会通过代理解析 DNS,因此主机名不会发送到本地解析器。单次请求的 fetch --proxy 优先于进程级默认设置。
设置 WEBSEARCH_PROXY 后,所有离开这台机器的路径都会使用它:两个抓取层级、ddgs 引擎、Ahmia、arXiv、GitHub、诊断探测、SearXNG 和 Tor 的安装,以及本地 SearXNG 实例自身的引擎请求。测试涵盖两项重要行为:
- DNS 解析。 配置代理后,SSRF 防护不会在本地解析主机名。
socks5h://会在出口节点解析主机名。即使不进行查找,字面 IP 仍会被拒绝,包括http://127.0.0.1和169.254.169.254元数据端点。 - 故障行为。 如果代理不可用,每个组件都会返回错误,而不是通过直接连接重试。这包括会在 Python 外部打开套接字的
ddgs(Rust)和curl_cffi(libcurl)。
可选的 websearch doctor --baseline 检查会发起一次直接请求,以比较直接连接和代理连接的出口 IP。默认情况下该检查处于禁用状态,因为它会将直接 IP 发送到回显服务;而在配置了代理时,还需要设置 WEBSEARCH_EGRESS_LOCK=off,因为这是唯一会离开隧道的请求。
自托管 SearXNG 请求包含两跳,且有意采用不同的代理方式。客户端直接连接本地 SearXNG 的 127.0.0.1,因为这一跳不会离开这台机器,而远程出口尝试访问其自身的 localhost 每次都会失败。随后,SearXNG 会自行查询 Google、Brave、Mojeek 等服务,这一跳才会离开机器:两个技术栈都会将代理写入其 outgoing.proxies(并设置 extra_proxy_timeout,因为 SOCKS 出口需要一次往返),因此这些搜索的出口位置与该工具的其他流量一致。websearch searxng status 会将该地址显示为 egress,websearch proxy use <city> 会将正在运行的实例重启并切换到新出口,而 searxng.sh egress 会打印 Docker 技术栈的两个 IP。设置 SEARXNG_OUTGOING_PROXY=off 可让实例直接出站。访问远程 SearXNG 地址时,会像访问其他主机一样通过客户端代理。
网络观察者能看到什么
如果你不从事安全工作,请跳过本节:它讨论的是一个边缘情况,只有在有人记录你自己的网络路径上的流量时才有影响,而普通设备通过普通连接时并非如此。
查询和页面内容通过 TLS 端到端传输:HTTPS 会话从这台设备经由代理连接到网站,因此代理和线路上的任何观察者都无法读取搜索查询或返回的页面。SOCKS5 不会对线路上的观察者隐藏的是元数据:你正在与 NordVPN 服务通信这一事实、目标主机名(位于 SOCKS 握手和 TLS SNI 中),以及 SOCKS 用户名和密码,因为该协议会以明文发送这些信息。这些是该代理服务专用的服务凭据:它们不能用于登录 Nord 账户,而且可以在控制面板中重新生成。网站只能看到出口 IP。NordVPN 的 TLS 代理(端口 89)会对服务凭据返回 HTTP 407(已进行实时验证;请参见“限制”),因此在协议层面无法使用 TLS 拨号连接该代理,而这正是零安装设置所付出的代价。
要彻底关闭它,需要在操作系统层面处理:运行服务商的 VPN 应用(WireGuard)并启用其终止开关,将 WEBSEARCH_PROXY=off,并声明 WEBSEARCH_VPN=nordvpn,以便 doctor 验证隧道,而不是默认认为隧道已启用。此后,设备发送的每个字节都会经过加密,包括此工具发送的数据,而且线路上完全不会出现代理握手。终止开关能将“隧道连接时加密”变成“绝不直连”:没有它,隧道断开时就会故障开放。运行该应用并保留代理也可行(此时握手会在隧道内进行,代理会固定出口城市),但关闭代理是最简单的做法。
Tor
启动前处于关闭状态。普通模式和 Tor 模式使用相同的命令,只需切换一个选项:websearch tor up 会开启该层,之后的每条命令都会通过 Tor 路由;--tor on 只对单条命令生效;在搜索中使用 --onion 会选择 onion 索引;开启该层后,web-fetch 也可访问 .onion URL。web-search-tor 技能为 Agent 封装了这一整套功能。完整的设置只需运行 websearch tor up:
websearch tor up # start Tor, verify the exit, turn the layer on
websearch web-search "query" --onion # search the onion indexes
websearch web-fetch "http://<addr>.onion/" # read an onion page, same output as any other
websearch tor status # listening, and is the traffic really Tor
websearch tor down # stop it and turn the layer off
up 会使用已在监听的 Tor;如果没有,则使用 PATH 中的 tor;再不然,就会将官方 Tor Expert Bundle(约 30 MB)下载到状态目录,并根据其旁边发布的 sha256 校验文件进行验证。该二进制文件未经 GPG 验证:这里信任的是与 torproject.org 的 TLS 连接,以及该摘要。Tor 会在独立会话中启动,因此会像 SearXNG 一样,在命令结束后继续运行;up 会等待启动完成,然后询问 check.torproject.org 流量是否确实经由 Tor 发出。端口有响应不等于它就是 Tor,因此 is_tor 是与 reachable 分开的字段;doctor 遇到 false 时会报错,而不会把“有程序在监听”当作就绪。
开启该层后,所有路径都会通过 Tor:搜索、抓取、arXiv、GitHub。.onion 地址可以正常使用;关闭该层时,这类地址会在解析前被拒绝,因为即使最终无法访问,在本地查询 onion 名称也会在失败前将其泄露给你的解析器。
--onion 会将 clearnet 引擎替换为 onion 引擎(Ahmia,以及运行本地实例时 SearXNG 的 onions 分类,其中还会加入 Torch)。这是替换而非扩展:没有 clearnet 引擎会索引 onion 服务,也没有 onion 索引会爬取 clearnet,因此混合扇出只会将两个半空列表在彼此不重叠的语料库上合并。Onion 搜索需要 10 到 30 秒,因此默认超时时间也会相应延长。
Tor 不会取代你的代理。 如果设置了 WEBSEARCH_PROXY,该值会写入 Tor 自己的 torrc,作为其上游代理(Socks5Proxy / HTTPSProxy),因此路径会变为你、代理、Tor:VPN 跳仍会向 ISP 隐藏 Tor 的使用情况,而启用本来要增加一跳的层时,也不会悄悄移除已有跳数。Tor 无法拨号连接的代理协议(例如 WireGuard)会明确报错,而不是被静默跳过。唯一会改变的是 VPN 检查:Tor 开启时会跳过该检查并说明原因。经由 Tor 时,外界只能看到出口节点,因此无法从外部确认 Tor 前方是否有 VPN。
在生成的 torrc 旁放置你自己的 Tor 指令到 torrc.local 中;该文件会被包含在配置中,并在重新生成时保留。WEBSEARCH_TOR_SOCKS 用于指定你已运行的 Tor(socks5h://127.0.0.1:9150 是 Tor Browser 使用的地址);WEBSEARCH_TOR_PORT 用于更改端口;WEBSEARCH_TOR_BINARY 用于跳过下载;WEBSEARCH_TOR_VERSION 用于固定 Bundle 版本。
Onion 页面会索引到单独的文件中(与普通索引放在一起的 pages-onion.json),因此通过 Tor 读取的内容不会混入 clearnet 存储,其历史记录也可以单独删除;不可信内容防护还会增加一行,将来源标记为 onion 服务:这类服务的来源按设计无法归属,因此无法举报或屏蔽其背后的任何人,也就最有可能遇到专为 Agent 而非人类编写的载荷。
这是 Tor,不是 Tor Browser。它会隐藏请求的来源,但不会为不同网站隔离电路,也不会让你发送的内容匿名。这里不存在浏览器指纹暴露面(没有 JS、canvas,也不会在不同抓取之间共享 cookie jar),但每个请求都会携带相同的客户端标识,因此可以通过这些标识将不同出口上的请求关联起来。
VPN
WEBSEARCH_VPN 记录预期的隧道状态,但不会配置路由。如果隧道断开,doctor 会报告失败。nordvpn 会通过 NordVPN 的无密钥连接端点进行验证,该端点会报告调用方是否位于其网络内。any 只检查是否存在活动的隧道接口,因为没有特定于服务提供商的端点。如果设置了出口代理,doctor 会通过它进行检查;否则会直接检查。
nordvpn 适用于所有平台,因为它是 HTTP 检查。any 会读取接口名称;这些名称在 Linux(tun、wg、nordlynx)和 macOS(utun)上有意义,但在 Windows 上没有意义,因为 Windows 上的接口名称类似 ethernet_32770;在 Windows 上,它会报告隧道状态未确认,而不是妄加判断。
websearch init
websearch init 会读取设置文件,在启用 Tor 层时启动 Tor,在未设置 --skip-searxng 时启动本地 SearXNG,并运行 doctor 检查:
uv run websearch init # bring everything up, then report
uv run websearch init --json # the same run as an Envelope
uv run websearch init --quick # skip the slow sweep; unprobed capabilities read "unknown"
uv run websearch init --skip-tor # leave Tor alone even with the layer on
ok env read /config/websearch.env
skip tor off (WEBSEARCH_TOR is not set); egress is not going through Tor
ok searxng SearXNG 2026.7.25 answering at http://127.0.0.1:8888, 83 of 278 engines
warn doctor 18 ok, 4 warn, 0 fail, 3 skipped
capabilities
web_search ok
web_fetch ok
arxiv ok
github ok
searxng ok
proxy ok
vpn off
tor off
ready: search online (5 of 9 keyless providers + SearXNG, 83 engines); fetch, arxiv, github ok; egress through socks5h://***:***@nl.socks.nordhold.net:1080
等待 data.ready。data.state 可能为 ready、degraded(搜索可用,但缺少某项请求的功能)或 broken(搜索不可用)。data.capabilities 列出可用命令,data.next_actions 列出修复步骤,data.doctor 包含完整的诊断载荷。搜索可用时(包括结果为 degraded)退出代码为 0;搜索不可用时为 1。
websearch doctor
websearch doctor 会检查当前功能和服务提供商状态:
uv run websearch doctor # everything
uv run websearch doctor --quick # skip the engine fanout, tools, and fetch tiers
uv run websearch doctor --check engines --check proxy
uv run websearch doctor --check tor # just the Tor layer
uv run websearch doctor --json # the same run as an Envelope
它会打印四个可选层的状态,然后检查 Python 和依赖闭包、直连互联网和出口 IP、出口代理以及出口 IP 是否实际发生变化、Tor(是否正在监听、是否经 check.torproject.org 确认是 Tor,以及是否能实际获取 onion 内容)、声明的 VPN、自托管 SearXNG(运行状况、活动引擎数量、实时 JSON 查询)、每个 ddgs 服务提供商的独立状态、arXiv 和 GitHub,以及两个抓取层级。只有出现故障时,退出代码才为 1:已关闭的可选层会跳过,某个服务提供商受到速率限制则会显示警告。代理凭据绝不会出现在输出中,HTTP 客户端错误文本中也不会包含这些凭据。
SearXNG 交叉检查有助于判断 ddgs 故障的类型。对于 CAPTCHA、速率限制,以及解析器无法读取标记内容的成功响应,ddgs 都会报告“未找到结果”。运行 SearXNG 时,doctor 会通过 SearXNG 单独维护的抓取器查询同一服务提供商:
warn engine:ddgs:google No results found. (SearXNG reached it: 260 results)
-> ddgs's parser, not a block on your IP. Query it through SearXNG.
warn engine:ddgs:startpage No results found. (SearXNG got nothing from it either)
-> startpage is refusing this IP. Only a different egress exit changes that.
2026 年 7 月,在同一家庭网络上间隔几分钟运行两次,九个 ddgs 服务提供商的结果各不相同。两次运行中,Brave、Yahoo 和 Yandex 均有响应。通过 ddgs 查询时,Google 和 Mojeek 均无响应,但通过 SearXNG 分别返回 181 和 10 条结果,这表明 ddgs 解析器出现故障。通过两种路径查询 Startpage 和 Wikipedia 均无结果,表明请求被拦截。DuckDuckGo 和 Grokipedia 的结果在两次运行之间有所变化,而 NordVPN 的共享 SOCKS 出口又导致一个服务提供商无法访问。请运行 doctor 获取当前结果。
安全性
Fetch 接受任意 URL 和页面内容,因此包含 SSRF 和提示词注入防护:
- SSRF 防护(内置): fetch 强制执行 http(s) 协议允许列表,并解析每个主机名,拒绝私有、环回、链路本地(
169.254.169.254云元数据端点)、保留和多播地址。重定向由程序手动跟进,并在每一跳执行相同检查,因此公共 URL 无法重定向到内部网络。对于有意进行的内部抓取,可使用--allow-private-hosts按请求覆盖此限制。 - 不可信内容(内置,第 3 层): 抓取的页面文本绝不会作为指令呈现。
web_fetch和web_open会依据 2026 年一手来源指南,用围栏包裹每个页面:在起始和结束标记中加入每个实例独有的 128 位随机 nonce、数据专用指令,并中和正文中重复出现的标记副本。可选的数据标记(--datamark)还能增强防护。围栏可防止突破边界,但无法阻止说服性内容。仍然需要隔离工具输出、遵循最小权限原则,并阻断数据外泄路径。较低层级的fetch命令会返回不带围栏的提取正文,以便通过管道传递和组合处理。
架构
每一层都是一个文件夹,其中包含一个接口(以能力命名的接口)和一个或多个适配器,且仅通过版本化的 JSON Schema 2020-12 契约进行连接。接口字段以能力命名(snippet、fused_score、sources);后端原生数据结构会在该后端的适配器中映射到接口。默认部署以进程内方式运行,以提升速度;由于各层仅通过契约耦合,之后可将某一层迁移到子进程或本地服务,而无需改动相邻层。契约的增量变更属于 MINOR(消费者会忽略未知字段);移除、重命名或更改类型属于 MAJOR,消费者驱动的契约测试会在生产者变更破坏已记录的固件时失败。完整设计见 docs/ARCHITECTURE.md。
七轴评分卡
评分卡将检索质量、成本、延迟和运行限制分别评估:
| 轴 | 本工具 | 备注 |
|---|---|---|
| 检索质量 | 对于常见查询,与领先 API 相当 | 2026 年的领先方案在质量上统计结果不相上下 |
| 新鲜度 | 按需筛选近期内容 | 按引擎区分,尽力而为 |
| 提取召回率 / 噪声 | 具有竞争力(Trafilatura 的 F1 约为 0.79,文章约为 0.93) | 在质量和成本上,启发式方法优于神经网络方法 |
| 反机器人检测成功率 | 不使用付费代理时约为 70% 至 90% | 受保护的网站需要住宅网络出口 |
| 端到端延迟 | 随引擎响应速度而变化 | 多引擎并行请求和融合会增加延迟 |
| 成本 | 软件层面几乎为零 | 基础设施成本另有说明 |
| 引用准确性 | 以来源为依据并去重的结果 | 不会编造 URL |
受保护的网站通常需要付费住宅网络出口(即使是 Firecrawl,在经过独立测试的受保护网站上得分也只有约 34%)。内置代理支持搜索地理位置定向和速率限制轮换。它无法绕过页面级反机器人系统,因为这类系统通常会将商业 VPN 使用的数据中心 IP 标记为可疑。住宅网络出口适配器已列入计划。
基准测试
docs/BENCHMARK.md 将相同查询在同一时间与 Claude Code 中托管的网页搜索进行对比,并提供了复现命令。两者都找到了相关且较新的页面。本项目还提供本地提取、多引擎融合,以及 arxiv 和 github 命令;托管搜索则通过一次调用返回摘要。
验证
这份代码库有两类证据支撑:一套锁定行为的离线测试,以及针对真实网络运行的端到端测试。
测试套件包含 793 项测试,没有一项会打开套接字:每个网络边界(httpx 传输、ddgs 客户端、curl_cffi、SearXNG、doctor 的 HTTP 端口)都通过注入提供,因此在断网机器和 CI 上运行的结果完全一致。每项契约承诺都对应一项测试,并通过真实入口执行;出口规则也有专门的验证:代理后不进行本地 DNS 解析、拒绝字面 IP 的 SSRF 请求(包括云元数据端点和 CGNAT(RFC 6598))、在每次重定向跳转时重新进行防护检查、跨源重定向时限定凭据作用域、围栏 nonce 完整性、凭据绝不出现在任何输出中,以及锁会拒绝所有未使用代理的路径(包括诊断运行)。
最近一次实时验证于 2026-08-13,在真实 NordVPN SOCKS5 出口上进行:
websearch proxy status通过 NordVPN 自己的 insights 端点确认出口信息:出口 IP、城市、protected: true。- doctor 出口扫描确认所有请求都经由代理,直接请求数为零;启用锁且代理不可用时,完整 doctor 运行没有发出任何网络请求,并按名称报告了每项拒绝。
web-search合并了实时 ddgs 和 SearXNG 结果;web-fetch返回带围栏的分页页面;web-open从存储中提供后续页面,不接触网络。- 冷启动运行
websearch tor up下载了 Tor Expert Bundle(15.0.19),验证了其公布的校验和,完成引导,并由 check.torproject.org 确认出口为 Tor;--onion搜索返回了 onion 结果,.onion抓取结果带有围栏和 onion 来源说明。 - 关闭代理后再次运行同一扫描,以确认默认直接连接行为:search、fetch、open、arxiv、github 和完整 Tor 生命周期均正常,没有拒绝,也没有限制。
限制及其归属
以下每项限制都位于边界的服务提供方一侧;客户端一侧均已实现并经过测试。
- SOCKS5 元数据(NordVPN)。 上文的观察部分说明了 SOCKS5 会在你自己的线路上暴露哪些信息。NordVPN 在 89 端口运行 TLS 代理(
*.proxy.nordvpn.com,证书由 Sectigo 签发且有效),这些服务器会用 HTTP 407 响应服务凭据(2026-08-13 实时验证):它们只对浏览器扩展进行身份验证,其凭据服务采用 SOCKS5。客户端已支持WEBSEARCH_PROXY=https://user:pass@host:port,并会在 TLS 内拨号连接此类代理,主机名和凭据均经过加密;因此,任何提供凭据式 TLS 代理的服务商,只需添加一行设置即可解决此问题,无需修改代码。 - 数据中心出口和反机器人屏障。 商业 VPN 出口使用数据中心 IP,反机器人系统无论客户端如何都会将其标记。检测到拦截时,抓取层级会升级为浏览器模拟;需要住宅网络出口的网站仍无法访问,直到计划中的付费适配器推出。
- 引擎可用性因网络和日期而异。 无需密钥的服务提供方会按自己的时间表限制速率、拦截请求或更改标记;
websearch doctor会检测当前哪些服务能从你的连接获得响应,而 SearXNG 扇出机制则会补回 ddgs 已无法解析其页面的引擎。 - 无密钥 API 的额度上限。 GitHub 每分钟允许约 10 次未认证搜索,超过后会返回
rate_limited;arXiv 会限制速率,客户端会按其计划退避。 - Tor 出口是公开的。 许多网站会直接拒绝它们;这是出口列表本身的特性。若网站如此,替代方案是通过代理走明网路径。
路线图
当前的分发方式包括 npx skills add、Claude Code 插件和市场,以及 PyPI/uvx。各受支持 Agent 的相关信息,请参阅 docs/INSTALL.md。
出口代理(NordVPN 凭据、WEBSEARCH_PROXY 或 --proxy)会覆盖所有离开本机的路径,包括自托管 SearXNG 自身的引擎请求;配置后,它会锁定出口流量:无法使用该代理的路径会被拒绝,而不是回退到直接连接。
以下计划尚未实现:
- 付费出口适配器: 为受保护的长尾请求提供住宅代理适配器。
- 本地重排: 通过交叉编码器处理,将多引擎召回转化为精准结果。
- 更多引擎: 在现有
EngineAdapter接口后接入需要密钥的适配器(Brave、Exa、Tavily);以及可选的神经索引。
开发
uv sync # install deps (including the dev group)
uv run pytest # 748 tests, no network
uv run ruff check .
CI 通过 uv 在 Linux 上对 Python 3.11、3.12 和 3.13 运行 ruff 和 pytest。该软件包本身是纯 Python,不包含特定于操作系统的导入;它的两个已编译依赖(curl_cffi 和 ddgs 下的 primp)都为 Linux、macOS 和 Windows 上的 x86-64 与 arm64 发布了 wheel,因此 macOS 和 Windows 应该也能正常运行;但 CI 不会覆盖这些平台,因此在信任其运行结果前,请先在这些平台上运行 uv run pytest 和 uv run websearch doctor。有两点平台相关说明:websearch doctor 会读取网络接口名称以处理 WEBSEARCH_VPN=any,而 Windows 无法实用地提供这些信息(因此会报告隧道状态未经确认;WEBSEARCH_VPN=nordvpn 则在所有平台上都能正常工作,因为它使用 HTTP 检查);Docker SearXNG 堆栈由 bash 脚本驱动,在 Windows 上需要 WSL 或 Git Bash(websearch searxng up 是 Python 实现,没有此要求)。
契约测试会使用冻结的 JSON Schema 验证实际输出,因此任何破坏契约结构的更改都会导致 CI 失败。每次只构建一个隔离层,并遵循其版本化契约;添加或替换引擎或提取器时,只需修改相应的适配器模块。
许可证
MIT。请参阅 LICENSE。依赖 AGPL 组件(例如 nodriver)的可选反机器人层级会作为需单独安装的外置适配器提供,不会捆绑到 MIT 核心中。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。