跳到主要内容

平台基础

Libre WebUI 支持本地优先的 solo 配置和共享的 team 配置。Solo 使用 SQLite、加密本地 blob、加密嵌入式向量、本地协调和嵌入式持久工作进程;Team 使用 PostgreSQL、S3 兼容私有 blob、PGVector、Redis 协调和外部持久工作进程。启动过程会拒绝混合配置,避免在本地与共享后端之间静默拆分状态。

当前里程碑

领域已实现基础剩余调用方工作
持久化SQLite/PostgreSQL 仓库、不可变迁移、池化事务新领域必须使用仓库边界
Blob加密本地和 S3 兼容流式存储、范围、校验和、持久配额迁移聊天附件、头像和其他剩余内联二进制字段
向量加密嵌入式向量、PGVector ACL、删除安全的文档索引重建新嵌入调用方必须保留相同权限与生命周期契约
协调本地/Redis 事件、缓存、租约、速率限制、失效和健康状态保持 Redis 非权威性
作业/事件SQLite/PostgreSQL 队列、事务事件、工作进程、重试、取消、管理每项新副作用都需要幂等或 outbox 设计
运维健康门禁、签名/加密备份归档、干净目标恢复、验证针对每个部署环境演练恢复和跨副本验收

运行时配置

LIBRE_PLATFORM_MODE=solo 是默认值,选择 SQLite、本地 blob、嵌入式向量、本地协调和嵌入式持久工作进程。Solo 可选择 Redis,但这不会让 SQLite 或本地文件适合多副本共享。

LIBRE_PLATFORM_MODE=team 要求同时提供所有共享依赖:

  • DATABASE_BACKEND=postgresDATABASE_URL
  • BLOB_STORE_BACKEND=s3
  • VECTOR_STORE_BACKEND=pgvector
  • COORDINATION_BACKEND=redisREDIS_URL;以及
  • JOB_WORKER_MODE=external

这些选择器必须成套配置。缺少任何共享依赖或混入本地后端时,Team 启动都会失败。

迁移现有 Solo 安装

迁移前停止所有 Libre 应用和工作进程。示例使用全局 npm 或 Homebrew 安装的 libre-webui;未全局安装时替换为 npx --yes libre-webui@latest。从源代码检出时,先构建一次,再将 libre-webui migrate-postgres 替换为 npm run migrate:postgres --。按目标 Team 部署准确配置 PostgreSQL、S3 和版本化加密密钥环境,然后先运行只读分析:

libre-webui migrate-postgres \
--source /absolute/path/to/data.sqlite \
--plugins /absolute/path/to/plugins \
--mode dry-run

只应用到报告标识的空目标。失败运行会留下带校验和的导入日志;请恢复同一源和目标,不要开始无关导入:

libre-webui migrate-postgres \
--source /absolute/path/to/data.sqlite \
--plugins /absolute/path/to/plugins \
--mode apply

# Only after an interrupted apply of this exact source and target:
libre-webui migrate-postgres \
--source /absolute/path/to/data.sqlite \
--plugins /absolute/path/to/plugins \
--mode apply --resume

libre-webui migrate-postgres \
--source /absolute/path/to/data.sqlite \
--plugins /absolute/path/to/plugins \
--mode validate

只有关系行、插件定义、本地加密 blob、嵌入式向量和旧角色向量全部传输并在 PostgreSQL/S3/PGVector 中通过验证后,才会写入完成标记。命令绝不会臆造源加密密钥:ENCRYPTION_KEY 必须匹配源 .encryption_keySTORAGE_ENCRYPTION_KEYS 必须包含配置的活动密钥和匹配的 legacy 条目。

运行捆绑的 Team 配置

从随附的失败关闭模板开始。将完整环境文件放在仓库外,并限制为操作员可访问:

cp deploy/team/.env.example /absolute/path/to/libre-team.env
chmod 600 /absolute/path/to/libre-team.env

