1. 项目概述:为OpenClaw构建私有搜索后端

如果你和我一样,在折腾本地AI工具链时,对OpenClaw的 web_search 功能又爱又恨,那么这个项目可能就是你的解药。OpenClaw是一个强大的AI代理框架,但其内置的网页搜索功能通常依赖于Brave Search等外部商业API。对于注重隐私、希望数据不出内网,或者单纯想省下API调用费用的自托管玩家来说,这多少有点“卡脖子”的感觉。

openclaw-searxng-bridge 这个项目,本质上是一个轻量级的“协议转换器”。它巧妙地利用了OpenClaw某些版本中 web_search 工具对Brave Search API的硬编码依赖,在中间插入了一个兼容层。这个兼容层会拦截原本发往Brave的搜索请求,将其无缝转发到你自托管的SearXNG实例,再由SearXNG去聚合Google、Bing、DuckDuckGo等各大搜索引擎的结果。最终,你得到的是一个完全私有化、可掌控的搜索数据流,而OpenClaw对此浑然不觉,依然以为自己在和Brave愉快地对话。

这个方案特别适合已经拥有或打算搭建SearXNG搜索集群的Homelab爱好者、隐私敏感型开发者,或者任何希望将AI工作流的依赖项尽可能内网化的技术玩家。它不要求你修改OpenClaw的核心代码,而是通过一个简单的Node.js服务和一个补丁脚本,实现“偷梁换柱”。接下来,我会带你从零开始,手把手搭建这套系统,并分享我在部署和调试过程中踩过的坑和总结的技巧。

2. 核心架构与设计思路拆解

在动手之前,理解整个数据流是如何工作的至关重要。这能帮助你在出现问题时,快速定位是哪个环节掉了链子。

2.1 数据流转全景图

整个系统的核心数据流可以概括为以下路径:

OpenClaw Agent (发起 `web_search` 请求)
  -> OpenClaw Gateway (路由请求,使用 `provider: "brave"` 配置)
    -> 硬编码的Brave Search API端点 (已被补丁修改)
      -> `openclaw-searxng-bridge` 服务 (监听在 `http://<bridge-host>:8899/res/v1/web/search`)
        -> 自托管 SearXNG 实例 (监听在 `http://<searxng-host>:8888/search`)
          -> 上游搜索引擎 (Google, Bing, DuckDuckGo等)

这个链条的关键在于“补丁”环节。在OpenClaw的某些发行版中,Brave Search API的URL是直接写死在编译后的JavaScript bundle文件里的。我们的补丁脚本,就是去找到这些硬编码的URL字符串,将其替换为我们桥接服务的地址。这样,当OpenClaw试图调用Brave时,请求实际上被重定向到了我们自己的服务器上。

2.2 为何选择桥接方案,而非直接修改OpenClaw?

你可能会问,为什么不直接给OpenClaw贡献代码,增加一个原生的SearXNG搜索提供商呢?这是一个好问题,也是项目作者在Roadmap中提到的最终目标。但在当下,桥接方案有几个现实优势:

  1. 即时可用性 :无需等待OpenClaw官方合并、发布新版本。你现在就能用上自托管的搜索后端。
  2. 非侵入性 :你不需要理解或修改OpenClaw复杂的内部工具调用逻辑和认证机制。桥接服务只模拟Brave API的 接口形态 ,内部实现完全自定义。
  3. 低风险 :补丁仅修改分发文件,不触及源代码。如果出现问题,恢复备份或重新部署OpenClaw即可回退。
  4. 灵活性 :桥接服务是你完全控制的。你可以在其中添加日志、结果过滤、缓存、甚至请求重试等逻辑,而无需动OpenClaw分毫。

当然,这个方案也有其局限性,最主要的就是 依赖补丁 。每次升级OpenClaw,如果其分发文件被覆盖,就需要重新打补丁。这算是一个为了快速实现功能而接受的“技术债”。

2.3 组件选型与部署考量

