📍 真實場景
阿凱,一間小型網路電商的後端工程師,負責維護自動訂單客服機器人
他打算把 LLM 接進客服系統,讓 AI 直接把顧客傳來的訊息轉成訂單系統看得懂的 JSON 資料,省掉人工輸入的步驟
😖 卡住的地方:系統三不五時就在解析 AI 回傳的資料時噴錯——有時候欄位型別不對(數字寫成文字、文字寫成數字),有時候 AI 多嘴加了一句「很樂意為您服務」,把整包 JSON 包在客套話裡,程式一解析就整條當機
💡 這課會告訴他:與其一直加防呆程式碼硬接,不如搞懂『結構化輸出的守門邏輯』是什麼,以及怎麼用小模型微調,把『守規矩』直接練進模型的行為習慣裡
🧭 這到底是什麼(白話版)
你有沒有想過,為什麼客服機器人平常答得好好的,一接進真正的訂單系統就整組壞掉?問題常常不是「內容對不對」,而是「格式對不對」。這篇文章講的就是 結構化輸出(structured output)要求 AI 不要自由發揮講一段話,而是照著指定的格式,比如固定欄位的 JSON,把答案吐出來,方便程式直接讀取 這件事——而且特別去衡量,AI 輸出的東西有沒有符合 schema格式的規格書,規定資料長什麼樣子,例如「一定要有 order_id 這個欄位,而且必須是文字」。合不合規往往就是能不能把 AI 接進真正系統的分水嶺。
文章示範的做法,是拿一顆只有 參數量(350M)模型裡面『旋鈕』的數量,350M 代表 3.5 億個旋鈕,數字越大通常能力越強,但也越貴、跑起來越慢 的小模型,做一次 微調(fine-tuning)拿一個已經訓練好的通用模型,用少量特定任務的資料再訓練一小段,讓它更擅長做那件特定的事。訓練方法用的是 GRPO一種強化學習訓練法(Group Relative Policy Optimization),讓模型針對同一題產生多個候選答案,互相比較評分,再把分數較高的答案的思路留下來,而且只練了 100 步——目標不是要打敗排行榜,而是要證明:一顆小模型針對特定任務練過之後,有機會追上體積大得多的模型的表現。
為了驗證這件事,作者先在自己的筆電上,用 llama.cpp一套能在一般電腦(甚至筆電)上跑 AI 模型的軟體,還能開一個網路服務讓其他程式呼叫模型 把模型服務起來——用的是壓縮打包成 GGUF一種把 AI 模型壓縮打包的檔案格式,方便在一般電腦上載入運行 格式、精度是 BF16一種數字精度格式,精度越低通常檔案越小、跑得越快,但可能犧牲一點準確度 的版本,接上開源評測工具 IFStruct,量出微調前的基準分數,再決定值不值得投入時間去微調。
🔍 程式碼漫遊(點有 ● 的行看白話講解)
這段指令在做什麼:把還沒微調的 LFM2.5-350M 模型用 llama.cpp 服務起來,開一個網址讓評測程式送題目過來。
●llama-server \
💬 啟動 llama.cpp 內建的本機模型伺服器
● -hf LiquidAI/LFM2.5-350M-GGUF:BF16 \
💬 直接從 Hugging Face 抓這顆用 BF16 精度包好的 GGUF 模型檔來服務,不用自己下載轉檔
● -c 32768 \
💬 設定一次能塞給模型看的文字上限(prompt context 大小)
● -np 4 \
💬 同時處理 4 個評測請求,加速跑完整份 2000 題的題庫
● -ngl 99 \
💬 盡量把模型的每一層都丟給 GPU 算,沒有 GPU 時會自動退回用 CPU(速度會慢很多)
● --alias LiquidAI/LFM2.5-350M \
💬 評測工具是靠這個名字認出要打哪個模型,要跟評測端設定的名稱一致
● --host 127.0.0.1 --port 8080
💬 開出一個本機網址,讓評測程式當成一般 OpenAI API 端點來呼叫
🧠 工程思維透鏡(資深工程師看到的是什麼)
🔭 為什麼不乾脆用提示詞硬性要求 AI 只輸出 JSON,而要花力氣做微調?
材料裡的評測動作本身就是答案——沒微調過的 LFM2.5-350M 就算收到「請輸出結構化 JSON」的提示,實測也只有 22.6% 真的守規矩。可見光靠提示詞對小模型是不夠的,提示詞只能『講規則』,微調才能把規則刻進模型的行為習慣裡,這對要接進真實系統、不能有例外的場景特別關鍵。
🔭 為什麼作者要先花力氣重現 base model 的分數,而不是直接開始微調?
這是資深工程師常見的『先量基準再動手』紀律——沒有基準分數,永遠不知道微調到底有沒有進步、進步多少。材料特別強調這份筆記本『不是想重現 IFStruct 排行榜分數,而是要證明小模型微調後能追上大模型』,代表評測的目的是給自己一把量尺,而不是為了排名。
🔭 為什麼訓練跟評測要刻意拆成雲端 GPU 跟本機筆電兩個地方跑?
這是成本與資源的權衡——訓練需要反覆試錯、算梯度,非常吃顯示卡,所以借免費的 Colab/Kaggle GPU 額度;但評測只是讓模型回答固定題目,用 llama.cpp 把模型壓縮成 GGUF 格式後,一台筆電的算力就夠用,不需要浪費雲端 GPU 的珍貴時數在評測這種相對輕量的工作上。
🔭 llama-server 指令裡特地設定 -ngl 99,把所有層丟給 GPU,這跟輸出正確性有關係嗎?
這其實是『速度』而非『正確性』的權衡——就算不把層數都丟給 GPU,模型一样能算出一模一樣的輸出結果,只是評測 2000 筆題目會變得非常慢。工程上先確保結果可信(基準分數可重現),再用硬體設定去換取更快的迭代速度,是評測階段常見的取捨順序。
📝 隨堂考(點選答案,立即回饋)
Q1. IFStruct 這個評測基準,主要在測 LLM 的什麼能力?
✅ 材料開頭就說明,結構化輸出常被合併進更廣的推理或抽取分數裡,但 IFStruct 是特別把『輸出是否有效、可解析、符合指定格式』單獨拿出來測。
Q2. 文章裡,為什麼要特地跑一次『重現 base model 分數』的步驟?
✅ 有了可信的基準分數,才能判斷之後微調到底有沒有效、進步了多少。
Q3. 評測時為什麼是在本機 MacBook 上用 llama.cpp 跑,而不是繼續用雲端 GPU?
✅ 材料提到評測可以在 MacBook 上透過 llama.cpp 起一個 OpenAI 相容伺服器來跑,是刻意把訓練跟評測的算力需求分開處理。
Q4. llama-server 指令裡的 -ngl 99 大致在做什麼?
✅ -ngl 控制卸載到 GPU 的層數,99 代表盡可能把所有層都丟給 GPU 加速。
Q5. 如果一個 LLM 輸出的 JSON 在 order_id 欄位填了數字 1029 而不是文字 "1029",在嚴格的 schema 驗證下會發生什麼事?
✅ 結構化輸出比對的是型別是不是符合規格,型別不對(數字 vs 文字)在嚴格 schema 驗證下就是不合格,這正是本課互動示範要練習抓出來的錯誤型態。