自托管 AI 知识库与联网搜索全套方案:SearXNG + mcp-searxng + Infinity + R2R + pgvector

目标:用 4 个开源组件 + 1 个 MCP 桥接服务,在本地搭一套完全自托管的「向量知识库(RAG)+ 隐私联网搜索」基础设施,供 Claude、OpenCode、Cursor 等 AI 客户端调用。

一、方案总览

1.1 组件与镜像

组件 镜像 作用
SearXNG searxng/searxng:latest 自托管元搜索引擎,聚合 Google/Bing/DuckDuckGo 等结果,不追踪用户
mcp-searxng isokoliuk/mcp-searxng:latest(或 npx 本地运行) MCP 协议桥,把 SearXNG 的搜索能力暴露给 AI 客户端(Claude Desktop/Code、Cursor、OpenCode 等)
Infinity michaelf34/infinity:0.0.77-cpu 高吞吐 Embedding/Rerank 推理服务,提供 OpenAI 兼容的 /embeddings 接口,CPU 版无需显卡
R2R (RAG to Riches) sciphiai/r2r:3.6.6-amd64 生产级 RAG 服务:文档解析、切片、向量化入库、混合检索、RAG API
pgvector pgvector/pgvector:pg16 内置 pgvector 扩展的 PostgreSQL 16,作为向量数据库持久层

1.2 架构图

                    ┌──────────────────────────────┐
                    │   AI 客户端(Claude/OpenCode)│
                    └──────┬───────────────┬───────┘
              MCP 协议     │               │  HTTP API
                           ▼               ▼
              ┌─────────────────┐   ┌──────────────────┐
              │   mcp-searxng   │   │    R2R :7272     │◄── 你自己的应用
              │  (搜索工具桥) │   │   RAG 服务       │    (/v1/retrieval 等)
              └────────┬────────┘   └───────┬──────────┘
                       │ HTTP JSON          │ 调用 embedding
                       ▼                    ▼
              ┌─────────────────┐   ┌──────────────────┐
              │  SearXNG :8080  │   │ Infinity :7997   │
              │  元搜索         │   │ bge-m3 向量模型  │
              └────────┬────────┘   └──────────────────┘
                       │ 抓取各搜索引擎            │ 向量读写
                       ▼                            ▼
                 Google/Bing/...        ┌──────────────────┐
                                        │ pgvector (PG16)  │
                                        │ 5432 向量存储    │
                                        └──────────────────┘

两条能力线相互独立又互补:

  • 联网搜索线:客户端 → mcp-searxng → SearXNG → 各大搜索引擎。解决「模型不知道最新信息」的问题。
  • 私有知识线:文档 → R2R → Infinity 向量化 → pgvector 存储 → 检索问答。解决「模型不知道你的私有资料」的问题。

1.3 为什么选这套组合

  1. 全部可自托管:搜索记录不出内网;Embedding 在本地 CPU 跑,不依赖 OpenAI。
  2. 版本都经过社区验证:Infinity 0.0.77 与 R2R 3.6.x 是各自项目稳定期版本,镜像多架构齐全。
  3. 标准协议对接:MCP 是 AI 工具生态事实标准;Infinity 和 R2R 都讲 OpenAI 兼容 HTTP,替换任何一个组件都不影响整体。

二、环境准备

要求 说明
Docker ≥ 24 + Compose v2 所有服务容器化部署
内存 ≥ 8GB Infinity 加载 bge-m3 约占 2~3GB;R2R 约占 1GB
磁盘 ≥ 20GB 含模型权重(bge-m3 约 2GB)、Postgres 数据
可访问 HuggingFace 首次启动拉取模型;国内建议配 HF_ENDPOINT=https://hf-mirror.com

目录结构约定:

/opt/ai-stack/
├── docker-compose.yml
├── .env                  # 密码、密钥等敏感配置
├── searxng/
│   ├── settings.yml      # SearXNG 主配置
│   └── limiter.toml
├── r2r/
│   └── r2r.toml          # R2R 配置(指向 infinity + pgvector)
└── pgdata/               # PG 数据卷

