跳至主要内容

備份與遷移

「系統 > 備份與遷移」頁(/admin/backup)承擔四類工作:完整備份的匯出與下載、整庫匯入還原、輕量的站點配置匯出 / 匯入,以及 Qdrant 向量庫的檢查與重建。完整備份是引擎中立的邏輯歸檔,同一個 zip 可以在 SQLite 與 PostgreSQL 部署之間互相匯入,跨機遷移、跨引擎遷移、災備恢復全部走這一條路徑,不需要碰 pg_dump 或資料庫檔案。

完整備份匯出

歸檔裡有什麼

匯出產物是單個 zip,內部結構:

aivory-docker-backup-20260711-153000-xxxxxxxxxx.zip
├── manifest.json # 格式版本、源引擎方言、各錶行數、是否含檔案
├── db/
│ ├── users.jsonl # 每表一個 JSONL,每行一個 JSON 物件
│ ├── conversations.jsonl # 按外部索引鍵安全順序排列,引擎中立
│ ├── messages.jsonl
│ └── ... # 全部資料表
├── files/ # 可選:勾選「包含上傳檔案與生成產物」時才有
│ ├── uploads/... # 使用者上傳的檔案
│ └── artifacts/... # 模型生成的產物(圖片、文件等)
└── qdrant/ # 可選:部署配置了 QDRANT_URL 時自動包含
└── collections/
└── aivory_c1536.jsonl # 逐 collection 的向量點位匯出

資料行是邏輯 JSONL 而非資料庫轉儲:二進位制列 Base64 編碼,大整數保精度,這正是它能跨 SQLite / PostgreSQL 的原因。向量 collection 按 aivory_c<維度> 命名(如 1536 維模型對應 aivory_c1536)。

匯出選項

選項預設說明
包含上傳檔案與生成產物一併打包 uploads 與 artifacts 目錄,歸檔明顯更大;不勾則只有資料庫行
Qdrant 向量自動部署配置了 QDRANT_URL 即包含,無需勾選;未配置 Qdrant 的部署自然沒有這一段

非同步任務與歸檔列表

頁面上的「匯出備份」走非同步任務:點選後任務在後臺生成,頁面顯示進度(準備中、讀取資料庫、寫入歸檔),期間可以離開頁面。要點:

  • 同一時間只能有一個匯出任務在跑;匯出與下文的向量維護任務互斥,一方執行時另一方拒絕啟動。
  • 匯出基於只讀事務,是一致的時間點快照,期間使用者的正常使用不受影響。
  • 完成後歸檔出現在「已生成的歸檔」列表,點「下載」儲存到本地。歸檔檔案本身存放在伺服器的 BACKUP_DIR 目錄(預設 ./data/backups,compose 部署對映在資料卷裡),列表按生成時間倒序。

另有一個同步流式端點適合指令碼化定期備份:GET /api/admin/backup/export(查詢引數 files=1 含檔案,qdrant=0 可排除向量),響應直接是 zip 流。小庫用它一步到位,大庫建議走頁面上的非同步任務,避免下載連線長時間掛著。

歸檔不會自動清理

非同步匯出生成的歸檔會一直留在伺服器的 BACKUP_DIR 裡,系統不做自動輪換。每個全量歸檔可能相當大(含檔案與向量時尤甚),下載離機儲存後,記得定期到該目錄刪除陳舊歸檔,避免資料卷被備份佔滿。

順帶區分:普通使用者在「設定 > 隱私」裡也有一個"匯出全部資料",那是單個使用者自己的 GDPR 式 JSON 匯出,與這裡的全站管理員備份是兩回事,見分享與資料管理

匯入(整庫替換)

操作步驟

  1. 在「匯入與還原」區選擇一個上面匯出的 zip 歸檔。
  2. 在確認彈窗中輸入確認詞 REPLACE(必須完全一致)。
  3. 點選「匯入並替換資料」,等待完成。
  4. 匯入成功後當前會話立即失效並自動登出,用備份裡的賬號密碼重新登入。

替換語義

