教學

產生架構圖

使用 IBM Bob 分析 Galaxium Travels 程式碼庫,並產生 Mermaid UML 類別圖、時序圖及使用案例圖。學習如何在 Ask mode 中使用 context mentions 探索程式碼,以及如何使用 Agent mode 將結果儲存至存放庫。

架構圖為你提供了在修改程式碼庫之前共用的視覺化語言。在本教學中,你將使用 Bob 讀取 Galaxium Travels 原始檔案,並產生三種 UML 圖:UML 類別圖、時序圖和使用案例圖。你使用 Ask mode 安全地探索程式碼並產生圖表標記,標記使用 Mermaid。然後切換至 Agent mode 將圖表儲存至專案。

GitHub 原生支援 Markdown 檔案中的 Mermaid 圖表,因此你可以將產生的圖表儲存為 .md 檔案,並在 GitHub 上查看渲染後的圖表。

在本教學中,Bob 的輸出結果可能因程式碼庫的現況而與範例有所不同。請將產生的標記作為起點,並依需求加以調整。

你將學到的主要功能

  • Context mentions:使用 @ 符號在提示中參照特定檔案和資料夾。Context mentions 讓 Bob 確切知道要分析哪些檔案,以產生精確的圖表。
  • Ask mode:讀取和分析程式碼,而不讓 Bob 對你的檔案進行任何變更。
  • Agent mode:讓 Bob 自主寫入檔案,將產生的成果持久化儲存至你的專案。

先決條件

完成本教學,你需要以下項目:

  • 已安裝 Bob IDE
  • 已在本地安裝 Git,以便複製 Galaxium Travels 範例存放庫。
  • 熟悉使用 Bob 的基本操作。如果你是 Bob 的新使用者,請先從快速入門教學開始。

設定工作區

複製 Galaxium Travels 存放庫

在終端機中,執行以下命令以複製 Galaxium Travels 範例存放庫:

git clone https://github.com/ibm/galaxium-travels.git

啟動 IBM Bob

在電腦上啟動 IBM Bob IDE。

開啟範例專案

在 Bob IDE 中,開啟你複製的 galaxium-travels 資料夾。如果 Bob 詢問「Do you trust the authors of the files in this folder?」,請按一下 Yes, I trust the authors

查看根目錄中的 README.md 檔案,以了解應用程式及其架構的概覽。Galaxium Travels 應用程式模擬一個航班預訂系統,包含 React 前端、Python FastAPI 後端,以及 Java 庫存保留服務。這個程式碼庫具有刻意設計的複雜性,貼近真實世界的應用程式,非常適合用來產生架構圖。

開啟 Bob 聊天介面

如果聊天介面尚未開啟,請按一下導覽列中的 Bob 圖示,或使用快捷鍵 Option + Command + B(Mac)或 Ctrl + Alt + B(Windows)。

初始化專案 context

Bob 啟動時預設為 Agent mode。如果你已切換模式,請確保在執行初始化命令前切換回 Agent mode。Bob 需要寫入檔案以設定專案 context。

在聊天介面的輸入欄位中輸入 /init 命令。如果你已停用自動核准,Bob 會請求你的許可以讀取檔案並寫入 AGENTS.md 檔案。

 /init

Bob 會讀取專案中的相關檔案,然後在根目錄中產生主要的 AGENTS.md 檔案。Bob 也會建立一個 .bob 資料夾,其中包含各模式的 AGENTS.md

查看產生的 AGENTS.md 檔案,了解 Bob 如何設定專案 context,以及 Bob 在每種模式下具備哪些功能。

切換至 Ask mode

在聊天輸入欄位下方的模式選擇器中選取 Ask。你也可以在聊天輸入欄位中輸入 /ask 來切換模式。

與 Agent mode 不同,Ask mode 為唯讀模式。Bob 可以讀取和分析檔案,但無法建立或修改任何內容,使其非常適合用於安全的程式碼探索。

產生 UML 類別圖

UML 類別圖用於對應應用程式的資料模型:實體(類別)、其屬性,以及它們之間的關係。對於 Galaxium Travels,這涵蓋後端的 Python SQLAlchemy 模型和庫存保留服務中的 Java 領域類別。

