---
title: "Agent 獨立更新 — PM 問答 (FR-172)"
brand: "Guidant AI · **FR-172** PM 問答"
eyebrow: "FR-172 · 機制問答"
h1: "Agent 獨立更新問答"
subtitle: "每題先給結論，再給事實與程式位置"
lede: "整理 PM 與業務最常問的 16 題。版號、流程、程式路徑以主系統 1.28.3、Agent 1.5.5 為準；完整交付內容看 [FINAL-SPEC.md](FINAL-SPEC.md)。"
chips: [
  {text: "16 題", kind: accent},
  {text: "主系統 1.28.3／Agent 1.5.5", kind: plain},
]
footer: "FR-172 PM 問答 · 現況見 FINAL-SPEC.md · 設計見 design.md、design-v1.1.md"
---

## 更新方式 {#group-how nav="更新方式"}

### Q1　主系統和 Agent 現在是分開更新嗎？ {#q1}

**結論**：是。兩個安裝包、兩條版本線、各自升級，互不需要對方先升。

| | 主系統 | Agent |
|---|---|---|
| 安裝包 | `guidant-ai-<版>.tar.gz`（約 3.5 GB） | `guidant-agent-compose-<版>.tar.gz`（約 1.7 GB） |
| 更新站版本線 | 主系統 | Agent |
| 目前版號 | 1.28.3 | 1.5.5 |

主系統包裡已經不帶 Agent。修 Agent 不必再出一包主系統、也不必停主系統。

### Q2　有哪幾種方式可以更新 Agent？ {#q2}

**結論**：三種，最後都走同一條升級流程。

| 方式 | 在哪按 | 適合 |
|---|---|---|
| 主系統更新中心 Agent 區 | 勾選要更新的台，按「更新選取的 N 台到 X」 | 管理員一次更新多台 |
| Agent 主控台「更新到 X」 | 每台 Agent 自己的主控台（8444） | 在現場、只更新這一台 |
| Agent 主控台「離線上傳更新包」 | 同上 | Agent 連不到主系統時 |

前兩種實際上都是主系統去下載、驗證、推送；主控台那顆只是「請主系統替這一台做」。

### Q3　一定要先按「預先下載」嗎？ {#q3}

**結論**：不用。直接勾選按更新即可，主系統會自己判斷要不要先下載。

- 主系統手上**沒有包**、或手上的包**比更新站查到的新版舊**，就先下載（畫面有進度、可取消），下載完自動推。
- 手上已經是最新就直接推。
- 「預先下載」保留為選用：想先把包抓下來、晚點再推時才用。

下載途中又有人按更新（例如另一台的主控台），會併進同一份待推清單，不會把先按的人選的台蓋掉。

程式：`app/product_update/service/agent_release_service.py`（`bundle_is_latest`、`newer_on_site`）、`product_update_app_service.py`（`agent_push`）。

### Q4　按下更新後，從頭到尾發生什麼事？ {#q4}

**結論**：主系統下載並驗證包 → 直接推指令給 Agent → Agent 跟主系統拿包、寫升級單 → Agent 所在主機跑升級步驟 → 每一步即時回報主系統。

```{.mermaid cap="圖 1 — 從按下更新到 Agent 換好版本。"}
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
sequenceDiagram
  autonumber
  participant P as 管理員
  participant M as 主系統
  participant U as 更新站
  participant A as Agent
  participant H as Agent 主機
  P->>M: 更新選取的台到 X
  opt 手上不是最新
    M->>U: 下載 Agent X 並驗章
  end
  M->>A: 推送更新指令（版號、雜湊、大小）
  Note over A: 進入維護模式，停收新工作
  A->>M: 下載包、核對雜湊
  A->>H: 寫升級單
  H->>H: 驗新版簽章 → 換版 → 健康檢查
  A-->>M: 每一步、結果、升級紀錄
  M-->>P: 畫面顯示每台進度
```

