做到 Day 14 之後,Visual Learning Lab 已經可以把教材裡的 Concept Map、Guided Learning、Adaptive Review 和來源資訊串在一起。
但我這幾天一直有一個感覺:如果今天教材裡出現的是數學公式,AI 最後還是在「跟我解釋公式」。
例如 Sinusoids 裡一直出現:
v(t)=V_m cos(ωt+θ)
目前系統可以告訴我 V_m 是振幅、ω 是角頻率、θ 是相位,也可以把這些概念畫成 Concept Map,甚至在 Quiz 答錯之後帶我回去複習。
但真正要理解這個公式,最直覺的方法可能根本不是再看一段解釋。
而是:
自己把 V_m 拉大看看。
自己把 ω 改掉看看。
自己把 θ 從 0 拉到 π/2 看看波形到底跑去哪裡。
所以 Day 15 我想做一個到目前為止我自己最喜歡的功能:
Interactive Learning Lab。
AI 不只分析教材,而是從教材裡辨識出適合操作的數學模型,自動產生一份「互動實驗規格」,再由 Visual Learning Lab 在本機把 slider、即時圖形和衍生數值真的做出來。
在做 Interactive Lab 之前,我先處理一個已經看不下去很久的問題。
前面的 Visual Learning Lab 雖然功能越來越多,但字體一直偏細,而且很多介面預設是英文。尤其 Concept Map、Guided Learning、Focused Review 全部疊在一起之後,小字看久其實滿痛苦的。
所以 Day 15 同時加入了語言系統。
現在網站預設是繁體中文,上方也多了一個 語言 / Language 選項,可以切換 繁體中文 和 English。

這裡有一個我刻意分開的概念:
介面語言、AI 產生的內容、原始教材,不是同一件事。
如果我丟一份英文 PDF,但目前選擇繁體中文,那 Quick Summary、Guided Learning、Quiz、Focused Review 都可以用繁中產生;但來源教材本身還是保留英文,不會把翻譯後的文字假裝成原文。
另外整體字體也重新調整了一次,改成比較適合中英文混排的字體 fallback,字重、行距和對比也比之前明顯。
這其實不是什麼很炫的 AI 功能,但網站變成繁中之後,我第一次覺得它真的比較像「我自己會拿來讀教材的東西」。
Interactive Lab 最重要的一個決定,是我不想讓 AI 直接產生 Python 程式碼然後執行。
這件事看起來很方便:
AI 看到了公式 → 寫一段 Python →
exec()→ 畫圖
但這也等於讓模型輸出的內容直接變成可執行程式,我不太想為了畫一條正弦波就開這個洞。
所以這次換了一個做法。
AI 只能產生一份 declarative specification,大概像:
{
"title": "探索正弦波參數",
"formula": "V_m*cos(omega*t + theta)",
"parameters": [
{"id": "V_m", "min": 0.5, "max": 5, "default": 1},
{"id": "omega", "min": 0.1, "max": 5, "default": 1},
{"id": "theta", "min": -3.14, "max": 3.14, "default": 0}
]
}
AI 可以決定「這份教材適不適合做實驗」、「有哪些參數值得調」、「合理範圍是多少」、「應該畫哪些 series」、「哪些衍生量值得顯示」。
但它不能產生任意 Python 去跑。
真正的數學計算會先通過一層 restricted expression evaluator。
目前允許的是像 + - * / **、括號,以及 sin、cos、tan、exp、log、sqrt 這些白名單函數和 pi 等常數。
像 __import__("os")、open()、attribute access、lambda、任意 function call 之類的東西都會被拒絕。
也就是:
AI 負責描述實驗,程式負責安全地執行數學。
我覺得這個分工比直接跑 AI code 安心得多。
第一個當然還是拿已經被我折磨很多天的 Sinusoids PDF 測。
這次 AI 自己產生了「正弦波參數實驗」,並抓出三個可調參數:
V_m、ω、θ。

現在只要拖 slider,右邊的 Plotly 圖就會立刻更新。
例如把 V_m 拉到 3.6,波形上下峰值就直接變大;把 ω 拉高,同樣時間範圍內就會出現更多週期;調整 θ 則會看到整條波形沿時間軸平移。
而且我另外保留了一條「預設值」曲線。
所以畫面上同時會看到:
這個我覺得比只顯示目前結果有用很多,因為可以直接看到「我剛才到底改變了什麼」。
下面也會即時計算像 T=2π/ω 這種 derived metric。
最重要的是:
拖 slider 完全沒有呼叫 OpenAI API。
第一次分析教材時,AI 已經把 Interactive Lab spec 一起產生好了。之後所有 slider 移動、函數重新計算、Plotly redraw,都是本機完成。
| 操作 | OpenAI API |
|---|---|
| 第一次 Visualize 教材 | 是 |
| 產生 Interactive Lab 規格 | 跟主分析一起完成 |
| 拉 slider | 否 |
| 即時重畫圖形 | 否 |
| 計算週期等衍生量 | 否 |
| Reset parameters | 否 |
所以即使把 slider 拉二十次,也不會變成二十次 API request。
做到這裡之後,我最擔心的其實不是 Sinusoid 能不能跑。
因為前十五天的測試資料一直都是這份教材,如果最後做出來的東西只對 cos() 特別好用,那其實只是把一個正弦波 Demo 包裝成 AI 功能。
所以接下來我故意完全不給 PDF,直接貼不同類型的數學教材文字。
第一個拿來壓它的是阻尼振動:
x(t)=Ae^{-bt}cos(ωt+φ)
這次 AI 自己抓出:
A、b、ω、φ
四個參數。

