做 AI Agent 的朋友应该都有过这种体验:OpenClaw 自带的 web_search 用起来是挺省事,但跑几天下来问题就攒起来了。额度说没就没,请求稍微密集一点就被限流,更别提频繁换 key、调参数那些碎活。我一开始也忍着,后来实在觉得这玩意儿不够稳,就在本地用 Docker 部署了一个 SearXNG 私有搜索引擎,然后把 OpenClaw 的 web_search 整个替换成了这个本地服务。SearXNG 是个开源的元搜索引擎,能把多个搜索引擎的结果聚合到一个统一页面和统一 API 里。对 OpenClaw 这类 Agent 来说,最有价值的其实是它的 JSON 接口:搜索、抓结果、回传结构化数据,一条链路下来非常干净。这篇文章就把我的完整操作整理出来,从 Docker 环境准备、SearXNG 启动,到 OpenClaw 接入配置和踩坑排查,适合手头有 OpenClaw、想干掉外部搜索限额的朋友参考。
1. 先把话说清楚:OpenClaw 为什么需要一个私有搜索引擎
1.1 内置 web_search 的三个扛不住
我挑三个最典型的来说。
第一是限额。OpenClaw 内建的 web_search 背后通常是某家搜索引擎或 AI 平台的 API,免费额度给得很抠,一个稍微复杂点的 Agent 任务可能几分钟就烧完了。我的项目经常要批量查资料,基本一天不到就见底,然后整个任务链就瘫了。
第二是限流。额度没烧完也会遇到 429 状态码,脚本一密集就触发,然后整个 Agent 流程卡在那里,等重试还是等超时,非常尴尬。尤其是我这边喜欢一次性丢给 Agent 十几个子任务,每个子任务都要查好几轮资料,限流几乎成了必然事件。
第三是隐私。所有关键字都走在第三方通道上,做内部资料检索的时候总觉得不太踏实。虽然不是机密内容,但每次查询都被外部服务记录,时间久了心里难免犯嘀咕。
这三个问题不是设置一两个参数能解决的,本质上是“搜索这个能力不掌握在自己手里”。我当时选型的标准非常明确:本地部署、有标准化 API、支持 Docker、不会被上游随时改规则。SearXNG 恰好全都满足。
1.2 为什么是 SearXNG 而不是别的
可能有人会说,直接申请一个正式搜索引擎官方 API 不就行了?可以,但那条路要绑卡、填申请、走审核流程,个人项目用起来很重。还有一条路是让 OpenClaw 直接解析某个网页搜索结果的 HTML,这个太脆了,页面结构一改就挂,维护成本全堆在自己身上。剩下一个候选是本地跑一个爬虫脚本自己抓,代码量不小,还得处理反爬和去重,想着就头大。
SearXNG 在这几个方案里算是最省事的:它把多个来源的搜索结果统一成自己的格式,提供 HTML 页面和 JSON API 两种出口。镜像在 Docker Hub 上一直有维护,装完以后基本零维护。另外它本身就是隐私友好定位,没有任何商业压力,不会无缘无故砍掉某个接口。我把几个方案放在一起比过:
| 方案 | 部署成本 | 稳定性 | 是否需要付费 | API 完备度 | 隐私可控 |
|---|---|---|---|---|---|
| OpenClaw 内置 web_search | 无 | 一般,受上游影响 | 按量或限额 | 封装好但不可控 | 低 |
| 申请搜索引擎官方 API | 中 | 高 | 通常收费 | 高 | 中 |
| 自己写爬虫脚本 | 高 | 低 | 无 | 自己说了算 | 高 |
| Docker 部署 SearXNG | 低 | 高 | 无 | 高(JSON API) | 高 |
1.3 替换之后的整体架构
部署完以后的链路是这样:OpenClaw 发起搜索请求,配置里的 web_search 地址指向本地 SearXNG 的 JSON 接口,SearXNG 再去上游搜索引擎取结果,统一转成结构化 JSON 返回给 OpenClaw。整个链路里只有 SearXNG 到上游搜索这一段依赖外网,其他全部在本机闭环。搜索历史、缓存、临时数据都留在这台机器上。
这个架构最大的好处是:OpenClaw 的代码不用大改,只在配置层把搜索工具的 endpoint 换一下就行。而且因为 SearXNG 天然支持多种格式输出,就算后面 OpenClaw 升级了或者你想接别的 Agent 框架,这套搜索服务仍然可以直接复用。
2. Docker 环境准备:Windows 和 Linux 两套方案
2.1 Windows 下 Docker Desktop 安装的关键点
如果你的本机是 Windows,路径通常是安装 Docker Desktop。这里有两个开关容易卡住:一是 WSL2,二是 BIOS 里的虚拟化。
Docker Desktop 现在默认用 WSL2 后端跑 Linux 容器,所以装之前先把 Windows 的“适用于 Linux 的 Windows 子系统”功能打开。打开方式:控制面板,程序和功能,启用或关闭 Windows 功能,勾选“适用于 Linux 的 Windows 子系统”,然后重启。想确认 WSL2 是不是默认版本,可以在 PowerShell 里敲:
wsl --status看到“默认版本: 2”就对了。如果你之前装过 WSL1 的老环境,可能需要手动wsl --set-default-version 2升级一下。
另一个更隐蔽的坑是 BIOS 虚拟化没开。很多机器买回来默认没开 SVM(AMD)或 VT-x(Intel),Docker Desktop 启动时会直接报 "Virtualization support not detected" 或者 "Docker Desktop failed to start" 这类提示。解决办法是进 BIOS,找到虚拟化开关打开。具体按键因主板而异,常见的是开机时按 Del 或 F2,进去找 AMD SVM 或 Intel VT-x,把 Disabled 改成 Enabled,保存重启。
2.2 Linux 下安装 Docker Engine
Linux 的安装路径清爽很多,以 Ubuntu 和 Debian 系为例,直接走官方脚本最简单:
curl -fsSL https://get.docker.com | bash sudo usermod -aG docker $USER newgrp docker第一行装好 Docker Engine 和 compose 插件,第二三行把你的用户加进 docker 组,避免每次敲命令都要 sudo。Debian 或 Ubuntu 老版本如果脚本跑不了,就用手动方式:加 GPG key、加软件源、apt install docker-ce docker-ce-cli containerd.io,三步走完,也不复杂。
装完以后验证一下:
docker --version docker compose version能看到版本号就说明环境没问题了。这里有个小提醒:很多教程让新手装 Docker Desktop 的 Linux 版本,其实 Linux 服务器上完全不需要,装 Engine 就够了,少一层 GUI 反而更省资源更稳定。
2.3 镜像拉不动?先配镜像加速器
这一步经常被忽略,等 deploy 的时候才发现镜像下不动。SearXNG 的官方镜像在 Docker Hub 上,国内直连的速度很看网络心情。最简单的办法是给 Docker 配置 registry mirror。Windows 和 Linux 都一样,在 Docker Engine 配置文件里加一段registry-mirrors,填入可用的镜像加速地址,然后重启 Docker。
注意:镜像加速只影响 docker pull 环节,拉下来之后容器运行不受影响。如果你用 Docker Desktop,直接在 Settings 的 Docker Engine 页面里编辑 JSON 就行,保存后会自动重启引擎。Linux 下则改
/etc/docker/daemon.json,改完执行sudo systemctl restart docker。
如果不想动全局配置,也可以对单条命令加参数,但日常使用还是全局配置省心。我建议在部署 SearXNG 之前就把这一步做好,免得 docker compose up 的时候卡在 pull 镜像上,那种等待非常磨人。
3. SearXNG 一键部署:从 docker-compose 到浏览器验证
3.1 准备部署目录和 docker-compose.yml
先给出一个完整可复制的部署目录:
searxng/ ├── docker-compose.yml └── searxng-data/ # 挂载出来的配置目录,启动后自动生成docker-compose.yml 核心内容:
version: "3" services: searxng: image: searxng/searxng:latest container_name: searxng ports: - "8080:8080" environment: - SEARXNG_BASE_URL=http://127.0.0.1:8080/ - SEARXNG_SECRET=generate_a_long_random_string volumes: - ./searxng-data:/etc/searxng restart: unless-stopped几个点解释一下。端口映射写的是8080:8080,左边是宿主机端口,右边是容器端口;如果你机器上 8080 已有服务在跑,把左边改成 8081 就行,容器内部不用动。SEARXNG_SECRET是必填的,官方镜像启动时如果检测不到这个变量,会直接拒绝启动,因为后面所有 session、API 签名都要用它。生成随机串最快的方法是:
openssl rand -hex 32SEARXNG_BASE_URL看起来只是个展示地址,但它会影响页面里生成的链接和部分 API 返回值,建议填你实际访问这个服务的地址。如果你后面让 OpenClaw 也部署在同一台机器,保持 127.0.0.1 是最省事的。restart: unless-stopped的意思是容器崩了自动拉起,但手动 stop 之后不会自动复活,适合常驻服务。
3.2 settings.yml:JSON 接口和限速开关
镜像第一次启动时会向挂载目录写入一份默认配置。默认配置可以直接用,但如果要让 OpenClaw 能拿到 JSON 结果,必须确认一下search.formats里有没有json。新版本默认是开了的,旧版本可能只有 html。看配置目录下的 settings.yml,找到这两个块:
server: secret_key: "your_random_secret_key" limiter: true search: formats: - html - jsonlimiter: true默认开启,对公网实例是好事,防止被刷。但如果你是本地或者内网专用,它反而可能误伤高频调用,Agent 一批任务下去容易触发 429。我个人的做法是内网部署时把它改成 false,或者先用默认配置跑一阵,观察一下会不会频繁 429,再决定要不要关。
3.3 启动服务和浏览器验证
配置好了直接:
docker compose up -d第一次会拉镜像,稍等片刻。启动以后浏览器打开http://127.0.0.1:8080/,应该能看到一个偏简洁的搜索页面,搜个关键词能出结果,就说明实例活了。
这时建议顺手检查一下容器状态:
docker ps docker logs -f searxngdocker logs里如果出现类似 "listen tcp :8080: bind: address already in use" 就说明端口冲突了,回去改映射端口就好。如果没有报错,下一步才是关键。
3.4 JSON API 验证
OpenClaw 要用的不是网页,是 JSON 接口。用 curl 测一下:
curl "http://127.0.0.1:8080/search?q=test&format=json"返回大段 JSON,里面能看到results、query、number_of_results这些字段,就说明 API 通道是通的。这时候可以看一眼返回结构里每个结果的字段,通常有url、title、content、engine、score等,Agent 解析主要靠这几个字段。有些时候页面上能搜到结果但 API 返回空,多半是 SearXNG 对 JSON 请求走了另一套引擎策略,后面排查章节再谈。
4. 把 OpenClaw 的 web_search 切到 SearXNG
4.1 先想清楚 OpenClaw 侧要改什么
OpenClaw 的 web_search 工具本质上是“调用一个搜索 API 然后把结果喂回给模型”。要换成 SearXNG,核心就一件事:把搜索工具的请求地址从原来的外部服务改成http://127.0.0.1:8080/search。不同版本的 OpenClaw 配置入口可能略有差异,有的在配置文件的 tools 段,有的在启动时的参数里,但思路都一样。我在用的版本里,搜索工具相关配置大概是这样的结构:
tools: web_search: provider: custom api_base: http://127.0.0.1:8080/search api_format: json query_param: q max_results: 10这是基于我实际部署时记录下来的配置形态,如果你的版本字段名不同,对照一下官方文档里的 web_search 配置说明即可,核心字段无非是 endpoint、请求格式、结果条数这几个。如果你的 OpenClaw 是通过 MCP 插件体系接入工具的,那更简单:社区里有现成的 SearXNG MCP Server,把 MCP 的 server 地址指向http://127.0.0.1:8080/search就行,工具名照样还是 web_search 或者 searxng_search。
4.2 一个最容易忽略的坑:127.0.0.1 到底是哪台机器
如果你的 OpenClaw 和 Docker 跑在同一台物理机上,127.0.0.1:8080没问题。但如果 OpenClaw 跑在宿主机,Docker 也跑在宿主机,而 OpenClaw 本身又跑在容器里(常见于 OpenClaw 也容器化部署),那“127.0.0.1”指向的是 OpenClaw 自己的容器,根本访问不到 SearXNG。这时候要么让 OpenClaw 容器和 SearXNG 容器挂同一个 Docker network,然后地址写服务名http://searxng:8080/search;要么直接用宿主机局域网 IP,比如http://192.168.1.100:8080/search。
我在 Ubuntu 上装 OpenClaw 时就是这么处理的:OpenClaw 在本机进程里,SearXNG 在 Docker 里,两者共享宿主机的网络命名空间,所以写127.0.0.1就通。如果你的环境是 Windows 上跑 WSL2,情况又不一样,从 Windows 侧访问 WSL2 里容器映射出来的端口,通常用localhost没问题,但反过来 WSL2 里访问 Windows 侧的 OpenClaw 服务,就要用 Windows 主机 IP 了。这个链路经常把人绕晕,建议在改配置之前先做一次连通性验证,别等 Agent 跑起来才发现全是不通的。
4.3 配置完的完整测试路径
改完配置不要急着跑完整 Agent 流程,先用最小方式验证:在 OpenClaw 的交互面板里单独调用一次 web_search,输入一个测试关键词,比如“OpenClaw 最新版本”,看返回是否正常。正常的返回应该是有几条带 title、url、content 的结果列表。如果这一步通了,再跑一个带搜索环节的完整任务,观察日志里搜索请求是否都打到了 SearXNG 上。
我换完以后跑过一批需要联网查资料的任务,效果提升最明显的是:不再 429,响应速度稳定在几百毫秒到一两秒,而且搜索结果不受外部额度限制。整个过程下来 OpenClaw 的代码一行没改,纯粹是配置替换。
5. 踩坑实录:部署和接入过程中的典型问题
5.1 Docker Desktop 启动失败:Virtualization support not detected
这个报错出现频率极高,我第一次在 Windows 上装就遇到了。原因基本就是 BIOS 里的虚拟化没开,或者 Hyper-V 没启用。解决顺序:先确认 BIOS 里 SVM 或 VT-x 是 Enabled,再确认 Windows 功能里的 Hyper-V 和“虚拟机平台”都勾上了。如果 BIOS 已经开了还是报错,去 PowerShell 里以管理员身份跑:
bcdedit /set hypervisorlaunchtype auto然后重启。这些都是常规操作,但顺序别搞反,先 BIOS 后系统。如果你用的是 AMD 平台,BIOS 里那项通常叫 SVM Mode,Intel 平台叫 VT-x 或者 Virtualization Technology,不同主板命名略有差异,但找“Virtualization”关键词一般没错。
5.2 容器起不来或反复重启
docker ps -a看容器状态,如果是 Exited,用docker logs searxng看日志。我遇到过的两类典型问题:一是 secret_key 没设,日志里明确会提示缺少 secret_key;二是挂载目录权限不对,导致容器内进程写不了配置文件,日志里会出现 permission denied,解决方法是给目录加写权限或者修正目录属主。
还有一种情况是内存不足。SearXNG 本身不重,但 Docker Desktop 在 Windows 上默认内存配额不高,跑的任务多了可能 OOM,去 Docker Desktop Settings 里把内存调到 4GB 以上更稳。Linux 服务器上如果同时跑着 OpenClaw 和其他容器,也要留意系统可用内存,free -h看一眼就知道够不够。
5.3 页面能搜到结果,但 JSON 接口返回空
这个我实打实排查过。页面和 JSON 接口在部分引擎下会走不同的策略,比如某些引擎对无浏览器环境返回空结果。方法有三:在 settings.yml 里多启用几个上游引擎,别单一依赖某个容易空的;把server.limiter关掉或者调高时间窗口;确认请求头里有合理的 User-Agent。还有一个细节,JSON 格式下若返回 403,多半是 SearXNG 把非浏览器请求当成了机器人,可以尝试在 settings.yml 里调整 botdetection 配置,本地部署可以直接放宽。
5.4 搜索接口正常,但 OpenClaw 解析不到结果
这个现象我遇到过两次,表现为日志里明明打了搜索请求,返回也有 JSON,但 Agent 认为没结果。原因通常是 SearXNG 返回结构里的字段名,和 OpenClaw 预期解析的字段名对不上。比如 OpenClaw 期望content字段当摘要,SearXNG 某些引擎返回的却是空 content,只有snippet。解法是检查你传入的max_results参数不要太激进,同时确认 SearXNG 返回的results列表长度不是 0。另外有些引擎对连续查询会临时封掉,导致间歇性空结果,可以在 settings.yml 里把search.safe_search调一下,或者直接换更稳定的引擎组合。
5.5 高频调用被限流,频繁触发 429
本地自建搜索引擎的唯一好处就是没有云厂商限流,但 SearXNG 自己默认的 limiter 还是会拦。前面提过,server.limiter: true改成 false 是最直接的解法,但要注意如果端口暴露到了公网,这个开关就不建议关。内网和本机使用,关了没问题。如果不想全关,也可以调整限流的时间窗口和请求次数上限,按你的实际调用频率配一个余量。我自己的配置是直接把 limiter 关掉了,因为就我一个人用,不存在被刷的风险。
5.6 数据持久化和升级备份
最后补一条运维向的。SearXNG 的挂载目录里不止有 settings.yml,还有搜索引擎的缓存数据。升级镜像前先备份整个searxng-data/目录,特别是当你在 settings.yml 里改过自定义引擎配置时,备份能让你失败后一秒回滚。升级操作也很简单:
docker compose pull docker compose up -d容器会自动用新镜像重建,数据目录因为挂载在外面所以不会丢。这个习惯我一直在用,每次改配置或者升级前都会顺手 tar 一下整个目录,成本极低,但真到要回滚的时候能救命。
我个人在实际使用中的一个体会是:SearXNG 最值钱的不是那个搜索页面,而是那个稳定的 JSON 接口。把 OpenClaw 的 web_search 切过来以后,我一直是让 Agent 在本地查资料,额度焦虑直接消失了。最后再分享一个习惯:每次改完 settings.yml 我都会用docker compose restart重启容器,并且翻一下docker logs确认没有加载报错再去跑任务,这个小习惯帮我避免了很多“看似正常其实配置没生效”的尴尬。如果你也正在给 OpenClaw 找稳定的搜索后端,这套方案可以直接复制过去试试。