AI接入 v1.0
UI更新
This commit is contained in:
@@ -0,0 +1,467 @@
|
||||
# SearXNG 自建搜索引擎搭建指南
|
||||
|
||||
> 用途:给 AI 助手提供**联网搜索**能力(后端 `web_search` 工具的后端服务)
|
||||
> 环境:Docker 29.7.2 / SearXNG `2026.9.23-3cd69d30e` / Ubuntu(腾讯云 231)
|
||||
> 验证状态:**已上线运行**,实测 14–17 条结果、零异常、约 1.5 秒
|
||||
|
||||
---
|
||||
|
||||
## 0. 这套东西解决什么问题
|
||||
|
||||
大模型自己**不能上网**。你问它"今天的天气"或"Flutter 最新版有什么变化",它只能靠训练数据里的旧信息编——这叫做幻觉。
|
||||
|
||||
正确做法是给它一个**工具**:
|
||||
|
||||
```
|
||||
你提问 → LLM 判断"我需要联网查一下"
|
||||
→ 它让后端调用 web_search("Flutter 3.47 新特性")
|
||||
→ 后端去搜索引擎拿结果
|
||||
→ 把结果喂回给 LLM
|
||||
→ LLM 基于真实结果回答
|
||||
```
|
||||
|
||||
问题在于**中间那个搜索引擎从哪来**:
|
||||
|
||||
| 方案 | 问题 |
|
||||
|---|---|
|
||||
| Google / Bing 官方 API | 要钱、要申请 key、按次计费 |
|
||||
| 直接爬搜索引擎页面 | 很快被封 IP,还要处理反爬 |
|
||||
| **SearXNG(本方案)** | 开源自托管、免费、有现成的 JSON 接口 |
|
||||
|
||||
---
|
||||
|
||||
## 1. 先理解原理(不然后面调优会瞎猜)★
|
||||
|
||||
**这是全文最重要的一节。**
|
||||
|
||||
SearXNG 自己**不会搜索**,它是**元搜索引擎**(聚合器):
|
||||
|
||||
```
|
||||
┌─→ Google ─┐
|
||||
你的查询 ─→ SearXNG ─→ DuckDuckGo ─┼─→ 汇总 / 去重 / 排序 ─→ 返回
|
||||
├─→ Brave ─┤
|
||||
└─→ 百度 ─┘
|
||||
```
|
||||
|
||||
**推论(记住这一条,能省你一小时):**
|
||||
|
||||
> SearXNG 的可用性 = 它底下那些引擎在你服务器上**通不通**。
|
||||
|
||||
所以:
|
||||
- 装在**国外**服务器上 → 默认配置开箱即用(Google/Bing 都通)
|
||||
- 装在**国内**服务器上 → **默认配置返回 0 条结果**,因为默认开的全是墙外的
|
||||
|
||||
这不是 SearXNG 装坏了,是它的引擎连不上。第 4 节专门讲怎么解决。
|
||||
|
||||
---
|
||||
|
||||
## 2. 安装
|
||||
|
||||
### 2.1 前置
|
||||
|
||||
```bash
|
||||
docker --version # 需要 Docker
|
||||
```
|
||||
|
||||
### 2.2 建配置目录
|
||||
|
||||
SearXNG 容器里以 **uid 977** 的用户运行,目录权限必须给对,否则它写不了配置:
|
||||
|
||||
```bash
|
||||
mkdir -p /home/nzy/searxng
|
||||
chown -R 977:977 /home/nzy/searxng
|
||||
```
|
||||
|
||||
> 第一次启动时 SearXNG 会自动生成 `settings.yml`(含随机 secret_key)。预先把目录 chown 好,避免它因为没权限而静默失败。
|
||||
|
||||
### 2.3 启动容器
|
||||
|
||||
```bash
|
||||
docker run -d --name searxng --restart unless-stopped \
|
||||
-p 127.0.0.1:8888:8080 \
|
||||
-v /home/nzy/searxng:/etc/searxng:rw \
|
||||
-e BASE_URL=http://127.0.0.1:8888/ \
|
||||
-e INSTANCE_NAME=qiangbao-search \
|
||||
searxng/searxng
|
||||
```
|
||||
|
||||
逐项说明:
|
||||
|
||||
| 参数 | 作用 |
|
||||
|---|---|
|
||||
| `-p 127.0.0.1:8888:8080` | **只绑本机**。外面访问不到,降低攻击面和运维负担 |
|
||||
| `-v .../searxng:/etc/searxng:rw` | 配置持久化,容器删了配置还在 |
|
||||
| `--restart unless-stopped` | 开机自启 / 挂了自动拉起来 |
|
||||
| `BASE_URL` | 影响 SearXNG 生成的链接,即使本机用也建议设对 |
|
||||
|
||||
### 2.4 为什么只绑 127.0.0.1
|
||||
|
||||
后端和 SearXNG 在**同一台机器**上,走 localhost 就够了。不对外暴露的好处:
|
||||
|
||||
- 不用管 `limiter`(防爬限流)—— 本项目就是关掉的
|
||||
- 不用担心被当成公开实例滥用、被扫
|
||||
- 不用配 HTTPS、不用备案
|
||||
|
||||
> 如果哪天你需要从别的机器访问它,**不要**直接把端口开到公网。至少加上 `limiter: true` + 反代 + 鉴权。
|
||||
|
||||
### 2.5 验证起来了
|
||||
|
||||
```bash
|
||||
docker ps --filter name=searxng --format " {{.Names}} {{.Status}} {{.Ports}}"
|
||||
# 期望:searxng Up xx seconds 127.0.0.1:8888->8080/tcp
|
||||
|
||||
ls -la /home/nzy/searxng/
|
||||
# 期望:看到自动生成的 settings.yml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 两个必踩的坑 ★
|
||||
|
||||
### 坑一:JSON 接口默认是**关**的
|
||||
|
||||
**现象**:请求 `?format=json` 返回 **403**,而且报错信息完全看不出原因。
|
||||
|
||||
**原因**:SearXNG 官方镜像默认只开启 `html` 格式,JSON 需要显式打开。
|
||||
|
||||
**修法**:在 `settings.yml` 里加
|
||||
|
||||
```yaml
|
||||
search:
|
||||
formats:
|
||||
- html
|
||||
- json # ← 没有这行,你的程序永远拿不到数据
|
||||
```
|
||||
|
||||
改完**必须重启**容器:
|
||||
|
||||
```bash
|
||||
docker restart searxng
|
||||
```
|
||||
|
||||
> 排查技巧:如果你看到 403 但浏览器打开首页是正常的,**先怀疑这一条**。
|
||||
|
||||
### 坑二:国内服务器上默认引擎**全军覆没**
|
||||
|
||||
**现象**:接口返回 200,但 `results` 是**空数组**。
|
||||
|
||||
**原因**:默认启用的通用引擎是 `google cse` / `duckduckgo` / `brave` / `wikipedia` / `wikidata` —— 在国内服务器上**全部连不上**。
|
||||
|
||||
**实测数据**(2026-09-24,腾讯云国内机器):
|
||||
|
||||
```
|
||||
结果数: 0
|
||||
无响应引擎: [['brave','timeout'], ['duckduckgo','timeout'], ['google cse','timeout'],
|
||||
['wikidata','timeout'], ['wikipedia','timeout']]
|
||||
```
|
||||
|
||||
**更糟的是**:这些引擎不是立刻失败,而是**各等 3 秒超时**。所以你还会觉得"搜索怎么这么慢"。
|
||||
|
||||
**修法**:见下一节。
|
||||
|
||||
---
|
||||
|
||||
## 4. 引擎调优(国内服务器重点)
|
||||
|
||||
### 4.1 第一步:学会看诊断信息
|
||||
|
||||
SearXNG 的 JSON 返回里有个**关键字段** `unresponsive_engines`,它会告诉你哪些引擎挂了、为什么挂。这是排错的第一入口:
|
||||
|
||||
```bash
|
||||
curl -s --get --data-urlencode "q=Flutter 状态管理" --data "format=json" \
|
||||
http://127.0.0.1:8888/search | python3 -c "
|
||||
import json, sys
|
||||
d = json.load(sys.stdin)
|
||||
print('结果数:', len(d.get('results', [])))
|
||||
print('异常引擎:', d.get('unresponsive_engines', []))
|
||||
eng = {}
|
||||
for r in d.get('results', []):
|
||||
eng[r.get('engine')] = eng.get(r.get('engine'), 0) + 1
|
||||
print('各引擎贡献:', eng)
|
||||
"
|
||||
```
|
||||
|
||||
**三个指标都要看**:
|
||||
|
||||
| 指标 | 含义 |
|
||||
|---|---|
|
||||
| 结果数 | 0 就是没搜到,说明引擎全挂 |
|
||||
| 异常引擎 | 谁挂了、挂的原因(timeout / CAPTCHA / crash) |
|
||||
| 各引擎贡献 | 谁真的在干活。**贡献 0 的引擎可以直接关掉**,省它的等待时间 |
|
||||
|
||||
### 4.2 第二步:拿到引擎的**准确名字**
|
||||
|
||||
**这一步千万别跳过。** SearXNG 是按 `name` 覆盖配置的,**名字写错不会报错,只会静默失效**——你会以为改了,其实没生效。
|
||||
|
||||
```bash
|
||||
# 看镜像里装了哪些引擎模块
|
||||
docker exec searxng ls /usr/local/searxng/searx/engines/
|
||||
|
||||
# 用 /config 接口拿准确名字和当前启用状态(推荐)
|
||||
curl -s http://127.0.0.1:8888/config | python3 -c "
|
||||
import json, sys
|
||||
keys = ['baidu', '360', 'quark', 'sogou', 'bing']
|
||||
for e in json.load(sys.stdin).get('engines', []):
|
||||
if any(k in e['name'].lower() for k in keys):
|
||||
print(f\"{e['name']:<20} enabled={e['enabled']}\")
|
||||
"
|
||||
```
|
||||
|
||||
### 4.3 第三步:实测结论(本项目)
|
||||
|
||||
逐个开关测出来的结果:
|
||||
|
||||
| 引擎 | 分类 | 实测 | 处置 |
|
||||
|---|---|---|---|
|
||||
| **360search** | general | ✅ 可用 | **开启** |
|
||||
| **quark**(夸克) | general | ✅ 可用 | **开启** |
|
||||
| bing | general,web | ⚠️ 没报错但贡献 0 条 | 保留(无害) |
|
||||
| baidu | general | ❌ `CAPTCHA`(被风控拦) | 关闭 |
|
||||
| sogou | general | ❌ `unexpected crash` | 关闭 |
|
||||
| google cse | general,web | ❌ `timeout` | 关闭 |
|
||||
| duckduckgo | general | ❌ `timeout` | 关闭 |
|
||||
| brave | general | ❌ `timeout` | 关闭 |
|
||||
| wikipedia | general | ❌ `timeout` | 关闭 |
|
||||
| wikidata | general | ❌ `timeout` | 关闭 |
|
||||
|
||||
> **注意**:这个结论**只对国内服务器成立**。如果你的服务器在香港/海外,Google 系反而应该开着。**别抄结论,抄方法**。
|
||||
|
||||
**为什么百度也不行?** 搜狗、百度这类国内引擎的反爬很激进,SearXNG 的对应实现经常被拦(返回验证码页)。所以"国内引擎"不等于"国内服务器上能用"——必须实测。
|
||||
|
||||
### 4.4 最终配置
|
||||
|
||||
`/home/nzy/searxng/settings.yml` 完整内容:
|
||||
|
||||
```yaml
|
||||
# SearXNG —— 给强宝小助手用
|
||||
#
|
||||
# 关键一条:search.formats 必须包含 json。官方镜像默认只开 html,
|
||||
# 不开的话 /search?format=json 直接返回 403,且报错信息看不出原因。
|
||||
use_default_settings: true
|
||||
|
||||
server:
|
||||
secret_key: "<首次启动自动生成的随机串,保持原样别改>"
|
||||
image_proxy: true
|
||||
limiter: false # 本机自用,限流会让 JSON 接口返回 429
|
||||
public_instance: false
|
||||
|
||||
search:
|
||||
formats:
|
||||
- html
|
||||
- json
|
||||
|
||||
# 引擎取舍:SearXNG 自己不会搜索,它只是聚合各家引擎。
|
||||
# 这台机器在国内,google/duckduckgo/brave/wikipedia 全部连不上,
|
||||
# 而且每个都要白等 3 秒超时 —— 必须关掉,否则搜索又慢又空。
|
||||
engines:
|
||||
# 国内能通的
|
||||
- name: 360search
|
||||
disabled: false
|
||||
- name: quark
|
||||
disabled: false
|
||||
- name: bing
|
||||
disabled: false
|
||||
|
||||
# 实测不行的:baidu 被 CAPTCHA 拦、sogou 报 unexpected crash
|
||||
- name: baidu
|
||||
disabled: true
|
||||
- name: sogou
|
||||
disabled: true
|
||||
|
||||
# 实测 timeout 的(2026-09-24 测出来 5 个全挂)
|
||||
- name: google cse
|
||||
disabled: true
|
||||
- name: duckduckgo
|
||||
disabled: true
|
||||
- name: brave
|
||||
disabled: true
|
||||
- name: wikipedia
|
||||
disabled: true
|
||||
- name: wikidata
|
||||
disabled: true
|
||||
```
|
||||
|
||||
**改完必做**:
|
||||
|
||||
```bash
|
||||
chown 977:977 /home/nzy/searxng/settings.yml # 权限别丢
|
||||
docker restart searxng
|
||||
sleep 7 # 给它点启动时间
|
||||
docker logs searxng 2>&1 | grep -iE "error|invalid|unknown" | tail -5
|
||||
```
|
||||
|
||||
> 日志里如果有 `can't register engine` 说明**引擎名写错了**,配置那行会静默失效——这就是 4.2 要你先拿准确名字的原因。
|
||||
|
||||
### 4.5 调优后的效果
|
||||
|
||||
```
|
||||
查询「Flutter 状态管理」 → 12 条结果,1.5 秒,异常 []
|
||||
查询「MySQL 主从复制 搭建」→ 14 条结果,异常 []
|
||||
查询「深度求索 DeepSeek」 → 17 条结果,异常 []
|
||||
各引擎贡献: {'360search': 6, 'quark': 8}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 验证清单
|
||||
|
||||
装完之后按顺序验三件事:
|
||||
|
||||
```bash
|
||||
# ① 服务活着 + JSON 格式已开(这一步只验格式,不验引擎)
|
||||
curl -s -o /dev/null -w "HTTP %{http_code}\n" \
|
||||
"http://127.0.0.1:8888/search?format=json&q=test"
|
||||
# 200 = 格式开了;403 = 回去看 3.1
|
||||
|
||||
# ② 引擎真的能搜到东西
|
||||
curl -s --get --data-urlencode "q=测试" --data "format=json" \
|
||||
http://127.0.0.1:8888/search | python3 -c "
|
||||
import json,sys; d=json.load(sys.stdin)
|
||||
print('结果数:', len(d.get('results',[])), '异常:', d.get('unresponsive_engines',[]))
|
||||
"
|
||||
# 结果数 >0 且 异常=[] 才算通
|
||||
|
||||
# ③ 中文查询也正常(很多引擎对中文支持差)
|
||||
curl -s --get --data-urlencode "q=今天有什么新闻" --data "format=json" \
|
||||
http://127.0.0.1:8888/search | python3 -c "
|
||||
import json,sys; print(len(json.load(sys.stdin).get('results',[])))
|
||||
"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 接入后端(本项目)
|
||||
|
||||
### 6.1 配置
|
||||
|
||||
后端通过环境变量读地址(见 `application.yml` 的 `ai.search.base-url`):
|
||||
|
||||
```bash
|
||||
# /home/nzy/.env
|
||||
SEARCH_BASE_URL=http://127.0.0.1:8888
|
||||
```
|
||||
|
||||
`manage.sh` 会在启动 java 之前自动 source 这个文件。改完重启:
|
||||
|
||||
```bash
|
||||
cd /home/nzy && ./manage.sh restart
|
||||
# 确认变量真的进到进程里了
|
||||
tr '\0' '\n' < /proc/$(cat app.pid)/environ | grep SEARCH_
|
||||
```
|
||||
|
||||
**不配这个变量会怎样**:后端**不注册** `web_search` 工具——模型不知道自己能联网,也就不会瞎编"我查到了"。这是刻意的设计。
|
||||
|
||||
### 6.2 后端怎么用它
|
||||
|
||||
```
|
||||
LLM 决定联网
|
||||
↓ tool_calls: web_search({"query": "..."})
|
||||
SearxngApiClient.search(query, maxResults=5)
|
||||
↓ GET {SEARCH_BASE_URL}/search?format=json&q=<urlencoded>
|
||||
取前 5 条 → 拼成 JSON(title/url/snippet)→ 回填给模型
|
||||
↓
|
||||
模型基于真实结果回答,并标注来源
|
||||
```
|
||||
|
||||
代码在 `src/main/java/com/accounting/service/SearxngApiClient.java`。
|
||||
|
||||
### 6.3 ⚠️ 一个安全提醒
|
||||
|
||||
**脱敏层保护的是「发给 LLM 的内容」,不包含搜索词。**
|
||||
|
||||
搜索词会原样发给 360search / 夸克(以及它们的上游)。所以:
|
||||
|
||||
- ✅ 「帮我查一下 Flutter 3.47 有什么新特性」
|
||||
- ❌ 「帮我查一下 155.103.159.109 这台机器」
|
||||
|
||||
第二句会把你的服务器 IP 送到第三方搜索引擎。**别在联网搜索里带敏感信息。**
|
||||
|
||||
---
|
||||
|
||||
## 7. 日常维护与排错
|
||||
|
||||
### 7.1 常用命令
|
||||
|
||||
```bash
|
||||
docker logs searxng 2>&1 | tail -30 # 看日志
|
||||
docker restart searxng # 改配置后重启
|
||||
docker stats searxng --no-stream # 资源占用
|
||||
```
|
||||
|
||||
### 7.2 排错对照表
|
||||
|
||||
| 现象 | 原因 | 处置 |
|
||||
|---|---|---|
|
||||
| `?format=json` 返回 **403** | `search.formats` 没加 json | 见 3.1 |
|
||||
| 返回 200 但**结果数为 0** | 引擎全连不上 | 见 3.2 / 4.3 |
|
||||
| 结果里有 **`CAPTCHA`** | 该引擎被风控拦 | 关掉它 |
|
||||
| 结果里有 **`unexpected crash`** | 该引擎实现有 bug | 关掉它 |
|
||||
| 结果里有 **`timeout`** | 网络不通 | 关掉它(别留着白等) |
|
||||
| 返回 **429** | `limiter` 开着 | 设 `limiter: false` 并重启 |
|
||||
| 日志报 `can't register engine` | **引擎名写错** | 用 `/config` 拿准确名字(4.2) |
|
||||
| 容器反复重启 | 配置目录权限不对 | `chown -R 977:977 /home/nzy/searxng` |
|
||||
| 本机 curl 不通 | 端口没发布 / 绑错地址 | 检查 `-p 127.0.0.1:8888:8080` |
|
||||
| 搜索很慢(3 秒以上) | 有引擎在等超时 | 用 `unresponsive_engines` 找出并关掉 |
|
||||
|
||||
### 7.3 升级 SearXNG
|
||||
|
||||
```bash
|
||||
docker pull searxng/searxng
|
||||
docker stop searxng && docker rm searxng
|
||||
# 重新执行 2.3 的 docker run(配置在挂载目录里,不会丢)
|
||||
```
|
||||
|
||||
> 升级后**重新跑一遍第 5 节的验证**——新版本可能改了默认引擎列表。
|
||||
|
||||
---
|
||||
|
||||
## 8. 附录
|
||||
|
||||
### 8.1 命令速查
|
||||
|
||||
```bash
|
||||
# 启动
|
||||
docker start searxng
|
||||
|
||||
# 看哪些引擎启用中
|
||||
curl -s http://127.0.0.1:8888/config | python3 -c "
|
||||
import json,sys
|
||||
for e in json.load(sys.stdin)['engines']:
|
||||
if e['enabled']: print(e['name'], '|', ','.join(e.get('categories',[])))
|
||||
"
|
||||
|
||||
# 完整搜索测试(三个指标一起看)
|
||||
curl -s --get --data-urlencode "q=关键词" --data "format=json" \
|
||||
http://127.0.0.1:8888/search | python3 -c "
|
||||
import json,sys; d=json.load(sys.stdin)
|
||||
print('结果数:', len(d.get('results',[])))
|
||||
print('异常引擎:', d.get('unresponsive_engines',[]))
|
||||
eng={}
|
||||
for r in d.get('results',[]): eng[r['engine']]=eng.get(r['engine'],0)+1
|
||||
print('各引擎贡献:', eng)
|
||||
"
|
||||
|
||||
# 浏览器里直接用(图形界面,方便手工试)
|
||||
# 把 8888 端口临时转发出来,或直接在服务器上用 lynx/curl 看 html
|
||||
```
|
||||
|
||||
### 8.2 本项目的部署信息
|
||||
|
||||
| 项 | 值 |
|
||||
|---|---|
|
||||
| 服务器 | 腾讯云 231(国内) |
|
||||
| 容器名 | `searxng` |
|
||||
| 监听 | `127.0.0.1:8888`(不对外) |
|
||||
| 配置目录 | `/home/nzy/searxng/` |
|
||||
| 版本 | SearXNG `2026.9.23-3cd69d30e` |
|
||||
| 后端配置项 | `SEARCH_BASE_URL`(在 `/home/nzy/.env`) |
|
||||
| 可用引擎 | 360search、quark(bing 保留) |
|
||||
| 停用方式 | `docker stop searxng`(后端会自动不给模型 web_search 工具) |
|
||||
|
||||
### 8.3 一句话总结
|
||||
|
||||
> **SearXNG 装起来只要三行命令,难的是「它在你的服务器上能不能真的搜到东西」——而那 100% 取决于底层引擎的网络可达性。先测、再配,别抄别人的引擎清单。**
|
||||
|
||||
---
|
||||
|
||||
*文档创建:2026-09-24 · 所有数据均为在本项目服务器上实测*
|
||||
Reference in New Issue
Block a user