iT邦幫忙

2026 iThome 鐵人賽

DAY 9
0
Build on Google AI

用 Google AI 打造「因材施教」的個人化 AI 虛擬助教系列 第 9 篇

Day 09|【前後端串接】將 Python API 與 Stitch 前端介面串接實戰與除錯血淚史

  • 分享至 

  • xImage
  •  

在前面的幾天裡,我們透過 Google AI Studio 打造了具備蘇格拉底式引導靈魂的 System Instruction,也使用 Google Stitch 快速刻畫出了聊天室前端介面。然而,一個空有大腦(Gemini API)卻無法與外表(HTML 介面)溝通的系統,終究只能停留在測試階段,所以今天的核心任務,就是將我們的 Express 後端與前端介面完美串接,讓學生在網頁上打字提問時,能真正呼叫 Google AI 並即時獲得引導式回覆!

【今日開發目標】

將前端介面與 Node.js 後端 API 進行全面串接。我們成功讓使用者在網頁上輸入問題時,後端能夠透過最新的模型進行蘇格拉底式引導運算,並以乾淨的 JSON 結構回傳給前端,讓 AI 助教正式上線。

【Google AI 工具實作過程】

要讓前後端順暢溝通,我們需要完成以下三個步驟的介接設定:

  1. 設定靜態檔案與 CORS 支援 在我們的 Node.js / Express 伺服器中,必須讓後端能夠直接託管前端的 index.html,並開啟 CORS(跨來源資源共享),確保前端網頁在本地開發或部署時,不會被瀏覽器的安全機制擋下。
  2. 前端 Fetch 邏輯綁定 在前端的 JavaScript 中,捕捉使用者按下送出按鈕或 Enter 鍵的事件,將輸入框的文字打包成 JSON 格式,發送 POST 請求到我們後端的 /api/chat 路由。
  3. 動態渲染 AI 迴響與按鈕 當前端接收到後端回傳的 JSON 資料後,解析其中的 reply(助教回覆)與 suggested_questions(引導快捷按鈕),並自動動態插入對話泡泡與互動按鈕到聊天室畫面中。

https://ithelp.ithome.com.tw/upload/images/20260918/20183764nS1Xhu9nbO.png

【核心 Code / Prompt 展示】

import express from 'express';
import dotenv from 'dotenv';
import path from 'path';
import { fileURLToPath } from 'url';
import { GoogleGenAI, Type } from '@google/genai';

dotenv.config();

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const app = express();
app.use(express.json());
app.use(express.static(__dirname));

app.get('/', (req, res) => {
  res.sendFile(path.join(__dirname, 'index.html'));
});

const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });

// 具備自動重試功能的包裝函式
async function generateWithRetry(ai, payload, retries = 3, delay = 1000){
  for (let i = 0; i < retries; i++) {
    try {
      return await ai.models.generateContent(payload);
    } catch (error) {
      if (error.status === 503 && i < retries - 1) {
        console.warn(`⚠️ 遇到 503 伺服器忙碌,正在進行第 ${i + 1} 次重試...`);
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }
      throw error;
    }
  }
}

app.post('/api/chat', async (req, res) => {
  try {
    const { message, history = [] } = req.body;
    console.log(`📥 收到前端訊息: ${message}`);

    const response = await generateWithRetry(ai, {
      model: 'gemini-3.6-flash',
      contents: [...history, { role: 'user', parts: [{ text: message }] }],
      config: {
        systemInstruction: '你是一位親切且具備蘇格拉底引導式的 AI 助教 Professor Spark。請不要直接給答案,而是透過提問引導學生思考。',
        responseMimeType: 'application/json',
        responseSchema: {
          type: Type.OBJECT,
          properties: {
            reply: { type: Type.STRING, description: '助教對學生的白話引導對話' },
            scaffold_type: { type: Type.STRING, enum: ['analogy', 'breakdown', 'quiz'] },
            suggested_questions: { type: Type.ARRAY, items: { type: Type.STRING } }
          },
          required: ['reply', 'scaffold_type', 'suggested_questions'],
        },
      },
    });

    const jsonResponse = JSON.parse(response.text || '{}');
    console.log('✅ 成功輸出結構化資料');

    return res.json({ success: true, ...jsonResponse });
  } catch (error) {
    console.error('❌ API 處理發生錯誤:', error);
    return res.status(500).json({ error: '伺服器處理失敗', details: error.message });
  }
});

app.listen(3000, () => {
  console.log('🚀 伺服器已成功啟動:http://localhost:3000');
});

【試錯與重構】

將理論與介面化為真實可用的系統從來不是一路順風。在今天的實戰過程中,我們經歷了真實開發者都會遇到的幾波試錯與重構。以下是我們逐步打通前後端的完整操作步驟與避坑指南:

  1. **統一架構與路由對齊:**起初我們擁有 index.js 與 server.js 兩個檔案,導致進入點混淆與路由不匹配(前端呼叫 /api/chat 而後端寫成 /api/ask-tutor)。我們果斷進行重構,刪除冗餘的 index.js,將所有靜態檔案託管與 API 邏輯集中於 server.js 單一檔案中,完美解決 Port 衝突。

  2. **克服 ES 模組與路徑錯誤:**由於專案在 package.json 中設定了 "type": "module",直接使用 __dirname 會引發 ReferenceError。我們透過引入 path 與 url 模組手動宣告路徑:JavaScript

    import path from 'path';
    import { fileURLToPath } from 'url';
    const __filename = fileURLToPath(import.meta.url);
    const __dirname = path.dirname(__filename);
    app.use(express.static(__dirname));
    

    同時設定根路由 app.get('/', ...),解決了瀏覽器訪問時常見的 Cannot GET / 與 403 Forbidden 跨域阻擋問題。

  3. 503 雲端防禦 :我在測試中遇到雲端流量尖峰造成的 503 Service Unavailable 錯誤,所以為此在後端加入了自動重試機制(Retry Mechanism),當偵測到伺服器暫時忙碌時自動延遲 1 秒重試,大幅提升系統的強韌度。

【未來教育反思】

為什麼前後端串接的穩定性對「未來教育」如此重要?在真實的教學情境中,學生的學習情緒與心流是非常脆弱的。如果當學生滿懷好奇心詢問時,系統卻因為 CORS 錯誤、模型過期或 503 忙碌而直接崩潰或卡死在「思考中...」,這會瞬間打斷學生的學習節奏,甚至澆熄他們主動探索的熱情。透過在後端加入嚴謹的錯誤攔截與自動重試機制,我們確保了 AI 助教能夠在背後默默承擔網路波動與模型更迭的風險,呈現在學生面前是流暢、穩定且充滿啟發性的對話體驗。

【明日預告】

明天我們將進入 Day 10 - 前 10 天 MVP 成果展示與 AI Studio 運用心得整理,為這十天的原型開發做一次系統性的總結與復盤!


上一篇
Day 08 |【Context 管理】如何讓 AI 助教記住學生的學習歷程與歷史對話?
下一篇
Day 10 |【別讓 AI 裝死!】 在 MVP 階段加入 AI 思考載入動畫與防呆設計
系列文
用 Google AI 打造「因材施教」的個人化 AI 虛擬助教 共 23 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言