iT邦幫忙

2026 iThome 鐵人賽

DAY 2
0
AI Engineering

一天一個 PR,讓我告訴你嵌入式開發的殘酷:如何為 AI Agent 建立可信的工程閉環系列 第 2

Day 2 - Test PASS,但只跑了三分之一:揭穿自動化測試的假成功

  • 分享至 

  • xImage
  •  

系列說明

本系列大部分 PR 來自私人或公司專案,部分程式碼、環境設定與實作細節不便公開。

我只能保證文中提到的 PR 與問題皆為真實案例,但會經過必要的匿名化與內容調整。

本系列主要分享問題如何被發現、背後的思考方式,以及解法如何形成,不會深入討論完整實作與部署細節,敬請見諒。

Today’s Change

  • Change Ref: PR #3 — fix(wifi_llapi): 強化 full run 指令解析與報告輸出

  • Issue: 單一 UART command 可以正常執行,但進入 Full Run 後,開始出現多命令遺失、Readback 執行錯誤、RC 判斷錯誤與報告汙染。

  • Root Cause: Test Case、Shell Command、UART Transcript 與執行結果全都混在普通字串裡,系統只能不斷使用 Regex 猜測真正的邊界。

  • Solution: 強化 Command Extraction、多命令執行與 Readback Fallback;修正 serialwrap RC 擷取;加入 YAML Command Audit 與 Report Sanitization。

  • Evidence: 完成 415 個官方 Case 的實機 Full Run,Regression Tests 由 38 個增加至 46 個。


真的閉環了嗎?

上一篇,我們終於讓 Agent 可以透過 serialwrap 對 UART 下 Command,再從 minicom log 裡取得執行結果。

不需要每次重新教 Agent:

  • minicom 位於哪一個 tmux pane。

  • send-keys 要怎麼下。

  • Log 應該從哪裡切。

  • 哪一段 Output 才屬於剛才執行的 Command。

實際用起來也真的不錯。

Agent 終於可以自己到板子上找證據,不再只拿 Source Code 證明自己腦補出來的 Runtime 行為。

這次好像真的閉環了。

有了可以反覆運作的環境,大膽的想法自然會愈來愈多。

那麼,把它接進一套真正的測試流程,看起來似乎也是非常合理的一件事。

嗯……但是。

就是那個 But

人類最常犯的錯誤,就是看到一個東西能跑一次,便開始覺得它可以跑四百次。

四百次……

四百次……

四百次……

(迴音)


把 serialwrap 接進測試流程

搞測試這件事,從來都是吃力不討好。

看起來好像做了很多事,但最後又很像什麼都沒有做。

在反覆追查、驗證、確認、核實一大堆連我自己都不知道到底對不對的 HAL(Hardware Abstraction Layer,硬體抽象層)時,除了無法獲得任何多巴胺,還會確實喚醒我的懶懶魂。

「凡我所不欲,悉使 Agent。」

這是我在 AI 時代最信奉的一句座右銘。

以前遇到這種工作,我大概會:

  1. 寫一個 Bash Script 做 Parser。

  2. 寫一個 minicom Script 執行驗證。

  3. 一邊看 Code,一邊處理各種例外。

  4. 最後發現九成的 Case 本身就是例外。

花了大半個月寫出來的工具,可能還不如直接 K Code,一條一條硬啃。

這是駑鈍如我,在多年硬幹之後得到的普通 RD 沒用心得。

但現在不一樣了。

我有 Agent、有 Gemini、有 serialwrap。

我可以對 Agent 說:

「工具給你,馬上測。」

然後 Agent 就會告訴我:

「結果出來了,87 條 Pass。」

隔天再跑一次:

「結果出來了,78 條 Pass。」

再跑一次:

「結果出來了,8 條 Pass。」

最後一次:

「結果出來了,全數 Pass。」

老兄,不是這樣的吧?

同一條 Case 可以這樣過了又掛、掛了又過嗎?

這份測試結果到底還能不能信?

聰明如你,當然也想到了那句話:

用魔法打敗魔法。
用檢討逼你就範。
用工具強迫你說實話。

出來吧,Harness!我還你原形!

這就是 TestPilot。

一套用來執行 Embedded Test Case 的測試框架。

