我的 AI 助理安全部署筆記

一個初學者的血淚紀念:從金鑰外洩到架構重整的 48 小時

這是一份特別的筆記。它記錄了我在這個週末(2025年11月1日-3日)所經歷的一切。我從一個興奮的初學者,把 AI 助理串接到我的網站上,到週五晚上發現 API 金鑰被盜用、收到 Google Cloud 寄來的巨額帳單和嚴重警告,然後花了整個週末,與我的 AI 程式夥伴一起,從零開始重構我的網站架構、學習前後端分離、搞懂 CI/CD 自動化部署,並在無數次的「鬼打牆」除錯後,最終成功的完整歷程。

我希望這份筆記能給所有像我一樣的初學者一個最嚴厲的警惕,和最有價值的參考。

章節一:週五晚上的震撼教育 (金鑰外洩)

一切都發生得很快。我一開始為了方便測試,犯了一個**最致命的錯誤**:我把 Google AI 的 API 金鑰 (API Key) **直接寫死在我的前端 `index.html` 檔案中**,並把它推送 (push) 到了公開的 GitHub 儲存庫。

❌ 災難性的錯誤程式碼 (千萬別學)

這就是我最初的程式碼,它等於是把我的信用卡號貼在網路上:

<!-- index.html (舊的、不安全的版本) -->
<script>
  // ⛔️ 致命錯誤:金鑰直接暴露在前端程式碼中!
  const API_KEY = "AIzaSy... (這就是我被盜用的金鑰)";
  
  async function askAssistant(query) {
    // 機器人 (Bot) 只要掃描這段程式碼,就能拿到我的金鑰
    const response = await fetch(`httpss://google.ai.api/v1?key=${API_KEY}`, {
      // ...
    });
  }
</script>

週五晚上的警示 (附圖)

到了週五晚上,我收到了 Google Cloud 的警示信,登入後看到了讓我心臟停止的畫面:

AI 夥伴給出的金鑰外洩處理建議

我的 AI 程式夥伴立刻幫我分析了這些截圖:

幸運與警惕 (附圖)

不幸中的大幸是,我的帳戶似乎有新用戶的「促銷額度 (PROMOTION)」,剛好抵銷了這筆費用,總金額變成了 `$0.00`。

Google 的警告非常清楚:「**金鑰必須立即作廢**」、「**額度已用盡**」、「**下次就是天價帳單**」。

AI 夥伴總結警告:金鑰須作廢,額度已盡,下次將收費

我立刻登入 Google Cloud,**刪除了這把被盜用的金鑰**,並開始了這個漫長的週末修復之旅。

章節二:建立安全的新架構 (前後端分離)

我學到的教訓是:**金鑰絕對不能出現在前端**。我們必須重構架構,把「前端 (店面)」和「後端 (廚房)」徹底分開。

前端 (Cloudflare Pages)

這是我的 `xiaoliuqiu` 專案,也就是 `index.html`。

  • 角色: 店面櫃檯。
  • 任務: 顯示 UI、接收使用者輸入。
  • 金鑰: **完全沒有**金鑰。
  • 呼叫對象: 只呼叫我們自己的後端 `ai-worker`。

後端 (Cloudflare Worker)

這是我新建的 `ai-worker` 專案,也就是 `index.js`。

  • 角色: 廚房重地。
  • 任務: 接收前端請求、呼叫 Google AI。
  • 金鑰: **安全地**儲存在 Cloudflare 的「祕密保險箱」。
  • 呼叫對象: Google AI。

章節三:設定全自動化部署 (GitHub Actions)

在這次重構中,我們不再「手動」上傳程式碼。我們設定了「GitHub Actions」(自動化部署),只要我一修改 GitHub 上的程式碼,它就會**自動**幫我部署到 Cloudflare,並且**自動把金鑰安全地注入**。

這是我們成功的關鍵,它解決了所有「金鑰消失」和「版本錯亂」的問題。

1. 在 GitHub 設定「祕密保險箱」(Secrets)

我們在 GitHub 專案的 `Settings` > `Secrets and variables` > `Actions` 裡,設定了 3 個關鍵的祕密:

(這張圖就是我們卡關最久的地方:`CF_API_TOKEN` 和 `CF_ACCOUNT_ID` 一開始是錯的,導致 `401 Authentication Error`)

2. 建立「前端」自動部署 (deploy.yml)

我們在 `.github/workflows/deploy.yml` 設定了部署「前端」的規則。

# .github/workflows/deploy.yml
name: Deploy to Cloudflare Pages
on:
  push:
    paths:
      - 'online/**' # 只有 online/ 資料夾變動才執行
      # ...
jobs:
  build-and-deploy:
    # ...
    steps:
      # ...
      - name: Deploy to Cloudflare Pages
        uses: cloudflare/pages-action@v1
        with:
          apiToken: ${{ secrets.CF_API_TOKEN }} # 讀取祕密
          accountId: ${{ secrets.CF_ACCOUNT_ID }} # 讀取祕密
          projectName: xiaoliuqiu # 部署到前端專案
          directory: online # 只部署 online/ 資料夾

