我們把 AI 寫 PLC 的準確率量出來了
「AI 自動生成 PLC 程式,效率提升 10 倍。」——每一家都這樣寫。沒有一家給數字。
原因很簡單:給了數字就要負責。而且一旦你認真去量,量出來的數字通常不好看。
這篇是我們的量測結果,包含不好看的那幾項。也包含兩段我不太願意寫、但必須寫的過程:我們的量尺本身壞了,而我差一點就照著那個壞掉的數字去調整整個引擎;以及後來我們花了一整輪基準測試,證明了一件對自己不利的事。
為什麼要自己做基準測試
在這之前,我們每改一次提示詞、每加一條規則,只能憑感覺說「好像變好了」。
而且在 PLC 這個領域,「好像」是不夠的。你不會想在客戶的曝氣池上、在別人的產線上,發現我們的「好像」是錯的。
學術界有 benchmark(Agents4PLC 用了 23 題、LLM4PLC 有自己的題庫),但那些題目跟台灣的現場長得不一樣。沒有人在 benchmark 裡放「養殖池溶氧感測器斷線時,水車該開還是該關」這種題目——而那正是我們客戶每天面對的東西。
20 題,全部來自真實案場
題目分成五組,全部是易歐特實際做過的案型:
| 組別 | 題目 |
|---|---|
| 基本功(5 題) | 馬達啟停自保持、正反轉互鎖、液位兩點控制、輸送帶計數分揀、紅綠燈時序 |
| 廢水處理(4 題) | 曝氣池溶氧控制、pH 加藥、三台提升泵交替運轉、污泥排放定時程序 |
| 淨水 / 純水(3 題) | 多介質過濾器自動反洗、RO 產水導電度監控、原水槽與產水槽連動 |
| 溫室環控(3 題) | 降溫序列與天窗連動、定時灌溉、CO2 施肥控制 |
| 水產養殖(3 題) | 溶氧控制、自動投餌、電子圍籬 |
| 跨品牌(2 題) | 同樣的需求換成西門子 S7-1200、台達 DVP |
每一題都跑完整的驗證管線——跟客戶按下「產生」時走的是同一條路,一步都沒有簡化。
如果我們為了跑得快而簡化了任何一步,量出來的數字就是假的。而假的數字比沒有數字更危險——它會讓你對錯誤的方向充滿信心。
四個維度,以及為什麼不比對「標準答案」
最直覺的做法是準備標準答案來比對。但 PLC 沒有唯一正確寫法。十個工程師會寫出十種都對的程式:有人用 SET/RST,有人用 OR 自保持;有人拆成三個 Rung,有人寫成一個 CASE 狀態機。拿標準答案去比,只會量出「像不像我」,不是「對不對」。
所以我們比對的是「該有的性質」:
| 維度 | 怎麼量 |
|---|---|
| ① 編譯通過 | 送進 matiec(真的 IEC 61131-3 編譯器)實際編譯。編不過就把錯誤訊息餵回去請 AI 修,最多三輪。 |
| ② 行為測試 | 編成執行檔,在虛擬 PLC 上驅動 I/O、模擬時間、驗證輸出。「編得過」不等於「做的事是對的」。 |
| ③ 品牌白名單 | 拿該品牌的指令白名單,逐行比對每一個助記碼。有沒有把西門子的 MOVE 寫進三菱程式。 |
| ④ 結構正確性 | 這一題「該成立的規則」有沒有被違反。馬達啟停題如果「缺少自保持」觸發了,那就是錯了——不管它寫得多漂亮。 |
然後定義一個最嚴格、也最誠實的數字:「整體全對」= 三項全部通過才算。
第一次跑出來的結果
| 指標 | 結果 |
|---|---|
| 編譯通過率 | 85% |
| 品牌指令乾淨 | 95% |
| 結構正確性 | 50% |
| 整體全對 | 40% |
結構正確性只有一半。最常被違反的是「缺少自保持」——20 題裡有 6 題觸發。
我當下的反應是:那就去加強提示詞、多給自保持的範例、把規則寫得更兇。
然後我停下來,去看了實際的程式碼
「缺少自保持」這條規則,把所有沒有把自己 OR 回來的 M 繼電器全部列為可疑。
問題是:一支稍微大一點的程式裡,大部分的 M 根本不該自保持。它們是每次掃描重算的旗標——「訊號有效」「警報成立」「條件符合」「在自動模式」。這些東西本來就該跟著條件走,自保持反而是錯的。
結果:這條規則在任何複雜一點的程式上幾乎必定觸發。它量的不是 AI 的錯誤率,是它自己的誤報率。
如果我沒有停下來看程式碼,接下來會發生什麼事?
我會針對「自保持」瘋狂加強提示詞。AI 會學乖,開始把每一個 M 都 OR 回來——包括那些根本不該自保持的旗標。於是「警報成立」這個旗標一旦亮起就永遠不會熄滅,「訊號有效」的判斷會卡在某個狀態下不再更新。
我會用一個壞掉的量尺,把一個原本正常的引擎,調成一個真的有問題的引擎。而分數還會變得很漂亮。
這就是為什麼我說假數字比沒有數字更危險。
修好量尺
把規則改成只抓真正的「啟動鈕樣式」:這個 M 所在的那一段,是由 X 接點(實體按鈕)起始的,而且整段裡沒有把自己 OR 回來 → 放開按鈕就會消失 = 寸動。由感測器比較、其他 M 運算出來的旗標,不在此列。
然後用三個案例驗證這條規則本身:
A. 真的缺自保持(按鈕直接驅動 M0,沒 OR 自己) → 必須抓到 ✅ B. 正確的自保持寫法 → 不可誤報 ✅ C. 由其他 M 運算出來的旗標 → 不可誤報 ✅
還有第二個量測錯誤,更隱蔽
我們的產品在把程式交給客戶之前,會自動訂正機械性問題(雙線圈、計時器編號重複、指令借錯牌),並且重新編譯驗證過。
但基準測試量的是訂正之前的原始輸出。
量錯了對象,再漂亮的數字也沒有意義。客戶拿到的不是那份東西。
兩個都修好之後,重跑一次。
真實的數字
| 指標 | 修正前 | 修正後 |
|---|---|---|
| 編譯通過率 | 85% | 95% |
| 品牌指令乾淨 | 95% | 100% |
| 結構正確性 | 50% | 70% |
| 整體全對 | 40% | 65% |
提升來自三件事:把提示詞從瀏覽器搬進核心(以前核心連「自己怎麼問」都不掌握)、寫入八條現場鐵則、加上實案範例庫(錯誤寫法 vs 正確寫法的對照),以及編譯回修從 1 輪加到 3 輪。
但先講清楚這些數字的精度
我們後來又跑了三輪。四輪下來:
· 編譯通過率:80~95%
· 品牌指令乾淨:100%(四輪都是)
· 結構正確性:65~70%
· 整體全對:55~65%
這就是小樣本基準的極限,而我不打算假裝它有它沒有的精度。 所以我們對外公布的是區間,不是單點——挑最漂亮的那一次貼出來,是在騙人。
然後我們花了一整輪,證明了一件對自己不利的事
行為測試的覆蓋率一開始只有 55%——有將近一半的程式,我們其實跑不起來。查下去才發現原因跟計時器毫無關係:
matiec 會把識別字全部轉成大寫(
X000_Start → X000_START),但 AI 設計測試案例時用的是原本的大小寫。
測試骨架產出 inst.X000_Start.value,gcc 找不到這個成員 → 編譯失敗 → 整組行為測試被丟掉。我之所以查了很久,是因為診斷訊息本身有 bug:它會試兩種型別名稱,但只留下「最後一次」的錯誤——也就是那個注定失敗的備用嘗試。真正的錯誤被自己的診斷蓋掉了。
還有第二個,更難堪:
停止鈕、過載是常閉接點——正常時是 ON。但測試台把所有變數初始化成 0,等於「過載跳脫中 + 停止鈕被按住」。
於是一支失效安全做得完全正確的程式,馬達永遠啟動不了,三個測試全部失敗。
我們一邊要求 AI 用常閉接點,一邊用一個假設常開的測試台去考它。 這比 AI 寫錯還糟——它讓正確的答案看起來是錯的。而如果我沒查清楚就去「修」那支程式,我會親手把斷線安全改掉。
兩個都修好之後,覆蓋率從 55% 拉到 80%。行為測試第一次變成一個有意義的數字。
然後我們讓 AI 自己修
做法是:測試沒過 → 讓 AI 當裁判,判斷是「程式錯」還是「測試錯」 → 如果是程式錯,讓它提出修正 → 修正必須通過三道守門員(不可弄壞安全邏輯、必須還編得過、重跑測試必須真的變好),任一道沒過就整個回退。
結果:
| 審判結果 | 次數 |
|---|---|
| 判定「AI 程式真的寫錯」 | 10 |
| 判定「AI 出的考題寫錯」 | 5 |
| → 判定程式錯,而且真的修好了 | 2 |
| → 判定程式錯,但修正被守門員擋下 | 8 |
關鍵在於:那 8 次回退,是被哪一道守門員擋的?
| 守門員 | 次數 | 意義 |
|---|---|---|
| 修了也沒變好 | 7 | 模型能力的天花板 |
| 回了說明文字不是程式 | 1 | 格式問題 |
| 編譯不過 | 0 | — |
| 想弱化安全邏輯 | 0 | — |
如果回退是因為「編譯不過」,那是工程問題——我加一輪編譯器回修就能救。
如果是因為「它想弱化安全來讓測試通過」,那是守門員立功,我該慶祝。
但它是「修了也沒變好」。7 次都是。
意思是:AI 診斷得出問題,提出的修正語法正確、編譯得過、也沒動安全邏輯——然後跑測試,沒有變好。
我們甚至懷疑是不是它的輸出被截斷(修正一支 400 行的程式需要很多 token),於是把輸出上限加倍再跑一輪。一點幫助都沒有。
結論
這不是提示詞的問題,不是模型不夠大的問題,也不是多跑幾輪能解決的。這是今天這一代模型的能力邊界。
所以我們不會再往這個方向加輪數。那是拿客戶的點數去買一個已經被證明無效的東西。
行為測試回修迴圈最後的實際產出是 2/10,把行為測試通過率從 17.7% 拉到 22.9%。有用,但很有限。
而這個發現本身,比多榨出來的那幾個百分點值錢得多——因為它精確地說明了為什麼四層驗證必須存在,以及為什麼「必須由合格工程師審查」不是一句免責聲明。
那是我們自己量出來的事實。
AI 寫 PLC 的錯誤,九成不是「不會寫程式」,而是「沒在現場待過」。
它不知道停止鈕要用常閉、不知道 4 小時不能寫成
K144000(16 位元定時器上限 K32767)、不知道溶氧感測器斷線時要把水車「打開」而不是關掉。這不是能力問題,是經驗問題。而經驗是可以用範例傳遞的。
那錯掉的 35%,錯在哪
這是這篇文章最重要的一段。
最難看的一題:錯的是我們,不是 AI
原本我們在這裡舉了一個「AI 犯的安全錯誤」當例子。後來發現:AI 寫的是對的,是我們的規則寫反了。
當時我們展示了一段 AI 產出的程式,說它錯了:
LD X002 (* 過載保護,實體常閉接線 *) OR M1 OUT M1 (* 過載故障鎖定 *)
我們的規則說:「停止、急停、過載一律用 ANI / LDI 讀取,這才是斷線安全。」
我們的 linter 照著這條規則,把上面這段標成紅色錯誤。
那條規則是反的。
常閉接線的過載保護,沒跳脫的時候電路是導通的 → PLC 輸入 X002 = ON(1)。
跳脫、或線斷掉 → X002 = OFF(0)。
所以「允許運轉」的條件必須在 X002 = 1 時成立 → 這正是常開接點(
AND X002)。如果照我們原本的規則寫
ANI X002:X002 平常就是 1,條件恆為 false → 馬達永遠啟動不了。口訣:實體常閉 → 程式常開。接線與程式的接點型式是相反的。
真正危險的不是「啟動不了」
設備啟動不了,是個很吵的錯誤——試車第一天就會被發現。
危險的是下一步:現場為了讓設備能動,最直覺的做法就是把停止鈕改接成常開。
從那一刻起,線斷掉 = 訊號恆為 OFF = 程式判定「沒人按停止」= 停不下來。失效安全消失了,而且沒有人會發現,因為設備「看起來完全正常」。
一個接點寫反,毀掉的是整套安全設計。而我們把這個錯誤寫進了提示詞、寫進了 few-shot 範例庫(還打了 ✅)、寫進了 linter,以及四篇公開的技術文章裡。模型不是笨——它是照著我們教的寫。
這件事怎麼被抓到的
不是靠人看程式碼。是靠行為測試。
我們的測試平台會把安全輸入初始化成 ON(常閉接線的正常狀態——這一塊我們一開始就寫對了)。於是規則叫 AI 寫 ANI,測試把輸入設成 1,馬達永遠不動,測試必定失敗。
兩個相反的假設在系統裡並存了很久,而測試分數一直在替我們付這個帳。我們卻把失敗歸因成「AI 修不好問題」。
行為測試通過率、整體正確率,有多少是模型的問題、有多少是我們自己造成的,舊數據分不出來。
修完之後重跑,分數反而更低
我們以為修好規則、重跑一輪,數字就會回來。結果是:結構正確 55%、整體全對 40%——比作廢的舊數據還難看。
照理說應該高興才對:這才是「誠實的低分」。但有一個地方不對勁。
一支被編成執行檔、在虛擬 PLC 上實際跑過「按下啟動 → 放開按鈕 → 馬達仍在運轉」並且通過的程式,不可能缺少自保持。
不是程式錯了。是量尺在亂叫。
查下去,量尺有三個洞:
一、把「猜測」當成「事實」在扣分。
那條規則的完整標題是「狀態繼電器可能缺少自保持」,說明裡還寫著「若本來就是寸動,可忽略此提醒」。它是一條啟發式的警告(warn),不是確定性的錯誤(err)——但計分程式一視同仁,照扣不誤。
它對這種寫法誤報:
LD X010 (* 手動/自動 選擇開關 —— 維持型,撥過去就一直保持 *) OUT M10 (* 自動模式旗標 *)
選擇開關不是瞬時按鈕,它本來就不需要自保持。但規則看到「X 接點驅動 M 線圈、沒有 OR 回來」就開叫。
二、一個我們自己剛剛親手弄壞的檢查項。
修正安全規則時,我們把它的標題從「安全訊號用了常開接點」改成「…反相接點」。但忘了同步基準測試裡的檢查清單。於是整套基準最重要的那個安全檢查,變成一個永遠不會觸發的死檢查——而分數看起來完全正常。
沒有量尺,你知道自己不知道。
量尺壞了還在報數字,你會以為自己知道。
三、一個 JSON 解析失敗被算成「品牌指令混用」。
有一題的輸出爆掉了,解析不出來。檢查器對著一堆殘骸判定「這支程式混用了他牌指令」。那不是模型的錯,那是我們在對著空氣打分數。
三個修正
1. warn 只有在行為測試也失敗時才採信。
行為測試是真的把程式編譯成執行檔、灌進虛擬 PLC 跑過的。當一條猜測性的規則和一個真的跑起來的測試打架,該輸的是規則。
2. 加上量尺自檢(auditRuler)。
每次載入時自動比對:基準測試裡的每一個檢查項,是不是真的對得上某一條存在的規則。對不上就在啟動 log 裡大聲叫。這次是規則改名讓檢查項無聲死掉——下次不會再無聲。
3. 檢查器學會辨認維持型開關。
從 IO 表判斷「選擇 / 切換 / 模式 / 手動自動」這類開關,不再對它們要求自保持。這個誤報原本也會出現在客戶面前。
量尺修好之後的真實數字
| 指標 | 舊(已作廢) | 壞量尺那輪 | 修正後 |
|---|---|---|---|
| 通過真實編譯器 | 80~95% | 80% | 85% |
| 品牌指令混用 | 0% | 5% | 0% |
| 結構正確 | 65~70% | 55% | 80% |
| 整體全對 | 55~65% | 40% | 65% |
| 解析失敗 | — | 1 題 | 0 題 |
失分的 4 題,每一項都說得出是什麼:1 題真的把安全訊號寫成反相接點(那個復活的安全檢查抓到了一個真的錯誤)、1 題雙線圈、2 題真的缺自保持——而且這 2 題的行為測試也同時失敗,兩邊互相佐證。另有 3 題編譯不過。
審判迴圈判定「程式真的寫錯」5 次,4 次回退全部是「修了也沒變好」。
有趣的是它也判定「測試寫錯」5 次——次數一樣多。連我們的測試都不見得是對的。
那我們還是不自動修安全問題
這次的事件反而讓這個原則更站得住腳。
停止鈕該怎麼接、程式該用哪種接點,取決於你現場的實體接線。我們不知道,所以我們不猜——我們只把它標出來給你看。
一個「被自動修好」的安全問題,比一個「被明確標示」的安全問題危險十倍。因為前者會讓工程師停止思考。他看到綠色勾勾就簽名了。
這一次,停止思考的是我們。標示出來的那道防線,是我們自己也需要的。
所以我們的分工是:
| 問題類型 | 我們怎麼做 |
|---|---|
| 機械性(雙線圈、計時器編號重複、指令借錯牌) | 自動訂正,並重新編譯驗證。改壞了自動回退。 |
| 安全性(接點型式、互鎖、時基、急停) | 絕不自動修。找出來、講清楚、告訴你為什麼,決定權在你手上。 |
我們自己的兩個洞
既然要誠實,就一起講完。
洞一:行為測試覆蓋 80%,還有 20% 跑不起來
「把程式真的跑起來」這一層,是我們跟同業最大的差異。修好大小寫與常閉初值那兩個 bug 之後,覆蓋率從 55% 拉到 80%。
但仍有 20% 的程式,測試骨架建不出來——這代表這些程式我們沒有「真的跑起來驗證過」,它們只通過了編譯、規範檢查與規則檢查。這是我們自己工具的限制,不是 AI 的問題,而我們還在修。
洞二:西門子的 SCL 編譯通過率較低
matiec 檢查的是標準的 IEC 61131-3 ST。西門子的 SCL 有自己的擴充語法(REGION、雙引號識別字、%I0.0 位址格式),編不過不必然代表 TIA Portal 不接受。
所以我們對西門子的判定是保守的:「通過」講得肯定,「沒過」講得保守。不要嚇到客戶,也不要騙他。
這套基準測試的意義
它讓「準確率」從一句話術,變成一個可以被證明、可以被改進、也可以被推翻的數字。
之後我們每改一次核心——加一條規則、換一個提示詞、調一個參數——就跑一次這 20 題。變好還是變差,跑完就知道。不用再猜,也不用再賭。
跑一輪要花我們大約 US$3 的模型費用。這筆錢不跟客戶收。它買的不是程式碼,是「我們知道自己多準」。
通過這 20 題不代表 AI 會寫 PLC。它代表的是:在這 20 種我們見過的情況下,它沒有犯我們知道的錯。
這是有意義的,但不要拿它當安全保證。
任何 AI 產出的 PLC 程式,上線前都必須由合格工程師審查並實機驗證。安全功能(急停、互鎖)必須以硬體安全迴路實現,不能只靠程式邏輯。
這不是免責聲明。這是我們做這行的規矩。
自己試一次,看看它會標出什麼
用中文說出你的控制需求,立即產生階梯圖與 ST。每一份都會跑過編譯器、PLCopen 規範、行為測試與現場規則——包括那些我們刻意不替你修、只標示出來的安全問題。
免費試用 AI PLC 工具 →免費會員每月 15 點 · 不需信用卡 · 產生失敗不扣點
這種事,交給真的在做工程的人
易歐特科技不只是賣工具。廢水處理、淨水純水、溫室環控、水產養殖、雲端監控——10 年以上、100+ 完成案例。從盤面設計、程式撰寫到現場試車,可以整案委託。
提出工程需求 →免費評估 · 7 個工作天內報價
延伸閱讀:我們怎麼驗證 AI 產生的 PLC 程式:四層管線 · 自保持電路與斷線安全 · 4-20mA:為什麼是 4 不是 0