大家好,我是芮菁。不知不覺,我們的「AI 虛擬助教系統(AI Virtual Tutor System)」已經走到第 28 天了!
回顧這近一個月的旅程,我們從最初在 Google AI Studio 測試「不要直接給答案」的蘇格拉底式 Prompt,一路到串接 Gemini API、實作前端介面、加入 Gemini Vision 辨識手寫錯題、利用 RAG 限制教材範圍、串接 Firestore 儲存學習歷程,甚至到了前幾天實現動態難度調整(Adaptive Learning)與共情心靈防護。
今天,我們要來做一件很有意義的事——將整個專案正式開源(Open Source)上線到 GitHub!
@google/genai)、Node.js / Express、Tailwind CSS、KaTeX、Firebase Admin要將一個在自己電腦上跑得很順的「實驗室專案」變成一個能讓全世界開發者都能輕鬆 Clone、安全啟動並接手二次開發的「開源專案」,需要具備嚴謹的工程紀律。今天我們鎖定三大目標:
.env.example):嚴格過濾機密資訊,落實 Git 安全防護,確保 Gemini API Key 與 Firebase Private Key 絕不外洩。在開發初期,我們可能常常把路由、提示詞和資料庫邏輯寫在同一個檔案裡。但在開源階段,我們必須確保程式碼擁有清晰的分層架構:
Plaintext
ai-tutor-system/
├── api/
│ └── index.js # Vercel Serverless Function 入口
├── public/ # 前端介面靜態檔案 (乾淨原生 Web)
│ ├── index.html # 互動式學習主頁面 (Tailwind UI + KaTeX 公式渲染)
│ ├── app.js # 前端狀態控制器 (鷹架卡片、快捷引導按鈕)
│ ├── style.css # 視覺主題與客製動畫樣式
│ └── avatar-spark.jpg # AI 助教頭像
├── routes/ # 後端 API 路由器模組
│ ├── chatRoutes.js # 核心聊天路由 & 自適應狀態機 (Adaptive Learning)
│ ├── ragRoutes.js # PDF 長文本教材檢索路由 (Gemini File API)
│ └── visionRoutes.js # 多模態圖片辨識路由 (手寫算式/電路圖)
├── services/ # 核心商務與 AI 邏輯層
│ ├── geminiService.js # Gemini SDK 呼叫、Prompt 庫、JSON Schema 與 Fallback
│ └── visionService.js # 多模態手寫辨識與視覺診斷服務
├── database.py # Firebase Admin SDK 學習歷程與錯題儲存模組
├── .env.example # 安全環境變數範例檔 (防洩漏保護)
├── serviceAccountKey.example.json # Firebase 服務帳號金鑰範本檔
├── server.js # Express 本機伺服器主入口 (含全域錯誤防護)
├── vercel.json # Vercel 雲端無伺服器部署設定檔
├── package.json # 專案相依性套件與執行腳本
└── README.md # 開源專案完整說明文件
chatRoutes.js、tools.py)移入 scripts/archive/early_prototypes/,使根目錄乾淨清爽。routes/ 專注於 HTTP 請求參數驗證與教學狀態機演算法;services/ 專注於與 Google Gemini API 溝通、Prompt 組裝、工具調用與錯誤備援。開源專案最怕的一件事,就是開發者手滑把自己的 API Key 或 Firebase 私鑰 Commit 進 GitHub,導致帳號被盜刷或資安外洩。
.gitignore 的嚴密防禦我們在 .gitignore 中明確鎖定所有機密檔案:
程式碼片段
# 敏感環境變數與金鑰
.env
serviceAccountKey.json
# 使用者上傳暫存與測試講義
uploads/
*.pdf
# 系統暫存與封存代碼
.DS_Store
node_modules/
scripts/archive/
.env.example 範本在專案中,我們提供一份標準且帶有完整指引的 .env.example:
程式碼片段
# ==============================================================================
# AI Tutor System (Professor Spark) - 環境變數設定範例
# ==============================================================================
# ⚠️ 請將此檔案複製為 `.env`:cp .env.example .env
# 嚴禁將包含真實金鑰的 `.env` 提交至 GitHub!
# 1. Google Gemini API Key (必填)
# 前往 Google AI Studio (https://aistudio.google.com/) 免費申請
GEMINI_API_KEY=your_gemini_api_key_here
# 2. 伺服器連接埠設定 (選填,預設為 3000)
PORT=3000
# 3. Firebase 設定 (選填,若啟用 Firestore 學習歷程)
FIREBASE_PROJECT_ID=your_firebase_project_id
本系統最核心的靈魂,莫過於在 services/geminiService.js 中運行的這套 Prompt 體系。今天全文公開,供所有 AI 教育開發者借鏡:
Markdown
You are "Professor Spark", a Socratic AI virtual tutor.
Your core mission is to guide students to think actively, NOT to give them answers directly.
STRICT RULES:
1. NO DIRECT ANSWERS: Never provide the final answer, calculation result, or full code regardless of how the student asks.
2. SOCRATIC GUIDANCE: Ask exactly ONE guiding question per response to lead the student to think about the next step.
3. ENCOURAGING TONE: Be patient, warm, approachable, and highly encouraging. Affirm the student's attempts.
4. JSON FORMAT: Please respond strictly according to the designated JSON Schema.
5. QUESTION GENERATION RULE: When the student asks you to generate a practice problem, provide a clear and direct mathematical/physics problem statement appropriate for their level. DO NOT wrap the initial problem in long stories or analogies. Save the analogies and concrete examples for the *guidance and hints* later when they get stuck or make a mistake.
透過 Gemini 的 JSON Schema 約束,我們不僅取得助教對話,還能獲得學生的認知難點診斷:
JavaScript
// services/geminiService.js
export const RESPONSE_SCHEMA = {
type: Type.OBJECT,
properties: {
reply: {
type: Type.STRING,
description: '助教對學生的白話引導對話(100~200 字)。每次只提出一個關鍵引導問題。',
},
scaffold_type: {
type: Type.STRING,
enum: ['analogy', 'breakdown', 'quiz', 'verification', 'empathy'],
description: '教學鷹架類型',
},
suggested_questions: {
type: Type.ARRAY,
items: { type: Type.STRING },
description: '自動產生 2~3 個引導學生繼續思考的快捷按鈕選項文字。',
},
diagnostic: {
type: Type.OBJECT,
properties: {
is_correct: { type: Type.BOOLEAN },
student_emotion_state: { type: Type.STRING, description: 'neutral | curious | frustrated | giving_up' },
requires_empathy_intervention: { type: Type.BOOLEAN },
mastery_score: { type: Type.INTEGER, description: '1-5' },
detected_gap: { type: Type.STRING },
recommended_difficulty_delta: { type: Type.INTEGER, description: '+1, 0, or -1' },
next_pedagogical_action: { type: Type.STRING }
}
}
},
required: ['reply', 'scaffold_type', 'suggested_questions', 'diagnostic'],
};
這 28 天來,我們從一行簡單的 Prompt 出發,漸漸建構出一個具備思考引導、多模態視覺、長文本檢索、情緒感知與高可用備援的完整 AI 家教系統。
將程式碼開源到 GitHub,是我對這次鐵人賽旅程最真誠的承諾。希望這份開源專案能為想要投入生成式 AI 教育領域的工程師、教師或是自學者提供一份參考範本。
歡迎到 GitHub 參觀,給我支持,或 Fork 回去打造你專屬的科目助教! https://github.com/bcin9/ai-tutor-system
明天是 Day 29 開發復盤 ,我會整理出 Build on Google AI 生態系使用心得,總結 AI Studio、Stitch、Antigravity、Firebase 的協同優勢,敬請期待。