完整版時序圖（含端點名稱）看 [FINAL-SPEC §2](FINAL-SPEC.md#flows)；每一步跑哪支程式看 [upgrade-flow-guide.md](upgrade-flow-guide.md)。

### Q5　Agent 怎麼收到更新指令？還有用心跳嗎？ {#q5}

**結論**：主系統直接連到 Agent 推指令，不靠心跳。心跳只代表「Agent 活著」，不帶任何指令或資料。

- 主系統連 Agent 的 8443 埠，雙向憑證加上 60 秒有效、綁定這個動作的 JWT，呼叫 `POST /update`。
- Agent 那時剛好離線，等它下次心跳回來，主系統會補推一次。
- 進度與結果是 Agent 主動送事件給主系統（`/agents/events`），不是主系統去問。

程式：主系統 `core/plugins/_agent_commands.py`（`push_update_soon`）；Agent `guidant_agent/sync/api/cmd_update.py`、`sync/app/update_sync.py`。通道設計見 FR-171。

---

## 升級期間 {#group-during nav="升級期間"}

### Q6　Agent 升級時還能用嗎？ {#q6}

**結論**：不能，會進入維護模式。從收到更新指令那一刻起就停收新的掃描工作，進行中的工作先做完再換版，完成後自動恢復。

| 階段 | 算升級中 |
|---|---|
| 下載主系統推來的包 | 是 |
| 等進行中的工作做完 | 是 |
| 升級單已寫好、主機在換版 | 是 |

換版完成後主控台不必重新登入（登入狀態存在磁碟上，換容器不會掉）。

### Q7　Agent 主控台什麼時候會鎖畫面？ {#q7}

**結論**：Agent 回報「升級中」時就整頁鎖住，只顯示進度。不管是誰發動的都一樣。

- **在主控台自己按更新**：按下的當下就鎖。
- **由主系統發動**：開著的主控台最慢 30 秒內鎖住（主控台平常每 30 秒問一次狀態）；鎖住後每 3 秒更新一次進度。
- **主控台沒開著**：之後打開或重新整理，第一次問就會鎖。
- 結束後：版本換了就整頁重新載入、回到按更新前所在的那一頁；失敗退回舊版就解鎖顯示結果。

這 30 秒內 Agent 已經停收新工作，使用者頂多看到畫面還能點，但送出的掃描會被拒絕。要做到「一收到就鎖」得讓 Agent 主動推給瀏覽器，目前裁示先不做。

程式：FE `console/useUpdateStatus.js`（輪詢與鎖定）、`console/update.js`（`lockState`）、`console/components/UpdateLockMask.vue`。

### Q8　主系統自己升級時，使用者會看到什麼？ {#q8}

**結論**：按「更新到 X」的人看到全頁遮罩加進度；其他人在停機那幾步看到維護頁。

- 下載與驗證期間系統照常可用。
- 主機開始跑升級後，「等工作做完」到「換成新版」這幾步前門顯示維護頁。190 實測整次 6 分 42 秒，維護頁約 4.5 分鐘（資料量不同時間會不同，所以畫面不寫分鐘數）。
- 任一步失敗會自動退回原版。

### Q9　升級失敗會怎樣？看得到原因嗎？ {#q9}

**結論**：會自動退回原版；失敗原因分兩層，畫面看得到摘要，也能下載完整紀錄。

- 畫面：失敗那一步標紅，「看原因」顯示該步錯誤輸出的最後 20 行。
- 完整紀錄：Agent 會把整次升級的主機紀錄上傳主系統，更新紀錄頁按「下載升級紀錄」取得；主系統自己的升級成功或失敗也都能下載。
- 每一步的結果與耗時寫進系統日誌。

---

## Agent 不連外網 {#group-offline nav="不連外網"}

### Q10　Agent 不能連外網，包從哪裡來？ {#q10}

**結論**：一律經過主系統。主系統向更新站下載、驗證，再交給 Agent；Agent 從不直接連更新站。

主控台的「立即檢查」也是請主系統當下去更新站查，主系統再告訴 Agent 有沒有新版（全機 5 分鐘內只查一次）。主系統斷線時，主控台只提供離線上傳。

### Q11　怎麼確定包沒有被改過？ {#q11}

**結論**：每一手都驗。驗章只認**本機已經裝好的公鑰**，不拿包裡附的公鑰驗自己。

| 誰驗 | 驗什麼 |
|---|---|
| 主系統下載後 | 發布清單的章（Agent 專用章型別）、整包雜湊 |
| Agent 從主系統拿包 | 大小與雜湊（數字來自主系統驗過的清單） |
| Agent 主機升級前 | 用**舊版** Agent 驗新版程式樹的完整性章 |
| 離線上傳 | 用現行版的公鑰驗章、雜湊、版本、磁碟 |

---

## 維運與成本 {#group-ops nav="維運"}

### Q12　更新包會一直佔空間嗎？ {#q12}

**結論**：不會，用完就清。

- 主系統的 Agent 包：整批推送全部成功後，清掉用不到的舊包。
- 主系統自己的升級包：升級成功後 `incoming/` 只留清單（之後要重試會重新下載）。
- 升級過程的暫存（解開的包、舊映像、舊資料庫快照）在最後一步「清理」處理。

### Q13　主系統和 Agent 版本不相容怎麼辦？ {#q13}

**結論**：只擋一種情況——Agent 新版要求的主系統版本比現在的主系統新，按鈕會反灰並說明要先升主系統。

- Agent 比主系統新是允許的。
- 主系統新版要求 Agent 至少某版時，畫面標「建議更新」，不擋主系統升級。

### Q14　同版重套是什麼？正式環境會出現嗎？ {#q14}

**結論**：測試機專用，把目前這一版照正式升級流程重跑一次。正式環境不會出現，因為按鈕要靠兩個環境變數才會打開，任何出貨範本都不帶這兩個鍵。

- 主系統：`PRODUCT_UPDATE_ALLOW_SAME_VERSION=1`；Agent：`AGENT_UPDATE_ALLOW_SAME_VERSION=1`。
- 降版、跨主版號不論開關一律擋。
- 用途：測試機升到最新版之後，要再看一次升級畫面，不必為此再出一版。
- 目前只開在 190。

### Q15　出一版要多久？做了哪些加速？ {#q15}

**結論**：主系統完整出包約 51 分鐘、Agent 約 16 分鐘（測試包）。編譯只佔不到四成，大部分時間在打包壓縮與安全掃描。

| 段落 | 時間（主系統＋Agent） |
|---|---|
| Nuitka 編譯 | 約 19.5 分 |
| 打包壓縮 | 約 13 分 |
| SBOM＋弱點掃描 | 約 9 分 |
| 建映像、smoke、其他 | 約 10 分 |

已做的加速：

- 測試包略過 SBOM 與弱點掃描（正式包照掃）：Agent 19 分 30 秒 → 15 分 52 秒，主系統約省 5 分。
- 主系統封包改多核心壓縮：預估省約 4 分。
- 版本固定的第三方映像（postgres、redis、seaweedfs、bugsink、證據分類）匯出一次就快取：每版不再重匯約 3 GB。
- 只改一邊時只出那一邊。

Nuitka 在 build 機本來就沒開 LTO，`--lto=no` 不會更快。出版自動化（CI、Vault 簽章）在 FR-173。

---

## 交付狀態 {#group-ship nav="交付狀態"}

### Q16　現在可以給客戶了嗎？ {#q16}

**結論**：功能已在 190 實測通過，但還沒出正式版。目前更新站上的都是測試章簽的內部測試包；第一個正式版是 1.29，用 FR-173 的自架 Vault 簽章。

| 機器 | 主系統 | Agent |
|---|---|---|
| 190 測試機 | 1.28.3 | 1.5.5 |
| 189 POC | 1.27.x | 1.4.x |

189 升到 1.28.x 時，Agent 要手動升一次：1.4.x 的 Agent 沒有新的推送端點，主系統推不動它。之後就都能從主系統更新。