启动前替换每个 REPLACE_* 值。PostgreSQL 密码请使用 URL 安全字符集生成(如 openssl rand -hex 32),因为同一字面值既是服务器密码,也是 DATABASE_URL 的一部分。ENCRYPTION_KEYSTORAGE_ENCRYPTION_KEYS 中每个值都必须恰为 64 个十六进制字符。新安装中 legacy 必须等于 ENCRYPTION_KEY;SQLite 迁移时二者都必须等于源密钥。新 blob 写入可使用不同活动密钥,但应保留旧密钥,直到对象清单证明其不再使用。

同一文件可设置 POSTGRES_MIGRATION_MODEPOSTGRES_POOL_MAX、支持的 PostgreSQL 超时、REDIS_CONNECT_TIMEOUT_MSOLLAMA_BASE_URLOLLAMA_TIMEOUTOLLAMA_LONG_OPERATION_TIMEOUTOLLAMA_MAX_CONTEXT;共享 Compose 环境会把相同值传给应用和外部工作进程。提供商超时接受 1,000-3,600,000 毫秒,最大上下文接受 128-2,097,152 个令牌,长超时不能短于标准超时;格式错误会让两个服务器入口都在创建状态前失败。外部持久工作进程不支持节点本地 Agent CLI 二进制文件和 Codex OAuth 令牌文件,因此 Team 配置固定关闭两条提供商路径,尝试启用时启动会被拒绝。然后启动应用副本、外部持久工作进程、PostgreSQL/PGVector、Redis、版本化 MinIO bucket 和网关:

docker compose --env-file /absolute/path/to/libre-team.env \
-f docker-compose.team.yml up --build --scale libre-webui=3 -d
docker compose --env-file /absolute/path/to/libre-team.env \
-f docker-compose.team.yml ps

基础 Team 配置刻意不挂载 Docker socket,因此 Docker 支持的 Work 不可用。只有在每条生命周期命令中加入随附生产覆盖时才启用:

docker compose --env-file /absolute/path/to/libre-team.env \
-f docker-compose.team.yml -f docker-compose.team.work.yml \
up --build --scale libre-webui=3 -d
docker compose --env-file /absolute/path/to/libre-team.env \
-f docker-compose.team.yml -f docker-compose.team.work.yml ps

该覆盖让应用和工作进程指向内部网络上的同一个过滤式 Docker socket 代理。两者都不会收到原始 socket 或 socket 组成员身份,主机文件夹 Work 工作区仍禁用。代理只开放 info、images、containers、exec、volumes、networks 及这些生命周期调用所需的写方法。这缩小了 API 面,但 Docker 仍不是租户边界:创建容器仍可绑定挂载主机路径。重视主机隔离时,请使用专用虚拟机或无 root/独立 Work 守护进程。

不要直接公开 Compose 管理的 PostgreSQL、Redis 或 MinIO 服务。托管依赖请使用 Helm Team 配置并保留经验证的 TLS;Compose 文件只在其私有项目网络上禁用 PostgreSQL TLS。外部工作进程出现前,就绪状态始终失败。

持久化与迁移边界

身份和授权现在使用异步仓库。仓库事务回调接收绑定同一数据库连接的工作单元;在回调内使用全局仓库会被拒绝。这是 PostgreSQL 连接池使用的事务边界,同时保持现有 SQLite 行为。

SQLite 迁移协调器只有验证必需架构后才接纳现有安装。它记录带编号的迁移名称和校验和,每次启动都验证,拒绝更新、未知或不匹配的账本,迁移或架构验证失败时阻止启动。就绪性和恢复清单使用同一规范检查契约。

导入有状态应用服务前,启动过程会把现有 SQLite 数据库和活动 WAL/SHM 文件复制到私有临时目录并验证副本。PLATFORM_PREFLIGHT_TMP_DIR 必须有足够空间容纳数据库及 WAL。随附 Docker 和 Helm 部署在那里挂载专用磁盘临时存储,不依赖受限的 /tmp tmpfs。旧加密密钥缺失或存在历史嵌套数据目录时,会在创建替代密钥、数据库或插件状态前阻止启动。