匯入是整庫替換,不是合併:

  • 在一個數據庫事務裡清空所有表,再按外部索引鍵安全順序從 JSONL 逐表過載;歸檔裡存在而當前版本沒有的列會被跳過(前向相容)。中途任何一步失敗都不會提交,資料庫保持匯入前的狀態
  • 檔案恢復:歸檔中記錄的儲存路徑字首會被重寫為本機的上傳 / 產物目錄,換機器換路徑不需要手工處理。
  • 向量恢復:歸檔含 Qdrant 段時逐 collection 重建點位;向量恢復的告警不會中斷匯入,可事後用向量維護補齊。
  • PostgreSQL 目標庫會自動重置自增序列;SQLite 目標庫在恢復期間臨時關閉外部索引鍵檢查。因此跨引擎匯入開箱即用:SQLite 的備份可以匯入 Postgres 部署,反之亦然。
  • 匯入完成後設定快取即刻失效,備份裡的站點配置立即生效。
管理員降級規則(務必讀完再遷移)

匯入完成後,除了"執行本次匯入的管理員郵箱"之外,備份帶來的所有 admin 賬號一律被自動降級為普通使用者。這是防提權設計:否則任何人拿到一份構造過的備份,就能給自己塞進一個管理員賬號。

實際影響:新例項首啟時建立的管理員郵箱,應與舊例項的管理員郵箱一致。如果不一致,匯入後舊例項的管理員會全部變成普通使用者,而執行匯入的賬號(其郵箱在備份裡可能只是普通使用者甚至不存在)也未必還能登入管理後臺,需要進資料庫手工修復。按下文遷移清單操作即可避開這個坑。

大小上限與 Cloudflare

匯入上傳的硬上限由環境變數 MAX_BACKUP_BYTES 控制,預設 20 GiB(見核心環境變數)。如果站點掛在 Cloudflare 後面,注意 Cloudflare 對請求體另有 100 MB 級別的套餐上限,大歸檔必須繞開代理直連源站匯入,做法見 Cloudflare 代理配置。反向代理層(如 Nginx 的 client_max_body_size)同樣要為備份匯入放寬,見反向代理

匯入常見報錯

現象原因與處理
400,提示確認詞不符REPLACE 必須逐字元一致(全大寫、無空格)
413 / 請求體過大歸檔超過 MAX_BACKUP_BYTES,或被 Cloudflare / 反代的請求體上限攔截;調大上限或走直連通道
manifest 校驗失敗上傳的不是本系統匯出的備份 zip,或下載 / 傳輸中被截斷;重新匯出並核對檔案大小
restore failed (no changes committed)恢復中途出錯,事務已整體回滾,資料庫仍是匯入前的狀態;看服務端日誌定位具體的表與行後重試
匯入成功但知識庫檢索不到內容備份未含向量段(舊例項沒配 Qdrant)或向量恢復有警告;到「向量檢查」跑一次重建即可

配置匯出 / 匯入(輕量路徑)

完整備份之下還有一條更輕的路徑:只搬站點配置,不搬使用者資料。適合把開發機的一套配置複製到生產、跨部署統一配置、或災備前留檔。

方向行為
匯出配置 ZIP打包站點設定、渠道、模型、技能、OAuth 提供商、圖片風格、使用者組、模型額度,以及圖示與技能資產檔案
匯入配置歸檔按 ID UPSERT 合併:同 ID 的配置行被覆蓋,本地多出的配置保留;絕不觸碰使用者、對話、訊息、上傳檔案、會話與日誌。也相容舊版純 JSON 配置檔案

配置匯入是非破壞性的、會話安全的:不需要輸 REPLACE,匯入後不用重新登入,單個確認框即可執行。

配置包含明文金鑰

配置 ZIP 裡帶著明文的渠道 API Key、OAuth Client Secret、SMTP 密碼、物件儲存與搜尋金鑰(否則匯入後無法直接工作)。請像對待金鑰本身一樣保管這個檔案,不要提交進倉庫或散發。

跨引擎遷移:SQLite 到 PostgreSQL 實操