三、逐个部署

3.1 pgvector:PostgreSQL 16 + 向量扩展

pgvector/pgvector:pg16 就是官方 PostgreSQL 16 镜像加了 pgvector 扩展,用法与普通 PG 完全一致:

  postgres:
    image: pgvector/pgvector:pg16
    restart: unless-stopped
    environment:
      POSTGRES_USER: ${POSTGRES_USER:-r2r}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set in .env}
      POSTGRES_DB: ${POSTGRES_DB:-r2r}
    volumes:
      - ./pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-r2r}"]
      interval: 10s
      timeout: 5s
      retries: 5

验证扩展可用(R2R 会自动建表,但可以手动确认扩展存在):

docker compose exec postgres psql -U r2r -c "CREATE EXTENSION IF NOT EXISTS vector;"
docker compose exec postgres psql -U r2r -c "SELECT extname, extversion FROM pg_extension WHERE extname='vector';"

注意:pgvector 的索引(HNSW/IVFFlat)和查询参数由 R2R 自动管理,一般不需要手工建表。向量维度必须与 Embedding 模型输出一致——本文用 bge-m3(1024 维),中途换模型必须重建集合并重新入库。

3.2 Infinity:CPU 版 Embedding 服务

BAAI/bge-m3:多语言(中英效果好)、1024 维、支持长文本(8192 tokens),是中文知识库的主力选择。

compose 片段:

  infinity:
    image: michaelf34/infinity:0.0.77-cpu
    restart: unless-stopped
    environment:
      HF_ENDPOINT: ${HF_ENDPOINT:-}          # 国内镜像加速,如 https://hf-mirror.com
    command: >
      v2
      --model-id BAAI/bge-m3
      --served-model-name bge-m3
      --port 7997
      --batch-size 16
    volumes:
      - ./infinity-cache:/app/.cache          # 缓存模型权重,重启不用重新下载
    ports:
      - "127.0.0.1:7997:7997"                 # 只暴露给本机/容器网络

验证(OpenAI 兼容接口):

curl http://127.0.0.1:7997/embeddings \
  -H "Content-Type: application/json" \
  -d '{"model":"bge-m3","input":["你好,世界"]}'

# 返回 JSON 中 data[0].embedding 应为长度 1024 的数组

要点说明:

  • 0.0.77 版本起命令行入口为 v2 子命令,所有参数也可用 INFINITY_ 前缀环境变量代替(如 INFINITY_MODEL_ID=BAAI/bge-m3;)。
  • -cpu 镜像内置 ONNX/CPU 优化,无 NVIDIA 显卡时的最佳选择;有卡请换默认镜像并加 --gpus all
  • 还可以再挂一个 rerank 模型(如 --model-id BAAI/bge-reranker-base)供 R2R 重排用,按需增加。
  • 首次启动要下载约 2GB 权重,耐心等待日志出现 Uvicorn running 再测接口。

3.3 R2R:RAG 编排服务

R2R 负责最重的活:文档摄取(PDF/DOCX/HTML/MD)、语义切块、调 Infinity 向量化、写入 pgvector、提供检索与 RAG 问答 API。

r2r/r2r.toml 关键配置(把 embedding 指到本地 Infinity,把存储指到本地 pgvector):

[completion]
# 生成模型仍需要一个 LLM 提供方;provider 用 litellm 时模型名要带 openai/ 前缀
provider = "litellm"
concurrent_request_limit = 16

  [completion.generation_config]
  model = "openai/gpt-4o-mini"     # 也可以指向任意 OpenAI 兼容的本地大模型
  temperature = 0.1
  max_tokens_to_sample = 1024
  stream = true

[embedding]
provider = "openai"                # 走 OpenAI 兼容协议 → 即本地 Infinity
base_model = "bge-m3"              # 对应 --served-model-name

[database]
provider = "pgvector"

配套环境变量(写入 .env 或 compose 的 environment):

# 让 R2R 的 openai/litellm 客户端打到本地 Infinity
OPENAI_API_BASE=http://infinity:7997/v1
OPENAI_API_KEY=empty                      # Infinity 不校验,占位即可