项目推荐将SearXNG和桥接服务部署在同一台“搜索虚拟机”上,而OpenClaw Gateway部署在另一台机器。我强烈建议遵循这个架构,原因如下:

  • 网络隔离与安全 :桥接服务(端口8899)和SearXNG(端口8888)只需要在搜索主机内部互通。你只需要将桥接服务的8899端口暴露给运行OpenClaw的主机即可,无需将SearXNG的管理界面或API直接暴露给OpenClaw网络。这遵循了最小权限原则。
  • 资源管理 :SearXNG在进行搜索时,可能会消耗一定的CPU和内存资源(取决于并发请求和启用的引擎数量)。将其与OpenClaw Gateway分离,可以避免资源竞争,影响AI推理的稳定性。
  • 维护便利 :搜索基础设施(SearXNG + Bridge)可以作为一个独立的单元进行维护、备份和升级。

在桥接服务的实现上,项目选择了Node.js。这是一个合理的选择,因为它轻量、异步IO模型适合处理网络代理请求,并且生态丰富。对于SearXNG,项目示例使用了Podman容器部署,这也是目前最主流、最便捷的方式,能很好地解决依赖和环境一致性问题。

3. 分步部署与核心配置详解

理论说完了,我们进入实战环节。我会假设你拥有两台Linux主机(物理机或虚拟机均可),并具备基本的命令行操作和编辑配置文件的能力。

3.1 阶段一:搭建SearXNG搜索实例

首先,在你的“搜索主机”上操作。

1. 准备工作目录与配置

# 创建一个专用用户和目录(可选,但推荐用于权限隔离)
sudo useradd -m -s /bin/bash searxng
sudo su - searxng
mkdir -p ~/searxng
cd ~/searxng

2. 生成关键的settings.yml配置文件 这是SearXNG的核心配置文件。项目提供了一个极简版本,但为了长期稳定运行,我建议进行一些增强。创建一个 settings.yml 文件:

# 使用默认设置作为基础
use_default_settings: true

server:
  # 绑定地址,设为0.0.0.0以接受来自本机桥接服务的请求
  bind_address: "127.0.0.1"
  # 必须修改!使用一个强密钥,以下命令生成:openssl rand -hex 32
  secret_key: "你的32位以上十六进制密钥"
  # 限制器关闭,因为我们是内部服务,无需防爬虫
  limiter: false
  # 启用JSON格式输出,这是桥接服务需要的
  formats:
    - json
    - html

search:
  # 安全搜索过滤器,设为0关闭,避免结果被过滤
  safe_search: 0
  # 每个请求的最大结果数,可以调高
  max_results: 20
  # 搜索引擎超时时间(秒)
  timeout: 5.0

# 日志配置,方便排查问题
logging:
  level: INFO

关键提示 secret_key 绝对不能使用默认的 ultrasecretkey 。请务必使用 openssl rand -hex 32 或项目提供的Python脚本生成一个随机字符串。这是SearXNG的安全基石。

3. 使用Podman启动SearXNG容器 Podman是一个无需守护进程的容器运行时,比Docker更轻量。确保已安装 podman

# 退出searxng用户环境(如果还在的话)
exit
# 使用root或具有sudo权限的用户操作
sudo podman run -d --name searxng \
  --restart=always \
  -p 127.0.0.1:8888:8080 \
  -v /home/searxng/searxng/settings.yml:/etc/searxng/settings.yml:Z \
  docker.io/searxng/searxng:latest

这里有一个重要细节: -p 127.0.0.1:8888:8080 将容器端口8080映射到 宿主机的127.0.0.1:8888 。这意味着SearXNG服务只对本机可见,外部网络无法直接访问,增加了安全性。桥接服务作为本机进程,可以通过 127.0.0.1:8888 访问它。

4. 验证SearXNG运行状态

curl -s "http://127.0.0.1:8888/search?q=test&format=json" | jq '.results[0].title' 2>/dev/null || echo "请安装jq工具,或直接查看原始JSON输出"

如果返回了包含“test”相关结果的JSON对象,说明SearXNG运行正常。如果失败,检查Podman容器日志: sudo podman logs searxng 。常见错误是 settings.yml 格式错误(YAML对缩进极其敏感),或者 secret_key 未更改。

3.2 阶段二:部署OpenClaw-SearXNG桥接服务