以最常見的"單機 SQLite 起步,長大後遷到 Postgres"為例:

  1. 舊例項:進入「備份與遷移」,勾選「包含上傳檔案與生成產物」匯出完整備份並下載(配置了 Qdrant 的話向量自動在包裡)。
  2. 新例項:按 Docker Compose 部署拉起 Postgres 模式的全套服務,訪問站點完成 /setup 首啟設定。首啟管理員的郵箱必須與舊例項管理員一致(密碼可以隨意設,匯入後以備份裡的密碼為準)。
  3. 用這個管理員登入,進入「系統 > 備份與遷移」,選擇歸檔、輸入 REPLACE、匯入。序列、外部索引鍵、路徑重寫全部自動處理。
  4. 匯入完成自動登出,用舊例項的賬號密碼重新登入。
  5. 驗證:使用者列表數量、抽查幾個對話與上傳檔案、知識庫檢索是否命中。若備份未含向量(舊例項沒配 Qdrant)或檢索異常,用下文「向量維護」重建。

反方向(Postgres 遷回 SQLite)步驟完全相同,見 SQLite 模式

跨機遷移清單

換伺服器(引擎不變)時,按順序核對:

  1. 舊機匯出完整備份(含檔案、含向量)並下載到本地。
  2. 新機部署同版本或更新版本的映象(舊版本匯入新備份沒有保證)。
  3. 新機首啟 /setup 用舊例項管理員的郵箱建號(降級規則,見上文紅色警告)。
  4. 歸檔大於 100 MB 且新機掛了 Cloudflare:準備好直連通道(本機 127.0.0.1:8787 或灰雲子域),見 Cloudflare 代理配置
  5. 匯入、重新登入、驗證(使用者 / 對話 / 檔案 / 知識庫檢索 / 渠道金鑰是否工作)。
  6. DNS 切到新機;舊機資料保留到驗證徹底完成之後再下線。

向量維護

「向量檢查」區管理 Qdrant 向量庫與資料庫的一致性,常見使用場景:匯入了一份不含向量的備份、從舊品牌歸檔遷移、Qdrant 資料卷丟失或更換了 Qdrant 例項。

操作行為費用
檢查向量逐一核對資料庫中的文件切塊在 Qdrant 裡是否有非空向量,產出審計報告:應有 / 正常 / 缺失 / 空向量 / 跳過,並列出問題樣例免費,只讀比對,不呼叫嵌入介面
重建缺失向量對缺失與空向量的切塊,用資料庫裡已儲存的切塊文本重新呼叫嵌入模型,把向量寫回對應的 aivory_c<維度> collection;按嵌入模型分組分批執行,完成後報告重建 / 失敗數量消耗嵌入 API 呼叫,大知識庫一次重建會產生真實的嵌入費用,執行前留意嵌入渠道的計費

要點:

  • 重建不需要原始檔案,切塊文本本來就在資料庫裡,所以"備份未含向量"並不損失任何資料,只是需要花一次嵌入費用恢復檢索。
  • 兩種任務都是非同步後臺任務,頁面輪詢進度;同一時間只能跑一個,且與備份匯出互斥。
  • 前提是部署配置了 Qdrant 向量後端;未配置時按鈕直接報"向量後端未配置"。

升級與日常備份習慣

版本升級走滾動更新:

cd /opt/aivory # 你的 compose 目錄
docker compose pull
docker compose up -d

資料庫結構在新版本首次啟動時自動遷移(增量加列、建表),無需手工執行 SQL。即便如此,請養成兩個習慣:

  • 升級前先匯出一份完整備份。自動遷移是前向的,回滾到舊版本不受保證;有歸檔在手,任何升級事故都能用一次匯入回到升級前。
  • 定期匯出並離機儲存BACKUP_DIR 裡的歸檔和資料庫在同一臺機器上,磁碟故障會一起丟;把下載的歸檔放到物件儲存或另一臺機器上才算真正的災備。配置 ZIP 也建議在每次大改配置後留一份。
備份頻率參考

小團隊自部署,每週一次全量(含檔案)+ 每次升級前一次,已經足以把最壞情況的損失控制在幾天之內。歸檔是普通 zip,可直接用任何物件儲存的生命週期策略做保留輪換。