架构 v4 为加密身份电子邮件添加带密钥的相等令牌。恢复要求每个令牌存在且匹配其已验证电子邮件。v4 提交后的狭窄崩溃窗口中,启动允许已验证电子邮件缺少令牌,或存在非信封旧值,以便仓库初始化完成加密/令牌回填。旧版本接受任意电子邮件字符串并以空值清除字段;接纳时保留非空值并把空白规范化为 NULL。损坏的信封形值和任何非 null 不匹配仍会让预检失败。

应用服务使用异步方言仓库。原生 SQLite 仅限 SQLite 适配器、迁移/恢复检查和显式注入的健康检查。运行时存储从所选 Persistence 初始化;激活 PostgreSQL 绝不会回退到 SQLite 单例或依赖历史 cwd 的 JSON 文件。

通用持久作业运行时也与驱动无关。参与者授权从所选身份仓库读取,原生作业仓库构造局限在一个适配器组合边界。事务域发布者在 SQLite 中接收不透明同步执行器,在 PostgreSQL 中接收事务绑定执行器;绝不会收到 better-sqlite3 句柄。持久化边界测试会拒绝通用作业、资源、身份、聊天和 Work 契约中的原生驱动句柄。

Blob 与向量存储基础

生成的图库媒体和文档源文件使用 BlobStore;文档 RAG 和角色记忆使用 VectorStore。SQLite 旧图库行会双读,并在首次访问时接纳为 blob 引用。关系元数据和持久引用具有权威性;提供商 URL 和物理 S3 键绝不会作为应用内容持久保存。聊天附件、头像及剩余内联二进制字段尚未调用 blob 存储,不得描述为已迁移。

恢复门禁会在明确总量限制下依次验证每个持久对象和嵌入式向量信封;也会用应用 ENCRYPTION_KEY 严格验证可识别旧文本信封及所有已保存声音二进制信封,绝不使用运行时“解密失败则返回原值”的兼容回退。它不会初始化、修复、改写或删除源存储;密文损坏、密钥未知或错误、blob 布局不规范及超过验证限制都会阻止快照。

默认恢复上限为 250,000 个本地对象、64 GiB 加密和明文 blob 字节、250,000 个向量行、4 GiB 序列化向量密文和 5 亿个向量分量。测试和嵌入式调用方可通过 RecoveryInventoryOptions 覆盖单次上限;CLI 绝不会静默采样或跳过超量状态。

旧密文验证默认限制为一百万个已填充候选字段,以及已存储和已验证明文各 16 GiB。旧架构的明文行仍兼容,因为旧文本信封没有持久标记;报告只统计已验证信封。已保存声音信封含义明确,始终以配置文件/所有者/字段身份作为附加数据验证。

加密本地 Blob

BlobStore 按所有者隔离,提供流式写入/读取、元数据/stat、包含端点的字节范围和幂等删除。LocalEncryptedBlobStore 在应用提供的根目录下写入以不透明 UUID 为键的对象;集成目标是 ${DATA_DIR}/blobs。它使用独占暂存文件、fsync 和同一文件系统内的原子重命名,目录权限为 0700,文件为 0600

每个对象都有随机 256 位数据密钥。AES-256-GCM 加密私有元数据,并独立验证有界正文分块。附加身份验证数据绑定 blob ID、所有者、用途、块索引和明文长度。版本化存储 keyring 包装每个数据密钥。描述符记录明文大小、SHA-256、内容类型、创建时间、格式版本和加密密钥 ID。完整读取验证 SHA-256;范围读取验证每个涉及的块。

配额契约在流式传输前预留容量、消耗实际字节,只在原子可见后提交,并释放失败预留。SQLite 使用 BEGIN IMMEDIATE;PostgreSQL 使用可串行化事务和行锁。S3 对象元数据与配额用量在同一数据库事务中提交或回滚。启动会协调过期预留及物理 blob 缺失的配额对象。BLOB_QUOTA_BYTES_PER_USER 设置每位所有者的持久限制,BLOB_QUOTA_RESERVATION_TTL_MS 限制弃置预留。