桥接服务是本次改造的核心枢纽,它运行在搜索主机上。

1. 获取并准备桥接服务代码 假设我们在 /opt 目录下操作:

sudo mkdir -p /opt/openclaw-bridge
sudo chown $USER:$USER /opt/openclaw-bridge
cd /opt/openclaw-bridge
# 假设你已经通过git clone或下载zip包获得了项目代码
# 项目结构应包含 bridge.js, package.json 等文件

2. 安装Node.js依赖并测试运行 确保你的Node.js版本在18以上(推荐22+)。

npm install
# 设置环境变量并临时运行
PORT=8899 SEARXNG_BASE=http://127.0.0.1:8888 npm start

如果看到服务启动在8899端口的日志,说明基础运行成功。按 Ctrl+C 停止。

3. 创建系统服务(Systemd)实现开机自启 这是保证服务稳定性的关键步骤。创建服务文件 /etc/systemd/system/searxng-bridge.service

[Unit]
Description=OpenClaw to SearXNG Bridge Service
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
# 指定运行用户,建议使用非root用户,如 searxng
User=searxng
Group=searxng
# 设置工作目录和环境变量
WorkingDirectory=/opt/openclaw-bridge
Environment="PORT=8899"
Environment="SEARXNG_BASE=http://127.0.0.1:8888"
# 启动命令,使用绝对路径的node
ExecStart=/usr/bin/node /opt/openclaw-bridge/bridge.js
Restart=always
RestartSec=10
# 日志相关
StandardOutput=journal
StandardError=journal
SyslogIdentifier=searxng-bridge

# 安全加固
NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=/opt/openclaw-bridge
PrivateTmp=true

[Install]
WantedBy=multi-user.target

注意 User Group 需要根据你实际的用户设置修改。 WorkingDirectory 必须指向桥接服务代码所在的目录。 SEARXNG_BASE 环境变量必须与你的SearXNG实例地址一致。

4. 启动并启用服务

sudo systemctl daemon-reload
sudo systemctl enable --now searxng-bridge
sudo systemctl status searxng-bridge

查看状态应为 active (running) 。你可以用之前的命令测试桥接服务是否正常工作:

curl "http://127.0.0.1:8899/healthz" # 应返回 OK
curl "http://127.0.0.1:8899/res/v1/web/search?q=openclaw" | head -c 200

第二个命令应该能返回从SearXNG获取的搜索结果摘要。

3.3 阶段三:配置OpenClaw并应用补丁

现在,转到运行OpenClaw Gateway的主机上操作。你需要知道搜索主机的IP地址(假设为 192.168.1.100 )。

1. 配置OpenClaw的web_search工具 编辑你的OpenClaw配置文件(通常是 openclaw.json 或类似名称)。找到 tools.web.search 部分,确保其配置如下:

{
  "tools": {
    "web": {
      "search": {
        "enabled": true,
        "provider": "brave", // 关键:必须保持为 "brave"
        "apiKey": "dummy-key-required", // 关键:某些版本需要非空值,任意字符串即可
        "brave": {
          "mode": "web"
        }
      }
    }
  }
}

这里的 provider: "brave" 是触发OpenClaw使用Brave API路径的关键。 apiKey 在某些OpenClaw构建版本中是必填的验证字段,虽然我们的桥接服务会忽略它,但填一个占位符可以避免OpenClaw因验证失败而拒绝发送请求。

2. 获取并运行补丁脚本 openclaw-searxng-bridge 项目中的 scripts/patch-openclaw-searxng.sh 脚本复制到OpenClaw主机上。你需要修改脚本中的一个关键点,或者直接在运行时传入参数。

首先,查看你的OpenClaw安装目录。通常,可执行文件或网关服务所在的目录下,会有一个 dist build 文件夹,里面存放着编译后的前端资源(JavaScript bundle文件)。补丁脚本就是在这里面查找并替换硬编码的Brave API URL。

运行脚本(假设脚本已赋予执行权限 chmod +x patch-openclaw-searxng.sh ):

