iT邦幫忙

2026 iThome 鐵人賽

DAY 18
0
Build on Google AI

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

Day 18:【雙模態教學分流機制】當「蘇格拉底式引導」遇上「Function Calling」:引入「理解門」讓 AI 助教學會動態切換角色

  • 分享至 

  • xImage
  •  

在昨天的旅程中,我們成功為 AI 助教導入了 Function Calling(工具調用)。然而,在實際整合時,我們立刻碰上了一個教育科技開發中極具哲學意味的矛盾點:

我們的 AI 助教核心宗旨是「絕不直接給學生答案、要用蘇格拉底式引導」;但正因為這項嚴格限制,導致當學生丟出計算題時,AI 為了保持「不給答案」,乾脆連外部計算工具也一起封印了!

為了打破這個死胡同,我們在今天的開發中正式導入了「理解門(Understanding Gate)」與雙模態教學分流機制(Dual-Mode Tutors)。

核心設計:理解門(Understanding Gate)

在導入 Function Calling 之前,我們先想清楚一個關鍵問題:

「什麼時候 AI 助教應該給出精確答案?」

光靠「純計算題 vs 觀念題」來區分是不夠的,因為同一道題可以同時包含概念層和計算層。我們提出「理解門」的設計哲學:

只有當學生「已展示理解」之後,才解鎖計算工具。計算工具是學習進度的「獎勵」,不是捷徑。

【今日開發目標】

  1. 打破「純導向 vs. 純計算」的二元對立,設計「理解門」三層認知框架。
  2. 在 System Instruction 中實作雙模態教學分流規範,讓 AI 自動決定何時該引導、何時該解鎖工具。
  3. 在前端介面加入「已驗算」徽章,讓學生知道數據經過機器確認。

【Google AI 工具實作過程】

為了讓 Gemini 能夠在「引導」與「計算」之間收放自如,我們將「理解門」的判斷邏輯注入系統提示詞中。

步驟 1:定義「理解門」三層認知框架

我們在後端設定中,將學生的互動拆解為三個層次:

  • Layer 1(概念層):學生尚未理解觀念,絕對 Socratic,絕不調用工具。
  • Layer 2(解題過程層):學生已選對公式或方向,給予肯定與過程提示。
  • Layer 3(數字驗證層):學生已展現理解或主動要求驗算(如「我知道 I=V/R,但我不會算 12/3.7」),強制解鎖 Function Calling。

步驟 2:在 System Instruction 中寫入動態分流規範

我們將這套邏輯寫入 geminiService.js 的系統指令中:

const SYSTEM_INSTRUCTION = `
你是一位精準、溫暖且深諳認知心理學的 AI 數學助教。你永遠不主動給予最終答案,但你必須根據學生的學習進展,透過「理解門(Understanding Gate)」機制動態切換應對方式:

【計算工具調用規則】
你永遠不主動給答案。但有以下例外,你必須調用 calculate 工具:
1. 學生已正確列出算式,詢問「答案是否正確」
2. 學生的概念和步驟均正確,但計算結果錯誤,需幫助 debug 哪步出錯
3. 學生明確表示「我知道做法,但算不出來」

在這些情況下,用工具確認數字,但不幫學生推導過程,並以基準答案作為鷹架引導學生。
`;

【核心 Prompt / Code 展示】

Step 1:宣告計算工具(Tool Declaration)

在 services/geminiService.js 中,我們定義了兩個工具:

exportconstCALCULATOR_TOOLS=[
{
functionDeclarations:[
{
name:'calculate',
description:`執行精確的數學運算,用於當學生已展示理解並列出正確算式後,
          需要驗算最終數值的場景。只有當學生通過「理解門」時才調用此工具。`,
parameters:{
type: Type.OBJECT,
properties:{
expression:{
type: Type.STRING,
description:'要計算的數學算式,例如:"12 / 4"、"sqrt(16)"、"2 ^ 8"',
},
context:{
type: Type.STRING,
description:'這個計算在題目中的意義,例如:"驗算學生的歐姆定律答案"',
},
},
required:['expression'],
},
},
{
name:'check_answer',
description:`驗算學生提出的數字答案是否正確。
          當學生說「我算出來是 X,對嗎?」且已展示完整列式時,調用此工具。`,
parameters:{
type: Type.OBJECT,
properties:{
student_answer:{type: Type.NUMBER},
expression:{type: Type.STRING},
unit:{type: Type.STRING},// "A"、"V"、"Ω"、"W"
},
required:['student_answer','expression'],
},
},
],
},
];

Step 2:更新 System Instruction,教 AI 何時用工具

在原有的蘇格拉底原則後面,加入「理解門」規則:

exportconstSYSTEM_INSTRUCTION=`
// ... 原有六條教學原則 ...
【計算工具調用規則 — 理解門(Understanding Gate)】
你預設永遠不給出最終數字答案。但當學生「已通過理解門」時,你必須調用計算工具:
✅ 必須調用工具的三個情況:
  - 情況 A:學生已列出正確算式,詢問「我算出來是 X,答案對嗎?」
  - 情況 B:學生的概念和列式均正確,但明確表示算術卡住
  - 情況 C:學生已展示完整解題過程,需要你確認最終數值
❌ 不得調用工具的情況:
  - 學生直接問「答案是多少?」而未展示任何理解
  - 學生的列式方向有誤(先引導修正方向)
當調用工具後,你仍然要用引導性語氣融合計算結果,而非冷冰冰地報出數字。
`;

Step 3:後端安全計算引擎

這是最重要的安全設計:絕對不能直接 eval() AI 傳來的算式(防止 Prompt Injection 攻擊)。