建立一個提示,以分析兩個服務的資料模型,並產生 Mermaid classDiagram。使用 context mentions 指定要讓 Bob 分析的相關檔案。Bob 預設會將 Mermaid 圖表輸出為渲染圖片。若要查看原始 Mermaid 標記,請在提示中加入「Output only the Mermaid code block. Do not render the Mermaid diagram.」的指示。

在 Ask mode 中,於聊天輸入欄位輸入以下提示:

Analyze the data models in @booking_system_backend/models.py and the 
Java domain classes in @booking_system_inventory_hold_service/src/main/java/com/galaxium/holdservice/domain.

Generate a Mermaid classDiagram that shows all classes, their attributes,
their methods (if any), and the relationships between them. 
Include the BookingStatus enum.

Output the Mermaid markup. Do not render the Mermaid diagram.

Bob 讀取兩個檔案後,會產生與以下內容相似的圖表標記:

classDiagram
    direction LR

    %% ── Python / SQLAlchemy (booking_system_backend/models.py) ──────────

    class User {
        +int user_id PK
        +str name
        +str email
    }

    class Flight {
        +int flight_id PK
        +str origin
        +str destination
        +str departure_time
        +str arrival_time
        +int base_price
        +int economy_seats_available
        +int business_seats_available
        +int galaxium_seats_available
    }

    class Booking {
        +int booking_id PK
        +int user_id FK
        +int flight_id FK
        +str status
        +str booking_time
        +str seat_class
        +int price_paid
    }

    class BookingStatus {
        <<enumeration>>
        BOOKED = "booked"
        CANCELLED = "cancelled"
        CANCELED = "cancelled"
        COMPLETED = "completed"
    }

    %% ── Java / JPA (holdservice/domain) ────────────────────────────────

    class Quote {
        +String quoteId PK
        +Integer flightId
        +String seatClass
        +Integer quantity
        +Integer travelerId
        +String travelerName
        +Long pricePerSeat
        +Long totalPrice
        +Instant expiresAt
        +QuoteStatus status
        +Instant createdAt
        #onCreate() void
    }

    class QuoteStatus {
        <<enumeration>>
        CREATED
    }

    class Hold {
        +String holdId PK
        +String quoteId FK
        +HoldStatus status
        +Instant reservedUntil
        +String externalBookingReference
        +String errorMessage
        +Instant createdAt
        +Instant updatedAt
        #onCreate() void
        #onUpdate() void
    }

    class HoldStatus {
        <<enumeration>>
        HELD
        EXPIRED
        CONFIRMED
        RELEASED
        CONFIRMATION_FAILED
    }

    class AuditEvent {
        +String eventId PK
        +String entityType
        +String entityId
        +String eventType
        +String details
        +Instant createdAt
        #onCreate() void
    }

    %% ── Relationships ───────────────────────────────────────────────────

    User        "1" --> "0..*" Booking      : places
    Flight      "1" --> "0..*" Booking      : booked on
    Booking          ..>        BookingStatus : status

    Quote       "1" --> "0..*" Hold         : generates
    Quote            ..>        QuoteStatus  : status
    Hold             ..>        HoldStatus   : status

    AuditEvent       ..>        Quote        : references entityId
    AuditEvent       ..>        Hold         : references entityId

產生時序圖

時序圖顯示元件在特定流程中如何依時間順序互動。Galaxium Travels 的預訂流程橫跨 React 前端、Python FastAPI 後端,以及 Java 庫存保留服務。

建立一個提示,以追蹤完整的預訂流程並產生 Mermaid sequenceDiagram。使用 context mentions 指定要讓 Bob 分析的相關檔案。你在提示中對分析檔案和要繪製的流程描述得越具體,輸出結果就越精確。

在 Ask mode 中,於聊天輸入欄位輸入以下提示:

Analyze the booking flow across @booking_system_frontend/src/services,
@booking_system_backend/server.py, @booking_system_backend/services/booking.py,
and @booking_system_inventory_hold_service/src/main/java/com/galaxium/holdservice/api.

Generate a Mermaid sequenceDiagram showing the complete flow for a
user booking a flight, including the quote and hold steps with the Java service.