# 假设搜索主机IP是 192.168.1.100,桥接服务端口是默认的8899
./patch-openclaw-searxng.sh 192.168.1.100

脚本会执行以下操作:

  1. 备份 dist 目录(例如 dist_backup_20250415 )。
  2. 递归查找 dist 目录下所有 .js 文件。
  3. 将文件中所有匹配 https://api.search.brave.com/res/v1/web/search 的字符串替换为 http://192.168.1.100:8899/res/v1/web/search
  4. 输出替换了多少处匹配。
  5. 尝试重启OpenClaw网关服务(如果检测到systemd服务名为 openclaw openclaw-gateway )。

3. 验证补丁是否生效 补丁完成后,重启OpenClaw网关服务(如果脚本没有自动完成):

sudo systemctl restart openclaw-gateway # 请根据你的实际服务名调整

然后,通过OpenClaw的Web界面或API触发一个 web_search 。同时,在搜索主机上监控桥接服务的日志:

sudo journalctl -u searxng-bridge -f --since "1 min ago"

如果你看到类似 GET /res/v1/web/search?q=... 的访问日志,并且返回了200状态码,那么恭喜你,补丁成功,流量已经导向了你的私有搜索桥接!

4. 深度排错与运维经验实录

即使按照步骤操作,也可能会遇到各种问题。下面是我在多次部署中遇到的典型问题及其解决方案。

4.1 桥接服务启动失败或无法连接

问题现象 systemctl status searxng-bridge 显示失败,或 curl http://localhost:8899/healthz 无响应。

排查步骤:

  1. 检查Node.js环境与依赖

    node --version # 确保 >= 18
    cd /opt/openclaw-bridge
    npm list # 查看依赖是否完整安装,没有明显的ERROR
    

    有时 npm install 可能因为网络问题失败。可以删除 node_modules package-lock.json 后重试。

  2. 检查端口冲突

    sudo ss -tulpn | grep :8899
    

    如果8899端口已被其他进程占用,修改 bridge.js 中的默认端口或systemd服务文件中的 PORT 环境变量。

  3. 检查SearXNG连接 : 桥接服务启动时需要能访问 SEARXNG_BASE 。手动测试:

    curl -v http://127.0.0.1:8888/healthz # SearXNG的健康检查端点(如果有)
    curl -v "http://127.0.0.1:8888/search?q=test&format=json"
    

    如果SearXNG没响应,检查Podman容器状态: sudo podman ps ,查看日志: sudo podman logs searxng

  4. 查看详细日志

    sudo journalctl -u searxng-bridge -n 50 --no-pager
    

    关注错误堆栈信息。常见错误包括环境变量未设置、配置文件路径错误、权限问题(如服务用户无法读取工作目录)等。

4.2 补丁后OpenClaw仍调用原始Brave API

问题现象 :OpenClaw执行搜索时,桥接服务日志无任何请求记录,但网络抓包显示请求发向了 api.search.brave.com

原因与解决:

  1. 补丁未找到所有硬编码点 :OpenClaw的不同构建版本,其代码打包和压缩方式可能不同,硬编码的URL字符串可能以多种形式存在(如分段字符串、编码后字符串)。补丁脚本使用的是简单的字符串替换,可能不全面。

    • 解决方案 :检查补丁脚本的输出,看替换了多少处。如果为0,说明没找到匹配项。你需要手动搜索 dist 目录下的文件:
      grep -r "api.search.brave.com" /path/to/openclaw/dist/ --include="*.js"
      grep -r "brave.com/res/v1" /path/to/openclaw/dist/ --include="*.js"
      
      找到具体的字符串后,可以手动编辑文件替换,或者修改补丁脚本的正则表达式以匹配找到的格式。
  2. 浏览器或客户端缓存 :如果你通过Web界面测试,浏览器可能缓存了旧的JavaScript文件。

    • 解决方案 :强制刷新浏览器缓存(Ctrl+Shift+R),或使用无痕模式测试。
  3. OpenClaw服务未正确重启 :补丁修改的是磁盘文件,需要重启OpenClaw进程才能加载新的代码。

    • 解决方案 :确认重启了正确的服务。有时可能不止一个相关进程(如前端服务、后端网关)。找到主服务并重启:
      sudo systemctl list-units | grep -i openclaw
      sudo systemctl restart <正确的服务名>
      