# pgvector 连接
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
POSTGRES_USER=r2r
POSTGRES_PASSWORD=your-strong-password
POSTGRES_DB=r2r

提示:不同小版本的 toml 字段名偶有调整,以上结构以 R2R GitHub 仓库 v3.6.x 的示例配置为准,冲突时以官方模板为准。

compose 片段:

  r2r:
    image: sciphiai/r2r:3.6.6-amd64
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
      infinity:
        condition: service_started
    environment:
      OPENAI_API_BASE: http://infinity:7997/v1
      OPENAI_API_KEY: empty
      POSTGRES_HOST: postgres
      POSTGRES_PORT: "5432"
      POSTGRES_USER: ${POSTGRES_USER:-r2r}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB:-r2r}
    volumes:
      - ./r2r/r2r.toml:/app/config/r2r.toml
      - ./r2r/data:/app/data
    ports:
      - "7272:7272"          # R2R API

常用操作:

# 上传文档建立知识库(会自动切片→Infinity向量化→入pgvector)
curl -X POST http://127.0.0.1:7272/v1/documents \
  -F "file=@./manual.pdf"

# RAG 问答:检索 + LLM 生成
curl -X POST http://127.0.0.1:7272/v1/retrieval/rag \
  -H "Content-Type: application/json" \
  -d '{"query":"设备保修政策是什么?"}'

排错速查:

现象 原因与处理
R2R 启动即退出 pgvector 未就绪或密码不对,看 docker logs r2r
入库报维度不匹配 换过 Embedding 模型;删掉对应 collection 重新入库
入库很慢 Infinity 首次下载模型中;CPU 下 bge-m3 吞吐有限属正常,可调大 --batch-size

3.4 SearXNG:隐私元搜索

SearXNG 必须开启 JSON 输出格式,否则 mcp-searxng 拿不到数据(最常见的坑)。

searxng/settings.yml 最小可用配置:

use_default_settings: true

server:
  secret_key: "change-me-to-random-string"   # openssl rand -hex 32 生成
  limiter: false                             # 仅本机/内网使用时可关
  image_proxy: true

search:
  safe_search: 0
  formats:                                    # ← 关键!默认没有 json
    - html
    - json

engines:
  - name: google
    disabled: false
  - name: bing
    disabled: false
  - name: duckduckgo
    disabled: false

compose 片段(SearXNG 官方推荐 Redis 做缓存):

  redis:
    image: valkey/valkey:8-alpine
    restart: unless-stopped
    command: valkey-server --save 30 1 --loglevel warning

  searxng:
    image: searxng/searxng:latest
    restart: unless-stopped
    depends_on:
      - redis
    environment:
      SEARXNG_BASE_URL: http://127.0.0.1:8080/
    volumes:
      - ./searxng/settings.yml:/etc/searxng/settings.yml:ro
    ports:
      - "8080:8080"

验证 JSON API:

curl "http://127.0.0.1:8080/search?q=docker+searxng&format=json"
# 返回 results 数组即成功;返回 403 说明 formats 里没开 json

3.5 mcp-searxng:给 AI 客户端装上搜索

mcp-searxng 不是 SearXNG 插件,而是独立的 MCP Server(Node.js 进程),唯一必填变量是 SEARXNG_URL。它通常跑在客户端一侧(STDIO 模式),不必进 compose。

Claude Code 注册(用户级):

claude mcp add --scope user --env SEARXNG_URL=http://127.0.0.1:8080 --transport stdio searxng -- npx -y mcp-searxng

Claude Desktop / Cursor / OpenCode 等(JSON 配置):

{
  "mcpServers": {
    "searxng": {
      "command": "npx",
      "args": ["-y", "mcp-searxng"],
      "env": {
        "SEARXNG_URL": "http://127.0.0.1:8080",
        "SEARXNG_MAX_RESULTS": "10",
        "SEARXNG_DEFAULT_LANGUAGE": "zh-CN"
      }
    }
  }
}