BLOB_STORE_BACKEND=s3 使用私有 S3 兼容 bucket。Libre 上传不透明对象键和应用加密分块流,在 PostgreSQL 保存加密描述符,支持包含端点的 HTTP 范围,验证明文/密文 SHA-256 摘要并幂等删除。删除行会一直持久保留,直到物理删除和原子元数据/配额移除成功;协调会重试中断删除并移除老化物理孤儿。Docker 门禁 MinIO 测试套件覆盖跨副本读取/删除、租户隔离、配额竞争、未消费流及提交和删除边界的注入数据库故障。

加密嵌入式向量

VectorStore 要求每次查询和变更都携带参与者。记录包含命名空间、不透明租户范围 ID、所有者、资源 ID、嵌入模型、维度、版本、源修订、相等属性,以及可选用户/组授权。

SQLite 在加密嵌入离开数据库前应用命名空间/模型/维度/版本、所有者或授权、资源和属性谓词。只有这个有界授权候选集会解密并进行余弦评分。相同不透明向量 ID 按所有者隔离,不会暴露其他租户是否存在。Upsert 原子替换嵌入、ACL 和属性;删除按所有者限定并级联相关行。

嵌入使用 AES-256-GCM,并将身份与模型元数据绑定为附加身份验证数据。可查询的身份、授权、模型、版本、修订和过滤元数据保持明文,因此调用方不得在过滤属性中放入机密。嵌入本身是敏感派生数据。

VECTOR_STORE_BACKEND=pgvector 在同一条含距离排序和 LIMIT 的 SQL 语句内应用命名空间、模型、维度、版本、资源、属性、所有者和授权谓词。禁止先取全局最近邻再后过滤。每次查询都从受信任当前成员解析器获取组授权;调用方提供的 groupIds 会被忽略。因此撤销立即生效,伪造组声明无法检索候选项。

文档摄取和嵌入再生成维护端点会在工作开始前捕获一份不可变执行规范:启用状态、模型、向量版本、分块器版本、块大小、重叠和相似度阈值。同一规范控制分块生成、关系发布、向量 upsert 和语义查询;运行中更改偏好不会产生混合模型块,也不会以不同阈值查询向量。已发布文档元数据记录聚合块修订和此规范,因此 SQL 仍是权威索引清单。

再生成会为每个文档持有自动续期协调器租约,并在关系发布前、向量变更前后重新检查所有者范围行及永久删除墓碑。删除可在 upsert 进行中提交;upsert 后权限检查会移除重新创建的向量。PostgreSQL/Team 语义读取绝不修改 PGVector。只有存储清单能证明确切当前模型和分块配置时,SQLite 才可惰性重新发布关系嵌入;该可选变更会在持有相同文档租约时重新加载行和块。忙碌或被取代的修订会跳过,仍可使用关键词回退或显式再生成。

文档索引以最多 1,000 个向量的补偿批次替换,精确索引检查会分页遍历完整资源清单,而不假设一个变更批次就是整个文档。单个文档最多发布 100,000 个块,因此不会超过可移植归档的总文档块上限。摄取会在嵌入或关系/向量发布前拒绝第 100,001 个块,并将该持久作业直接转入死信且不重试;请增大嵌入块大小或移除过多段落换行后再上传。

清单前的 Solo 数据库可能含已验证内联文档向量,却没有生成它们的模型或分块器记录。首次语义使用只把其存在视为升级信号:持有文档租约,按当前捕获规范重新分块权威文档文本并重新生成所有向量。绝不会复制旧载荷或标注为今日偏好。提供商失败或租约忙碌会保留旧行,并保持关键词可搜。