4.3 SearXNG返回结果慢或超时

问题现象 :OpenClaw搜索响应很慢,桥接服务日志显示请求到SearXNG耗时很长,或SearXNG日志显示上游引擎超时。

分析与优化:

  1. 调整SearXNG配置 :编辑 settings.yml ,重点关注以下参数:

    search:
      timeout: 3.0  # 降低超时时间,避免单个引擎拖死整个请求
      max_redirects: 1  # 减少重定向次数
      # 精简启用的搜索引擎。并非所有引擎都需要,保留几个稳定快速的即可。
      engines:
        - name: google
          engine: google
          shortcut: g
          timeout: 3.0
          # 可以配置代理(如果需要)
          # proxy: socks5://localhost:1080
        - name: bing
          engine: bing
          shortcut: b
          timeout: 3.0
        - name: duckduckgo
          engine: duckduckgo
          shortcut: d
          timeout: 3.0
    

    禁用一些不必要或速度慢的引擎可以显著提升响应速度。

  2. 网络与DNS问题 :SearXNG需要访问外网上游引擎。确保搜索主机网络通畅,DNS解析快速可靠。可以考虑在主机或容器内配置更优的DNS服务器(如 8.8.8.8 , 1.1.1.1 )。

  3. 桥接服务超时设置 :默认的 bridge.js 可能没有设置下游请求超时。如果SearXNG挂起,桥接也会一直等待。你可以修改 bridge.js ,在向SearXNG发起请求时添加超时选项(例如使用 axios node-fetch 的timeout配置)。

4.4 安全加固要点

项目文档提到了安全建议,这里我再强调和补充几点:

  1. 防火墙规则 :在搜索主机上,使用防火墙(如 ufw firewalld )严格限制端口访问。

    # 假设OpenClaw主机IP是 192.168.1.200
    sudo ufw allow from 192.168.1.200 to any port 8899 proto tcp
    sudo ufw deny 8888/tcp # 禁止外部直接访问SearXNG管理端口
    sudo ufw enable
    

    只允许OpenClaw主机访问桥接服务的8899端口。SearXNG的8888端口只允许本机(127.0.0.1)访问。

  2. 服务运行权限 :切勿以root用户运行桥接服务或SearXNG容器。按照上文,创建专用用户(如 searxng )并分配最小必要权限。

  3. 配置文件的秘密管理 settings.yml 中的 secret_key 以及任何可能的API密钥(如果SearXNG引擎需要)应妥善保管。可以考虑使用环境变量或密钥管理工具注入,而不是明文写在配置文件中。

  4. 定期更新 :关注SearXNG和Node.js依赖的安全更新。定期执行:

    # 更新SearXNG容器
    sudo podman pull docker.io/searxng/searxng:latest
    sudo podman stop searxng
    sudo podman rm searxng
    # 重新运行本文3.1节的podman run命令
    # 更新桥接服务依赖
    cd /opt/openclaw-bridge
    npm update
    sudo systemctl restart searxng-bridge
    

5. 性能调优与高级玩法

基础功能跑通后,我们可以考虑让这套系统更强大、更贴合个人需求。

5.1 为桥接服务添加结果缓存

频繁搜索相同内容会重复消耗SearXNG和上游引擎的资源。为桥接服务添加一个简单的内存缓存可以极大提升响应速度并减少外部请求。这里提供一个修改 bridge.js 的思路:

// 在文件开头引入一个内存缓存,例如使用 node-cache
const NodeCache = require('node-cache');
const searchCache = new NodeCache({ stdTTL: 600, checkperiod: 120 }); // 缓存10分钟