Output the Mermaid markup. Do not render the Mermaid diagram.

Bob 追蹤互動鏈後,會產生與以下內容相似的圖表標記:

sequenceDiagram
    autonumber
    participant U  as User (Browser)
    participant FE as Frontend<br/>(api.ts)
    participant PY as Python Backend<br/>(server.py)
    participant BS as BookingService<br/>(booking.py)
    participant QC as QuoteController<br/>(Java)
    participant QS as QuoteService<br/>(Java)
    participant HC as HoldController<br/>(Java)
    participant HS as HoldService<br/>(Java)
    participant DB as Python SQLite
    participant JDB as Java SQLite

    Note over U,JDB: ── Phase 1: Create Quote ──────────────────────────────────

    U->>FE: createQuote({ flightId, seatClass,<br/>quantity, travelerId, travelerName })
    FE->>PY: POST /quotes
    PY->>QC: POST /api/v1/quotes
    QC->>QS: createQuote(request)
    QS->>QS: generateQuoteId() → "Q-2025-000001"
    QS->>QS: pricingService.calculatePrice(flightId, seatClass)
    QS->>JDB: save Quote (status=CREATED, expiresAt=+24h)
    QS->>JDB: save AuditEvent (QUOTE / CREATED)
    QC-->>PY: 201 Quote
    Note right of PY: Returns {"error":"..."} HTTP 200<br/>if Java service unreachable
    PY-->>FE: Quote JSON
    FE->>FE: assertNotProxyError(response.data)
    FE-->>U: quoteId

    Note over U,JDB: ── Phase 2: Create Hold ───────────────────────────────────

    U->>FE: createHold(quoteId)
    FE->>PY: POST /quotes/{quoteId}/holds
    PY->>HC: POST /api/v1/quotes/{quoteId}/holds
    HC->>HS: createHold(quoteId)
    HS->>JDB: findById(quoteId)
    JDB-->>HS: Quote
    HS->>HS: check quote not expired
    HS->>HS: generateHoldId() → "H-2025-000001"
    HS->>JDB: save Hold (status=HELD,<br/>reservedUntil=+15min)
    HS->>JDB: save AuditEvent (HOLD / CREATED)
    HC-->>PY: 201 Hold
    PY-->>FE: Hold JSON
    FE->>FE: assertNotProxyError(response.data)
    FE-->>U: holdId

    Note over U,JDB: ── Phase 3: Confirm Hold → Create Booking ─────────────────

    U->>FE: confirmHold(holdId)
    FE->>PY: POST /holds/{holdId}/confirm
    PY->>HC: POST /api/v1/holds/{holdId}/confirm
    HC->>HS: confirmHold(holdId)
    HS->>JDB: findById(holdId)
    JDB-->>HS: Hold
    HS->>HS: check status == HELD
    HS->>HS: check reservedUntil not passed
    HS->>JDB: findById(hold.quoteId)
    JDB-->>HS: Quote

    HS->>PY: POST /internal/bookings/from-hold<br/>{ travelerId, travelerName, flightId, seatClass }
    PY->>BS: book_flight(db, user_id, name,<br/>flight_id, seat_class)
    BS->>DB: query Flight (check seats available)
    BS->>DB: query User (validate user_id + name match)
    BS->>DB: decrement {seat_class}_seats_available
    BS->>DB: insert Booking (status="booked")
    DB-->>BS: Booking row
    BS-->>PY: BookingOut

    alt booking succeeded
        PY-->>HS: 200 { booking_id, ... }
        HS->>JDB: update Hold (status=CONFIRMED,<br/>externalBookingReference=booking_id)
        HS->>JDB: save AuditEvent (HOLD / CONFIRMED)
        HC-->>PY: 200 Hold (CONFIRMED)
        PY-->>FE: Hold JSON
        FE->>FE: assertNotProxyError(response.data)
        FE-->>U: Booking confirmed ✓
    else booking failed (name mismatch / no seats / user not found)
        PY-->>HS: 400 { error, error_code, details }
        HS->>JDB: update Hold (status=CONFIRMATION_FAILED,<br/>errorMessage=...)
        HS->>JDB: save AuditEvent (HOLD / CONFIRMATION_FAILED)
        HC-->>PY: 400 Bad Request
        PY-->>FE: error response
        FE-->>U: Error shown to user ✗
    end