它會把原本散落在 Excel、YAML 與測試文件裡的內容整理成執行流程,再透過不同的 Transport 操作 DUT、STA 或其他測試設備。

大致上的路徑如下:

Excel / YAML Case
        ↓
TestPilot Orchestrator
        ↓
HALAPI Plugin
        ↓
serialwrap Transport
        ↓
UART / DUT
        ↓
Result Parser
        ↓
Excel Report

單獨看每一層都很合理。

Case 告訴 TestPilot 要做什麼,Plugin 把內容轉成 Command,serialwrap 負責送進 UART,最後再把結果寫回 Report。

執行過程不再讓 Agent 臨場自由發揮。

妥妥地 Vibe 出了一整套自動化測試框架。

Perfect。

直到 Full Run 開始。

FullRun


測試文件不是 Shell Script

既有的 415 條 Case,全數來自 Excel 與各種充滿歷史情懷的測試文件,再由 Agent 協助轉成逐 Case 的 YAML。

這些文件有一個共通點:

它們是寫給人看的,不是寫給 Parser 看的。

例如:

Set all radios transmit power to 50:

ubus-cli WiFi.Radio.1.TransmitPower=50;
ubus-cli WiFi.Radio.2.TransmitPower=50;
ubus-cli WiFi.Radio.3.TransmitPower=50

看到這裡,你知道、我知道,Agent 也知道要執行三條 Command。

但 Parser 不知道。

Plugin 只會從裡面找到第一個看起來可以執行的 Command,清掉前面的自然語言,再交給 serialwrap。

於是,它很認真地執行了:

ubus-cli WiFi.Radio.1.TransmitPower=50

Test PASS。

更精彩的是,第一條 Command 確實成功,Return Code 也是 0,所以整條 Flow 仍然會回報 Success。

只完成了三分之一的工作,卻產出了一份完整的成功報告。

你問我 Radio 2 跟 Radio 3 去哪裡了?

阿災。

可能放假去了吧。

321cmd


Verify,不是幫 DUT 改答案

另一類 Case 則會長成這樣:

Verify Associated Device Capabilities

ubus-cli WiFi.AccessPoint.1.AssociatedDevice.1.Capabilities="RRM,BTM,PMF"

人類看得懂它的真正意思:

查詢 DUT 回報的 Capabilities,確認結果是否符合預期。

但 Parser 看到的,是一條語法完整、可以直接執行的 Setter。

於是,它真的把答案寫進 DUT(Device Under Test,待測設備),再確認答案是否正確。

Good job!

這已經不是開書考試了。

是老師先幫考生把答案寫好,再宣布驗證通過。

因此,這次加入了 Readback Fallback

當 Step 的目的是擷取資料,而且 Case 裡有足夠的 Object 與 Field 資訊時,就不要直接照抄文件裡那段真假難辨的文字,而是重新組出真正的 Query:

ubus-cli "WiFi.AccessPoint.*.AssociatedDevice.*.Capabilities?"

這次也開始從 Step 裡找出多條 Command,依序執行。

其中任何一條失敗,就停在那裡,不再假裝後面的工作已經完成。

同時加入 YAML Command Audit,把藏在 ;&& 後面的 Command 先列出來。

注意。

列出來,不是直接幫我改。

因為:

cmd1 && cmd2

和:

cmd1
cmd2

看起來只是拆成兩行,語意卻可能完全不同。

自動改完四百多條 Case,確實很 Vibe。

也很適合替自己創造下一個月的工作量。

wrongcriteria


Console Log 不該是 UART 垃圾桶

可喜可賀,可喜可賀。

TestPilot 第一次在實質意義上完整跑完了 Full Run Test。

但回頭檢閱 Report 時,Runtime Log 裡卻塞滿了:

  • BEGIN/END Marker

  • RC Marker

  • Shell Prompt

  • Command Echo

  • 真正的 Output

這些 Marker 是 serialwrap 能夠解析 UART Log 的關鍵手段,卻也成了 TestPilot 最沉重的負擔。

__TP_BEGIN_abcd1234__
command output
__TP_RC_abcd1234__=0
__TP_END_abcd1234__

一份充滿 Marker 的 Log,身為剛好還是人類的我,讀起來真的很痛苦。

多年寫 Code,一朝 Vibe。

天天 Vibe,Vibe 到 Code 都快看不懂了。

