部署与运维
本文引用的文件
- deploy/env.sh
- cmd/uninstall.bat
- cmd/uninstall.sh
- ai-electron/package.json
- ai-electron/electron/config/config.default.ts
- ai-electron/electron/config/config.prod.ts
- ai-electron/electron/config/windowOptions.ts
- ai-electron/electron/main.ts
- ai-electron/electron/preload/lifecycle.ts
- ai-gateway/src/main/java/com/zsjz/gateway/GatewayApplication.java
- ai-gateway/src/main/resources/application.yaml
- ai-gateway/src/main/resources/application-pro.yaml
- ai-gateway/src/main/java/com/zsjz/gateway/admin/AdminService.java
- ai-gateway/src/main/java/com/zsjz/gateway/registry/HealthChecker.java
- ai-gateway/src/main/java/com/zsjz/gateway/route/UserRouteService.java
- ai-server/src/main/resources/application.yaml
- ai-server/src/main/resources/application-pro.yaml
- ai-server/src/main/java/com/zsjz/ai/common/config/SaTokenWebConfig.java
- ai-server/src/main/java/com/zsjz/ai/module/plat/controller/SystemController.java
目录
- 引言
- 项目结构
- 生产环境前置依赖
- 环境变量与服务配置
- 服务启动顺序与差异
- Electron 客户端构建、打包与自动更新
- 多节点扩展方案
- 日志位置与监控指标
- 备份恢复与数据生命周期
- 性能调优建议
- 常见故障排查清单
- 结论
引言
本指南面向生产环境的部署与运维人员,覆盖 PostgreSQL/pgvector、Redis、DuckDB 初始化思路,后端环境变量配置,ai-gateway 与 ai-server 的启动顺序和配置差异,Electron 客户端构建打包及自动更新流程,Windows/Linux 安装包卸载脚本用法,以及多节点粘性路由、负载均衡、健康检查、故障转移、日志、监控、备份恢复、性能调优和排障清单。
项目结构
从部署视角,系统由以下主要组件构成:
- 桌面客户端:ai-electron(Electron + ee-core)
- 网关:ai-gateway(Spring Boot,按用户粘性转发到 ai-server)
- 业务后端:ai-server(Spring Boot,连接 PostgreSQL/pgvector、Redis、Elasticsearch、可选 Neo4j 和本地 DuckDB 实例)
- 外部依赖:PostgreSQL(含 pgvector)、Redis、Elasticsearch、文件系统存储目录
- 部署配置:deploy/env.sh
安装包卸载脚本:cmd/uninstall.bat、cmd/uninstall.sh
graph TB
Client["桌面客户端<br/>ai-electron"] --> Gateway["网关<br/>ai-gateway:8080"]
Gateway --> Server1["后端节点 A<br/>ai-server:8980"]
Gateway --> Server2["后端节点 B<br/>ai-server:8980"]
Gateway --> DB["PostgreSQL<br/>pgvector"]
Gateway -.-> Redis["Redis<br/>会话与粘性路由缓存"]
Server1 --> DB
Server1 --> ES["Elasticsearch"]
Server1 --> Files["本地文件存储<br/>data/files"]
Server2 --> DB
Server2 --> ES
Server2 --> Files
图示来源
- ai-gateway/src/main/resources/application.yaml:1-81
- ai-server/src/main/resources/application.yaml:1-193
章节来源
- ai-gateway/src/main/java/com/zsjz/gateway/GatewayApplication.java:1-23
- ai-gateway/src/main/resources/application.yaml:1-81
- ai-server/src/main/resources/application.yaml:1-193
生产环境前置依赖
PostgreSQL 与 pgvector
- 数据库名默认使用
zsjz-ai,驱动为 org.postgresql.Driver。
- 必须启用 pgvector 扩展,因为向量索引、模板语义检索、附件 RAG 等能力依赖该扩展。
- 主库地址、用户名、密码通过环境变量或 application-pro.yaml 注入;网关也共享同一套 PostgreSQL。
- 网关会在首次启动时执行幂等的建表 SQL,服务与节点元数据保存在网关自己的数据库中。
建议步骤:
- 安装 PostgreSQL。
- 创建数据库
zsjz-ai。
- 启用 pgvector 扩展。
- 初始化网关表结构(可复用仓库中的 gateway 相关 SQL)。
- 校验端口、账号权限、网络连通性。
Redis
- Redis 是登录态硬依赖:sa-token 将 token 映射到登录用户信息并写入 Redis。
- Redis 不可用会导致登录相关接口异常。
- 网关还使用 Redis 缓存“用户 -> ai-server 节点”的粘性路由键。
- 生产环境需设置独立密码,并通过环境变量或配置文件注入 host、port、database。
建议步骤:
- 安装并启动 Redis。
- 设置强密码。
- 开放给 ai-gateway 和 ai-server 所在主机访问。
- 校验连接后确认 sa-token 能读写 token。
DuckDB
- DuckDB 不是常驻外部服务,而是以进程内或轻量实例形式管理案件库资源。
- 应用层通过
ZSJZ_DUCKDB_MAX_OPEN_CASES 控制同时打开的案件库数量上限,超出直接拒绝开案。
- DuckDB 内存预算、线程数、回收器延迟与间隔都可通过环境变量调整。
- 部署时需确保机器有足够内存,避免多个大案例并发导致堆外内存或系统内存压力。
建议步骤:
- 评估单机 CPU 核数和内存。
- 根据并发案例数调整
ZSJZ_DUCKDB_MAX_OPEN_CASES、ZSJZ_DUCKDB_MEMORY_RATIO、ZSJZ_DUCKDB_THREADS_PER_INSTANCE。
- 观察启动后的兜底回收器日志,确认未出现大量资源泄漏。
章节来源
- deploy/env.sh:1-172
- ai-server/src/main/resources/application.yaml:1-193
- ai-gateway/src/main/resources/application.yaml:1-81
- ai-gateway/src/main/resources/application-pro.yaml:1-14
环境变量与服务配置
deploy/env.sh 的作用
deploy/env.sh 集中声明了 ai-server 的环境变量,包括跨域、Spring 基础参数、PostgreSQL、Redis、Elasticsearch、本地存储、Neo4j、RAG、Insight、DuckDB、文件 AI 识别、Embedding、AI Clean、聊天附件解析、登录安全窗口等。其设计约定是:application.yaml 中的配置项写成 ${ENV_NAME:默认值},当未设置环境变量时使用 yaml 默认值;设置了环境变量则以环境变量为准。
典型用途:
- 在 Linux 上通过
set -a; source deploy/env.sh; set +a 再启动 ai-server。
- 在 systemd 单元中通过
EnvironmentFile=/opt/zsjz-ai/deploy/env.sh 注入。
注意事项:
- 文件中包含数据库口令,部署时应限制文件权限。
- 跨域开关默认开启,因为 Electron 前端可能通过 file:// 加载。
- Spring profile 由
SPRING_PROFILES_ACTIVE 控制,默认 dev;生产应改为 pro。
- Sa-Token、MyBatis-Plus 不参与此文件的参数化。
关键环境变量对照
| 类别 |
示例变量 |
说明 |
| 跨域 |
APP_CORS_ENABLED、APP_CORS_ALLOWED_ORIGIN_PATTERNS |
Electron file:// 前端需要允许跨域 |
| Spring |
SPRING_TASK_SCHEDULING_POOL_SIZE、SPRING_HTTP_CODECS_MAX_IN_MEMORY_SIZE、multipart 大小 |
调度线程池、HTTP 编码器和上传大小 |
| PostgreSQL |
SPRING_DATASOURCE_DYNAMIC_*_MASTER_* |
主库 URL、用户名、密码、驱动 |
| Redis |
SPRING_DATA_REDIS_HOST、SPRING_DATA_REDIS_PORT |
sa-token 登录态依赖 |
| Elasticsearch |
SPRING_ELASTICSEARCH_URIS、超时参数 |
全文检索集群地址 |
| 文件存储 |
STORAGE_LOCAL_ROOT_PATH、STORAGE_LOCAL_BASE_URL |
根目录与对外基础 URL |
| DuckDB |
ZSJZ_DUCKDB_MAX_OPEN_CASES、ZSJZ_DUCKDB_MEMORY_RATIO、ZSJZ_DUCKDB_THREADS_PER_INSTANCE |
案件库并发与资源预算 |
| Embedding |
ZSJZ_EMBEDDING_ENABLED、ZSJZ_EMBEDDING_MODEL_PATH、ZSJZ_EMBEDDING_DIMENSIONS |
本地 ONNX 向量模型开关与路径 |
| AI Clean |
ZSJZ_AI_CLEAN_VECTOR_* |
模板向量索引开关、阈值、重建策略 |
| Chat Attachment |
ZSJZ_CHAT_ATTACHMENT_* |
对话附件大小、分块、RAG 召回条数 |
| Auth |
ZSJZ_AUTH_IN_USE_WINDOW_MINUTES |
账号正在使用的判定窗口分钟数 |
章节来源
- deploy/env.sh:1-172
- ai-server/src/main/resources/application.yaml:1-193
- ai-server/src/main/resources/application-pro.yaml:1-87
服务启动顺序与差异
推荐启动顺序
- 启动 PostgreSQL、Redis、Elasticsearch。
- 启动 ai-server(至少一个节点)。
- 启动 ai-gateway。
- 验证
/js/a/sys/health 和网关管理端可用性。
- 启动 Electron 客户端。
原因:
- ai-server 提供业务接口和健康端点。
- ai-gateway 依赖 ai-server 的健康端点进行节点探活,并依赖 Redis 做粘性路由缓存。
- Electron 客户端通过网关访问后端,若后端未就绪会失败。
ai-server 配置要点
- 默认监听
8980,上下文路径 /js/a。
- 跨域开关受
app.cors.* 控制,生产应根据固定域名收敛允许来源。
- Sa-Token 通过请求头
x-token 传递,token 有效期 30 天,默认单端登录,支持通过 JVM 参数或环境变量开启多端。
- 向量能力依赖 pgvector 和可用 embedding 模型;缺失时链路 fail-open。
- 文件存储根目录默认为
./data/files,对外基础 URL 应与端口和上下文路径一致。
ai-gateway 配置要点
- 默认监听
8080。
- Sa-Token 配置必须与 ai-server 保持一致,否则无法正确解析 token。
- 服务定义包含 path-prefix、login-path、health-path、default-node-id 和 nodes 列表。
- 健康检查周期、超时、失败阈值可配置。
- 生产环境可通过 application-pro.yaml 通过 PG_URL、PG_USER、PG_PASSWORD、REDIS_HOST 等环境变量覆盖数据库和 Redis 配置。
启动命令参考
- ai-server:从部署根目录执行
java -jar ai-server.jar,并确保已 source env.sh 或通过 systemd EnvironmentFile 注入。
ai-gateway:执行 java -jar ai-gateway.jar,并使用 Spring profile pro。
sequenceDiagram
participant Admin as "运维"
participant Postgres as "PostgreSQL"
participant Redis as "Redis"
participant Server as "ai-server"
participant Gateway as "ai-gateway"
participant Client as "Electron 客户端"
Admin->>Postgres: 启动并初始化数据库
Admin->>Redis: 启动并设置密码
Admin->>Server: 启动后端节点
Server->>Postgres: 连接主库
Server->>Redis: 连接会话缓存
Admin->>Gateway: 启动网关
Gateway->>Server: 周期性探测 /js/a/sys/health
Client->>Gateway: 发起业务请求
Gateway->>Server: 转发到粘性节点
图示来源
- ai-gateway/src/main/resources/application.yaml:1-81
- ai-server/src/main/resources/application.yaml:1-193
章节来源
- ai-gateway/src/main/resources/application.yaml:1-81
- ai-gateway/src/main/resources/application-pro.yaml:1-14
- ai-server/src/main/resources/application.yaml:1-193
- ai-server/src/main/resources/application-pro.yaml:1-87
Electron 客户端构建、打包与自动更新
构建与打包命令
package.json 定义了常用脚本:
npm run build:构建前端、构建 Electron、加密。
npm run build-w:构建 Windows 64 位。
npm run build-we:构建 Windows 企业版。
npm run build-m:构建 macOS。
npm run build-m-arm64:构建 macOS ARM64。
npm run build-l:构建 Linux。
这些命令通过 ee-bin 调用 electron-builder,并按平台读取对应的 builder 配置。
运行时配置
- 默认入口是
public/electron/main.js。
- 默认关闭开发者工具,生产配置进一步确保不打开调试窗口。
- 窗口选项使用 ee-core 提供的 webPreferences,默认启用 nodeIntegration 并禁用 contextIsolation,主窗口与智能工作台窗口共用相同偏好以避免行为不一致。
- 日志级别默认 info,按日滚动,单个日志文件最大 100MB,日志名称包括应用日志、核心日志和错误日志。
- mainServer 协议为 file://,索引路径指向打包后的前端静态资源。
自动更新
项目依赖 electron-updater,并在各平台 builder 配置中包含 publish 字段,用于指定更新源。通常自动更新流程如下:
- 发布新版安装包到配置的更新服务器。
- 生成 latest.yml 等版本描述文件。
- 客户端启动时检查最新版本。
- 发现新版本后下载并提示或静默安装。
生产部署时需注意:
- 更新服务器必须可被客户端访问。
- latest.yml 的版本号必须与 package.json 版本号一致。
- 如果后端升级了 API,应先完成服务端灰度再推送客户端版本。
客户端生命周期
main.ts 注册 ee-core 生命周期钩子,preload/lifecycle.ts 处理 ready、electron-app-ready、window-ready、before-close 等阶段,负责显示窗口、居中缩放、二次启动聚焦、智能工作台窗口优先聚焦等行为。
flowchart TD
Start["运行 npm run build-*"] --> Frontend["构建前端资源"]
Frontend --> ElectronBuild["构建 Electron 应用"]
ElectronBuild --> Package["打包为 Windows/macOS/Linux 安装包"]
Package --> Publish["发布到更新服务器"]
Publish --> ClientCheck["客户端启动检查更新"]
ClientCheck --> Update["下载并安装新版本"]
Update --> Run["运行新版本客户端"]
图示来源
- ai-electron/package.json:1-42
- ai-electron/electron/main.ts:1-19
- ai-electron/electron/preload/lifecycle.ts:1-73
章节来源
- ai-electron/package.json:1-42
- ai-electron/electron/config/config.default.ts:1-50
- ai-electron/electron/config/config.prod.ts:1-10
- ai-electron/electron/config/windowOptions.ts:1-41
- ai-electron/electron/main.ts:1-19
- ai-electron/electron/preload/lifecycle.ts:1-73
多节点扩展方案
架构目标
- 多个 ai-server 节点共同承载业务。
- 网关按用户粘性路由,保证同一用户的请求尽量落到同一节点,避免状态不一致。
- 健康检查持续探测每个节点,连续失败标记 DOWN,一次成功恢复 UP。
- 管理端支持绑定用户到指定节点、导入已有绑定关系。
粘性路由与健康检查
- 用户路由缓存键包含 serviceId、userId、username,存储在 Redis 中。
- 健康检查每
gateway.health-check.interval 秒对启用的节点调用 {base-url}{health-path}。
- 连续失败达到
gateway.health-check.failure-threshold 次后节点标记 DOWN;一次成功即恢复 UP。
网关默认 health-path 为 /js/a/sys/health,对应 ai-server 的系统健康接口。
classDiagram
class HealthChecker {
+周期性探测()
+记录成功(nodeId)
+记录失败(nodeId, error, threshold)
}
class NodeHealthRegistry {
+快照()
+是否存活(nodeId) bool
+记录成功(nodeId)
+记录失败(nodeId, error, threshold)
}
class UserRouteService {
+查找路由(serviceId, userId) Mono
+绑定不存在(serviceId, userId, username, nodeId) Mono
+缓存用户(serviceId, userId, username, nodeId) Mono
}
class AdminService {
+绑定用户(serviceId, userId, username, nodeId)
+导入已有绑定(serviceId, nodeId) int
+检查节点(nodeId) Mono
}
HealthChecker --> NodeHealthRegistry : "更新状态"
UserRouteService --> NodeHealthRegistry : "判断节点存活"
AdminService --> UserRouteService : "写入粘性路由"
图示来源
- ai-gateway/src/main/java/com/zsjz/gateway/registry/HealthChecker.java:1-60
- ai-gateway/src/main/java/com/zsjz/gateway/route/UserRouteService.java:1-90
- ai-gateway/src/main/java/com/zsjz/gateway/admin/AdminService.java:1-290
负载均衡策略
当前实现以“用户粘性”为主,不是无状态轮询负载均衡。这意味着:
- 同一用户登录后,网关会将其绑定到某个 ai-server 节点。
- 适合需要会话或局部状态的推理、研判场景。
- 如果需要全局均匀负载,应在网关之上再加一层反向代理做请求级负载均衡,但要注意长连接和 SSE 场景。
健康检查与故障转移
- 健康检查只证明进程存活,不深入检查 PostgreSQL、Redis、Elasticsearch 是否全部正常。
- 若节点 DOWN,粘性路由不会主动把在线用户迁移到其它节点;新绑定或重新绑定时才会选择可用节点。
- 运维可在管理端手动触发节点检查、解绑、删除节点或重新导入绑定关系。
配置差异总结
| 项目 |
ai-server |
ai-gateway |
| 默认端口 |
8980 |
8080 |
| 上下文路径 |
/js/a |
不统一业务路径,仅转发 |
| 主库 |
PostgreSQL/pgvector |
自身服务元数据 |
| Redis |
sa-token 登录态 |
粘性路由缓存 |
| Elasticsearch |
全文检索 |
不使用 |
| 健康端点 |
/js/a/sys/health |
使用业务健康端点 |
| Sa-Token |
认证主体 |
只读 token->loginId |
章节来源
- ai-gateway/src/main/resources/application.yaml:1-81
- ai-gateway/src/main/java/com/zsjz/gateway/registry/HealthChecker.java:1-60
- ai-gateway/src/main/java/com/zsjz/gateway/route/UserRouteService.java:1-90
- ai-gateway/src/main/java/com/zsjz/gateway/admin/AdminService.java:1-290
日志位置与监控指标
日志位置
- Electron 客户端日志由 ee-core 管理,默认输出到应用日志、核心日志和错误日志文件,日志级别为 info,按日滚动,单文件最大 100MB。
- 后端日志取决于 Spring Boot 默认配置和具体日志框架实现;健康检查状态也会记录节点 UP/DOWN 信息。
排查建议:
- 先查看 Electron 应用的错误日志。
- 再查看 ai-server 的业务日志和调度日志。
- 最后查看 ai-gateway 的健康检查日志和管理端操作日志。
监控指标
- 进程存活:操作系统级进程状态、CPU、内存、磁盘、网络。
- 服务健康:
GET http://host:8980/js/a/sys/health。
- 网关健康:网关自身的 Spring Boot 健康端点和管理端接口。
- 数据库连接:PostgreSQL 活跃连接数、慢查询。
- Redis:连接数、内存、持久化状态。
- Elasticsearch:集群健康、索引大小、查询延迟。
- DuckDB:同时打开案例数、内存使用、回收器扫描日志。
- 向量模型:ONNX Runtime 加载耗时、批推理吞吐、失败重试次数。
章节来源
- ai-electron/electron/config/config.default.ts:1-50
- ai-gateway/src/main/java/com/zsjz/gateway/registry/NodeHealthRegistry.java:1-70
- ai-server/src/main/java/com/zsjz/ai/module/plat/controller/SystemController.java:1-60
备份恢复与数据生命周期
备份范围
| 数据 |
备份方式 |
恢复要点 |
| PostgreSQL |
逻辑备份或物理备份 |
保留 schema、pgvector 扩展、业务表、网关表 |
| Redis |
持久化文件或云托管备份 |
注意 token 过期策略和粘性路由键 |
| 本地文件存储 |
同步 data/files 目录 |
base-url 需与部署地址一致 |
| Electron 用户数据 |
用户目录下的 qingjian-client 相关目录 |
卸载脚本会清理 |
恢复顺序
- 恢复 PostgreSQL。
- 恢复 Redis。
- 恢复本地文件存储目录。
- 启动 ai-server。
- 启动 ai-gateway。
- 验证登录、粘性路由、向量索引、文件访问。
数据生命周期
- Insight 会话可配置留存天数,0 表示不清理。
- 聊天附件存在孤儿清理机制,长时间未发消息的附件会被清理。
- AI Clean 批次心跳超时会标失败,可由看门狗处理。
- DuckDB 案件库有兜底回收器,定期扫描释放资源。
章节来源
- ai-server/src/main/resources/application.yaml:1-193
- cmd/uninstall.sh:1-53
性能调优建议
ai-server
- 合理设置
SPRING_TASK_SCHEDULING_POOL_SIZE,避免批量任务拖住 SSE 心跳。
- 根据上传文件大小调整 multipart 大小限制。
- 根据机器内存和并发案例数调整 DuckDB 的最大案例数、内存比例和线程数。
- 向量模型首次加载可能占用较大堆外内存,生产建议预热或预留足够内存。
- 若使用本地 embedding 模型,确认模型路径、维度、优化级别与机器性能匹配。
ai-gateway
- 调整健康检查间隔、超时和失败阈值,平衡检测灵敏度与后端压力。
- 网关默认不对跨域做额外收口,避免重复 Access-Control-Allow-Origin 头。
- 管理端 IP 白名单可用于限制敏感管理接口。
Electron 客户端
- 生产构建关闭开发工具。
- 窗口大小和最小尺寸应避免过小影响图表和表格展示。
- 日志滚动大小可根据磁盘空间调整。
章节来源
- ai-server/src/main/resources/application.yaml:1-193
- ai-gateway/src/main/resources/application.yaml:1-81
- ai-electron/electron/config/config.prod.ts:1-10
常见故障排查清单
| 现象 |
可能原因 |
排查步骤 |
| 登录失败 |
Redis 不可用或 sa-token 配置不一致 |
检查 Redis 连通性、host/port/password;核对 ai-server 与 ai-gateway 的 Sa-Token 配置 |
| 跨域报错 |
前端 file:// 或浏览器跨域被拒绝 |
检查 APP_CORS_ENABLED、APP_CORS_ALLOWED_ORIGIN_PATTERNS;必要时收敛允许来源 |
| 向量功能不可用 |
pgvector 未启用或 embedding 模型缺失 |
检查 pgvector 扩展、模型路径、维度、模型目录是否存在 |
| 开案失败 |
DuckDB 并发超限或内存不足 |
查看 ZSJZ_DUCKDB_MAX_OPEN_CASES、机器内存、DuckDB 回收日志 |
| 健康检查一直 DOWN |
后端健康端点不可达或路径错误 |
检查 {base-url}/js/a/sys/health、网关 health-path、节点 base-url |
| 用户请求总是落到不同节点 |
粘性路由未命中或 Redis 丢失 |
检查 Redis 中路由缓存键、是否重启后丢失、是否手动解绑 |
| 文件访问链接无效 |
storage.local.base-url 与实际部署地址不一致 |
核对 server.port、context-path、base-url |
| 客户端启动白屏或打不开 |
前端资源路径错误或 mainServer 配置异常 |
检查构建产物、index.html 路径、日志中的 mainServer 配置 |
| 安装包卸载后仍残留数据 |
卸载脚本未执行或未以正确用户运行 |
以目标用户运行 cmd/uninstall.sh 或 cmd/uninstall.bat |
卸载脚本用法
- Linux:
cmd/uninstall.sh 会强制终止 qingjian-client 进程,然后递归删除用户目录下三个可能目录:$HOME/.config/qingjian-client、$HOME/.local/share/QingJian、$HOME/.qingjian-client。
- Windows:
cmd/uninstall.bat 提供对应卸载清理流程,应与 Linux 脚本配合使用,确保跨平台一致性。
章节来源
- ai-server/src/main/java/com/zsjz/ai/common/config/SaTokenWebConfig.java:1-40
- ai-server/src/main/java/com/zsjz/ai/module/plat/controller/SystemController.java:1-60
- cmd/uninstall.sh:1-53
- cmd/uninstall.bat:1-53
结论
生产部署应以 PostgreSQL/pgvector、Redis、Elasticsearch 为底座,按顺序启动 ai-server 和 ai-gateway,并通过 deploy/env.sh 统一管理环境变量。多节点扩展以用户粘性路由为主,配合健康检查和治理接口实现高可用。Electron 客户端通过 electron-builder 和 electron-updater 完成构建、打包与自动更新。运维重点在于 Redis 与 PgVector 可用性、DuckDB 资源预算、向量模型路径、跨域配置、健康检查路径、日志位置和卸载脚本的正确使用。