過去這一年,我一直在用 AI 幫我打造和維護一個真實的產品。
不是小型 demo。 不是週末玩玩的副專案。 不是只要看起來漂亮一次就好的頁面。
是一個真實的產品。
它是一套 AI 智能客服 SaaS。
SaaS 是「軟體即服務」的意思。 講白話,就是一種透過網站使用、不用安裝任何東西的工具。
這個產品大約有三萬行程式碼。
程式碼,是軟體產品背後的文字指令。 使用者看不到它,但產品能跑,就是靠它。
我的產品有資料庫、知識庫、快取、向量資料庫,還有一套 RAG 流程。
這聽起來有點技術,讓我用白話解釋。
資料庫存放一般資料。 知識庫存放給 AI 讀的文件和資訊。 快取是一種暫存,能讓產品跑得更快。 向量資料庫能讓 AI 用「語意」搜尋,而不只是比對一模一樣的字。 RAG 的意思是:AI 會先去查真實的資料,再根據那些資料來回答。
我不是傳統的工程師。
我比較像是一個產品人。
我在意的是很單純的事:
這個功能能不能用? 使用者看不看得懂? 產品會不會壞掉? 我自己一個人維護得了嗎?
一年下來,我學到一件很重要的事。
AI 真的能幫一個非工程師做出軟體。
但難的部分,不是叫 AI 寫程式。
難的是:你怎麼知道這段程式碼到底能不能信。
大多數人只盯著 prompt
當大家談 AI 寫程式,通常都在談 prompt。
prompt,就是你給 AI 的指令。
例如:
「扮演一位資深工程師。」 「一步一步想。」 「寫出乾淨的程式碼。」 「不要犯錯。」
這些 prompt 有幫助。
但它們不夠。
prompt 就像在跟一個人說:
「請好好做。」
聽起來很好。 但真實的產品,不是光靠拜託別人好好做就能蓋出來的。
真實的產品需要規則。
想想一間餐廳。
你不會只跟廚師說:「請做出好吃的菜。」
你還需要規則。
食材放在哪裡? 什麼東西一定要清洗? 什麼東西不能碰? 出餐前要怎麼檢查?
軟體也一樣。
在大公司裡,有很多人一起幫忙檢查產品。
一個人寫程式。 另一個人審程式。 測試人員檢查會不會壞。 系統跑自動化測試。 有一個團隊控制產品什麼時候上線。
但如果你是一個人在做,這些人都不存在。
沒有隊友幫你檢查。 沒有測試團隊。 沒有資深工程師盯著每一次改動。
所以我得自己打造一套安全系統。
不是更好的 prompt。
是一套能運作的流程。
AI 不是隨機出錯
我學到最大的一件事是這個:
AI 出錯,不是隨機的。
它常常一犯再犯,錯在同樣的地方。
它會在還沒讀真實檔案之前就先用猜的。 它改了一個地方,卻忘了另一個地方。 它說「完成了」,但真實的檔案根本沒變。 它專注在新功能上,忘了舊的規則。 有時候,它編輯一個很長的檔案,結果把結尾切掉了。
最後這一項非常危險。
我把它叫做截斷(truncation)。
截斷,是指一個檔案在它應該結束之前就被切掉了。
想像你在寫一封很長的訊息,但最後一段不見了。 前半看起來沒問題。 但結尾少了。
程式碼也會發生這種事。
AI 可能編輯一個很長的檔案。 產品照樣打得開。 頁面照樣看起來正常。 主要功能照樣能用。
所以你以為一切都好。
但在檔案接近結尾的某個地方,有東西不見了。
可能是一個函數(function)。 函數,是一小段做某一件事的程式碼。
可能是一段重要的收尾。 可能是一條使用者不是每天會碰到的路徑。
所以產品不會馬上壞。
它會晚一點才壞。
也許再三次更新之後。 也許再五次更新之後。
某一天,使用者點了某個東西,產品就掛了。
真正的麻煩這時才開始。
因為這個錯不是今天犯的。 是好幾個版本以前犯的。
這比一個明顯的錯誤更糟。
如果產品馬上壞,你知道該往哪裡找。
但如果它過很久才壞,你可能會怪錯對象。
你可能以為是資料庫的問題。 或是伺服器。 或是某個套件更新。 或是使用者資料。
但真正的問題,是一個更早之前就被悄悄切掉的檔案。
這件事教會我一件事:
AI 最危險的錯誤,不一定是你當下就看得到的那個。
有時候,最危險的錯誤,是今天看起來沒事、之後才壞的那個。
我那套簡單的 AI 寫程式規則
在踩過很多次雷之後,我建立了一套簡單的系統。
我把它叫做:
D / A / B / GO / S / P
這些不是什麼魔法咒語。
它們只是規則。
它們告訴 AI:什麼時候該讀、什麼時候該討論、什麼時候該改、什麼時候該檢查、什麼時候該存檔。
D 代表下載真實的專案
D 代表把真實的專案下載到沙盒(sandbox)裡。
沙盒,是一個安全的測試空間。 講白話,就是一個讓 AI 可以工作、又不會弄壞真實產品的地方。
這條規則之所以重要,是因為 AI 很愛猜。
如果我跟 AI 說:「我的產品有知識庫和向量資料庫」,它可能會想像出一套常見的設定。
但我的產品不是一個想像。 它是一個有真實檔案的真實產品。
所以第一條規則很簡單:
不要猜。 去看真實的檔案。
A 代表先問
A 代表先問。
在 AI 改任何東西之前,它必須先說明它的理解。
問題是什麼? 可能會影響哪些檔案? 有什麼地方不確定? 它打算怎麼做?
這一步對新手特別重要。
很多新手向 AI 求助,AI 就馬上開始改。
那感覺很快。
但快不一定好。
如果 AI 誤解了問題,它會很快地把錯的事情做出來。
所以我會讓 AI 先講。
討論之前,不准動手改。
B 代表把改動清單拆開列出來
B 代表把計畫拆開列出來。
在 AI 改任何東西之前,它必須列出:
它要改哪些檔案。 每個檔案它要改什麼。 它不會去碰什麼。 可能有什麼風險。
然後我確認。
這能防止 AI 做過頭。
有時候你叫 AI 修一顆小按鈕。 它把整個頁面重寫了。
有時候你叫它改一句話。 它把整個流程都改了。
AI 不一定是偷懶。
有時候它是太積極。
所以我把規則講清楚:
沒有確認過的清單,就不准動工。
GO 代表開始
GO 代表 AI 可以開始改了。
但只能在確認過的範圍內。
如果 AI 在工作途中發現新的問題,它必須停下來問我。
它不能自己默默改更多東西。
這樣反而省時間。
慢的不是討論。
慢的是收拾一個本來就不該發生的錯誤改動。
S 代表自我檢查
S 是最重要的部分。
S 代表自我檢查。
但不是這種自我檢查:
「我全部檢查過了,看起來沒問題。」
這句話幾乎沒有用。
真正的自我檢查,必須去檢查那些 AI 常常出錯的地方。
例如:
真實的檔案真的有變嗎? 有沒有一個大檔案被悄悄地沒存到? 檔案結尾有沒有被切掉? 檔案長度看起來合理嗎? 檔案的最後一段有沒有正常收尾? 有沒有舊的名稱殘留在某個地方? 有沒有把可見文字直接寫進 HTML? 翻譯檔有沒有更新? 權限、快取、或資料同步有沒有被漏掉?
HTML,是一個網頁的結構。 如果可見文字直接寫在 HTML 裡,之後會變得很難翻譯和維護。
翻譯檔,是存放不同語言文字的檔案。
在我的產品裡,可見文字一律要走 i18n。
i18n 是國際化(internationalization)的意思。 講白話,就是一套管理不同語言的系統。
例如,如果產品支援英文和中文,每一句可見的句子都應該被好好管理。 我不希望有隨便的文字被硬寫(hardcode)進頁面裡。
硬寫(hardcoded),是指直接寫死在某一個地方、之後很難改的寫法。
這正是 AI 在忙著做功能的時候,可能會忘記的那種規則。
所以我把它放進自我檢查這一步。
P 代表推送一個乾淨的版本
P 代表推送到 Git。
Git,是程式碼的版本歷史系統。
commit 是一個被存下來的版本。
push 是把那個存好的版本上傳。
我不希望 AI 把每一個小小的檔案改動,一個一個分開推。
那會讓歷史變得很亂。
我要的是:一個清楚的任務,配一個乾淨的 commit。
為什麼?
因為當之後有東西壞掉,我需要知道是哪一次改動造成的。
乾淨的歷史能幫我除錯(debug)。
除錯,就是找出並修好問題的成因。
那個差點騙到我的錯誤
有一次,我在跟 AI 討論,要不要在我的自我檢查清單裡再加兩項。
一項是關於 async 和 await。
async 的意思是:程式可以一邊等、一邊去做別的事。 await 的意思是:程式應該等某件事完成,再往下走。
另一項是關於快取和 embedding 更新。
embedding 的意思是:把文字轉成數字,讓 AI 更能用語意去搜尋。
AI 告訴我,這些檢查很重要。
它說我的產品有 async 程式碼、有快取、有向量資料庫、有知識庫。 所以我應該小心。
聽起來很聰明。
聽起來很專業。
聽起來合理到,我差點開始懷疑我自己。
也許我真的有這些 bug,只是我還不知道。
然後我叫 AI 停止猜測,去讀真實的程式碼。
結果很清楚。
那些問題早就處理好了。
快取在該清的地方都已經清了。 embedding 也早就跟著資料一起更新了。 我甚至在程式碼裡留了註解,解釋為什麼某些快取不應該被清。
所以 AI 並沒有找到一個隱藏的問題。
它是在讀真實檔案之前,就先製造了懷疑。
這是 AI 最危險的事情之一。
它不只會寫出錯的程式碼。
它還會用很有自信的口氣講話,讓你去懷疑一個本來就正確的東西。
解法很簡單:
不要讓 AI 用猜的。 逼它去檢查真實的檔案。
我那套協定的精簡版
這裡是我那份 AI 寫程式約定的簡單版本。
你可以複製它,再依照你自己的專案修改。
開始:
把專案下載到沙盒裡。
所有改動都在沙盒裡進行,不要直接動正式環境。
核心規則:
- 只改我明確要求的部分。
- 想優化什麼,先說明、等我確認。
- 有任何不確定,先問。
- 不要猜系統。
- 如果檔案被切掉、或需要補回缺少的程式碼,先跟原始的 Git 版本比對。
- 不要憑空捏造缺少的程式碼。
- 在新增或更新套件之前,先說明原因、等確認。
i18n 規則:
- 所有可見文字一律走翻譯系統。
- 不要把可見文字硬寫進 HTML。
- 所有啟用中的語言都要補上對應的翻譯 key。
- 既有文字改翻譯檔,不要直接動 HTML。
工具規則:
- 新檔案:用建立檔案的工具。
- 既有小檔(50 KB 以下):用針對性的差異編輯。
- 既有大檔(50 KB 以上):不要整檔重寫。
- 大量追加(超過 50 行):用安全的追加方式。
- 改完之後,去檢查 disk 上的真實檔案。
- 不要只相信工具說的話。
協定:
D —— 把真實專案下載到沙盒。
A —— 動檔案之前先問、先討論。
B —— 把改動清單拆開列出來,等確認。
GO —— 確認後才開始。
S —— 自我檢查真實檔案、檔案結尾、行數、diff、舊引用、i18n、權限、快取、資料同步。
P —— 檢查通過後,推一個乾淨的 commit。
這套不完美。
它只是好用。
每一條規則,都來自一次真實的失敗。
這對新手意味著什麼
AI 正在改變「誰能做軟體」這件事。
以前,如果你不會寫程式,你大概就做不出一個真實的軟體產品。
現在,AI 能幫你起步。
你可以做一個網站。 一個工具。 一個內部系統。 甚至可能是一個小型的 SaaS 產品。
這是一個很大的改變。
但風險並沒有消失。
它只是換了一個形狀。
以前,你最大的問題是:
「我不會寫程式。」
現在,你最大的問題可能變成:
「AI 寫了程式碼,但我不知道它安不安全。」
這就是那個新的技能。
不只是叫 AI 去創造。
而是懂得怎麼檢查 AI 創造出來的東西。
你不需要一夜之間變成資深工程師。
但你需要懂這件事:
「完成」不等於「可靠」。
AI 說「完成了」,不代表真實的檔案有變。 頁面打得開,不代表系統是完整的。 功能成功跑一次,不代表它可以安心上線(ship)。
ship 的意思是:把產品或功能釋出給真實的使用者。
如果你是新手,這是我希望你記住的教訓:
不要去追求那個完美的 prompt。
去建立你自己的規則。
每次 AI 犯錯,就把它寫下來。 如果同樣的錯再發生一次,就把它變成一個檢查點。 久了之後,你的這些檢查點,就會變成你的安全系統。
短期來看,prompt 寫得比較好的人,也許跑得比較快。
長期來看,流程比較好的人,會做出更可靠的產品。
未來不會只屬於工程師。
它也會屬於那些懂問題、懂使用者、並且懂得謹慎使用 AI 的人。
真正的差距,不會是在「用 AI 的人」和「不用 AI 的人」之間。
真正的差距,會是在「只會叫 AI 做東西的人」和「懂得怎麼判斷 AI 做出來的東西能不能信的人」之間。
補一句:這些心得,都來自我維護自己那套 AI 智能客服產品 Chungtair 的過程。
產品官網:chungtair.com