部署与运维实操
这一页是装完之后的手册:日常起停与重建、健康与监控、 生产配置清单、备份与升级、故障排查对照表。 安装本身的三种跑法(本地 REPL / compose 全套 / 独立进程)在 安装部署,这里不重复。
拓扑:四个容器,数据落在哪
compose 栈一共四个服务,职责和依赖关系是固定的:
postgres(业务表 + pgvector 向量 + 全文检索同实例)→
db-init(一次性灌入 BIRD 金融演示数据,幂等)→
backend(trove serve,纯 JSON API,全部路由在 /v1 下)→
frontend(nginx 托管 SPA 并反代 /v1)。
| 服务 | 镜像 | 对外端口 | 说明 |
|---|---|---|---|
postgres |
paradedb/paradedb |
不暴露(默认注释 5432) |
业务数据 + 向量/全文检索 + (设了 TROVE_STORAGE_URL 时)Trove 自己的内部状态 |
db-init |
trove-backend:local |
— | 跑完即退出的初始化容器;重复启动无害(IF NOT EXISTS + ON CONFLICT) |
backend |
trove-backend:local |
8000(仅供本机调试) |
JSON API;/v1/health 被 compose 用作健康检查 |
frontend |
trove-frontend:local |
8080 |
用户访问入口:nginx 发布 SPA,并把 /v1 反代到 backend |
数据落点决定了备份什么、迁移带什么:
| 数据 | 位置 | 说明 |
|---|---|---|
| 内部状态:会话、任务、用户、审计、定时任务、LangGraph 检查点、记忆(情节 / 偏好 / 用户事实) | 设了 TROVE_STORAGE_URL → Postgres;未设 → 各 store 路径下的 SQLite 文件(默认在 ~/.trove/ 与 .trove/) |
统一走一套 StorageBackend 抽象,compose 里指向同一个 Postgres 库 |
知识库(schema_notes / semantics / examples / rules / lessons、decisions.yml) |
.trove/kb/<数据源>/,compose 里 bind mount 到 /app/.trove |
YAML 是唯一真源;SQLite 镜像只是运行时检索的派生物,可重建 |
| 数据源注册表 | .trove/datasources.yml |
管理台注册的数据源持久化在这里,重启自动恢复 |
| LLM 凭证与全局配置 | ~/.trove/conf/agent.yml(容器内 /root/.trove/conf) |
compose 里的只读挂载默认注释掉——取消注释才会生效 |
| 业务数据本身 | 你自己的数据库 | Trove 对业务库只读:执行通道只放行 SELECT 类语句,不需要为它准备任何写权限 |
日常操作:起停、重建、看日志
docker compose up --build # 构建并启动(后端 :8000 仅调试,前端 :8080)
docker compose build frontend # 只重建前端镜像(前端改动不动后端)
docker compose build backend # 只重建后端镜像
docker compose restart backend # 只重启后端,前端容器不受影响
docker compose logs -f backend # 跟后端日志
docker compose down # 停止并移除容器(保留 pgdata 卷与 .trove 挂载)
| 我改了什么 | 要做什么 |
|---|---|
| 前端页面 / 样式 | docker compose build frontend && docker compose up -d frontend——后端不动 |
| 后端代码 / 提示词 | docker compose build backend && docker compose up -d backend——前端不动 |
| 知识库内容 | 优先走管理台或 /kb 接口改(它们会同步维护检索镜像);直接手改 YAML 后重启一次后端 |
| 数据源连接串 | 管理台 /admin/datasources 改,写入 datasources.yml;重启后自动恢复 |
| LLM 配置 | 改 ~/.trove/conf/agent.yml 后 docker compose restart backend |
trove serve 自带内嵌的定时任务巡检(默认每 30 秒一跳,
由 agent.scheduler_poll_seconds 控制)。不要再并行跑
trove-cli schedule --daemon——两个调度器会各跑一遍,
定时任务被重复执行。
健康检查与监控
GET /v1/health 是存活 + 真实依赖检查,三种结果:
| HTTP | status | 含义 |
|---|---|---|
| 200 | ok | 内部存储往返正常,全部数据源探测通过 |
| 200 | degraded | 进程活着,但某个数据源连不上;外部编排仍视其为可用 |
| 503 | unavailable | 内部存储不可达(Postgres 挂了 / TROVE_STORAGE_URL 指错)——这才是真正要告警的状态 |
$ curl -s localhost:8000/v1/health
{"status":"ok",
"checks":{
"storage":{"ok":true},
"datasources":{"financial":{"ok":true,"readonly":{"basis":"grants"}},
"demo":{"ok":true,"readonly":{"verified":null,"basis":"not_probed"}}},
"llm":{"mock":false,"target":"deepseek/deepseek-reasoner","providers":0}}}
LLM 一栏只报事实(mock / target / providers),
不做计费探测,也不下「能不能用」的结论——凭证是否可用的最终判定
是一次真实提问(见故障表「问答不可用」一行)。
GET /v1/metrics 输出 Prometheus 文本格式,直接可被
Prometheus / VictoriaMetrics 抓取。运维上最该关注的几个族:
| 指标 | 看什么 |
|---|---|
trove_http_requests_total / trove_http_request_duration_seconds | 接口流量与延迟;按 route/status 定位错误面 |
trove_llm_calls_total / trove_llm_call_duration_seconds | 按 provider/model/status 拆分——成本与供应商健康 |
trove_sql_queries_total / trove_sql_query_duration_seconds | 业务库执行次数与耗时 |
trove_sql_cache_hits_total | 精确结果缓存命中;命中即零 LLM 成本 |
trove_sql_degraded_total / trove_sql_kill_total | 预算降级与 EXPLAIN 守卫拦截——回答质量与安全的先行指标 |
trove_authz_deny_total / trove_authz_table_warn_total | 越权拒绝与越表告警;异常升高说明有人在探边界 |
trove_masking_applied_total | 脱敏实际发生的次数 |
指标是单进程内存计数、免鉴权
(计数值本身不敏感)。部署在公网时,在反向代理层给 /v1/metrics
和 /v1/health 加上来源限制即可,不需要应用内额外配置。
生产配置清单
| 配置 | 作用 | 建议 |
|---|---|---|
TROVE_ADMIN_PASSWORD |
首个 admin 账号的引导密码 |
必须显式设置。不设置时密码随机生成、只在首次启动日志里打印一次(compose 里的 admin123 仅本地演练) |
TROVE_STORAGE_URL |
内部状态的存储后端;设了 → Postgres,未设 → SQLite 回退 | 生产用 Postgres(多实例/备份/并发都更稳);单机演示保持不设即可 |
LLM 凭证(providers[].api_key,支持 ${ENV_VAR}) |
真实问答的前提 | 凭证只放环境变量或 ~/.trove/conf(只读挂载),不进仓库、不进镜像 |
--datasource |
启动时接入的数据源;业务库是示范数据时用 postgres://…,内置演示用 demo |
生产数据源交由管理台注册,写进 datasources.yml 持久化 |
agent.scheduler_poll_seconds |
内嵌调度巡检间隔(默认 30 秒) | 与上文的「不要双跑」是同一件事的两面 |
agent.language |
交互语言(提示词、答案、轨迹统一使用) | 与知识库内容语言保持一致;KB 内容语言与提问语言不一致会明显掉准确率 |
compose 默认不暴露 5432(那行 ports 是给本地调试用的),
保持注释状态。用户入口 8080 前面应接 TLS 终结(负载均衡或
nginx),8000 只留本机调试、不要对公网开放。
备份与升级
备份什么
| 对象 | 方式 | 恢复影响 |
|---|---|---|
| 内部状态(会话/用户/审计/任务/检查点/记忆) | Postgres 部署下即 pg_dump trove;SQLite 回退下备份对应 .sqlite / .db 文件 |
丢了 = 丢历史会话、用户与授权、审计记录 |
| 知识库与治理内容 | 打包 .trove/(重点是 kb/ 与 datasources.yml) |
丢了 = 丢失全部建模成果(语义模型、样例、教训、决策规则)——这是最贵的一份 |
| LLM 凭证与全局配置 | 备份 ~/.trove/conf/(进密钥管理,不进普通备份盘) |
丢了 = 问答不可用(health 里 llm.mock 会亮) |
升级步骤
# 1. 先备份(见上表)
pg_dump "$TROVE_STORAGE_URL" > trove-$(date +%F).sql
tar czf kb-$(date +%F).tar.gz .trove/
# 2. 拉新代码,重建镜像,滚动起来
git pull
docker compose build
docker compose up -d
# 3. 验证
curl -s localhost:8000/v1/health # 应为 ok / degraded
# 管理台登录 → 数据源健康 → 问一个已知问题对照答案
内部状态的库表迁移是版本化、幂等、自动应用的:新代码第一次 打开旧库会自动迁移到位,中途失败会回滚且不推进版本。KB 的 SQLite 检索镜像 是派生物,走重建而不是迁移——升级后如果检索异常,重跑一次 KB 初始化即可,YAML 真源不受影响。
迁移只前进不后退:旧代码打开新版本的库会被直接拒绝
(StorageSchemaTooNew,防止静默读丢数据)。所以回滚镜像时必须
连同数据库一起恢复到步骤 1 的备份,不能只回滚镜像。
故障排查对照表
| 症状 | 先看 | 处置 |
|---|---|---|
| 打开 8080 页面正常,但登录/接口 502 | docker compose ps——backend 是否 healthy |
看 docker compose logs backend 的启动报错;多半是依赖没就绪,等 compose 重试或 up -d 重拉 |
/v1/health 返回 503 |
checks.storage |
存储不可达:Postgres 容器是否在跑、TROVE_STORAGE_URL 指的库是否存在、网络是否通 |
status: degraded |
checks.datasources 里哪个源 ok:false |
该业务库的连接串/账号/网络问题;单源故障不影响其他源 |
| 能登录,但提问得到的不是真实答案(或提示无凭证) | checks.llm.mock:true 即未配置凭证 |
按配置参考给 providers[] 配 key(或挂载 ~/.trove/conf)后重启后端 |
| 登录失败,不知道 admin 密码 | 首次启动日志 | 未设 TROVE_ADMIN_PASSWORD 时密码是随机生成的、只在首次启动日志里打印一次;实在找不回可清掉用户表重建引导(先备份) |
| 用户端数据源下拉里看不到某个源 | 管理台 /admin/datasources 该源状态与 KB 状态 |
下拉只显示「已连接且 KB 已初始化」的源;非 admin 用户还需要在用户页勾选数据源授权 |
| 注册数据源直接报 400 | 错误正文 | 注册即连接探测,400 就是探测失败的原因(连接串、账号、网络或驱动 extra 没装)——按正文修 |
/kb init 报凭证错误、或只生成了骨架 |
LLM 凭证 | 没有 LLM 凭证时,初始化按配置走纯骨架或直接报错;补好凭证后重跑 /kb init |
| 定时任务被执行了两次 | 是否同时跑了 serve 与 schedule --daemon |
停掉其中一个;serve 自带内嵌巡检,二选一 |
| 中文提问命中率骤降、检索总是差一点 | KB 内容语言 vs 提问语言 | 两者必须一致(英文 KB 配英文提问是设计边界);在语义层为中文问法补同义词,或按使用语言重建 KB |
单次问答的完整轨迹在运行目录的 runs/<run_id>.log
(默认 ~/.trove/runs,容器内 /root/.trove/runs):
逐节点的输入、生成、校验与裁决都在里面,是排查「答案为什么不对」的第一现场。
平台侧的可观测入口见 可观测性。