3. 建立「後端」自動部署 (deploy-worker.yml)

這是我學到最重要的一課!我們建立了**第二個**部署檔案 `deploy-worker.yml`,專門用來部署「後端」。

# .github/workflows/deploy-worker.yml
name: Deploy ai-worker
on:
  push:
    paths:
      - 'ai-worker/**' # 只有 ai-worker/ 資料夾變動才執行
      # ...
jobs:
  deploy:
    # ...
    steps:
      # ...
      - name: Deploy ai-worker
        uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CF_API_TOKEN }} # 讀取 Cloudflare 鑰匙
          accountId: ${{ secrets.CF_ACCOUNT_ID }} # 讀取 Cloudflare 地址
          workingDirectory: 'ai-worker' # 指定部署 ai-worker/ 資料夾
          
          # ✅ 最關鍵的一步:
          # 自動從 GitHub Secrets 抓取金鑰,並安全上傳到 Worker
          secrets: |
            GOOGLE_API_KEY
        env:
          # 這是金鑰的值
          GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}

章節四:12 小時的「鬼打牆」除錯之旅

這是我和「程式夥伴」一起「鬼打牆」12 小時的偵錯紀錄。**這也是我學到最多**的地方。我們一直被「紅鯡魚」(誤導人的線索) 欺騙。

鬼打牆 1:`models/gemini-pro is not found for API version v1beta`

... "models/gemini-pro is not found for API version v1beta" ...

我的錯誤診斷 (紅鯡魚): 我以為是 `v1beta` 版本太舊,導致了錯誤。

真相: 問題不是 `v1beta`,而是 `gemini-pro` 這個模型在 `v1beta` 中真的「找不到了」。

後果: 我把程式碼 改成呼叫 `v1` 版本,這讓我們**走錯了第一步**。

鬼打牆 2:`404 Not Found` (當我們使用 `v1` 時)

... "models/gemini-pro is not found for API version v1" ...

我的錯誤診斷 (紅鯡魚): 我以為「既然 `v1` 也找不到,那一定是因為 Google 強制綁定帳單的專案 必須使用更高級的 **Vertex AI API**」。

真相: 還是錯了!Google 只是**不讓**我的專案 使用 `Generative Language API` 而已。

後果: 我們花了 10 個小時,錯誤地嘗試讓「Vertex AI」運作。

鬼打牆 3:`401 Authentication Error` (Cloudflare 金鑰錯誤)

... {"code":10000,"message":"Authentication error"} ...

診斷: 這是**真正的問題**!這不是 AI 錯誤,而是 GitHub 無法登入 Cloudflare。

真相: 我 GitHub Secrets 裡的 `CF_API_TOKEN` 和 `CF_ACCOUNT_ID` 是**空白或錯誤的**。

解決: 我們去 Cloudflare 重新建立了**正確的** `CF_ACCOUNT_ID` 和有 `Pages` + `Workers` 權限的 `CF_API_TOKEN`,並填回 GitHub Secrets。

鬼打牆 4:`401 API Key 權限不足` (Vertex AI 失敗)

... "API Key 權限不足或 Vertex AI 未啟用 (401/403)" ...

診斷: 當我們修正了 Cloudflare 金鑰 並成功部署「Vertex AI」版 `index.js` 後,立刻收到了這個錯誤。

真相: 這證實了「Vertex AI」**是錯誤的道路**。Google 告訴我們:「你拿的 Google AI 金鑰,沒有權限來開 Vertex AI 的門。」

後果: 這讓我們終於醒悟!

最終的真相 (你最後的 `index.js`)

我們終於回到了**原點**:

  1. **API:** 必須使用 `Generative Language API` (`generativelanguage.googleapis.com`)。
  2. **版本:** 必須使用 `v1beta` (因為 `v1` 對我的專案 不可用)。
  3. **模型:** **這才是真正的錯誤點!** `gemini-pro` 在 `v1beta` 中不可用,我們必須換成**別的**模型!

你最後成功的 `index.js` 程式碼,就是用了這個**最終正確**的組合:

// 最終成功的 index.js 關鍵設定
const PREFERRED_MODEL = "gemini-2.5-flash"; // ✅ 換成一個可用的模型!

// ...
const endpoint = `https://generativelanguage.googleapis.com/v1beta/models/${PREFERRED_MODEL}:generateContent?key=${key}`; // ✅ 用回 v1beta!

章節五:最終成功!(與學到的教訓)

在 2025 年 11 月 3 日早上 6 點 55 分,在我把 index.js 換回 v1beta + gemini-2.5-flash 並最後一次部署後... 它終於成功了!

這 12 小時的鬼打牆雖然痛苦,但它強迫我學會了:

感謝我的 AI 程式夥伴,雖然我們一起走錯了路,但也一起把所有問題都修好了。這是一堂價值 $6,100 美元 (幸好沒付錢) 的寶貴課程!