結果真的成功了。
提高 b,波形的 envelope 會更快衰減;提高 ω,固定時間內出現更多次振動;改變 φ,則會改變起始位置。
這題對我來說比正弦波重要很多,因為它已經不是單純 cos(),而是:
exp × cos
也就是同一條 expression 裡同時有指數衰減和週期振動。
這代表 safe expression evaluator 真的開始處理比較一般的數學模型,而不是我偷偷 hard-code sinusoid()。
接著我又丟:
y(x)=x tanθ - gx²/(2v₀² cos²θ)
這次模型自己判斷可調參數是初速度 v₀、仰角 θ 和重力加速度 g。
結果一樣生出了 Interactive Lab。
調整初速度,拋物線的高度和水平距離會跟著變;改變角度,整條 trajectory 的形狀也會更新。
這題其實比前面又更麻煩,因為裡面有 tan()、cos()、平方、除法,同時也可能遇到不合理參數造成數值問題。
但至少目前這組測試可以正常生成與計算。
這裡之後還有一個可以改進的地方:如果把它當成真正的「物體飛行軌跡」,那落到 y=0 之後理論上就可以停止,而不是繼續畫到地下。
不過這屬於下一層「物理有效 domain」的問題,目前 v1 先把它當數學函數來畫。
我還是不放心,所以最後又拿 Logistic Growth:
P(t)=K/(1+Ae^{-rt})

這次 AI 生出 K、A 和 r 三個參數。
比較有趣的是,它不只畫 P(t)。
它還自己把環境承載量 K 畫成水平線,並且產生 P(0) 和 K/2 這些有教學意義的 derived values。
我覺得這張反而是 Day 15 最能證明架構有用的畫面。
因為它完全不是 oscillation。
沒有 sine,也沒有 cosine。
圖形從週期波變成 S-shaped growth curve,參數意義也從振幅、頻率變成 carrying capacity、initial condition 和 growth rate。
但同一個 Interactive Lab engine 還是可以處理。
做到這裡,我才比較敢說 Day 15 做的不是:
「AI 幫正弦波生出三個 Slider。」
而比較接近:
「AI 根據教材裡的數學模型,自動產生一個可以操作的學習實驗。」
另外還有一件意外收穫。
Day 14 本來想把 Graphviz 升級成真正可以點擊、pan、zoom 的 interactive canvas,但當時 component 沒成功載入,所以系統只能 fallback 回 Graphviz。
這次再處理 Day 15 時,那條線也一起正常起來了。
現在 Concept Map 已經可以直接在 canvas 裡拖曳視角、縮放、選 node。
選到某個 node 後,Learning Inspector 仍然會接上前面 Day 14 做好的 lesson mapping、Explain This、source、Adaptive Review state。
所以前一天原本只有「底層關係接好了,但漂亮的互動圖沒跑起來」,現在終於開始真的長得像我想像中的 Learning Canvas。
Interactive Lab 跟前兩天做的 Guided Learning、Adaptive Review 也有接起來。
如果某個 lesson step 有對應的 interactive demo,就可以從課程直接進入實驗。
反過來,Interactive Lab 也知道自己跟哪幾個 Learning Step 有關,可以直接回去。
更有意思的是 Adaptive Review。
假設使用者在 Quiz 裡把 phase 和 amplitude 搞混,以前 Focused Review 會重新解釋兩者差異。
現在如果這個錯誤剛好有對應的 Interactive Lab,就可以讓使用者不只「讀一段補充說明」,而是真的去動手試:
固定
V_m和ω,只改變θ。
看完波形之後,phase 到底改了什麼通常就比再讀三段文字更清楚。
我覺得這是 Interactive Lab 真正開始跟前面功能產生關係的地方。
不是網站又多了一張圖。
而是:
錯誤可以變成一個可以操作的實驗。
回頭看 Day 3,我那時候只是把一段教材送進 OpenAI API,然後拿回 Quick Summary 和 Key Concepts。
一路做到 Day 15,現在同一份教材可以經過:
教材
↓
AI 理解內容
↓
Concept Map / Flow / Comparison
↓
Guided Learning
↓
Knowledge Check
↓
Adaptive Review
↓
Interactive Learning Lab
而今天對我來說最大的變化,是 AI output 的形式又變了一次。
以前 AI output 是:
文字。
後來變成:
結構化資料。
再後來變成:
圖。
今天開始,它變成:
一份可以被程式執行成互動學習工具的規格。
我覺得這個方向滿接近我一開始想做 Visual Learning Lab 的原因。
如果只是把 PDF 丟給 AI 問「請解釋這個公式」,ChatGPT 本來就做得到,而且做得很好。
那我做這個產品到底要幹嘛?
但如果系統可以自己看到教材裡有一個適合操作的數學模型,辨識有哪些參數值得改,建立安全的互動規格,再直接生出一個 slider + 即時圖形 + derived values 的 Lab,這件事情就比較不像一般聊天介面會自然提供的體驗。
而且今天測完 Sinusoid、Damped Oscillation、Projectile Motion 和 Logistic Growth 之後,我至少確認它不是只會做一種公式。
目前還只是 v1。
它還不懂更複雜的物理 constraints,也還沒有 2D vector field、3D、動畫或真正的 simulation engine。
但我覺得 Day 15 是目前整個專案一個很重要的節點:
AI 不再只是幫我解釋教材。
它開始根據教材本身,替我做出一個可以玩的學習工具。
GitHub Repo:
https://github.com/f24131128-lgtm/visual-learning-lab