安装部署
三种跑法:本地 REPL(最快看到效果)、
compose 全套(前后端 + 数据库,接近生产形态)、
独立进程(后端 trove serve + 前端 dev server,改代码时用)。
最快路径
内置了一个 BIRD 金融 demo 数据源,不需要连任何外部库、不需要灌数据:
uv sync # Python ≥ 3.12
uv run trove --datasource demo # REPL
一次性输出 JSON(适合脚本调用):
echo "哪个地区的平均贷款金额最高?" | uv run trove-cli --datasource demo --print
真实对话需要模型凭证。凭证放项目根的 .env(自动加载、已在
.gitignore 里)或直接导出环境变量,例如 DEEPSEEK_API_KEY。
解释器的版本要求写在 pyproject.toml 里:
pyproject.toml:11 requires-python
compose 拓扑
默认业务栈是 PostgreSQL——不是「随便选了个库」,
而是因为用的 paradedb 镜像把三件事放在同一个实例里:
业务表、pgvector 向量、pg_bm25 全文检索。这样
混合检索的两路通道不需要跨系统。
flowchart LR
B["浏览器"]:::entry -- ":8080" --> F["frontend 容器
nginx:托管 SPA + 反代 /v1"]:::entry
F -- "/v1" --> K["backend 容器
trove serve:纯 JSON API"]:::core
K -- "业务查询" --> P[("postgres 容器
业务表 + pgvector + pg_bm25")]:::ext
I["db-init 容器
灌 demo 数据,跑完即退"]:::entry -- "幂等灌数(backend 等它成功后才启动)" --> P
K -. "生成 / 反思" .-> L["LLM 网关
凭证从宿主机注入"]:::gen
V[".trove 卷
KB · 记忆 · 任务定义"]:::entry -. "挂载进 backend 容器" .-> K
classDef entry fill:#71717a14,stroke:#71717a59,stroke-width:1px;
classDef core fill:#6366f11f,stroke:#6366f1,stroke-width:2px;
classDef gen fill:#6366f114,stroke:#6366f199,stroke-width:1.5px;
classDef ext fill:transparent,stroke:#71717a80,stroke-width:1.5px,stroke-dasharray:4 4;
| 服务 | 作用 | 对外端口 |
|---|---|---|
| postgres | 业务数据 + 向量 + 全文检索(ParadeDB 镜像) | 内部 |
| db-init | 一次性灌入 BIRD 金融 demo 数据,幂等,跑完即退 | — |
| backend | trove serve,纯 JSON API,所有路由在 /v1 下 |
8000 |
| frontend | nginx 托管 SPA 并反代 /v1 到后端 |
8080 |
访问 http://localhost:8080/。后端那 8000 端口只作调试用
(可以直接 curl API),日常入口是前端。
docker compose up --build # 构建并启动
docker compose down # 停止并移除容器
docker-compose.yml:17 paradedb docker-compose.yml:43 init_postgres_demo docker-compose.yml:55 serve
两个镜像,各自独立重建
前后端是分开构建的镜像,不是一次构建出一个整体。 这不是为了「微服务好看」,而是为了改动的实际代价: 改一次前端文案不该重装 Python 依赖,改一次后端逻辑也不该重新 npm build。
docker compose build frontend # 只重建前端
docker compose build backend # 只重建后端
docker compose restart backend # 只重启后端,前端容器不受影响
前端镜像走多阶段构建:Node 阶段 npm ci + npm run build,
产物拷进 nginx 运行时镜像,所以最终镜像里没有 Node 工具链。
nginx 配置里两件事最关键——反代与 SPA 回退:
frontend/Dockerfile:7 AS build frontend/Dockerfile:17 nginx frontend/nginx.conf:32 proxy_pass frontend/nginx.conf:17 try_files
生产形态下前端与 /v1 同源(nginx 反代),浏览器视角里没有跨域。
开发形态下由 Vite 的 dev server 代理 /v1 到后端,同样没有跨域。
所以后端不开 CORS 不是遗漏——引入它反而会多一个需要维护的开放面。
登录与初始凭据
compose 里写了 admin123,这只用于本地演练。
生产要由 TROVE_ADMIN_PASSWORD 环境变量控制;不提供时系统会
随机生成一个 20 位密码并只打印一次。
docker-compose.yml:63 TROVE_ADMIN_PASSWORD main.py:157 TROVE_ADMIN_PASSWORD
数据源与 KB 的持久化靠挂载 ./.trove 卷——KB 里的 YAML、
记忆、任务定义都在这里。这个目录是资产的实体,容器可以随时重建,它不行。
本地开发态
后端与前端各跑一个进程,前端走 HMR:
uv run trove serve # 后端 :8000
cd frontend && npm run dev # 前端 :5173,反代 /v1 → 后端
serve 的参数可以改绑定地址,默认是本机回环:
main.py:752 --host
main.py:753 --port
main.py:768 async_main_serve
127.0.0.1 是默认值而不是 0.0.0.0。要对外提供服务必须显式改,
而改了之后就该同时考虑认证、限流与网络边界——见安全边界。
依赖 extras:按需安装
数据库驱动不放进基础依赖。这样「支持六种数据源」不会让所有人都背上六个驱动的安装成本。
| extras | 装什么 | 用途 |
|---|---|---|
| postgres | psycopg + langgraph checkpoint-postgres | 业务库 + 向量检索 + 检查点 |
| mysql | aiomysql | MySQL 协议 |
| doris | aiomysql | Doris 复用 MySQL 协议驱动 |
| clickhouse | clickhouse-connect | ClickHouse |
| duckdb | duckdb | 本地分析型文件库 |
uv sync --extra mysql --extra doris
pyproject.toml:47 postgres pyproject.toml:55 doris
存储后端怎么选
内部状态(会话、记忆、任务、检查点…)跑在哪,由一个环境变量决定:
| 变量 | 设置时 | 未设置时 |
|---|---|---|
| TROVE_STORAGE_URL | PostgreSQL 后端(生产) | SQLite 兜底(本地 / 测试) |
注意这个变量管的是 Trove 自己的状态,不是你的业务数据源。
业务数据源由管理端注册、持久化到 .trove/datasources.yml,
重启时自动恢复注册。
config_store.py:26 DEFAULT_PATH main.py:171 boot_register
环境变量速查
| 变量 | 作用 |
|---|---|
| TROVE_ADMIN_PASSWORD | 初始管理员密码;不设则随机生成并打印一次 |
| TROVE_STORAGE_URL | 内部状态的存储后端(PostgreSQL / 不设用 SQLite) |
| TROVE_SECRET_KEY | 连接串密码的加密密钥(Fernet) |
| TROVE_TOKEN_TTL_HOURS | 登录 token 有效期,默认 720 小时 |
| TROVE_GIT_KB_AUTHOR | KB git 提交使用的作者身份 |
| LANGFUSE_PUBLIC_KEY / SECRET_KEY | 两个都设才启用 Langfuse 追踪 |
| <厂商>_API_KEY | 模型凭证,由 litellm 回落解析 |
配置文件里也可以写 ${ENV_VAR} 占位符,加载时展开成环境变量值——
这样配置文件本身可以安全地进版本库。
config.py:580 resolve_env_vars
配置的搜索顺序是项目内 ./conf/agent.yml 优先,其次
~/.trove/conf/agent.yml。管理台里改的运行时设置存在
~/.trove/settings.db,启动时合入——也就是说文件是基线,界面改动是覆盖层。