如果某旧文档未被已验证的当前清单元数据和精确加密平台向量索引完全覆盖,SQLite 到 Team 迁移会失败关闭。当前偏好不能证明历史向量模型。dry-run 报告此阻塞项时,请用相同 DATA_DIRENCRYPTION_KEY 以 Solo/SQLite 模式启动当前发行版,启用并选择所需嵌入模型,为每位受影响所有者使用设置 -> 文档 -> 重新生成嵌入,再重跑迁移 dry-run。此后 Team 仓库读取才能忽略保留的内联密文,同时把已证明向量移到 PGVector。

不同后端的保密性不同。嵌入式 SQLite 在应用元数据 ACL 谓词后,以应用 AES-256-GCM 加密嵌入。PGVector 必须操作数字嵌入,因而不会在应用层加密该列。请将嵌入视为敏感派生数据:要求 TLS、加密 PostgreSQL 卷和备份、最小权限应用角色、受限数据库管理,以及绝不包含向量或源内容的 SQL 日志。源文本、角色记忆内容、图库元数据和 blob 描述符仍使用信封加密。向量属性是可查询明文,绝不能含机密。

存储加密密钥

当前调用方迁移期间,启用版本化 keyring 的部署必须设置稳定的 64 字符 ENCRYPTION_KEY,在 STORAGE_ENCRYPTION_KEYS 的确切 legacy 条目下包含同一密钥,并将 STORAGE_ENCRYPTION_ACTIVE_KEY_ID 设为其中一个条目。写入使用活动密钥;读取接受所有已配置密钥 ID,以支持分阶段轮换。临时旧密钥要求防止现有加密服务独立创建不同密钥。旧密钥应保留到每个对象和向量都已重写或重新包装并验证。

若该映射不存在,适配器会接受现有 64 字符 ENCRYPTION_KEY 作为密钥 ID legacy;环境密钥缺失时,则读取现有 ${DATA_DIR}/.encryption_key。存储工厂只接受权限私有、非符号链接的普通密钥文件;绝不会创建、改写或替换它。显式环境配置与持久密钥冲突时,启动失败关闭。轮换期间,检测到的旧环境/文件密钥必须继续位于版本化映射的确切 legacy ID 下,直到旧信封已重写并验证。缺失、格式错误、不匹配和未知密钥都会失败关闭。

嵌入式向量查询在 SQLite 中应用 ACL 和元数据谓词,然后汇总候选数、加密字节和按维度计数的评分工作,再将任何密文返回 Node 解密。超过任一预算的查询会失败关闭,必须通过资源或元数据范围缩小。

协调

协调器契约提供事件、过期缓存项、带隔离令牌的租约和固定窗口速率限制消耗。本地实现只适用于单副本 Solo。Redis 实现使用独立命令/订阅客户端、有界载荷、健康检查、键命名空间、原子脚本、唯一所有者令牌、租约过期和隔离令牌。Redis 错误后绝不会回退到本地协调。

Redis 不是事实来源。授权、持久作业和可重放事件必须保留在数据库中;Redis 只是唤醒、缓存失效、在线状态、配额和协调层。关键工作提交副作用前还必须验证数据库租约或隔离令牌。

应用票据、缓存、共享失效、连接限制、Work 事件和分布式运行时锁使用此边界。仅选择 Redis 仍不会让本地持久化可共享;Team 模式要求完整共享配置。

持久作业与事件

SQLite 迁移 v3 提供持久作业、尝试、事件流头和有序事件表。服务契约支持幂等入队、有界重试、取消、进度、租约心跳/回收、死信状态和按全局游标重放。加密 JSON 载荷使用平台 keyring,并以作业/事件身份作为身份验证数据;载荷引用是不透明有界标识符。

SQLite 迁移 v13 和 PostgreSQL 迁移 v12 添加匹配的 (stream_id, subject_id, global_cursor) 索引,用于生成范围聊天重放。流和主题过滤会在追赶限制前应用,因此长会话的较早生成既不会消耗当前生成重放预算,也不会迫使扫描完整事件流。

应用和独立工作进程启动会注册经审计的文档摄取、媒体继续和可重试资源清理处理程序。管理边界公开有界检查和取消。入队幂等,关系创建/删除路径会在同一 SQLite/PostgreSQL 事务中插入持久作业。资源清理通过重试安全操作移除向量、私有 blob、持久引用、缓存项和以资源为目标的排队工作。