常用可选变量:

变量 默认 说明
SEARXNG_URL 必填 SearXNG 地址,支持分号分隔多实例做故障转移
SEARXNG_FANOUT false true 时并行查询所有实例并合并去重
SEARXNG_DEFAULT_LANGUAGE all 默认搜索语言,如 zh-CN
SEARXNG_MAX_RESULTS 10 返回结果条数上限
SEARXNG_TIMEOUT_MS 10000 单次搜索超时

配置完成后在客户端里说一句"搜一下 xxx",能看到工具调用 SearXNG 即接入成功。


四、完整 docker-compose.yml(汇总)

services:
  postgres:
    image: pgvector/pgvector:pg16
    restart: unless-stopped
    environment:
      POSTGRES_USER: ${POSTGRES_USER:-r2r}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set in .env}
      POSTGRES_DB: ${POSTGRES_DB:-r2r}
    volumes:
      - ./pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-r2r}"]
      interval: 10s
      timeout: 5s
      retries: 5

  infinity:
    image: michaelf34/infinity:0.0.77-cpu
    restart: unless-stopped
    environment:
      HF_ENDPOINT: ${HF_ENDPOINT:-}
    command: >
      v2 --model-id BAAI/bge-m3 --served-model-name bge-m3
         --port 7997 --batch-size 16
    volumes:
      - ./infinity-cache:/app/.cache
    ports:
      - "127.0.0.1:7997:7997"

  r2r:
    image: sciphiai/r2r:3.6.6-amd64
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      OPENAI_API_BASE: http://infinity:7997/v1
      OPENAI_API_KEY: empty
      POSTGRES_HOST: postgres
      POSTGRES_PORT: "5432"
      POSTGRES_USER: ${POSTGRES_USER:-r2r}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB:-r2r}
    volumes:
      - ./r2r/r2r.toml:/app/config/r2r.toml
      - ./r2r/data:/app/data
    ports:
      - "7272:7272"

  redis:
    image: valkey/valkey:8-alpine
    restart: unless-stopped
    command: valkey-server --save 30 1 --loglevel warning

  searxng:
    image: searxng/searxng:latest
    restart: unless-stopped
    depends_on:
      - redis
    environment:
      SEARXNG_BASE_URL: http://127.0.0.1:8080/
    volumes:
      - ./searxng/settings.yml:/etc/searxng/settings.yml:ro
    ports:
      - "8080:8080"

.env 示例:

POSTGRES_USER=r2r
POSTGRES_PASSWORD=please-change-me
POSTGRES_DB=r2r
HF_ENDPOINT=https://hf-mirror.com

一键启停:

docker compose up -d
docker compose ps                 # 全部 healthy/running 即就绪
docker compose logs -f infinity   # 观察模型加载

五、验收清单

# 验证项 命令 预期
1 pgvector 扩展 psql -U r2r -c "CREATE EXTENSION IF NOT EXISTS vector;" 无报错
2 Embedding 服务 curl 127.0.0.1:7997/embeddings ... 返回 1024 维向量
3 RAG 入库+问答 POST /v1/documents 后 POST /v1/retrieval/rag 能引用上传文档作答
4 搜索 JSON API curl ".../search?q=test&format=json" 返回 results 数组
5 MCP 搜索 AI 客户端内发起一次搜索 工具调用成功返回网页摘要

六、安全与运维建议

  1. 不要把端口裸奔公网:SearXNG/R2R/Infinity/PG 只绑 127.0.0.1 或走反向代理加认证;mcp-searxng 若以 HTTP 模式对外,务必设置 MCP_HTTP_AUTH_TOKEN 并启用 hardened 模式。
  2. 密钥管理settings.ymlsecret_key.env 里的数据库密码都要换掉示例值;csdcn.env 类凭据文件不要进 git。
  3. 备份:定期备份 pgdata/ 目录(或用 pg_dump),向量库重建成本高。
  4. 升级策略:Infinity 与 R2R 升级可能改变向量维度或表结构,升级前备份,升级后先跑第五节验收清单。
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