quivr Docker Compose 部署指南

quivr 2.0.0-alpha.7 单机 Docker Compose 部署实测:官方发布包 setup.py init/prepare 全流程、9 服务编排栈(API/Worker/PostgreSQL/Weaviate/Temporal/SeaweedFS/嵌入服务/演示界面)、镜像 digest 选型、数据持久化、环境变量与配置参数、等价 docker run、运维命令与迁移排障。

quivrquivrRAGLLM知识库2026/10/23

quivr Docker Compose 部署指南

目标:在单台 Linux 服务器上用官方发布包 + Docker Compose 从零完成 quivr 2.0.0-alpha.7 的完整部署(9 个服务的编排栈:引擎 API/Worker、PostgreSQL、Weaviate 向量索引、Temporal 工作流、SeaweedFS 对象存储、CPU 嵌入服务与演示界面),覆盖初始化、模型缓存准备、启动验证、持久化、环境变量与运维排障全流程。已在 Ubuntu 24.04(x86_64)+ Docker Engine 29.8 + Docker Compose v5.5.1 环境实测通过,API 端口 8080、演示界面端口 3000 验证可用。

一、环境信息

本文所有命令与回显均在以下环境实测:

  • 操作系统:Ubuntu 24.04 LTS(x86_64),内核 6.8 系
  • Docker Engine:29.8 系(docker:dind 29.8.1 内核参数同真机),Docker Compose v5.5.1(docker compose version 实测回显见四.6)
  • Python:3.12.3(python3 --version 实测:Python 3.12.3)
  • quivr 版本:2.0.0-alpha.7(revision 7b5ffe3eaa031ccbb1f49244b76e8b9bf5d11426,API v0,插件引擎 0.2.0)
  • 安装目录:/opt/quivr(官方发布包解压目录,下文统一按此路径书写)
  • 演示安装参数:--embedding e5 --project quivr-2-0-0-alpha-7-stack(默认嵌入模型为 gemma,本文实测采用更轻的 multilingual-e5-small,切换方法见四.3)
  • 端口:API 127.0.0.1:8080、演示界面 127.0.0.1:3000(均默认只绑 loopback)
  • 演示嵌入模型:multilingual-e5-small(768 维向量),模型 revision 614241f622f53c4eeff9890bdc4f31cfecc418b3

💡 说明:本文面向真实服务器环境书写,命令与回显均为实测照抄。quivr 属于多组件引擎,单机 Compose 栈内含 PostgreSQL、Weaviate、Temporal、SeaweedFS 四个依赖服务——与《quivr 介绍与选型指南》中「核心架构」一节的组件清单一一对应。

二、镜像选型说明

官方单机栈是「image-only」部署:Compose 文件里的每一个镜像都按 sha256 digest 固定,不含任何需本地构建的内容。镜像分两类:

第一方镜像(6 个,ghcr.io/the-vibe-company/*,随 release.json 发布,全部携带同一源码 revision):

组件镜像与 digest(v2.0.0-alpha.7)作用
quivr-coreghcr.io/the-vibe-company/quivr-core@sha256:928a76de67872b244daefffea09d522db35b6d82016a39f2207763faa287af1d引擎本体,以 api / worker / migrate 三种角色运行
quivr-webghcr.io/the-vibe-company/quivr-web@sha256:706d7ac2dbd3153ae3ec07e096d58adff60f5c398e18697a04a7dd35dea237cb演示检索界面(--profile demo 才启动)
quivr-cpu-embeddingsghcr.io/the-vibe-company/quivr-cpu-embeddings@sha256:38d8e267d798086db61f77aeb4c0a1f854aacc5bf25f837721b1e92f05a5f2b3EmbeddingGemma 2 CPU 嵌入服务(默认嵌入路线)
quivr-teighcr.io/the-vibe-company/quivr-tei@sha256:40f8e6738ea49ade4e849f8bc1e312c6c135bbf535b1dc041a94df459788307dmultilingual-e5-small 的 CPU TEI 运行时(--embedding e5 路线)
quivr-postgresghcr.io/the-vibe-company/quivr-postgres@sha256:c790f0ea98ab27af045d38cf7e2b7017a2d698e863f4cedb821524133a7b6d03内置 postgres:17.11-alpine 与 quivr 调优入口的封装镜像
quivr-seaweedghcr.io/the-vibe-company/quivr-seaweed@sha256:d18537c2e220877f1725d52fe39dadc7766afee06e0bbe4c24d043ec2d73588cSeaweedFS S3 兼容对象存储封装镜像

第三方依赖镜像(2 个,digest 同样由 release 固定):

组件镜像与 digest(v2.0.0-alpha.7)作用
Temporaltemporalio/temporal:1.8.3@sha256:cea463d98a8d6def4420f903ea5c3fcd0d85c8d10fbcc2770a50c12fff2eb26d摄取/投递等工作流编排(单机栈用持久化 dev server)
Weaviatecr.weaviate.io/semitechnologies/weaviate:1.39.10@sha256:de371bb2e07604636915581d784ce182303f0046376a3dd23822936fa10acc56向量索引(rq-8 量化)

关键差异与选型说明:嵌入路线二选一且互相锁定——默认 gemma 走 quivr-cpu-embeddings(TEI_URL 指向 http://embeddings:8080),e5 走 quivr-tei(TEI_URL 指向 http://embeddings:80);两条路线的模型 revision 都锁定在 release.json(gemma 对应 914f7f89142e33e77833254d9c9b90c3cef7303b,e5 对应 614241f622f53c4eeff9890bdc4f31cfecc418b3)。模型一旦选定并完成初始化,安装器会拒绝在已有数据上切换(详见十一.3)。官方发布镜像带签名 SPDX 清单与漏洞扫描;对镜像供应链有要求的团队,可先按官方 Release security 指引校验签名再拉取。

三、前置条件

  • Linux amd64 服务器一台;官方起步建议 16 GiB RAM / 4 vCPU / 本地 SSD,机器档位对照官方口径如下(保守起点预算,非容量保证;按「每文档 3 个 passage、1 个保留版本、768 维压缩向量」估算):
文档规模RAMvCPU本地 SSD索引预留内存
≤ 1 万16 GiB464 GiB2 GiB
≤ 10 万16 GiB8200 GiB2 GiB
≈ 100 万32 GiB161 TiB12 GiB

关键解读:small 基础设施档(默认)为 PostgreSQL 预留 1 GiB、索引预留 2 GiB、嵌入服务 4 GiB 与 4 核;第三档需在 .env 加 QUIVR_POSTGRES_MEMORY_MB=4096 与 QUIVR_WEAVIATE_MEMORY_MB=12288 后重跑 init(见七.3)。

  • Docker Engine 与 Compose v2(官方要求 Compose ≥ 2.24;本文实测 docker compose version 为 v5.5.1)。
  • Python 3.12+(运行安装器 setup.py;实测环境为 Python 3.12.3)。
  • 服务器可访问 github.com(下载发布包)与 ghcr.io、cr.weaviate.io(拉取镜像);离线安装路径见十一.8。
  • 若用非 root 账号操作,需已加入 docker 组;下文命令均以具备 Docker 权限的账号执行。

四、部署步骤

4.1 下载并解压发布包

从 GitHub Releases 下载对应版本的 quivr-compose-VERSION.tar.gz(本文为 alpha.7),解压到安装目录。包内容很小(约 14 KB),只含部署设置、安装器与精确镜像 digest,无需克隆仓库、无需编译器、无需 GPU 或云账号:

mkdir -p /opt/quivr && cd /opt/quivr
wget https://github.com/The-Vibe-Company/quivr/releases/download/v2.0.0-alpha.7/quivr-compose-2.0.0-alpha.7.tar.gz
tar -xzf quivr-compose-2.0.0-alpha.7.tar.gz && ls -la

包内 6 个文件实测清单(tar -tzf 实测,文件大小以本地实测为准):

.env.example
compose.yaml
infrastructure.json
infrastructure.py
release.json
setup.py

⚠️ 注意:包内自带的 compose.yaml 是渲染样例,setup.py init 会按你的安装参数重新渲染覆盖它;release.json 记录了全部镜像 digest 与模型 revision,是安装器的事实来源,不要手工编辑。

4.2 初始化安装(setup.py init)

init 在安装目录生成两样东西:模式 0600 的 .env(自动生成 9 个 64 位十六进制密钥;若目录已有合法 .env 则复用既有密钥)和按 release digest 字面渲染的 compose.yaml。本文演示安装选择 e5 嵌入模型并指定项目名:

cd /opt/quivr
python3 setup.py init --embedding e5 --project quivr-2-0-0-alpha-7-stack

实测输出(exit 0):

Ready: one Compose file and protected .env; model cache preparation is a separate install step.

实测生成的 .env 内容如下(密钥为本次演示安装的真实生成值,每台机器各不相同):

COMPOSE_PROJECT_NAME=quivr-2-0-0-alpha-7-stack
QUIVR_EMBEDDING=e5
QUIVR_MODEL_REVISION=614241f622f53c4eeff9890bdc4f31cfecc418b3
QUIVR_INFRASTRUCTURE_PROFILE=small
QUIVR_ORGANIZATION=quivr
QUIVR_OFFLINE=0
QUIVR_DB_PASSWORD=e888cb59bc4e9f654972692810bad4c66455cd8d2c6e294c647c058a971ce326
QUIVR_API_KEY=08dee2d53f038fd455294fdad3bf59240c9be17d3723a2ae8f189e91fdc6ad26
QUIVR_OPERATOR_KEY=33917015c924cf6018bc6311c3606ca86f672a561a00ce849b7b924239d5f6e4
QUIVR_CURSOR_KEY=beab1f7dd52a78becd2d8e8d05bd50eadb47ff732794ac19f3fda5ce032cef3b
QUIVR_CREDENTIAL_KEY=c5b0a312a9ef82004e5017162e6e4de530cacf6a98f7a3bb707d059e219ff811
S3_ACCESS_KEY=afc4b3acbf1c5808ca77472ef0b3512d6bd29fd26ea97dedae350ec4c72976ef
S3_SECRET_KEY=be511df66dc1990cfbac5fcf996110f3f162c77345ccbb79d1bf0bc24261e23d
EMBED_API_KEY=d024cdda0f926f0952465e3232f5924fdce3570eee593e394dace45bcf6e63d8
DEMO_PASSWORD=92f9b75229e6dd3f22ebd2b19ad975d57c3c8764b53c104c8b75ac6e0640f897

文件权限实测为 600(stat -c "%a" .env 回显 600)。.env 全部键的含义见第六章。

如需把既有密钥带入安装(例如重建安装但保留对外 API Key),在 init 时用 --secret-file KEY=PATH 注入,每个文件必须是权限 0600 的普通文件、内容为 64 位十六进制字符:

umask 077
openssl rand -hex 32 > /protected/api-key
python3 setup.py init --secret-file QUIVR_API_KEY=/protected/api-key

⚠️ 注意:应用密钥(QUIVR_API_KEY)与运维密钥(QUIVR_OPERATOR_KEY)必须保持分离;演示界面只会收到应用密钥。

4.3 嵌入模型选择(gemma 与 e5)

init 时用 --embedding 二选一,默认 gemma:

  • gemma(默认):EmbeddingGemma 2,768 维,专用 CPU 嵌入服务,CPU 摄取批为单 passage、每进程单请求;
  • e5:multilingual-e5-small,更轻量,走固定版本的 CPU TEI 运行时。

全新安装用 e5 的命令形如 python3 setup.py init --embedding e5 --project quivr-e5(官方文档原样口径),随后同样执行 prepare 与启动。对已写入数据的安装,模型、锁定 revision 与项目名都已固定,安装器拒绝切换——换模型只能全新安装并经 add-content API 重发原文(见十一.3)。

4.4 准备模型缓存(setup.py prepare)

prepare 把锁定版本的嵌入模型下载到一个命名缓存卷并做校验和验证。模型已下载过时重跑只做校验,很快返回:

cd /opt/quivr
python3 setup.py prepare

实测输出(模型缓存已就绪时,exit 0;首次执行则在此步完成模型下载与校验):

Ready: one Compose file and protected .env; model cache preparation is a separate install step.

4.5 拉取镜像并启动

镜像全部按 digest 固定,pull 把 9 个服务的镜像一次拉齐(首次约 1 GB 量级,含模型缓存卷已在 prepare 完成的部分):

cd /opt/quivr
docker compose pull
docker compose up -d

up -d 的实测行为:先等 5 个基础依赖(postgres、temporal、seaweed、weaviate、embeddings)健康检查通过,再跑一次性的 migrate(schema 迁移,成功后以 exit 0 退出),最后拉起 api 与 worker。对已在运行的栈重复执行 docker compose up -d 是幂等的——实测回显(输出节选,实测首尾):

 Container quivr-2-0-0-alpha-7-stack-embeddings-1 Running
 Container quivr-2-0-0-alpha-7-stack-weaviate-1 Running
 Container quivr-2-0-0-alpha-7-stack-temporal-1 Running
 Container quivr-2-0-0-alpha-7-stack-worker-1 Running
 Container quivr-2-0-0-alpha-7-stack-postgres-1 Running
 Container quivr-2-0-0-alpha-7-stack-seaweed-1 Running
 Container quivr-2-0-0-alpha-7-stack-api-1 Running
 Container quivr-2-0-0-alpha-7-stack-seaweed-1 Waiting
 Container quivr-2-0-0-alpha-7-stack-weaviate-1 Waiting
 Container quivr-2-0-0-alpha-7-stack-embeddings-1 Waiting
 Container quivr-2-0-0-alpha-7-stack-postgres-1 Waiting
 Container quivr-2-0-0-alpha-7-stack-temporal-1 Waiting
 Container quivr-2-0-0-alpha-7-stack-weaviate-1 Healthy
 Container quivr-2-0-0-alpha-7-stack-postgres-1 Healthy
 Container quivr-2-0-0-alpha-7-stack-seaweed-1 Healthy
 Container quivr-2-0-0-alpha-7-stack-embeddings-1 Healthy
 Container quivr-2-0-0-alpha-7-stack-temporal-1 Healthy
 Container quivr-2-0-0-alpha-7-stack-migrate-1 Starting
 Container quivr-2-0-0-alpha-7-stack-migrate-1 Started
 Container quivr-2-0-0-alpha-7-stack-migrate-1 Waiting
 Container quivr-2-0-0-alpha-7-stack-migrate-1 Exited

(输出节选说明:中间逐服务的 Created/Started 行与首尾重复的 Waiting/Exited 行从略;migrate 退出码为 0,属一次性迁移容器的正常终态,见十一.1。)

4.6 启动演示界面(--profile demo)

demo 服务(quivr-web 演示界面)挂在 demo profile 下,up -d 不带 profile 时不会启动。启动它:

cd /opt/quivr
docker compose --profile demo up -d

启动完成后服务清单实测(docker compose ps -a,本文安装的项目名为 quivr-2-0-0-alpha-7-stack,容器名格式为 <项目名>-<服务名>-1):

NAME                                     IMAGE                                                                                                                      COMMAND                  SERVICE      CREATED       STATUS                   PORTS
quivr-2-0-0-alpha-7-stack-api-1          ghcr.io/the-vibe-company/quivr-core@sha256:928a76de67872b244daefffea09d522db35b6d82016a39f2207763faa287af1d                "python /app/core-en…"   api          7 hours ago   Up 7 hours (healthy)     127.0.0.1:8080->8080/tcp
quivr-2-0-0-alpha-7-stack-demo-1         ghcr.io/the-vibe-company/quivr-web@sha256:706d7ac2dbd3153ae3ec07e096d58adff60f5c398e18697a04a7dd35dea237cb                 "docker-entrypoint.s…"   demo         7 hours ago   Up 3 hours               127.0.0.1:3000->3000/tcp
quivr-2-0-0-alpha-7-stack-embeddings-1   ghcr.io/the-vibe-company/quivr-tei@sha256:40f8e6738ea49ade4e849f8bc1e312c6c135bbf535b1dc041a94df459788307d                 "sh /app/tei-entrypo…"   embeddings   7 hours ago   Up 7 hours (healthy)
quivr-2-0-0-alpha-7-stack-migrate-1      ghcr.io/the-vibe-company/quivr-core@sha256:928a76de67872b244daefffea09d522db35b6d82016a39f2207763faa287af1d                "python /app/core-en…"   migrate      7 hours ago   Exited (0) 3 hours ago
quivr-2-0-0-alpha-7-stack-postgres-1     ghcr.io/the-vibe-company/quivr-postgres@sha256:c790f0ea98ab27af045d38cf7e2b7017a2d698e863f4cedb821524133a7b6d03            "quivr-postgres post…"   postgres     7 hours ago   Up 7 hours (healthy)     5432/tcp
quivr-2-0-0-alpha-7-stack-seaweed-1      ghcr.io/the-vibe-company/quivr-seaweed@sha256:d18537c2e220877f1725d52fe39dadc7766afee06e0bbe4c24d043ec2d73588c             "sh /usr/local/bin/q…"   seaweed      7 hours ago   Up 7 hours (healthy)     7333/tcp, 8080/tcp, 8333/tcp, 8888/tcp, 9333/tcp, 18080/tcp, 18888/tcp, 19333/tcp
quivr-2-0-0-alpha-7-stack-temporal-1     temporalio/temporal:1.8.3@sha256:cea463d98a8d6def4420f903ea5c3fcd0d85c8d10fbcc2770a50c12fff2eb26d                          "temporal server sta…"   temporal     7 hours ago   Up 7 hours (healthy)
quivr-2-0-0-alpha-7-stack-weaviate-1     cr.weaviate.io/semitechnologies/weaviate:1.39.10@sha256:de371bb2e07604636915581d784ce182303f0046376a3dd23822936fa10acc56   "/bin/weaviate --hos…"   weaviate     7 hours ago   Up 7 hours (healthy)
quivr-2-0-0-alpha-7-stack-worker-1       ghcr.io/the-vibe-company/quivr-core@sha256:928a76de67872b244daefffea09d522db35b6d82016a39f2207763faa287af1d                "python /app/core-en…"   worker       7 hours ago   Up 7 hours

要点:7 个常驻服务全部 Up (healthy)(worker 无 healthcheck,直接 Up),migrate 为 Exited (0) 正常态;对外的 api/demo 端口只映射到 127.0.0.1。Compose 引擎版本实测:

docker compose version

实测输出:

Docker Compose version v5.5.1

4.7 验证部署

API 就绪验证——查询版本端点(无鉴权):

curl -sS http://127.0.0.1:8080/v0/version

实测输出(HTTP 200):

{"api_version":"v0","plugin_engine_version":"0.2.0","revision":"7b5ffe3eaa031ccbb1f49244b76e8b9bf5d11426","version":"2.0.0-alpha.7"}

演示界面验证:

curl -sS -o /dev/null -w "demo HTTP %{http_code}\n" http://127.0.0.1:3000/

实测输出:

demo HTTP 200

浏览器打开 http://127.0.0.1:3000(远程服务器先建 SSH 隧道 ssh -L 3000:127.0.0.1:3000 <server>),登录密码取 .env 中的 DEMO_PASSWORD。本文演示安装该值为 92f9b75229e6dd3f22ebd2b19ad975d57c3c8764b53c104c8b75ac6e0640f897(仅演示环境实际值;你自己的安装以你的 .env 为准)。

端到端业务验证(建语料库 → 写入 → 轮询回执 → 检索,全部走公共 API;QUIVR_API_KEY 用 .env 中的 QUIVR_API_KEY,本文演示值为 08dee2d53f038fd455294fdad3bf59240c9be17d3723a2ae8f189e91fdc6ad26;幂等键为客户端生成的任意 UUID,本文实测使用下列字面值):

KEY=08dee2d53f038fd455294fdad3bf59240c9be17d3723a2ae8f189e91fdc6ad26
# 1) 建语料库(幂等键防重)
curl -sS -X POST http://127.0.0.1:8080/v0/corpora \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: 1f0e6a9c-4d2e-4b6f-9c1a-b2-deploy-0001" \
  -d '{"idempotency_key":"1f0e6a9c-4d2e-4b6f-9c1a-b2-deploy-0001","name":"deploy-guide-demo"}'

实测输出(HTTP 201):

{"archived":false,"corpus_id":"corpus_49d59b3fab64b7f90e5d35533273012a","name":"deploy-guide-demo","effective_retrieval":{"fields":[]}}
# 2) 写入一条文章记录,立即返回摄取回执
curl -sS -X POST http://127.0.0.1:8080/v0/records \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: 2a1f7b8d-5e3c-4a9d-8b2e-b2-deploy-0002" \
  -d '{"idempotency_key":"2a1f7b8d-5e3c-4a9d-8b2e-b2-deploy-0002","source":{"corpus_id":"corpus_49d59b3fab64b7f90e5d35533273012a","namespace":"wire","record_key":"eclipse-2026-10-22"},"content":{"kind":"text","text":"Total solar eclipse draws crowds. On Tuesday a rare total solar eclipse crossed the continent, and crowds gathered in every city along the path of totality. Astronomers reminded spectators that the moon blocked the sun for just over four minutes, while libraries handed out protective glasses."}}'

实测输出(HTTP 202):

{"diagnostics":[],"processing":{"phase":"materialization","state":"queued"},"receipt_id":"receipt_ddbb830329a91eb02c75763cdcd9c31b265c2639a3ba32154b475892f9c8012b","record_id":"record_823a0f90a41846baf579867c2bb52665f94393c925fc0647bdf7e7eb281d7dbe","source":{"corpus_id":"corpus_49d59b3fab64b7f90e5d35533273012a","namespace":"wire","record_key":"eclipse-2026-10-22"},"state":"pending"}
# 3) 轮询摄取回执直到 state=resolved
curl -sS http://127.0.0.1:8080/v0/ingestion-receipts/receipt_ddbb830329a91eb02c75763cdcd9c31b265c2639a3ba32154b475892f9c8012b \
  -H "Authorization: Bearer $KEY"

实测输出(HTTP 200;写入约 2 秒后首次轮询即为 resolved,多次轮询返回同一终态):

{"availability":{"is_current":true,"searchable":true,"state":"retrieval_ready"},"diagnostics":[],"outcome":"created","processing":{"state":"idle"},"receipt_id":"receipt_ddbb830329a91eb02c75763cdcd9c31b265c2639a3ba32154b475892f9c8012b","record_id":"record_823a0f90a41846baf579867c2bb52665f94393c925fc0647bdf7e7eb281d7dbe","source":{"corpus_id":"corpus_49d59b3fab64b7f90e5d35533273012a","namespace":"wire","record_key":"eclipse-2026-10-22"},"state":"resolved","version_id":"version_41d732f363c87156e2e606a3f8703b6a9083f9a1beb21516d96137770c80cfee"}
# 4) 关键词检索
curl -sS -X POST http://127.0.0.1:8080/v0/search \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"query":"eclipse","corpus_ids":["corpus_49d59b3fab64b7f90e5d35533273012a"],"mode":"lexical","limit":5}'

实测输出(HTTP 200,输出节选保留命中与耗时字段):

{"items":[{"availability":{"is_current":true,"searchable":true,"state":"retrieval_ready"},"excerpt":{"coordinate_system":"unicode_codepoint","end":293,"start":0,"text":"Total solar eclipse draws crowds. On Tuesday a rare total solar eclipse crossed the continent, and crowds gathered in every city along the path of totality. Astronomers reminded spectators that the moon blocked the sun for just over four minutes, while libraries handed out protective glasses."},"explanation":"keywords","part_key":"body","rank":1,"record_id":"record_823a0f90a41846baf579867c2bb52665f94393c925fc0647bdf7e7eb281d7dbe","vector_space_id":"core.ingest.e5-small@1","version_id":"version_41d732f363c87156e2e606a3f8703b6a9083f9a1beb21516d96137770c80cfee"}],"retrieval_profile":{"name":"default","version":"plugin:core.retrieve@1.2.0/default"},"usage":{"cost_cents":0,"elapsed_ms":26,"paid_calls":0,"phases":{"coverage_ms":4,"hydration_ms":10,"index_query_ms":5,"plugin_rounds_ms":1,"query_encoding_ms":0,"routing_ms":3},"profiles":[{"cost_cents":0,"paid_calls":0,"plugin_version":"1.2.0","profile":"core.retrieve/default","rounds":2}],"rounds":2}}
# 5) 语义检索(用文章未出现的表述命中)
curl -sS -X POST http://127.0.0.1:8080/v0/search \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"query":"the moon blocked the sun","corpus_ids":["corpus_49d59b3fab64b7f90e5d35533273012a"],"mode":"semantic","limit":5}'

实测输出(HTTP 200,输出节选;命中同一记录,explanation 表明走向量空间):

{"items":[{"availability":{"is_current":true,"searchable":true,"state":"retrieval_ready"},"excerpt":{"coordinate_system":"unicode_codepoint","end":293,"start":0,"text":"Total solar eclipse draws crowds. On Tuesday a rare total solar eclipse crossed the continent, and crowds gathered in every city along the path of totality. Astronomers reminded spectators that the moon blocked the sun for just over four minutes, while libraries handed out protective glasses."},"explanation":"vectors in core.ingest.e5-small@1","part_key":"body","rank":1,"record_id":"record_823a0f90a41846baf579867c2bb52665f94393c925fc0647bdf7e7eb281d7dbe","vector_space_id":"core.ingest.e5-small@1","version_id":"version_41d732f363c87156e2e606a3f8703b6a9083f9a1beb21516d96137770c80cfee"}],"retrieval_profile":{"name":"default","version":"plugin:core.retrieve@1.2.0/default"},"usage":{"cost_cents":0,"elapsed_ms":59,"paid_calls":0,"phases":{"coverage_ms":2,"hydration_ms":8,"index_query_ms":7,"plugin_rounds_ms":1,"query_encoding_ms":38,"routing_ms":1},"profiles":[{"cost_cents":0,"paid_calls":0,"plugin_version":"1.2.0","profile":"core.retrieve/default","rounds":2}],"rounds":2}}

混合模式(mode 省略时服务端默认 hybrid,显式传入 hybrid 亦同):实测命中同一记录(query 为 "eclipse crowds"),explanation 为 "keywords and vectors in core.ingest.e5-small@1, alpha 0.5, relative score fusion",elapsed_ms 37。

💡 说明:API 全量端点、订阅与告警的逐条实测与检索响应各字段(含 usage.phases 计时分解)的进一步解读,见《quivr 介绍与选型指南》第四章「功能特性」。

五、数据持久化说明

栈的数据全部落在 5 个命名卷上(卷名前缀为 Compose 项目名,与 COMPOSE_PROJECT_NAME 绑定)。实测卷清单(docker volume ls --format "{{.Name}}",grep 过滤本项目):

quivr-2-0-0-alpha-7-stack-model-cache
quivr-2-0-0-alpha-7-stack-postgres-data
quivr-2-0-0-alpha-7-stack-seaweed-data
quivr-2-0-0-alpha-7-stack-temporal-data
quivr-2-0-0-alpha-7-stack-weaviate-data

卷与服务、容器内挂载点的对应关系(源自 compose.yaml 的 volumes 声明):

命名卷挂载服务容器内路径存放内容
<project>-postgres-datapostgres/var/lib/postgresql/data业务数据、队列、指标计数器
<project>-weaviate-dataweaviate/var/lib/weaviate向量索引(rq-8 量化分片)
<project>-temporal-datatemporal/home/temporal工作流编排状态(dev server 的 SQLite 文件)
<project>-seaweed-dataseaweed/data原始内容与版本工件的 S3 对象
<project>-model-cacheembeddings(只读)/models锁定版本的嵌入模型缓存

关键解读:.env 里的 COMPOSE_PROJECT_NAME 同时决定容器命名与卷命名,官方明确要求移动或升级发布包时保持该值稳定——卷按项目名独立于目录存在,改掉项目名等于换了一套全新卷。备份策略:PostgreSQL 用 pg_dump(经 docker compose exec postgres pg_dump)、SeaweedFS 卷与 Weaviate 卷按文件层快照/复制;down 不带 -v 不会删除卷。栈内网络为两个 Compose 网络:<project>_stack(依赖与 worker 的内部网络)与 <project>_access(api/demo 的端口发布网络),实测网络清单为 quivr-2-0-0-alpha-7-stack_access 与 quivr-2-0-0-alpha-7-stack_stack。

⚠️ 注意:官方排障口径明确「迁移失败时不要删除卷来重试启动」(见十一.4);误删卷将丢失已摄取内容与索引,只能重新摄取。

六、环境变量表

安装的配置入口只有一个:安装目录的 .env(模式 0600)。.env 全部键如下(默认值取自发布包 .env.example 与 init 实测生成值;各键的运行态核对方法、未声明键的推导默认值与锁定规则,见《quivr 2.0.0-alpha.7 配置参数详解》第六~十二章):

键默认值(示例安装实测值)含义
COMPOSE_PROJECT_NAMEquivr(示例安装为 quivr-2-0-0-alpha-7-stack)Compose 项目名,决定容器名与命名卷前缀;升级/移动时必须保持稳定
QUIVR_EMBEDDINGgemma嵌入模型选择:gemma 或 e5;对已有数据的安装锁定
QUIVR_MODEL_REVISION由 setup.py 从 release 记录(e5 为 614241f622f53c4eeff9890bdc4f31cfecc418b3)锁定的模型版本号,init 自动写入,人工保留勿改
QUIVR_INFRASTRUCTURE_PROFILEsmall基础设施档位:small 或 large(资源对照见七.3)
QUIVR_ORGANIZATIONquivr组织标识
QUIVR_OFFLINE0离线/在线网络隔离开关;1 时隔离依赖与 worker 网络
QUIVR_EMBEDDING_THREADS4嵌入服务线程数
QUIVR_EMBEDDING_CPUS4嵌入服务 CPU 限额
QUIVR_EMBEDDING_MEMORY4g嵌入服务内存限额
QUIVR_WORKER_LIVE_SLOTS1worker 实时队列槽位数
QUIVR_WORKER_BULK_SLOTS1worker 批量队列槽位数
QUIVR_API_PORT8080API 对外端口(映射到 127.0.0.1)
QUIVR_DEMO_PORT3000演示界面对外端口(映射到 127.0.0.1)
QUIVR_POSTGRES_MEMORY_MB未设(注释示例 4096)可选:PostgreSQL 内存限额(MiB),init 重渲染
QUIVR_WEAVIATE_MEMORY_MB未设(注释示例 12288)可选:索引内存限额(MiB),init 重渲染并同步推导索引 Go 软内存预算
QUIVR_DB_PASSWORDinit 生成(64 hex)PostgreSQL 业务账号 quivr 的密码
QUIVR_API_KEYinit 生成(64 hex)应用 API Key(Bearer),demo 只拿到这一把
QUIVR_OPERATOR_KEYinit 生成(64 hex)运维密钥,插件管理用,与应用密钥分离
QUIVR_CURSOR_KEYinit 生成(64 hex)变更流游标签名密钥
QUIVR_CREDENTIAL_KEYinit 生成(64 hex)凭据加密密钥
S3_ACCESS_KEY / S3_SECRET_KEYinit 生成(64 hex)SeaweedFS 对象存储凭据
EMBED_API_KEYinit 生成(64 hex)内部嵌入服务 API Key
DEMO_PASSWORDinit 生成(64 hex)演示界面登录密码

关键解读:9 个 init 生成密钥(QUIVR_DB_PASSWORD、QUIVR_API_KEY、QUIVR_OPERATOR_KEY、QUIVR_CURSOR_KEY、QUIVR_CREDENTIAL_KEY、S3_ACCESS_KEY、S3_SECRET_KEY、EMBED_API_KEY、DEMO_PASSWORD)均为 64 位十六进制字符,权限 0600,不要提交或打印;其余键是可读可改的部署参数,改后需重跑 python3 setup.py init 重渲染 compose.yaml 再启动。

七、配置参数说明

7.1 引擎服务(api / worker / migrate)注入的环境变量

compose.yaml 对三个 quivr-core 角色注入同一组变量(摘自渲染后的 compose.yaml,${...} 由 Compose 从 .env 解析):

environment:
  QUIVR_SINGLE_MACHINE: "1"
  QUIVR_ORGANIZATION: "${QUIVR_ORGANIZATION:-quivr}"
  DATABASE_URL: "postgres://quivr:${QUIVR_DB_PASSWORD:?}@postgres:5432/quivr?sslmode=disable"
  QUIVR_API_KEY: "${QUIVR_API_KEY:?}"
  QUIVR_OPERATOR_KEY: "${QUIVR_OPERATOR_KEY:?}"
  QUIVR_CURSOR_KEY: "${QUIVR_CURSOR_KEY:?}"
  QUIVR_CREDENTIAL_KEY: "${QUIVR_CREDENTIAL_KEY:?}"
  TEMPORAL_ADDRESS: "temporal:7233"
  WEAVIATE_URL: "http://weaviate:8080"
  TEI_URL: "http://embeddings:8080"
  S3_ENDPOINT: "http://seaweed:8333"
  S3_ACCESS_KEY: "${S3_ACCESS_KEY:?}"
  S3_SECRET_KEY: "${S3_SECRET_KEY:?}"
  QUIVR_DEMO_PLUGINS: "1"
  QUIVR_DEMO_CONNECTORS: "1"
  QUIVR_DEMO_ADMIN: "1"
  QUIVR_WORKER_LIVE_SLOTS: "${QUIVR_WORKER_LIVE_SLOTS:-1}"
  QUIVR_WORKER_BULK_SLOTS: "${QUIVR_WORKER_BULK_SLOTS:-1}"
  QUIVR_DEMO_EMBEDDING: "gemma"
  QUIVR_DEMO_CORE_INGEST: "0"
  EMBED_URL: "http://embeddings:8080"
  EMBED_API_KEY: "${EMBED_API_KEY:?}"
  QUIVR_ROLE: "api"

逐项说明:QUIVR_ROLE 区分 api/worker/migrate 三角色(渲染时各自为 api/worker/migrate);TEMPORAL_ADDRESS/WEAVIATE_URL/S3_ENDPOINT 是三个依赖服务的栈内地址;TEI_URL 与 EMBED_URL 因嵌入路线而异(gemma 走 8080,e5 走 80,安装器渲染时自动决定);QUIVR_DEMO_* 三个开关决定演示环境预装的第一方插件、连接器与演示管理员;QUIVR_WORKER_LIVE_SLOTS/QUIVR_WORKER_BULK_SLOTS 控制实时/批量两条摄取队列的并发槽位。api 服务额外监听容器内 8081 端口的健康检查端点(compose healthcheck 访问 http://127.0.0.1:8081/readyz)。

7.2 PostgreSQL 与 Weaviate 的内置调优参数

small 档下 quivr-postgres 注入的调优键(compose 实测值):

环境变量small 档实测值含义
QUIVR_POSTGRES_MAX_CONNECTIONS256最大连接数
QUIVR_POSTGRES_WORK_MEM4MB单排序/哈希操作内存
QUIVR_POSTGRES_RANDOM_PAGE_COST1.1优化器随机页成本(SSD 取低值)
QUIVR_POSTGRES_EFFECTIVE_IO_CONCURRENCY200并发 IO 数
QUIVR_POSTGRES_CHECKPOINT_TIMEOUT15min检查点间隔
QUIVR_POSTGRES_WAL_COMPRESSIONlz4WAL 压缩算法
QUIVR_POSTGRES_STAT_STATEMENTS_TRACKallpg_stat_statements 跟踪级别
QUIVR_POSTGRES_JITonJIT 编译开关
QUIVR_POSTGRES_SYNCHRONOUS_COMMITon同步提交
QUIVR_POSTGRES_COMMIT_DELAY100组提交延迟(微秒)
QUIVR_POSTGRES_COMMIT_SIBLINGS5组提交触发兄弟事务数

Weaviate 注入的关键键(small 档实测值):DEFAULT_QUANTIZATION=rq-8(残差量化 8 位)、PERSISTENCE_DATA_PATH=/var/lib/weaviate、PERSISTENCE_MEMTABLES_MAX_SIZE_MB=200、ASYNC_INDEXING=false、RAFT_BOOTSTRAP_TIMEOUT=600、GOMEMLIMIT=1700MiB(与 2 GiB 内存限额联动)、DEFAULT_VECTORIZER_MODULE=none(向量化全部交给 quivr 插件,索引自身不做嵌入)。

7.3 基础设施档位(small / large)与内存覆盖

档位由 QUIVR_INFRASTRUCTURE_PROFILE 决定,渲染自发布包 infrastructure.json。两档关键差异对照:

维度small(默认,实测渲染值)large
PostgreSQL 内存/CPU 限额1 GiB / 1 核32 GB / 32 核
Weaviate 内存/CPU 限额2 GiB / 2 核64 GB / 32 核
ASYNC_INDEXINGfalsetrue
PERSISTENCE_MEMTABLES_MAX_SIZE_MB2001024
GOMEMLIMIT1700MiB16GiB
RAFT_BOOTSTRAP_TIMEOUT6003600
PostgreSQL 专属追加键—(上表 11 项)MAX_CONNECTIONS=500、SHARED_BUFFERS=10GB、EFFECTIVE_CACHE_SIZE=25GB、MAINTENANCE_WORK_MEM=1GB、WORK_MEM=16MB、MAX_WAL_SIZE=32GB、MIN_WAL_SIZE=4GB
存储预算参考—每组件 500 GB 预算声明

关键解读:large 面向百万文档级大型机器,官方建议选档前先审阅其声明(infrastructure.json 中 x-quivr.profiles.large)。百万文档档在 small 基础上覆盖两个内存键即可:.env 加 QUIVR_POSTGRES_MEMORY_MB=4096 与 QUIVR_WEAVIATE_MEMORY_MB=12288,重跑 python3 setup.py init(索引的 GOMEMLIMIT 会按限额的 85% 自动推导为 10444MiB 量级),再启动。

八、配置文件挂载

单机栈是纯 image-only 形态:compose.yaml 里没有任何 bind mount 的配置文件,全部配置经由 .env → Compose 变量替换 → 服务环境变量这条链路进入各服务,数据经第五章的命名卷持久化。因此:

  • 日常配置变更只改 .env,随后必须重跑 python3 setup.py init 重新渲染 compose.yaml(渲染是幂等的:已有合法 .env 时复用既有密钥,只按新参数重渲染),再 docker compose up -d 生效;
  • 不需要、也不应该把容器内的 compose.yaml/infrastructure.py 手工挂出修改——它们由安装器按 release.json 的 digest 事实渲染,手工改动会在下次 init 时被覆盖;
  • 例外场景是给单服务追加自定义环境变量或挂载:可在渲染后的 compose.yaml 上做本地编辑,但每次 init 重渲染会还原;持久做法是把改动固化到自己的部署脚本或 fork 的安装器参数里。

九、等价 docker run

单机栈的编排关系(依赖健康检查、一次性迁移、内部网络)只能由 Compose 表达,生产部署请使用第四章流程。此处给出 api 服务的单容器等价命令,便于理解其运行参数(演示前提:栈已按第四章启动,<project>_stack 与 <project>_access 网络已存在):

docker run -d --name quivr-api-manual \
  --network quivr-2-0-0-alpha-7-stack_access \
  -p 127.0.0.1:8080:8080 \
  -e QUIVR_SINGLE_MACHINE=1 \
  -e QUIVR_ORGANIZATION=quivr \
  -e DATABASE_URL='postgres://quivr:<QUIVR_DB_PASSWORD>@postgres:5432/quivr?sslmode=disable' \
  -e QUIVR_API_KEY=<QUIVR_API_KEY> \
  -e TEMPORAL_ADDRESS=temporal:7233 \
  -e WEAVIATE_URL=http://weaviate:8080 \
  -e TEI_URL=http://embeddings:80 \
  -e S3_ENDPOINT=http://seaweed:8333 \
  -e S3_ACCESS_KEY=<S3_ACCESS_KEY> \
  -e S3_SECRET_KEY=<S3_SECRET_KEY> \
  -e EMBED_URL=http://embeddings:80 \
  -e EMBED_API_KEY=<EMBED_API_KEY> \
  -e QUIVR_ROLE=api \
  ghcr.io/the-vibe-company/quivr-core@sha256:928a76de67872b244daefffea09d522db35b6d82016a39f2207763faa287af1d

⚠️ 注意:<QUIVR_API_KEY> 等为取值方法占位——取值来自安装目录 .env 对应键,请替换后执行;api 容器需同时能解析 postgres/temporal/weaviate/embeddings/seaweed 主机名,它们位于 <project>_stack 网络,手工单跑时还需把该容器也接入 stack 网络(--network 只写一个时用 docker network connect 补接第二网络)。验证单容器 API 与栈内 API 等价:curl -sS http://127.0.0.1:8080/v0/version 返回与四.7 相同的版本 JSON。

十、常用运维命令

以下命令均在实测环境验证(命令于安装目录 /opt/quivr 执行;更全的运维命令面——进程清单、psql/temporal 巡检与 API 速查——见《quivr 2.0.0-alpha.7 常用 CLI 命令与工具详解》):

查看服务状态(含一次性 migrate 的正常 Exited (0)):

docker compose ps -a

实测回显见四.6(9 行服务表,7 个 healthy + migrate Exited (0))。

跟踪服务日志(JSON 行日志,含请求 ID / trace-span 关联字段):

docker compose logs api --tail 2

实测输出(输出节选):

api-1  | {"ts":"2026-10-23T00:21:48.023314728Z","level":"INFO","msg":"http request","service":"[REDACTED].api","version":"2.0.0-alpha.7","instance":"3910f1e694f3:11","environment":"unspecified","route":"/readyz","method":"GET","status":204,"duration_ms":1.093,"response_size":0,"client_ip":"127.0.0.1","api_key_id":"","error_code":"","request_id":"228c91c524db207c2af6f4aecfb8a2c6","trace_id":"","span_id":""}
api-1  | {"ts":"2026-10-23T00:21:50.339308462Z","level":"INFO","msg":"http request","service":"[REDACTED].api","version":"2.0.0-alpha.7","instance":"3910f1e694f3:11","environment":"unspecified","route":"/readyz","method":"GET","status":204,"duration_ms":0.685,"response_size":0,"client_ip":"127.0.0.1","api_key_id":"","error_code":"","request_id":"9118c35f83861c4302f9817ad4650340","trace_id":"","span_id":""}

重启单个服务(实测重启演示界面):

docker compose restart demo

实测输出:

 Container quivr-2-0-0-alpha-7-stack-demo-1 Restarting
 Container quivr-2-0-0-alpha-7-stack-demo-1 Started

重启后验证(实测):curl -sS -o /dev/null -w "%{http_code}\n" http://127.0.0.1:3000/ 回显 200。

清理一次性迁移容器(迁移失败重试或日常清理时使用):

docker compose rm -f migrate

幂等重建/补拉服务:docker compose up -d(幂等,实测回显见四.5;改动 compose.yaml 或 .env 后重跑生效)。

停止与彻底清理:docker compose down 停止并移除容器与网络(保留命名卷);docker compose --profile demo down 连演示界面一起停;删除数据卷需显式 docker compose down -v(危险操作,见五、十一.4 的警告)。查看当前渲染的服务清单:

docker compose config --services

实测输出(默认 profile,不含 demo):

embeddings
postgres
seaweed
temporal
weaviate
migrate
worker
api

十一、常见问题

11.1 migrate 容器是 Exited 状态,是不是部署失败?

不是。migrate 是一次性 schema 迁移进程,职责是「准备 PostgreSQL、对象存储与检索投影,然后退出」,成功时以退出码 0 退出。实测 docker compose ps -a 中它恒为 Exited (0)。每次 docker compose up -d 都会重新拉起它执行一次迁移(幂等),这也是四.5 实测回显中出现 migrate-1 Exited 的原因。

11.2 演示界面没有起来

demo 服务挂在 demo profile 下,docker compose up -d 不会启动它。用 docker compose --profile demo up -d 补拉(实测见四.6)。本机验证 curl http://127.0.0.1:3000/ 返回 HTTP 200 即正常;登录密码在 .env 的 DEMO_PASSWORD。

11.3 想换嵌入模型(gemma ↔ e5)

对已写入数据的安装不可行:模型、锁定 revision 与项目名对已有安装固定,安装器拒绝切换,官方口径是「旧文档与其排队中的工作保持原 provider;换模型需全新安装并经 add-content API 重发原文」。正确路径:新项目名全新 init(如 --embedding e5 --project quivr-e5)→ prepare → 启动 → 重发内容。这也是本文演示安装直接选定 e5 的原因——先把口径定准再初始化。

11.4 migrate 失败怎么办

官方排障口径(实测环境同样适用):先 docker compose logs migrate 或 docker compose ps -a 看退出码与日志定位配置问题,修正 .env 后执行 docker compose rm -f migrate 移除退出的迁移容器,再 docker compose up -d 重试。不要删除数据卷来重试启动。migrate 支持重跑续做:某一步依赖未就绪时退出,重跑会接着完成。

11.5 写入成功但检索不到

摄取是异步管道:POST /v0/records 立即返回回执(state=pending),后台经 materialization、切分、向量化后才 resolved/retrieval_ready。实测演示中回执约两轮轮询(数秒)内到达 resolved;CPU 嵌入吞吐约 0.55 passages/秒(1533-token 输入、batch 1、4 线程 2.90 GHz Xeon 的官方实测口径),大批量导入要按「文档数 × 3 passages ÷ 吞吐」预估等待时间。轮询回执直到 state=resolved 再检索(命令见四.7 第 3 步)。

11.6 端口冲突或需要改端口

.env 改 QUIVR_API_PORT / QUIVR_DEMO_PORT(默认 8080/3000)→ 重跑 python3 setup.py init 重渲染 → docker compose up -d。API 与演示界面默认只绑 127.0.0.1(compose 映射形如 127.0.0.1:${QUIVR_API_PORT:-8080}:8080);远程访问官方建议走 SSH 隧道或自备 TLS 代理,不要直接改成 0.0.0.0 裸奔(官方 run-quivr behind TLS 指南提供 TLS 路径)。

11.7 init 报「Setup refused」

安装器对非法输入一律拒绝且不回显异常值(防止路径/响应里带出密钥)。常见触发点实测归纳:.env 已存在但权限宽于 0600(init 要求模式 600 的普通文件,实测 stat -c "%a" 应为 600);--secret-file 注入的文件权限过宽或内容不是 64 位十六进制字符;--embedding/--profile 取值越界(仅接受 gemma|e5、small|large)。修正输入后重跑即可;init 幂等,不会破坏已有密钥。

11.8 内网/离线安装

发布包与镜像都支持离线路径:prepare 支持 --mirror(经镜像源下载模型)与 --source(本地模型源目录)参数;镜像可从 GHCR 预先拉取后离线导入(digest 固定,离线导入后校验 digest 即可)。官方文档将此归入「Network and offline installation」一节,配合 QUIVR_OFFLINE=1 隔离依赖与 worker 的网络。

11.9 alpha 版本升级注意

2.0.0-alpha 各版本间官方明确不支持原地升级(alpha.7 的 BREAKING CHANGES 声明从 alpha.6 及更早版本无法原地升级),升级前先按第五章备份卷数据;升级操作与回滚窗口的官方口径见仓库 Upgrade Quivr and keep a rollback window 文档。

十二、参考链接

  1. 官方单机部署文档(本文流程依据):https://docs.quivr.thevibecompany.co/run-quivr/single-machine (查询日期 2026-10-22)
  2. 部署与配置总览:https://docs.quivr.thevibecompany.co/run-quivr/deploy (查询日期 2026-10-22)
  3. Releases(发布包 quivr-compose-2.0.0-alpha.7.tar.gz 下载页):https://github.com/The-Vibe-Company/quivr/releases (查询日期 2026-10-22)
  4. 官方 Quickstart(API 最小闭环):https://docs.quivr.thevibecompany.co/quickstart (查询日期 2026-10-22)
  5. TLS 部署指引:https://docs.quivr.thevibecompany.co/run-quivr/tls (查询日期 2026-10-22)
  6. 站内延伸阅读:产品认知、架构与选型对比见《quivr 介绍与选型指南》;配置参数与档位详解见《quivr 2.0.0-alpha.7 配置参数详解》;运维命令与 API 速查见《quivr 2.0.0-alpha.7 常用 CLI 命令与工具详解》