實戰全紀錄 — 用 AI 從零做出一個真工具
這章結束你會把需求、規格、拆解、AI 協作、驗證與修 bug 串成一次完整專案流程。
開場 · 第一個真專案
很多人學到最後,最怕的不是語法,而是第一個真專案。看教學時每一步都懂,自己開新檔案時卻不知道先問 AI 什麼、怎麼判斷它做得對不對。本章不再講單點技巧,而是完整走一次「分帳神器」:朋友出遊後輸入誰付了多少錢,工具算出誰該補給誰。它夠小,不會拖成大工程;也夠真,會碰到除不盡、有人先走、資料打錯這些現場問題。你會看到一個專案從空白變成可用工具,中間每一步怎麼指揮 AI 這位實習生。
一、先選一個夠小又夠真的題目
第一個真專案不適合選「做一個社群平台」或「做一個完整記帳 app」。那種題目太大,會讓你同時卡在畫面、資料、登入、權限、手機版、同步與安全。黑帶實戰要練的是完整節奏,不是一次吞下所有技術。所以本章選「分帳神器」:朋友出遊後,每個人付的錢不同,工具算出每個人最後該收或該付多少。
這個題目剛好有三個優點。第一,生活中真的會用到,不是玩具題。第二,核心規則可以用一句話說清楚:總支出平均分給參與者,多付的人收錢,少付的人補錢。第三,它會自然長出邊界情境(edge case):有人中途先走、金額不能整除、有人沒有付錢、輸入負數、名字重複。這些不是麻煩,而是真專案的肌肉。
你可以把程式想成食譜。小練習像只煎一顆蛋,真專案則像做一桌菜;不只要有步驟,還要知道先洗菜、再備料、最後試味道。AI 是你的實習生,不是魔法箱。你如果只說「幫我做分帳工具」,它可能做出看起來能用、但除不盡時少掉一元的版本。你如果先給規格、再切里程碑、每一步驗收,它就比較像被好好帶班的實習生。
本章的目標不是讓你背分帳公式,而是讓你學會一種專案路線:先縮小題目,再寫規格,再拆成可驗收的小步,接著請 AI 每次只做一件事,最後用測試 case 擋住錯誤。這套流程可以搬去記帳、抽籤、倒數日、課表整理等同級專案。
const people = [
{ name: '小安', paid: 1200 },
{ name: '小美', paid: 800 },
{ name: '小志', paid: 0 }
];
const total = people.reduce((sum, p) => sum + p.paid, 0);
const share = total / people.length;
const balances = people.map(p => ({
name: p.name,
balance: p.paid - share
}));
console.log('總金額:', total);
console.log('每人平均:', share);
console.log('正數代表該收,負數代表該付:', balances);
二、Act 1:規格四件套先寫清楚
規格(specification)不是工程師才需要的正式文件。對完全不會寫程式的人來說,規格是你給 AI 實習生的工作單。工作單越清楚,AI 越不容易自己腦補。這章使用「規格四件套」:目標、輸入、輸出、規則與邊界。四件套不是為了漂亮,而是為了讓你在開始寫 code 前,就能先抓到會翻車的地方。
分帳神器的目標是:輸入一群人的名字、每個人實際付了多少、每個人是否參與整趟活動,最後輸出最少轉帳建議。輸入包含人名、付款金額與參與狀態。輸出不是只列每個人差額,還要轉成「小志付小安 667 元」這種真人看得懂的句子。規則是總費用由參與者平均分攤,多付者收回、少付者補出。邊界則要先寫:金額不得為負、人名不能空白、金額用整數元、不能整除時把餘數依序補到前幾位,總和必須完全對得上。
最容易被忽略的是「有人先走」。如果小美只參與第一天,第二天的花費不該算她一份。初版專案可以先明確限制:本工具只處理同一批人共同參與的單段活動;有人先走先不做自動分段,但要在畫面上提醒「若參與天數不同,請分成多筆活動計算」。這不是逃避,而是切範圍。你可以先交付一個誠實的小工具,不要交付一個假裝全能卻算錯錢的工具。
把限制寫進規格,AI 才會知道不要亂加功能。純 vibe coder 常常把「我想要完整一點」丟給 AI,結果得到一坨看似豐富、其實沒有驗收標準的 code。黑帶做法是先說清楚這版做什麼,也說清楚這版不做什麼。範圍清楚,才有完成的可能。
const spec = {
goal: '共同出遊後,算出最少轉帳建議',
inputs: ['人名', '付款金額', '是否參與本次活動'],
outputs: ['每人應付', '每人差額', '轉帳建議'],
rules: [
'付款金額不可為負數',
'只處理同一批人共同參與的單段活動',
'總轉出金額必須等於總轉入金額'
]
};
console.log('規格目標:', spec.goal);
console.log('輸入數量:', spec.inputs.length);
console.log('第一條規則:', spec.rules[0]);
三、Act 2:把專案拆成五個可驗收里程碑
拆解(decomposition)不是把大任務切成很多待辦而已,而是每個待辦都要有驗收條件。沒有驗收條件的里程碑,只是願望清單。本章把分帳神器拆成五步:資料模型、核心計算、轉帳建議、輸入介面、錯誤處理與完成 polish。每一步都能單獨檢查,才適合交給 AI 做。
第一個里程碑是資料模型:用一個清單表示人,每個人有名字與付款金額。驗收條件是三筆範例資料能被讀出總金額與人數。第二個里程碑是核心計算:算總金額、平均金額與每人差額。驗收條件是範例「1200、800、0」得到總額 2000,三人平均分攤時差額接近 533、133、-667,且總差額為 0。第三個里程碑是轉帳建議:把差額轉成誰付誰。驗收條件是少付者補給多付者,金額加總等於欠款。
第四個里程碑才做輸入介面。這個順序很重要,因為畫面漂亮不代表邏輯正確。你先把食譜的味道調對,再擺盤。介面驗收條件是可以新增人、刪除人、修改金額、按下計算後看到結果。第五個里程碑是錯誤處理與完成 polish:空白姓名、負數、不是數字、全部金額為零,都要有清楚提示;結果文字要讓非工程師看得懂。
每個里程碑交給 AI 時,只請它做當前這一步。不要一次要求「請做完整分帳神器,順便好看一點」。那會讓 AI 同時處理太多事,錯了你也不知道錯在哪。黑帶節奏是:小任務、小驗收、小修正。這跟 ch07 學過的除錯很像,縮小範圍後,錯誤才會露出來。
const milestones = [
{ id: 1, name: '資料模型', pass: true },
{ id: 2, name: '核心計算', pass: true },
{ id: 3, name: '轉帳建議', pass: false },
{ id: 4, name: '輸入介面', pass: false },
{ id: 5, name: '錯誤處理', pass: false }
];
const next = milestones.find(m => !m.pass);
console.log('已完成:', milestones.filter(m => m.pass).map(m => m.name));
console.log('下一個該做:', next.name);
四、Act 3:AI 協作時,每一步都要帶測試 case
AI 協作不是把需求丟出去等成品,而是像帶實習生:你交代一小段工作,拿到結果後立刻驗收,再決定通過或退件。這裡的關鍵字是測試 case(test case),也就是一組你早就知道答案的輸入與輸出。沒有測試 case,你只能憑感覺看畫面;有測試 case,你可以抓出看起來正常但其實算錯的版本。
例如核心計算這一步,好的 prompt 不是「幫我寫計算分帳的 JS」。更好的寫法是:「請寫一個純 JavaScript 函式,輸入 people 陣列,每筆有 name 與 paid,輸出 total、share、balances。先不要做畫面。請用這三組測試:三人 1200/800/0、兩人 100/0、三人 100/100/100,並用 console.log 印出結果。」這段 prompt 限定了語言、輸入、輸出、不要做什麼,以及驗收資料。
AI 回來後,你先不要急著貼進頁面。先用測試 case 看輸出。三人 100/100/100 時,每人差額都應該是 0;兩人 100/0 時,A 應收 50、B 應付 50。若這兩個都對,再看複雜案例。測試順序要從簡單到複雜,因為簡單案例都錯,複雜案例沒有討論價值。
退件也要具體。不要說「怪怪的」,要說「在 100/0 的案例中,你輸出的轉帳方向相反。請保留函式介面,只修正債務人與債權人的配對邏輯,並重新列出三個測試結果。」這種退件語氣像是在改食譜的某一步,不是叫實習生重做整桌菜。你會發現,會退件的人比只會下 prompt 的人更接近真正完成專案。
function calcBalances(people) {
const total = people.reduce((sum, p) => sum + p.paid, 0);
const share = total / people.length;
return people.map(p => ({ name: p.name, balance: p.paid - share }));
}
const cases = [
[{ name: 'A', paid: 100 }, { name: 'B', paid: 0 }],
[{ name: 'A', paid: 100 }, { name: 'B', paid: 100 }, { name: 'C', paid: 100 }]
];
cases.forEach((test, index) => {
console.log('測試', index + 1, calcBalances(test));
});
五、Act 4:修掉那一元,然後把方法帶走
分帳神器最真實的 bug,是「除不盡的一元去哪了」。假設總金額 100 元、三個人平分。若 AI 直接用 100 / 3,會得到 33.3333。畫面如果四捨五入成每人 33 元,總共只收 99 元;如果每人 34 元,又變成 102 元。這不是小數點難看而已,而是錢對不起來。金錢工具的底線是總額守恆:收進來與付出去必須完全相等。
修法是先用整數元處理。總額 100、三人平分時,基本份額是 33 元,餘數是 1 元,所以第一個人分攤 34 元,另外兩人分攤 33 元。這樣 34 + 33 + 33 正好等於 100。你也可以在規格裡明寫:「餘數依人員清單順序分配給前幾位,畫面需提示分攤規則。」這不是唯一公平方式,但它可解釋、可重現、可驗收。
完成的定義也要白紙黑字寫下來。這個工具不是「畫面有出現結果」就算完成,而是四個條件同時成立:正常案例算得對、邊界案例有提示、總額守恆、非工程師看得懂轉帳句子。你可以把這四點放在最後驗收清單,逐項打勾。只要其中一點沒過,就回到對應里程碑修,不要用感覺通過。
專案完成後,要做復盤(retrospective)。不是寫心得,而是記錄下次可複用的做法。這次有效的 prompt 有三種:先限制範圍的 prompt、要求保留介面的修 bug prompt、要求列出測試結果的驗收 prompt。最容易翻車的是兩個地方:一開始範圍太大,以及最後沒有檢查總額守恆。把這些寫下來,你下一個專案會少走很多冤枉路。
你的回合可以從三個同級題目選一個。記帳工具:輸入品項與金額,輸出分類小計。抽籤工具:輸入名單與獎項,輸出不重複中獎者。倒數日工具:輸入事件與日期,輸出剩餘天數。起手包都一樣:先寫目標、輸入、輸出、規則與邊界;再拆五個里程碑;每個里程碑準備兩個正常 case 與兩個邊界 case;最後才要求 AI 做畫面。你不是在求 AI 幫忙,而是在指揮一個專案按順序完成。
function splitInteger(total, count) {
const base = Math.floor(total / count);
const remainder = total % count;
return Array.from({ length: count }, (_, i) => base + (i < remainder ? 1 : 0));
}
const shares = splitInteger(100, 3);
const check = shares.reduce((sum, n) => sum + n, 0);
console.log('分攤結果:', shares);
console.log('加總是否等於原金額:', check === 100);
專案駕駛艙:做出分帳神器
依序完成 5 個里程碑:選 prompt、看 AI 產出、挑測試 case、決定通過或退件。 操作方式:先選本關 prompt 或修法,再勾必測 case,最後按「驗收本關」。即時回饋會告訴你哪個 bug 逃掉了。
測試 case · 必測不能漏
分帳神器成品
5 關通過後,這個小工具會載入固定範例資料。你可以新增或刪除人,按「計算」驗收分攤 667 / 667 / 666 與轉帳建議。
純 vibe coder 會把「幫我做完整工具」丟給 AI,然後用眼睛看畫面像不像完成。你會先寫規格四件套,再把專案切成有驗收條件的里程碑。每次請 AI 做一小步時,你會附上測試 case,拿到結果先驗算再繼續。遇到錯誤時,你會退件到具體行為,例如方向反了、總額不守恆,而不是要求整包重做。
檢查一下這章
下一章預告
下一章會把全課工具箱收攏成 30 天出師計畫,讓你把第一個工具交到真人手上。