🚀 Search Stack
Search Stack 是 AI Agent 专用的 Web 搜索与抓取中间层,为 OpenClaw、Claude Code、Dify 等 AI 智能体提供统一的 Web 访问 API。它具备多引擎搜索自动 fallback、无头 Chrome 反爬渲染、Cookie 注入登录态、正文精准提取等功能,一次部署,所有 Agent 均可共用。
🚀 快速开始
Search Stack 为 AI 智能体提供了强大的 Web 搜索与抓取能力。以下是快速部署和使用的步骤:
前置要求
- Docker + Docker Compose
- (可选)Tavily API Key — 免费 1000 次/月
- (可选)Serper API Key — 免费 2500 次
不配 Tavily / Serper 也能用,会自动 fallback 到 SearXNG(完全免费)。
1. 克隆项目
git clone https://github.com/pinkpills/search-stack.git
cd search-stack
2. 配置环境变量
cp .env.example .env
编辑 .env:
TAVILY_API_KEY=your_tavily_key
SERPER_API_KEY=your_serper_key
SEARXNG_SECRET=
PROXY_API_KEY=
BROWSERLESS_TOKEN=
REDIS_PASSWORD=
一键生成随机密钥:
python3 -c "
import secrets
for name in ['SEARXNG_SECRET', 'PROXY_API_KEY', 'BROWSERLESS_TOKEN', 'REDIS_PASSWORD']:
print(f'{name}={secrets.token_hex(16)}')
" >> .env
3. 配置 SearXNG
必做! 不做这步 SearXNG 的 JSON API 会返回 403。
cp searxng/settings.yml.example searxng/settings.yml
编辑 searxng/settings.yml,确保包含:
search:
formats:
- html
- json
如果你之前已经启动过 SearXNG(它会自动生成 settings.yml),需要手动加上 formats 配置后重启容器。
4. 启动服务
docker compose -f search-stack.yml up -d
等待所有容器健康(约 30 秒):
docker compose -f search-stack.yml ps
全部显示 healthy 即完成。
5. 验证
curl -s -H "X-API-Key: YOUR_PROXY_API_KEY" http://127.0.0.1:17080/health | python3 -m json.tool
curl -s -X POST http://127.0.0.1:17080/search \
-H "X-API-Key: YOUR_PROXY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "hello world", "count": 3}' | python3 -m json.tool
curl -s -X POST http://127.0.0.1:17080/search \
-H "X-API-Key: YOUR_PROXY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "hello world", "count": 3, "provider": "searxng"}' | python3 -m json.tool
curl -s -X POST http://127.0.0.1:17080/fetch \
-H "X-API-Key: YOUR_PROXY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "render": false}' | python3 -m json.tool
提示: 如果 SearXNG 返回 502 或空结果,大概率是缺少 formats: [html, json] 配置,参见步骤 3。
✨ 主要特性
- 多引擎 Fallback — Tavily → Serper → SearXNG 按优先级自动切换,单引擎挂不影响服务。
- 搜索 + 抓取一体 —
/search 搜索,/fetch 抓取正文,enrich=true 搜索后自动抓取全文。
- 抗反爬 — Browserless Stealth 模式,绕过 Cloudflare / JS Challenge。
- 正文提取 — trafilatura + BeautifulSoup + readability 三引擎,精准提取正文。
- Cookie 管理 — API 动态增删 Cookie,自动注入 Chrome 渲染,支持直接粘贴浏览器 Cookie。
- 登录/反爬检测 — 多维度启发式检测:HTTP 状态码(401/403)、文本关键词(中英日)、页面标题、HTML 结构(密码框、CAPTCHA 嵌入、meta refresh 重定向)、SPA 登录墙,返回
needs_login 标记引导 Cookie 更新。
- Cookie Catcher — 浏览器内远程登录:通过 WebSocket + CDP Screencast 在 Web UI 中操控远程 Chrome 完成登录,一键保存 Cookie。
- SSRF 防护 — 拒绝访问私网 IP(127/10/172.16/192.168/169.254)。
- URL 去重 — 自动去除追踪参数(utm_*、fbclid 等),同域名结果限制。
- Redis 缓存 — 15 分钟 TTL,重复查询即时返回。
- API Key 鉴权 + 限流 — 滑动窗口限流。
- MCP Server — stdio 模式 MCP Server(
mcp-server.ts),可通过 mcporter 注册供 OpenClaw 等 Agent 使用。
- TikHub 社交媒体 API — 可选集成,代理 TikHub 803 个社交平台工具(抖音、TikTok、微博等),内置自动回退。
- HTTP 代理 — 支持 HTTP / SOCKS5 代理,用于反爬固定 IP 或翻墙访问被墙网站(YouTube 等)。
- 全异步 — async Redis + 共享 httpx 连接池,高并发低延迟。
📦 安装指南
前置要求
- Docker + Docker Compose
- (可选)Tavily API Key — 免费 1000 次/月
- (可选)Serper API Key — 免费 2500 次
克隆项目
git clone https://github.com/pinkpills/search-stack.git
cd search-stack
配置环境变量
cp .env.example .env
编辑 .env 并可一键生成随机密钥:
python3 -c "
import secrets
for name in ['SEARXNG_SECRET', 'PROXY_API_KEY', 'BROWSERLESS_TOKEN', 'REDIS_PASSWORD']:
print(f'{name}={secrets.token_hex(16)}')
" >> .env
配置 SearXNG
cp searxng/settings.yml.example searxng/settings.yml
编辑 searxng/settings.yml 确保包含 formats: [html, json],若之前启动过需手动添加并重启容器。
启动服务
docker compose -f search-stack.yml up -d
等待容器健康:
docker compose -f search-stack.yml ps
验证
curl -s -H "X-API-Key: YOUR_PROXY_API_KEY" http://127.0.0.1:17080/health | python3 -m json.tool
curl -s -X POST http://127.0.0.1:17080/search \
-H "X-API-Key: YOUR_PROXY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "hello world", "count": 3}' | python3 -m json.tool
curl -s -X POST http://127.0.0.1:17080/search \
-H "X-API-Key: YOUR_PROXY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "hello world", "count": 3, "provider": "searxng"}' | python3 -m json.tool
curl -s -X POST http://127.0.0.1:17080/fetch \
-H "X-API-Key: YOUR_PROXY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "render": false}' | python3 -m json.tool
💻 使用示例
基础用法
curl -s -X POST http://127.0.0.1:17080/search \
-H "X-API-Key: KEY" -H "Content-Type: application/json" \
-d '{"query": "Docker best practices", "count": 5}'
curl -s -X POST http://127.0.0.1:17080/search \
-H "X-API-Key: KEY" -H "Content-Type: application/json" \
-d '{"query": "Python asyncio", "count": 3, "enrich": true}'
curl -s -X POST http://127.0.0.1:17080/search \
-H "X-API-Key: KEY" -H "Content-Type: application/json" \
-d '{"query": "AI news", "count": 5, "provider": "searxng"}'
高级用法
curl -s -X POST http://127.0.0.1:17080/fetch \
-H "X-API-Key: KEY" -H "Content-Type: application/json" \
-d '{"url": "https://example.com", "render": false}'
📚 详细文档
与 Brave Search 对比
| 维度 |
Search Stack |
Brave Search(OpenClaw 内置) |
| 搜索速度 |
0.8 - 1.5s(Tavily/Serper) |
~1 - 2s |
| 缓存命中 |
13ms(Redis 缓存 15 分钟) |
无缓存,每次重新请求 |
| 中文搜索 |
结果丰富(掘金、知乎、什么值得买等) |
中文结果偏少,偏英文源 |
| 英文搜索 |
优秀 |
优秀 |
| 高可用 |
三引擎自动 fallback |
单点,挂了就没了 |
| 全文抓取 |
enrich=true 搜索+正文一步到位 |
只返回摘要,需额外抓取 |
| 反爬站点 |
Browserless Chrome 渲染 |
无法抓取 |
| 需登录站点 |
Cookie 注入 + 自动检测引导 |
不支持 |
| 免费额度 |
SearXNG 无限量兜底 |
免费 Key 有严格限制 |
结论:搜索速度持平,中文质量更好,功能远超 Brave。
架构
+-----------+
AI Agent ──────────>| search- |──> Tavily API
(OpenClaw / Claude) | proxy |──> Serper API (Google)
POST /search | (FastAPI) |──> SearXNG (self-hosted)
POST /fetch +-----+-----+
|
+-------------+-------------+
| |
+-----+-----+ +--------+--------+
| Redis | | Browserless |
| (cache + | | (headless Chrome |
| rate-limit)| | anti-bot render)|
+------------+ +-----------------+
四个容器,一键启动:
| 服务 |
作用 |
| search-proxy |
FastAPI 核心代理,统一搜索/抓取接口 |
| Redis |
结果缓存(15 分钟 TTL)+ API 限流计数 |
| SearXNG |
自托管元搜索引擎(聚合 Google、DuckDuckGo、Brave 等,免费无限量) |
| Browserless |
无头 Chrome,渲染 JS 页面,Stealth 模式绕过反爬 |
集成 OpenClaw
方式一:原生插件(推荐)
openclaw plugins install --link /opt/search-stack/plugin/
- 步骤 2:配置
编辑
~/.openclaw/openclaw.json,在 plugins.entries 中添加:
{
"plugins": {
"entries": {
"search-stack": {
"enabled": true,
"config": {
"apiUrl": "http://127.0.0.1:17080",
"apiKey": "your_proxy_api_key",
"tikhubApiKey": "your_tikhub_key"
}
}
}
}
}
apiKey 的值就是 .env 中的 PROXY_API_KEY。
tikhubApiKey 可选,填入 TikHub API Key 可启用社交媒体 API。
注意: 配置必须放在 config 嵌套对象内,不能直接放在 search-stack 下。
- 步骤 3:禁用内置 Brave 搜索
编辑
~/.openclaw/openclaw.json:
{
"tools": {
"web": {
"search": {
"enabled": false
}
}
}
}
mkdir -p ~/.openclaw/workspace/skills/web-search/
cp /opt/search-stack/skill-template/SKILL.md ~/.openclaw/workspace/skills/web-search/SKILL.md
sudo systemctl restart openclaw
openclaw plugins list
重要: 如果 AI 仍在使用旧方式,需要归档旧 session。OpenClaw 的会话上下文会缓存之前的工具模式,即使配置已更新,旧 session 仍会沿用旧行为。详见下方「常见问题 → AI 不使用 search-stack」。
方式二:MCP + mcporter(备选)
curl -fsSL https://bun.sh/install | bash
bun add -g @modelcontextprotocol/sdk zod
- 步骤 2:注册到 mcporter
编辑
~/.mcporter/mcporter.json,添加 search-stack:
{
"mcpServers": {
"search-stack": {
"command": "/home/your_user/.bun/bin/bun",
"args": ["run", "/opt/search-stack/proxy/mcp-server.ts"],
"keepAlive": true,
"env": {
"SEARCH_STACK_URL": "http://127.0.0.1:17080",
"SEARCH_STACK_API_KEY": "your_proxy_api_key",
"TIKHUB_API_KEY": "your_tikhub_key"
}
}
}
}
验证注册:
mcporter daemon restart
mcporter list
- 步骤 3:创建 Skill 并重启
创建
~/.openclaw/workspace/skills/web-search/SKILL.md(使用 mcporter exec 调用格式),禁用 Brave 搜索,重启 OpenClaw。
注意: MCP+mcporter 方式中,AI 通过 exec 工具执行 mcporter call search-stack.* 命令。超时时 SIGKILL 会导致零输出,AI 可能认为"搜索引擎挂了"。推荐使用原生插件方式避免此问题。
异地部署(OpenClaw 和 Search Stack 在不同机器)
- 步骤 1:服务器 A — 配置反向代理(HTTPS)
location /search-stack/ {
proxy_pass http://127.0.0.1:17080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
安全提醒: API Key 会在请求头中明文传输,必须使用 HTTPS。建议用 Certbot 自动申请 Let's Encrypt 证书。
git clone https://github.com/pinkpills/search-stack.git /opt/search-stack
cd /opt/search-stack/plugin && npm install
mkdir -p /opt/search-stack && cd /opt/search-stack
git clone --depth 1 --filter=blob:none --sparse \
https://github.com/pinkpills/search-stack.git .
git sparse-checkout set plugin skill-template
cd plugin && npm install
- 步骤 3:服务器 B — 安装插件到 OpenClaw
openclaw plugins install --link /opt/search-stack/plugin/
- 步骤 4:服务器 B — 配置远程 API 地址
编辑
~/.openclaw/openclaw.json:
{
"plugins": {
"entries": {
"search-stack": {
"enabled": true,
"config": {
"apiUrl": "https://search.example.com/search-stack",
"apiKey": "your_proxy_api_key",
"publicUrl": "https://search.example.com/search-stack",
"tikhubApiKey": "your_tikhub_key"
}
}
}
},
"tools": {
"web": {
"search": {
"enabled": false
}
}
}
}
配置说明:
| 字段 |
说明 |
apiUrl |
服务器 A 的 Search Stack API 地址(通过 Nginx 代理后的 HTTPS URL) |
apiKey |
服务器 A .env 中的 PROXY_API_KEY |
publicUrl |
Cookie Catcher 链接中使用的公网 URL(用户浏览器需要能访问),通常与 apiUrl 相同 |
tikhubApiKey |
(可选)TikHub API Key |
- 步骤 5:服务器 B — 创建 Skill 并重启
mkdir -p ~/.openclaw/workspace/skills/web-search/
cp /opt/search-stack/skill-template/SKILL.md ~/.openclaw/workspace/skills/web-search/SKILL.md
sudo systemctl restart openclaw
验证
在 OpenClaw 中对话测试:
用户: "搜索一下 Claude Opus 4.6 评测"
AI: 调用 web_search → 返回结果(来自远程 Search Stack)
用户: "打开第一条链接看看全文"
AI: 调用 page_fetch → 返回全文(远程 Browserless 渲染)
如果工具调用失败,检查:
- 服务器 B 能否访问
apiUrl:curl -H "X-API-Key: KEY" https://search.example.com/search-stack/health
- 插件是否加载:
openclaw plugins list
- 旧 session 缓存:归档旧 session 后重启(详见「常见问题 → AI 不使用 search-stack」)
多机并发与资源控制
| 客户端数 |
MAX_CONCURRENT_SESSIONS |
memory |
服务器内存建议 |
| 1 - 2 台 |
5 |
2g |
4GB+ |
| 3 - 5 台 |
10 |
4g |
8GB+ |
| 5 - 10 台 |
20 |
8g |
16GB+ |
超出并发上限时,Browserless 会将请求排队等待;队列也满时返回 429,page_fetch 会报错但不影响搜索功能(web_search 不依赖 Chrome)。Cookie Catcher 另有 2 会话硬限制,多人同时登录需排队。
工具列表
| 工具 |
说明 |
web_search |
多引擎搜索,支持 enrich 全文抓取 |
page_fetch |
抓取网页正文,支持 Cookie 注入 + Chrome 渲染 + 登录检测 |
cookies_list |
列出已配置 Cookie 的域名 |
cookies_update |
添加/更新域名 Cookie(支持 raw 字符串粘贴) |
cookies_delete |
删除域名 Cookie |
cookie_catcher_link |
生成远程浏览器登录链接(Cookie Catcher) |
tikhub_call |
调用 TikHub 社交媒体 API(需配置 Key,按需使用) |
注意: 抓取工具名为 page_fetch 而非 web_fetch。这是为了避免与 OpenClaw 内置的 web_fetch 工具名冲突。内置 web_fetch 不支持 Cookie 注入和 Chrome 渲染,使用同名会导致 AI 调用错误的工具。
Cookie 工作流实战
方式一:手动复制粘贴(适用于桌面端)
用户: "帮我看看这个网页 https://zhuanlan.zhihu.com/p/xxxx"
AI: 调用 page_fetch → 正文不完整(只有标题/摘要)
AI: "这个网站的反爬比较严格,正文没有完整抓到。
如果你需要完整内容,可以提供该网站的 Cookie:
1. 在浏览器中打开该网址并登录
2. 按 F12 → Network 标签 → 刷新页面
3. 找到请求头中的 Cookie: 一行
4. 复制整个值发给我"
用户: "z_c0=xxx; _xsrf=yyy; d_c0=zzz ..."
AI: 自动提取域名 zhihu.com → cookies_update → 保存成功
AI: 用 bypass_cache:true 重新抓取 → 拿到完整文章内容
方式二:Cookie Catcher 远程登录(适用于复杂登录流程)
1. 浏览器打开:http://YOUR_HOST:17080/cookie-catcher?key=API_KEY&url=https://threads.net
2. 在远程 Chrome 画面中完成登录(支持鼠标/键盘/触屏操作)
3. 点击 "Save Cookies" → 自动保存到 cookies.json
4. 后续 /fetch 请求自动注入 Cookie
适合需要 OAuth 跳转、二维码扫码、手机验证码等复杂登录场景。
🔧 技术细节
API 文档
所有请求需携带 X-API-Key 头部。
GET /health
健康检查。
{
"ok": true,
"redis": true,
"order": ["tavily", "serper", "searxng"],
"browserless_configured": true,
"dedupe": { "enabled": true, "max_per_host": 2 }
}
POST /search
Web 搜索。
| 参数 |
类型 |
默认值 |
说明 |
query |
string |
必填 |
搜索关键词 |
count |
int |
5 |
返回结果数(1 - 10) |
provider |
string |
自动 |
强制指定:tavily / serper / searxng |
enrich |
bool |
false |
抓取每条结果的网页全文 |
max_chars |
int |
8000 |
enrich 时每页最大字符数 |
render |
bool |
true |
用无头浏览器渲染 |
concurrency |
int |
3 |
enrich 并发抓取数 |
POST /fetch
抓取网页正文。
| 参数 |
类型 |
默认值 |
说明 |
url |
string |
必填 |
目标 URL |
render |
bool |
true |
用无头浏览器渲染 |
max_chars |
int |
20000 |
最大提取字符数 |
timeout |
float |
25 |
超时秒数 |
headers |
object |
null |
自定义请求头 |
bypass_cache |
bool |
false |
跳过缓存(更新 Cookie 后用) |
当页面需要登录或被反爬拦截时,返回 needs_login: true:
{
"needs_login": true,
"has_cookies": false
}
has_cookies: true 时表示已有 Cookie 但已过期,需要重新导出。
检测规则覆盖以下信号(按优先级排列):
| 信号 |
条件 |
示例 |
| HTTP 401 |
直接判定 |
API 端点未认证 |
| HTTP 403 + 短内容 |
text < 2000 字符 |
访问被拒绝页面 |
| 文本登录关键词 |
1 hit + < 500 字符,或 2+ hits |
"请登录"、"sign in to continue"、"verify you are human" |
| 页面标题含登录词 |
+ text < 2000 字符 |
<title>Sign In - Example</title> |
| HTML 密码输入框 |
+ text < 3000 字符 |
<input type="password"> |
| Meta refresh → 登录 URL |
直接判定 |
<meta http-equiv="refresh" content="0;url=/login"> |
| CAPTCHA 嵌入 |
+ text < 1000 字符 |
reCAPTCHA、hCaptcha、Cloudflare Turnstile |
| 空壳备案页 |
2+ hits + < 800 字符 |
仅含 ICP 备案号的页面(小红书等) |
支持中文、英文、日文登录关键词,以及 OAuth 提示("continue with Google")、付费墙("subscribe to continue")、Cloudflare 验证("checking your browser")等。
Cookie 管理
GET /cookies
PUT /cookies/zhihu.com
{"raw": "z_c0=xxx; _xsrf=yyy; d_c0=zzz"}
PUT /cookies/zhihu.com
{"cookies": [{"name":"z_c0","value":"xxx"}, {"name":"_xsrf","value":"yyy"}]}
DELETE /cookies/zhihu.com
POST /cookies/reload
Cookie Catcher(远程浏览器登录)
浏览器访问:GET /cookie-catcher?key=YOUR_API_KEY[&url=https://target-site.com]
工作流程:
- 浏览器打开
/cookie-catcher?key=API_KEY,建立 WebSocket 连接
- 在地址栏输入目标网站 URL,点击 Go