恢复清单统计每种作业状态和尝试结果,记录事件流及最后游标,阻止不安全的运行中工作,并在总量限制下验证加密载荷。恢复还拒绝流头不匹配和流内序列不连续。

单调租约令牌阻止过期工作进程进行后续数据库提交。隔离不能提供恰好一次执行:工作进程可能完成外部副作用,却在记录成功前失败。因此接纳处理程序需要提供商幂等键或事务 outbox/inbox 协议,并在每项副作用前立即重新验证参与者授权。

SQLite 迁移 v4 在随机化身份密文旁添加唯一带密钥的电子邮件查找令牌。该令牌是使用应用加密密钥生成的 HMAC:无需存储明文或确定性加密即可恢复原子重复电子邮件约束。启动会在接受流量前验证并回填每个旧身份电子邮件。

健康状态与恢复

部署探针现会区分进程存活与依赖就绪:

  • /health/health/live 只检查进程;
  • /health/ready 检查数据库、规范架构账本、可写数据存储和已注册必需依赖,同时隐去细节;不会等待可选提供商;以及
  • /health/deep 要求当前管理员,并在 HTTP 事件循环外的有界工作进程中运行 SQLite 完整性和外键检查。它还把 Ollama 等可选服务器级提供商探针汇总为警告,不改变核心就绪状态。

运行 libre-webui recovery-check --json;从源代码检出时先构建后端,再使用 npm run recovery:check -- --json。该只读清单报告架构/密钥身份、本地 blob 根、旧版和平台向量数量;验证本地平台 blob/向量密文、旧应用与已保存声音密文、加密持久作业/事件载荷;还报告数据大小、插件定义及其是否在备份根内、嵌入媒体、Work 资源和确切所有权标签、作业/尝试/事件检查点、活动 Work 运行/预览和作业、阻塞项及已知排除项。它是备份前门禁,不是完整备份。请参阅恢复就绪性

经认证的多副本运行

Team 配置已认证可运行三个或更多应用副本及至少一个外部持久工作进程,前提是 PostgreSQL、PGVector、Redis、S3 兼容 blob、稳定共享机密和 JOB_WORKER_MODE=external 全部一起配置。Helm chart 在渲染时强制这些先决条件——副本数超过一但 Team 配置不完整会渲染失败,而不会部署不安全拓扑——架构迁移则通过 PostgreSQL advisory lock 选出唯一领导者,防止混合版本副本争用账本。

认证是可执行的,不是愿景:发行流水线运行三副本演练(npm run test:team-platform),构建真实镜像并测试跨副本流恢复、工作进程写入中途死亡后的确定性重放、Redis 中断时回退权威 SQL、协调器丢失期间的撤销执行、共享速率限制一致性、S3 删除重试和负载下租户隔离。操作员可用 secrets.existingSecret(引用操作员管理的 Secret,而不是把 chart 值渲染进去)和 networkPolicy.enabled(默认拒绝应用端口外的入站;持久工作进程不接受入站)进一步加固 Pod。无论如何,Pod 安全默认值都保持严格:非 root、只读根文件系统、丢弃 capabilities、seccomp RuntimeDefault、禁止权限提升。

已知剩余切换

此基础并不意味着每个二进制字段都已成为 blob。已保存声音音频、聊天附件、头像和未来插件定义二进制资源需要显式引用元数据、双读/回填、保留和删除测试后才能迁移。同样,每个未来嵌入调用方都必须通过 VectorStore 携带模型、维度、版本、源修订、所有者、资源范围和可信授权;不允许直接访问向量表作为捷径。

新的长时间运行或外部可见副作用必须注册持久资源目标,支持取消和重试,并与所属关系变更使用事务入队/outbox 边界。在 Team 部署中启用每种新资源前,请将其加入跨副本上传/读取/搜索/删除及备份/恢复验收门禁。