產生使用案例圖

使用案例圖用於識別系統中的參與者,以及每個參與者可執行的功能。Mermaid 沒有原生的使用案例圖類型,因此你使用 flowchart LR 來依參與者分組使用案例加以呈現。

建立一個提示,以識別完整應用程式中的所有參與者及其使用案例。參與者包括使用者類型和外部系統。使用 context mentions 指定要讓 Bob 分析的相關檔案,包括前端頁面、後端 REST 端點,以及 MCP 工具。你在提示中對要分析的檔案描述得越具體,輸出結果就越精確。此外,指示 Bob 在 Mermaid 標記中對大括號進行跳脫,以避免 Mermaid 渲染器將大括號解讀為樣板語法。

在 Ask mode 中,於聊天輸入欄位輸入以下提示:

Analyze the full Galaxium Travels application. 

Identify all actors (user types or external systems) and the use cases each
actor can perform, based on the frontend pages, backend REST endpoints,
and MCP tools.

Generate a Mermaid flowchart LR that represents this as a use case diagram,
grouping use cases under their respective actors using subgraphs.

Escape curly braces in Mermaid markup so that the Mermaid renderer does not
attempt to interpret the curly braces as template syntax.

Output the Mermaid markup. Do not render the Mermaid diagram.

Bob 分析應用程式後,會產生與以下內容相似的圖表標記:

flowchart LR

    subgraph Traveller["👤 Traveller (Browser)"]
        T1[Browse available flights]
        T2[Search flights by origin / destination]
        T3[Filter flights by date, price, seat class,\nduration, route category, time period]
        T4[Register account]
        T5[Sign in with name and email]
        T6[Select seat class\neconomy / business / galaxium]
        T7[Get price quote]
        T8[Place seat hold - 15-minute timer]
        T9[Confirm hold and create booking]
        T10[Release hold]
        T11[View active bookings]
        T12[View past bookings]
        T13[Cancel booking]
        T14[View pending holds with countdown]
        T15[Dismiss expired hold]
    end

    subgraph AIAgent["🤖 AI Agent (MCP Client)"]
        A1[list_flights]
        A2[register_user]
        A3[get_user_id]
        A4[book_flight]
        A5[get_bookings]
        A6[cancel_booking]
    end

    subgraph JavaService["☕ Java Hold Service\n(Internal System)"]
        J1[Confirm hold via POST /internal/bookings/from-hold]
        J2[Auto-expire holds after timeout]
    end

    subgraph RestAPI["🐍 Python REST API\n(External Consumers / Swagger)"]
        R1[GET  /flights — list and filter flights]
        R2[POST /register — register user]
        R3[GET  /user — look up user by name and email]
        R4[POST /book — book a flight]
        R5[GET  /bookings/&#123;user_id&#125; — get user bookings]
        R6[POST /cancel/&#123;booking_id&#125; — cancel booking]
        R7[POST /quotes — create quote proxy]
        R8[GET  /quotes/&#123;id&#125; — get quote proxy]
        R9[POST /quotes/&#123;id&#125;/holds — create hold proxy]
        R10[GET  /holds/&#123;id&#125; — get hold proxy]
        R11[POST /holds/&#123;id&#125;/confirm — confirm hold proxy]
        R12[POST /holds/&#123;id&#125;/release — release hold proxy]
        R13[GET  / — health check]
    end

    Traveller   -->|uses frontend which calls| RestAPI
    AIAgent     -->|MCP over HTTP at /mcp| RestAPI
    JavaService -->|calls back via internal endpoint| RestAPI

將圖表儲存至存放庫

將 Bob 切換至 Agent mode,然後請它將你產生的圖表儲存至存放庫。每張圖表會儲存為新建 docs/architecture/ 資料夾中的一個 Markdown 檔案。

切換至 Agent mode

在模式選擇器中選取 Agent,或在聊天輸入欄位中輸入 /agent

儲存全部三張圖表

請 Bob 建立架構文件檔案。

Create a docs/architecture/ folder in the repository root.

Save each of the three diagrams we generated as individual Markdown files:
- class-diagram.md — the UML class diagram
- sequence-diagram.md — the booking flow sequence diagram
- use-case-diagram.md — the use case flowchart

Each file should have a short title heading, the Mermaid code block we
generated, and a brief description of the diagram.

Bob 建立這三個檔案。對每個 Bob 寫入的檔案,按一下 ApproveSave

驗證輸出結果

在 Bob 的檔案瀏覽器中開啟每個檔案,確認 Mermaid 圍欄程式碼區塊已正確存在。你有以下幾種驗證圖表的方式:

  • 請 Bob 顯示 Markdown 檔案的預覽。

    在聊天輸入欄位中輸入以下提示:

      Show me a preview of docs/architecture/class-diagram.md

    Bob 會在聊天介面中渲染 Markdown 檔案,包括 Mermaid 圖表。按一下渲染後的圖表,可在較大的視圖中開啟它。

    你可以對這三個檔案各執行一次,以查看所有圖表的渲染結果。

  • 將圖表標記貼到 Mermaid Live Editor 中,以預覽渲染後的圖表。

  • 將變更 commit 並 push 至 GitHub 存放庫,然後在 GitHub 上查看檔案以確認圖表渲染正確。

疑難排解

Bob 產生的 Mermaid 標記無法編譯

Mermaid 的解析器非常嚴格。即使是單一無效字元、不支援的關鍵字,或遺漏的換行符,都可能導致圖表靜默失敗或拋出解析錯誤。使用以下方法診斷並修復問題。

找出問題所在的行

當 Bob 產生解析錯誤時,輸出內容會包含行號和問題程式碼的片段。

如果 Bob 沒有輸出解析器錯誤,請將標記貼到 Mermaid Live Editor 中。編輯器會標示出問題所在的行並顯示解析器錯誤,有助於你識別問題。

你也可以目視檢查標記,尋找常見問題,例如標籤中未跳脫的特殊字元、未關閉的 subgraph,或箭頭的語法錯誤。

症狀可能原因修復方式
{} 附近出現解析錯誤flowchartclassDiagram 節點標籤中的大括號未跳脫{ 替換為 &#123;,將 } 替換為 &#125;,或改寫標籤
() 附近出現解析錯誤節點 ID 中含有括號將標籤包在引號中:A["label (note)"]
出現意外的 endsubgraph 錯誤subgraph 未關閉確保每個 subgraph 區塊都有對應的 end
無法識別箭頭類型圖表類型使用了錯誤的箭頭語法--> 用於 flowchartclassDiagram 使用 -->..>--|> 等;sequenceDiagram 使用 ->>-->>
節點已定義但未連接孤立節點不會產生錯誤,但可能讓某些渲染器感到困惑連接該節點或將其移除
圖表渲染到一半就停止標籤中含有裸露的 " 字元在標籤內跳脫引號:A["it\'s a label"]

請 Bob 修復問題

將解析器錯誤和問題行提供給 Bob,然後請 Bob 修復特定行。

例如:

The Mermaid classDiagram fails to parse with this error:
Parse error on line 42: ...unexpected token 'NEWLINE'

Here is the relevant block:
    Booking ..> BookingStatus : status (active)

Fix the syntax so it compiles without changing the diagram structure.

Bob 可以針對特定問題進行修復,而不需要重新產生你已審閱過的內容。

請 Bob 在輸出前進行驗證

如果你要從頭重新產生圖表,請在提示中加入明確的驗證指示:

Before outputting the Mermaid block, mentally parse it and confirm every node ID
is valid, every subgraph is closed, and all special characters in labels are escaped.

當圖表過大時縮小範疇

如果包含許多節點的圖表持續產生無效標記,請請 Bob 分段產生,例如先產生 Python 模型,再產生 Java 模型,然後再請 Bob 將各段組合起來。較小的產生單位更容易讓 Bob 驗證,也更容易讓你進行差異比對。

後續步驟

在本教學中,你使用了 context mentions 和 Ask mode 來探索 Galaxium Travels 程式碼庫,並使用 Bob 產生三種架構圖,再透過 Agent mode 將它們儲存至存放庫。請繼續參考以下資源:

這個主題如何?