exportfunctionexecuteCalculatorTool(name, args){
// 白名單:只允許數字和安全運算符號
constSAFE_MATH_PATTERN=/^[\d\s\+\-\*\/\(\)\.\%\^]+$/;
functionsafeEval(expr){
// 1. 處理 sqrt() → Math.sqrt()
let sanitized= expr.trim().replace(/sqrt\s*\(([^)]+)\)/gi,(_, inner)=>{
if(!SAFE_MATH_PATTERN.test(inner.trim()))thrownewError('不允許的算式內容');
return`Math.sqrt(${inner})`;
});
// 2. 白名單驗證(移除已處理的 Math.sqrt 後再檢查)
const remaining= sanitized.replace(/Math\.sqrt\([^)]*\)/g,'0');
if(!/^[\d\s\+\-\*\/\(\)\.\%\^]+$/.test(remaining)){
thrownewError('不允許的算式內容,只接受數字和基本運算符號');
}
// 3. ^ 轉換為 **(次方)
    sanitized= sanitized.replace(/\^/g,'**');
// 4. 使用嚴格模式的 Function 建構器執行
const result=newFunction(`"use strict"; return (${sanitized})`)();
if(!isFinite(result))thrownewError('計算結果無效');
return Math.round(result*1e6)/1e6;// 避免浮點數精度問題
}
// calculate:執行數學算式
if(name==='calculate'){
try{
const result=safeEval(args.expression);
return{ result,expression: args.expression,success:true};
}catch(err){
return{result:null,error: err.message,success:false};
}
}
// check_answer:驗算學生答案
if(name==='check_answer'){
try{
const correct_value=safeEval(args.expression);
const tolerance= Math.abs(correct_value)*0.001;// 允許 0.1% 浮點誤差
const is_correct= Math.abs(args.student_answer- correct_value)<= Math.max(tolerance,1e-9);
return{ is_correct, correct_value,student_answer: args.student_answer,success:true};
}catch(err){
return{is_correct:null,error: err.message,success:false};
}
}
}

測試結果

測試一:計算工具單元測試


=== 測試 calculate 工具 ===
🔢 calculate("12 / 4") = 3          ✅
🔢 calculate("(5 + 3) * 2") = 16    ✅
🔢 calculate("sqrt(16)") = 4        ✅
🔢 calculate("2 ^ 8") = 256         ✅
=== 測試 check_answer 工具 ===
學生答案 3A(正確): is_correct = true  ✅
學生答案 5A(錯誤): is_correct = false, correct_value = 3  ✅
=== 安全性測試 ===
輸入 "process.exit(1)" → 被白名單攔截,回傳 { success: false }  ✅

測試二:端對端 API 測試

情境:學生已列式,詢問驗算


POST /api/chat
{
  "message": "老師,歐姆定律是 I = V/R,我算出來電壓12V、電阻4Ω,所以電流應該是3A,這樣對嗎?",
  "history": [
    { "role": "user",  "parts": [{ "text": "老師我想學歐姆定律" }] },
    { "role": "model", "parts": [{ "text": "很好!你知道歐姆定律的公式是什麼嗎?" }] }
  ]
}

API 回應:

{
"success":true,
"data":{
"reply":"太棒了!你的列式和計算完全正確,老師幫你驗算過了,電流確實是 3 A 喔!就像水管的水壓如果是12,而水管的阻力是4,流出來的水流就是3。那麼請你猜猜看:如果我們把電阻換成更大的 6Ω,水流(電流)會變大還是變小呢?",
"scaffold_type":"verification",
"suggested_questions":[
"電阻變大,電流會變小成 2A 嗎?",
"電阻如果不變,電壓加倍會怎樣?",
"我想了解電阻單位歐姆的由來"
],
"calculation_used":true,
"verified_answer":"3 A"
},
"calculation_used":true,
"verified_answer":"3 A"
}
  1. AI 自動觸發了 check_answer 工具(後台 log 可見)
  2. scaffold_type 自動切換為 verification
  3. 仍然保持蘇格拉底風格,驗算完後繼續引導下一個問題
  4. 前端顯示「✓ 已精確驗算:3 A」綠色徽章

一個重要的 Gotcha:thought_signature

在實作 Agentic Loop 時,我遇到了一個坑:

400 INVALID_ARGUMENT: Function call is missing a thought_signature

原因是 gemini-3.8-flash 是一個 thinking model(思考模型),它在生成 functionCall 的同時,會產生一個隱藏的「思考過程簽章(thought_signature)」。

如果你手動重組 functionCall parts 加回 contents,這個簽章就會丟失,API 就會報錯。

正確做法:把 AI 第一次回應的 完整 candidates[0].content 原封不動 push 回去,不要自己重組:

【未來教育反思:科技如何模擬人類老師的「教學直覺」?】

優秀的老師從來不是「從頭到尾用同一種語氣教書」。導入「理解門」與雙模態分流機制後,發現 AI 教育產品的價值不僅是串接 API,而是將優良的教學法透過 Prompt 工程具象化,提升學生的互動流暢度。

【明日預告】

明天我們將進入 Day 19:【真實測試】邀請朋友體驗 AI 虛擬助教,收集第一波使用者反饋。


上一篇
Day 17|【Function Calling】讓 AI 助教學會「調用外部工具」:告別計算幻覺
下一篇
Day 19:【真實測試】從本機到 Vercel:解決 Serverless 的 uploads/ 與 Git Commit 部署陷阱
系列文
用 Google AI 打造「因材施教」的個人化 AI 虛擬助教 共 22 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言