// 在处理 /res/v1/web/search 的路由函数中
async function handleSearch(req, res) {
  const query = req.query.q;
  if (!query) {
    return res.status(400).json({ error: 'Missing query' });
  }

  // 1. 检查缓存
  const cachedResult = searchCache.get(query);
  if (cachedResult) {
    console.log(`Cache hit for query: ${query}`);
    return res.json(cachedResult);
  }

  // 2. 未命中缓存,请求SearXNG
  try {
    const searxngResponse = await axios.get(`${searxngBase}/search`, {
      params: { q: query, format: 'json' },
      timeout: 10000,
    });
    const resultData = searxngResponse.data;

    // 3. 可选:对结果进行裁剪或格式化,以更贴近Brave API的响应结构
    const formattedResults = resultData.results.slice(0, 10).map(r => ({
      title: r.title,
      url: r.url,
      description: r.content,
      // ... 其他可能需要的字段
    }));

    const finalResponse = {
      // 模拟Brave API的响应结构
      web: { results: formattedResults }
    };

    // 4. 存入缓存
    searchCache.set(query, finalResponse);

    res.json(finalResponse);
  } catch (error) {
    console.error('Error fetching from SearXNG:', error.message);
    res.status(502).json({ error: 'Upstream search error' });
  }
}

注意 :这是一个简化示例。实际Brave API的响应结构可能更复杂,需要你根据OpenClaw的预期格式进行调整。添加缓存后,记得 npm install node-cache

5.2 部署高可用SearXNG集群

对于重度用户,单个SearXNG实例可能成为瓶颈或单点故障。你可以部署多个SearXNG实例,并在桥接服务中实现简单的负载均衡或故障转移。

架构思路:

  1. 在搜索主机上使用Docker Compose或Kubernetes部署2-3个SearXNG容器实例,每个实例使用不同的本地端口(如8888, 8889, 8890)。
  2. 修改桥接服务,维护一个可用的SearXNG实例地址列表。
  3. handleSearch 函数中,随机选择一个实例或使用轮询方式发起请求。如果某个实例请求失败,自动切换到列表中的下一个。

这能提升系统的吞吐量和容错能力。桥接服务可以作为一个简单的负载均衡器。

5.3 集成其他搜索源

SearXNG本身支持众多引擎,但你也可以让桥接服务不止于SearXNG。例如,你可以让它同时查询SearXNG和一个本地的文档数据库(如Elasticsearch),然后将结果合并、去重、排序后返回给OpenClaw。这需要你修改桥接服务的逻辑,使其成为一个“元搜索聚合器”。

实现的关键在于理解OpenClaw的 web_search 工具期望的响应格式。你需要通过抓包或查看OpenClaw源码,弄清楚它如何解析Brave API的返回结果,然后让你的桥接服务模拟出相同的格式。

6. 未来展望与维护建议

目前这个桥接方案是一个优雅的“临时”解决方案。它的长期维护性取决于两个因素:

  1. OpenClaw官方对SearXNG的支持 :正如项目Roadmap所言,当OpenClaw原生集成SearXNG作为搜索提供商时,这个桥接方案就可以光荣退役了。届时,你只需要在OpenClaw配置中将 provider "brave" 改为 "searxng" ,并配置对应的地址和密钥即可。
  2. OpenClaw构建版本的变化 :如果未来OpenClaw的构建流程改变,导致硬编码的API URL模式发生变化,补丁脚本可能需要更新。

给你的维护建议:

  • 文档化你的部署 :详细记录你的SearXNG配置、桥接服务安装路径、补丁脚本位置、OpenClaw版本以及所有自定义修改。这会在未来升级或故障排查时拯救你。
  • 监控服务状态 :为 searxng-bridge 服务和SearXNG容器设置简单的监控,比如使用 systemctl 状态检查,或者一个定时 curl 健康检查的脚本,失败时发送通知。
  • 定期测试搜索功能 :每隔一段时间,手动触发一次OpenClaw的搜索,确保整个链路依然畅通。自动化测试更好。
  • 关注上游更新 :订阅OpenClaw和SearXNG的发布动态。OpenClaw的大版本升级很可能需要你重新评估并应用补丁。

这个项目展示了在现有生态中通过“适配层”解决兼容性问题的经典思路。它可能不是永久性的,但它提供了当下就能实现的、完全自控的搜索能力。对于追求数据主权和隐私的Homelab玩家来说,这种掌控感带来的满足,远超过搭建过程中的那一点点折腾。

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