我不想連 Log 都一起看不懂啊。

所以這次也把 Marker、Prompt 與多餘空白清掉,Command 欄則改成一行一條。

Report Filename 也加入 run_id,避免下一次 Run 直接覆蓋上一次的測試證據。

畢竟測試的目的是留下證據,不是毀屍滅跡。

Say yes!

sayyes


真正的根因:原始測試資料沒有結構

這次 PR 修了不少問題:

  • 一個 Step 裡有三條 Command,卻只執行第一條。

  • 明明要做 Readback,卻把文件裡的 Setter 送進 DUT。

  • Command、預期結果與說明文字全部混在一起。

  • 最後產出的 Report,還得再清一次 UART 雜訊。

看起來每個問題都不太一樣。

但根因其實非常直接:

原始測試資料根本不是結構化的。

這些 Case 來自既有 Excel 與人工文件,本來就是寫給工程師看的。

一個儲存格裡,可能同時放著:

操作說明
+ 三條 Command
+ 預期結果
+ 前人留下來的貼心備註

人類看一眼,大概就知道要做什麼。

程式不行。

雖然有 Agent 協助把資料逐 Case YAML 化,但 415 個 Case 的工作量實在太大。

Agent 也會開始套用共通模式、補齊空白,或使用相似案例進行推論。

這些推論一旦被寫進 YAML,再交給 TestPilot 執行,就會從:

「可能是這樣。」

正式升級成:

「程式就是這樣跑。」

會偷懶的 Agent,寫出來的 TestPilot 也會偷懶。

最後程式只能努力猜:

哪一段是 Command?
到底有幾條?
這是要 Set,還是要 Read?
哪一段只是預期結果?

單獨執行幾條 Case 時,格式符合設計時的預期,看起來自然沒有問題。

但 415 條 Case 逐條跑下去,各種祖傳格式輪流登場,不同的測試流程互相混用,Parser 的運氣很快就會用完。

所以這次 PR 做的事情,說穿了就是替這批歷史資料加上一層翻譯:

  • 從自然語言裡找出 Command。

  • 把多條 Command 拆開並依序執行。

  • 分辨這一步是操作,還是 Readback。

  • 找出可能有問題的 ;&&,先列出來人工確認。

不是 TestPilot 突然想把事情搞得很複雜。

是輸入本來就很複雜,只是以前都由工程師的大腦免費處理。

現在換成程式接手,這些純手工累積的技術債,終於寄來帳單了。


但 serialwrap 好像也正在製造新的歷史問題

另一個很像的問題,是 Log 汙染。

但方向剛好相反。

原本設計給 Agent 使用的 serialwrap,為了辨認 UART 執行結果,會在 Log 中加入 BEGIN、RC 與 END Marker。

結果 TestPilot 還必須知道:

  • serialwrap 塞了哪些 Marker。

  • Return Code 藏在哪裡。

  • 哪些 Prompt 應該清除。

  • 如何把 Log 還原成人類可讀的樣子。

不過,這整件事是不是有哪裡怪怪的?

隱約有一種似曾相識的感覺。

硬幹多年後得到的普通 RD 沒用心得?

瘋狂處理例外邊界?

手工刻出來的 Excel 沒有結構,我只能先認命,替它補上一層翻譯。

但 serialwrap 是為 Agent 而生的。

怎麼連它也把 BEGIN、RC、END 全部丟給 TestPilot,再叫下一層從 Log 裡猜答案?

這不是在相容歷史問題。

這是在製造下一個歷史問題。

這個節奏不對。

Something is wrong!

「凡我所不欲,悉使 Agent。」

現在怎麼變成 TestPilot 在替 serialwrap 擦屁股?

下一篇,不再補 Regex,也不再多寫一層 Sanitizer。

我們直接把 serialwrap 拆掉重做,讓它自己對 Command、Output 與 Result 負責。

Have a nice day.

參考資料:
serialwrap
testtpilot-core


上一篇
Day 1 - 一天一個PR, 但今天沒有PR : 嵌入式的第一關
下一篇
Day 3 - 為了知道 Command 跑完沒,我們先把LOG搞髒了:UART LOG 汙染
系列文
一天一個 PR,讓我告訴你嵌入式開發的殘酷:如何為 AI Agent 建立可信的工程閉環4
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言