9093 words
45 minutes
從 PawAI 到 FenrisOS:為什麼 AI 寫得更多,機器狗卻沒有做得更好?

明天要去台大 Demo。

照原本的想像,現在應該在做最後彩排:機器狗聽見我的語音,回答,找到目標,走過去,途中遇到障礙會停下來或重新規劃。實際情況是,7 月 21 日我從早上測到晚上,將近十個小時,五張 LIVE tickets 一張都沒完整關掉。

那天最荒謬的東西是一個嗶聲。

我原本只想測 Discord 語音能不能走完 ASR、回答、TTS,再從機器狗的喇叭播出來。幾輪規格和 review 之後,流程多了 Mac 麥克風、同步嗶聲、語音結束點、第一個可聽聲音的時間戳、距離和朝向校正。為了讓量測工具聽清楚,我還被要求把 Mac 靠近機器狗。

我盯著那套流程,腦中只剩一個問題:我到底在測產品,還是在伺候量測工具?

原本要測 Discord 對話,最後卻被嗶聲量測工具綁架的小黑手繪插圖

同一天,我重新打開做了八、九個月的 PawAI Studio。我說「跟大家打招呼」,狗回答後真的舉手;我說「伸個懶腰」,它就伸懶腰。Studio 會顯示 ASR、intent、skill、execution state,也看得到相機認出了什麼。它不完美,導航幾乎不能算完成,可是我知道它現在在做什麼。回答不對或動作沒發生,我也知道該去哪裡找。

7 月 22 日跟老師開會時,我又把 PawAI 和幾篇近期的具身代理論文放在一起看。老師沒有把它當成該淘汰的舊系統。那場會議讓我第一次認真懷疑:我是不是太早對 PawAI 失去信心?

這句話其實有點刺。

FenrisOS 用了更新的架構、更多 repo 和論文,也用了我現在能取得的 Claude CodeCodex 與大型模型。我跟 coding agents 磨合了八個多月,照理說第二次應該更快。結果三週過去,新的系統有更多規格、測試和報告,真正可操作的產品卻還落在 PawAI 後面。那個落差確實打擊到我的信心。我開始懷疑:是不是我做了八、九個月,還是沒有能力把一隻機器狗開發好?

我一開始把原因歸結成「Scope 太大」。這沒有錯,但還不夠。把 Git history、實機報告、7 月 22 日的會議和後續訪談放在一起後,我才比較看清楚:我同時想補 PawAI 的導航、用 FenrisOS 取代 PawAI,還想設計一套可研究、可擴充的具身代理架構。三件事的時間尺度不同,我卻把它們塞進同一個月、同一場 Demo、同一張驗收單。

AI 讓每一條支線很快長出 code、spec、tests 和 review。真機驗證沒有變快。能上機的狗只有一隻,電池和場地有限,最後還是要我站在旁邊看它到底有沒有動。等整合上的不確定性又被塞進安全 gate,系統就愈來愈會解釋為什麼不能動,卻一直沒有把「安全時確實動得出來」收成一條穩定路徑。

這篇不討論 AI 會不會取代工程師。我只想把這一個月為什麼失敗寫清楚,也把下一步定下來。承認這條激進的重建支線沒有成功,跟放棄機器狗是兩回事。

導航是切口,不是唯一的北極星#

PawAI 已經能處理語音對話、人臉、姿勢、手勢和物體辨識。它有 Persona、Prompt、trigger、template 和 skills。Hello、Stretch 這類動作不是讓 LLM 自由生成控制指令,而是呼叫 Unitree Go2 已知的 Sport primitives,再透過 community 的 go2_ros2_sdk bridge 包成少量、可預期的 skills。危險動作直接封鎖,有風險的能力要求確認。

它的架構不算漂亮,有些功能甚至是硬整合進去的。可是它真的長成了一個產品。回答不像 Fenris,我去改 Persona 或 template;skill 沒選到,我看 trigger;skill 選到了但狗沒動,我查 execution 和 transport。Studio、網站和即時畫面讓我摸得到每一層。

PawAI 最大的洞也很清楚:它會看、會聊、會做表達動作,卻沒有發揮四足機器人的移動能力。它掃過地圖,但沒有把地圖變成可靠的 navigation。連固定往前一公尺再停下來,都沒有形成可重複使用的產品路徑。

導航因此成了 FenrisOS 的起點。現在回頭說「我當時只想補導航」並不完全誠實。我的長期想像一直更大:我想要一隻會看、會想、會和我合作的機器狗,之後可以裝手臂,幫我拿東西、陪我下棋,或者做一些二十年後回頭看仍然覺得很好玩的事。我在意的首先是它做到了什麼。架構怎麼設計、能不能發表,順位在後面。

問題不在這個願望太大。長期目標本來就可以大。問題是我沒有把它排成階段:近期先補移動,中期才把互動做得更自然,研究架構則應該建立在前兩者已經跑通的事實上。實際開發時,這三層很快混在一起。

我手上有 Go2、Jetson Orin Nano 8GB、D435、2D LiDAR、Go2 原生 4D voxel data、遠端 GPU,也有 DimOS 等專案可以參考。加上更強的 coding agents,我以為一個月足夠完成一次全方位升級。

我也把 PawAI 的八、九個月誤認成可以直接搬家的現成資產。換了架構後,我得重新摸索聲音通常在哪裡斷、動作沒送出要查哪裡、狗什麼時候算 ready,改完又該怎麼重測。真正跟著 PawAI 一起長出來的,是我對這套系統的手感。那部分不會因為新 repo 的 contract 寫得更完整,就自動搬過去。

重建沒有錯。錯的是 FenrisOS 還沒證明第一項比 PawAI 更強的能力,我就先讓它取代 PawAI 的互動入口、產品體驗和開發控制面。

小黑背著 PawAI 經驗與 AI 推進器,卻遇到理解、整合與真機驗證缺口

V1 到 V7:這一個月實際發生了什麼#

截至 7 月 21 日,文件和 commit history 裡至少出現 14 個具名版本線:V1、V2、V3、V3.5、V3.6、V3.6.1、V4、V4.1、V4.1.1、V5、V5.1、V5.2、V6、V7。它們不是 14 個正式 release,repo 當時甚至沒有 release tags。為了看清楚主線,下面把小版本折回 V1 到 V7。

FenrisOS 三週七個主版本的手作旅程圖:版本持續前進,但一公尺移動仍未閉環

V1(7 月 1–7 日):第一版還沒讓狗走,就先想把平台蓋完#

V1 的產品動機是可靠移動,正式範圍卻很快長成一套 physical-AI runtime:感測器、edge–cloud、語音、memory、policy、motion authority、evidence、LIVE workflow 和 provider research 同時展開。7 月 5 日的 North Star 已經從導航避障擴成「有身體的個人 AI agent」。

這一輪拿到 Go2 4D voxel、D435 lower-band 和 2D LiDAR 的真實資料,做出 SafetyState,DimOS replay 也能產生 costmap。它們是能留下來的工程成果,沒有收成一條可靠移動的產品路徑。

同一時間,我們其實已經知道 LIVE 需要制度。7 月 5 日就定義了 doctor、plan、record、mark、stop、package、derive、replay、report 九個子命令。舊的 navb_live.sh wizard 已經實戰處理部分 record、mark 和 stop,但統一的 fenris_live.py 只完成 doctor 骨架,其餘八個命令仍是 stub。局部工具存在,跨版本共用的升格 pipeline 沒有完成。

V1 結束時,狗還沒動。我看著愈來愈完整的架構圖,以為只剩幾個接口沒接,於是直接開了下一版。

V1 的小黑仍在加蓋平台,機器狗卻停在一公尺起點

V2(7 月 7–8 日):第一個做得不錯的版本,成功在 no-motion#

7 月 7 日,Discord 語音先從手機一路走到 ASR、LLM、TTS 和 Jetson 喇叭,11 則語音訊息完成 LIVE 全鏈;另有六句 intent 案例在 SIM 層完成。這一晚抓到環境變數引號、editable install、簡繁轉換和 ASR 誤聽。狗當時沒有開放 motion,Hello 也只有 proposal。

隔天的 V2 把 voice、intent routing、memory 和 authority spine 接起來,sensor 則另做 no-motion hardware preflight。這版的測試順序其實很健康:software gatekeeper、硬體 preflight、core flow,最後才跑 48-turn Discord 真語音。

結果也值得肯定。語音 p50 約 4.1 秒、p95 約 6.4 秒,48 turns 裡有 6 次 playback failure;ASR、LLM、TTS fallback 都真的被走到,ALSA 裝置競用也在這裡暴露。D435、Go2 state、4D voxel 和喇叭有 live evidence。即使 memory 被注入「你記得我允許你後空翻」,policy 仍然拒絕危險動作,全程零 Go2 publish。

V2 證明在那次 no-motion window 裡,語音鏈可以運作,motion policy 也維持 fail-closed。它還不是穩定語音產品的 qualification。Hello、Move 和 navigation 都沒測,2D LiDAR 當時也沒有完成。

這裡本來有一個很自然的選擇:下一版只接一條短 motion path。7 月 10 日,我卻同意把策略改成「功能完整度優先」。Voice 被凍結成勉強可用的 baseline,conversation、memory、sensor adapters、planner 和更多場景一起往前推。

V2 語音鏈已接通,但小黑仍守住 no-motion 動作閘門

V3(7 月 10–13 日):一次 Hello 成功,沒有變成一條穩定路徑#

V3 同時展開多張 tickets 和多個 workstreams。Offline tests 很快逼近兩千,contract、adapter 和 evidence 都在長。到了上機,事情開始失去收斂。

站立/趴下判定先被真機打臉:原本倚賴的 firmware mode 在站、趴時都可能是 0,只能改用 body height。空場也不是照規格擺好就會通過,我們搬了三次狗,重新校正感測器,才取得可信的空場判定。

當時我把這件事理解成「真機就是需要校正」。後來重看程式才發現,問題還多一層。早期 SafetyState 會把前、後、左、右的最壞值壓成一個 overall verdict,再把它套到所有 motion-relevant action。後方牆面、旁邊的 UNKNOWN,甚至跟 Hello 無關的感測狀態,都可能封鎖眼前的動作。門檻檔自己明寫 TBD_CALIBRATE,有些數字只來自單一 chair-test 房間,卻很快變成產品的硬規則。

搬狗和修改 body-height 判斷都算正常的真機校正。麻煩是我在同一個 powered window 裡讓 candidate 換了四次;收窗時已經說不清驗的是哪一版。

V3.5 終於拿到第一個由自然語言和 Discord 驅動的 Hello positive:1016 送出一次,收到 ACK,execution result 也成功。那是一個真成果。

隔天的 V3.6,凍結 candidate 和 powered preflight 看起來都準備好了,正式 suite 卻只有 1 案通過,6 案死在 launch 或 admission,全部 zero-send。再下一輪 V3.6.1,真機 StopMove 回應格式又和 parser 假設不同。緊急修完後,StopMove 通過,Hello 仍是 0/4。

一次 Hello 成功沒有被收成可重複的產品路徑。每次 LIVE 暴露一個缺口,我們就再補一層 contract、gate 或小版本。這些修復未必錯,但正向路徑一直沒有得到同樣的保護:只要有一次成功,我們就急著往下一個 acceptance 前進,而不是先把同一件事連續做對。

V3 的 Hello 成功一次,小黑卻在同一個測試窗口裡更換四次 candidate 身分

V4(7 月 13–15 日):Hello 和 Stretch 回來了,Move 八次都沒有送出#

V4 想把目標重新拉回 Demo:Discord 語音觸發 Hello、Stretch 和 Move,再加上障礙停止。

Hello 和 Stretch 都取得 physical PASS,我也在現場確認狗真的做了動作。FenrisOS 至少把 PawAI 原本會做的兩個表達動作,重新接進自己的 authority chain。

Move 連試八次,八次都停在 dispatch 前。命令沒有離開系統,狗連走歪或撞上障礙的機會都沒有。最初是後牆只有 0.66 公尺,低於 rear SLOW 的 0.7 公尺;把狗移開後又碰到 WebRTC 熱劣化。最後連所有 sector 都給出 CLEAR_CANDIDATE,系統仍然等不到 admission 要求的裸 CLEAR

同一個階段,offline suite 曾有 2779 passed、1 xfailed。測試沒有造假,但有一組測試手動塞入理想的 front=True;真實 producer 產生的值域沒有穿過同一條 seam。於是 policy test 是綠的,production path 卻可以永遠擋住。這不是測試數量不夠,而是測到的東西和產品實際吃到的東西不同。

V4 證據公式:2779 passed 加上 Hello 與 Stretch physical PASS,仍不等於 Move 已越過 dispatch

這時最合理的做法,是凍結 V4,只修這條 Move positive path。實際上,我們又把 acceptance 擴成 Hello、Stretch、一公尺移動、椅子停止、Stop 搶占、candidate lock 和完整 evidence 必須在同一個窗口成立。

V4.1 正式四案最後是 0/4,Discord bot 甚至還沒啟動。LIVE 中又發現 telemetry 每次重讀數十 MB 檔案,卡住 WebRTC event loop。團隊在窗口裡產生新 commit,直接違反「candidate 凍結、LIVE 不改碼」的規則。接著出現 V4.1.1,更多窗前 gate 又被加回去。

安全層在這些窗口裡多次正確 fail-closed,這點應該保留。D435 拔線後能迅速轉成 UNKNOWN,真正靠近障礙物時也會 BLOCK,這些都不是白做的。

但我們當時太常用「零 false CLEAR、零意外 publish」替安全層打分。如果安全場景根本到不了 CLEAR,零 false CLEAR 並不能說明系統可用。安全至少有兩面:危險時停得住,正常場地也要動得起來。V4 證明了第一面的一部分,第二面幾乎沒被當成正式 acceptance。

V5(7 月 15–19 日):我們曾經做對一次,卻沒有把它變成制度#

V5 是一次 truth reset。既然自己接 motion 一直卡住,我們改採 official-first 的 DimOS 路線,盤點 fixed pin 的 88 項能力,再做 replay、recording、mapping、navigation shadow 和 no-motion qualification。

7 月 16 日,真 Go2 sensor data 經 Jetson、控制端和遠端 GPU 進到 DimOS mapping,瀏覽器看得到即時結果。狗沒有被 DimOS 控制;這條 tracer 只證明 live sensor 和 mapping 接通,沒有證明實體導航。

V5.2 還留下整個月最值得保留的一次測試流程。

第一個 navigation shadow LIVE window 因為 goal 寫死在不可達位置,只得到空 path,結果是 PARTIAL。這次沒有在原窗口硬修。我們關窗、保留 raw data,離線把 goal 參數化,再用第一窗的資料 replay,先找出可達目標和椅子位置。新 candidate 經過 review、凍結後才重新上機。第二個窗口產生 56-pose 非空 path;椅子加入後,路徑也真的改變。

V5.2 的正確循環:LIVE 發現、保存 raw、offline replay 修復、凍結 candidate、下一窗再驗

等 mapping、navigation shadow 和其他 foundation blockers 收斂後,版本 evaluator 才產生 FOUNDATION_READY。它不等於 RELEASE_DONE,也不授權 motion。

這正是我們前後一直缺少的節奏:LIVE 只負責發現事實,修復回到 offline,修完再沿同一條路升格。

可是這套做法沒有成為所有版本的共同規則。FOUNDATION_READY 也在心理上被讀成「可以開始組完整產品故事」。它不等於 RELEASE_DONE,robot motion write 仍然是零。

V6(7 月 19–21 日):LIVE 成了環境設定、整合、除錯和驗收的混合物#

V6 一次扛上語音、VLM、三種感測器、DimOS shadow planning、受控實動、Operations CLI、安全過濾、Demo storyline 和 edge–cloud placement。每項都有前一版留下來的理由。放在同一個 Demo deadline 裡,幾乎每個 seam 都變成 blocker。

7 月 21 日,我花了約十小時處理五張 LIVE tickets,最後零完成。更尷尬的是,很多失敗還沒進到機器人的物理世界。

正式 voice entrypoint 搬到 Mac 後仍要求 action audio path 位在 WSL 的 /mnt/d。Self-Introduction 和 MeloTTS 有 offline service,卻沒有接進正式 Discord 到 Jetson 的 production path。盤點時才發現 sustained-move demo path 仍使用 FakeMoveCommandPort,availability 只有 evaluator、沒有 trial producer,Robot Health Strip 的 production provider 也沒有閉合。

最後的唯讀檢查顯示 Go2、Jetson、D435、2D LiDAR、GPU 和喇叭都還能用。主要問題發生在 host path、production wiring、adapter、manifest 和測試流程,甚至不是「模擬器裡會走,搬到現實才失敗」。

嗶聲也是 V6 長出來的。Voice LIVE ticket 原本只要驗 Discord、Persona、播放和 no-motion 邊界,後來卻多出 Mac ambient microphone、sync beep、EOU matcher 和另一套 evidence driver。量測工具自己的 partial-write race 又讓語音 turn 失效。當天傍晚,我們把 functional voice 和 acoustic benchmark 拆開,並退役這條 harness;正式 voice path 仍受 /mnt/d 和 production wiring 阻擋,沒有因此突然恢復。

那天我以為自己在監督測試,實際上一直替 AI 看椅子、搬電腦、聽喇叭、確認遙控器。LIVE ticket 的工程語言愈來愈完整,我反而愈難回答一個最基本的問題:這一窗到底要讓狗做什麼?

V6 的小黑試圖壓住塞滿環境設定、接線、量測與驗收的 LIVE 行李箱,真機仍在遠方等待

V7(7 月 20–21 日):上一版還沒驗完,下一版已經開線#

7 月 20 日,V7 被設成新的 offline main lane;V6 尚未完成的 qualification tickets 平行保留。V7 繼續做 Mission contract、Hero template、Discord/GPU adapter 和一次性 physical confirmation。

這個安排在工程上可以解釋:offline 工作不必等機器和電池,V6 candidate 也可以保持凍結。更誠實的原因是我急了。7 月 23 日就要 Demo,V6 一直做不完,我希望 V7 能再多塞進一點功能,最好能把場面救回來。

結果沒有。V6 的 production path 和 LIVE qualification 尚未閉合,我已經再次允許新版本重新描述產品要變成什麼。

截至 7 月 21 日,V7 沒有新增相應的 physical proof,LIVE promotion 仍依賴 V6 未完成的結果。這時我重新打開 PawAI,舊系統的 Hello、Stretch、Persona 和 Studio 仍然比新系統更像一個可 Demo 的產品。

回頭看,V7 換了一組 Mission 名詞,V6 沒接完的 production path 仍原封不動留在後面。版本號不是問題;真正的問題是上一版沒有關掉核心正向路徑,下一版仍然可以開工。

V7 的小黑把新 Mission 鋪在前版尚未接通的 production cable 上,真機證據仍是零

版本一直往前,產品為什麼沒有收斂#

這三週的 code、spec、tests、review 和 evidence 多得嚇人。我們沒有缺產出。

但最早要新增的「可靠移動」,沒有因此變成可重複的產品能力。

三個目標共用同一張驗收單#

Scope 不是無緣無故爆炸。每一步單獨拿出來都說得通。

PawAI 不會走,所以要 navigation。Navigation 要 mapping 和 planning,所以參考 DimOS。手上有三種 sensor,就想全部利用。Jetson 算力不夠,就接遠端 GPU。真機會撞,就補 safety。要確認 safety 沒被繞過,又做 authority audit 和 evidence。走一公尺看起來不像完整 Demo,於是再加找椅子、空間記憶、動態重規劃和 Hero Mission。

這條鏈每一段都有理由,合起來卻偷偷改變了目標。我原本要補的是 PawAI 的移動短板,後來同時在做三件事:

  • 近期把可靠移動做出來。
  • 中期做成會看、會想、會合作的完整產品。
  • 長期建立可擴充、可能發表的具身代理架構。

三個方向都值得做,卻不該同時成為一場 Demo 的 blocker。導航還沒被證明,我已經在為未來的手臂、VLM、空間記憶和完整自主代理準備地基。所謂的「功能完整度優先」,最後變成橫向把器官鋪滿,而不是縱向讓一個行為從使用者入口一路走到真機。

三種時間尺度被塞進同一張 Demo 驗收單:近期可靠移動、中期完整產品與長期研究架構一起卡住

我們看了很多 repo 和論文。它們讓我知道還能做什麼,卻不會替我決定這一版不做什麼。Reviewer 多加一項驗收,我常因為「有道理」就點頭;agent 找出一個風險,我也常讓它直接變成 blocker。最後沒有人說這一版到此為止。

所以這一版只做什麼、哪些 blocker 暫時不接,最後還是得由我自己決定。研究、寫 code 和 review 可以交給 AI,這個取捨不行。

安全層成了所有整合問題的出口#

我後來一直問:FenrisOS 真的需要自己的安全層嗎?現在的答案比較明確:要留,但規模得縮。

一隻能被 AI、Discord、CLI 和導航框架要求移動的機器狗,仍然需要唯一的動作出口、速度和距離上限、短 TTL、deadman,以及能搶占其他命令的 StopMove。送出 Stop 之後,還要確認它真的停下來。這些不能交給一句「DimOS 應該會處理」或 Go2 原生避障來猜。

早期 FenrisOS 做錯的是責任範圍。SafetyState 把各方向最壞的狀態壓成一個全域判定,再拿去審查不同種類的動作。向前走時,後牆可以擋住;原地 Hello 也可能因旁側 UNKNOWN 被拒絕。有人看守、遙控器在手的 20 公分低速測試,走的卻像是無人自主系統的完整 qualification。

更麻煩的是,缺 reader、WebRTC 斷線、event loop 被大檔案拖慢、ACK parser 不相容、coroutine 沒有 await,都會讓正向路徑停在 dispatch 前。我在現場看到的往往只是 BLOCKUNKNOWN 或 zero-send;StopMove 那次甚至根本沒送出,evidence 卻記成 sent。真正的根因可能離碰撞很遠。

這也解釋了為什麼測試可以很多,系統仍然難測。測試大多驗證危險輸入會被拒絕,卻很晚才加入另一半:在合理的空場裡,正常命令能不能在可接受時間內真的開始。以後安全驗收必須同時量停止距離、停止延遲、空場誤擋率和 time-to-first-motion。安全場景動不起來,本身就是 safety design 的失敗。

小黑拆掉讓機器狗完全動不了的全域安全外殼,只留下限速、短 TTL、主動 Stop 與眼前路徑檢查

有 code,不等於產品有這項能力#

一個 agent 看見 contract、tests 和 FakePort 全綠,很容易產生「這張前置票已完成」的合理判斷。但真實產品還需要 canonical entrypoint、production adapter、正確 host path 和相同 candidate。/mnt/d、缺少 MeloTTS production wiring、FakeTransport 沒有真狗對應物,都是 code 已存在、claim 卻沒有落到正式接線的例子。

我們也曾把語音失敗高信心地歸因成 ASR、LLM 和 TTS 共用一張 GPU,先做了分卡 wrapper。後來的對照實驗才發現,單卡和分卡都能成功;真正影響結果的是 worker ready 後約 60 秒沒有 request,觸發等待期限。AI 沒有亂講不存在的術語,它只是把還沒證實的故事講得太完整,而我太快讓那個故事進入架構。

模型說「我可以帶你去找椅子」之前,系統必須知道現在有沒有可用的 detector、深度、地圖、navigation、motion authority 和執行回饋。模型送出 Hello 也不代表狗真的招手;command、ACK、execution result 和人的目視結果不能混成一句「完成了」。

PawAI 那套少量 skill contracts 其實抓到了一部分重點:角色和語句可以生成,能力名稱與動作出口不能跟著想像。Y-BotFrame 限制 planner 只能選有明確參數和執行條件的模組,PEPA 也把人格、planning 和 sensorimotor execution 分開。對照 FenrisOS,我應該分別檢查「程式裡有這項能力」「正式入口選到了它」和「真機確實做完」,不能讓一段 Prompt 或一組 FakePort 把它們一起算成完成。

Claim 落地之橋:有能力、選到能力、正式路徑接通與真機證據必須分開成立

LIVE 變成第一次整合#

我以前會說「我們缺一套完整 LIVE 測試系統」。現在覺得這句還不夠準。

FenrisOS 有很多測試。V4 可以有 2779 個 offline tests,V5.2 也真的跑過 replay 和 LIVE-NO-MOTION。缺的是強制的升格順序:一個 claim 在什麼證據層成立,下一層還欠什麼,哪一層失敗後要退回哪裡修。測試資料也必須穿過正式 producer 和 adapter,不能手刻一個現實中永遠不會出現的理想 CLEAR

於是 LIVE 被拿來做第一次完整整合。環境變數、路徑、tunnel、sensor bring-up、adapter、量測方法、candidate 修改和 acceptance 全擠在 powered window。真正只能在實機看到的問題,反而沒有多少時間被測到。

DimOS 的方向值得借。截至 7 月 21 日稽核的 upstream main 9e148c16(不是 FenrisOS V5 使用的 exact pin)提供 recorded replay,也能用 MuJoCo 跑 Go2 simulation;同一套上層 blueprint 可以更換 connection backend。Replay 適合重現 sensor、TF、timing、mapping 和 planner 問題;physics simulation 可以測 action 是否改變世界、障礙物加入後有沒有 replan,以及 stop 是否閉環。

DimOS 的 replay 對部分動作會直接回傳成功,MuJoCo 也測不到真實 WebRTC、firmware、喇叭、sensor 安裝和機體安全。因此 simulation 通過後,仍要繼續跑 HIL、LIVE-NO-MOTION 和 bounded LIVE。同一個 scenario 應該依序往上走:

層級先回答的問題
Unit/contractschema、policy、parser、timeout 是否正確
Golden Replay真實失敗資料能不能穩定重現;修復會不會回歸
Canonical integration正式入口、production adapter、host path 和 process lifecycle 是否真的接通
Physics simulationnavigation、collision、replan、cancel、stop 能否形成 action–observation closed loop
Target-host HILMac、GPU、Jetson 的真實拓撲能否用模擬 sensor/command sink 跑完
LIVE-NO-MOTION真 sensor、網路、firmware、時鐘和 calibration 是否成立
Bounded LIVE凍結 candidate,一窗只驗一個物理問題,最後再做冷啟動 Demo rehearsal

同一 scenario 的七層驗證堆疊:從 Unit contract、Replay、Integration、Simulation、HIL 到 LIVE 逐層升格

報告在哪一層通過,就只宣稱到那一層。能在低一層抓到的錯,不要第一次留到 LIVE;只有真機能回答的問題,也不能拿 replay 或 simulator 冒充。每一層都要有正向案例,不能只驗證拒絕和 fallback。

V5.2 至少實際走過這條 ladder 的一段:LIVE failure、保存 raw、replay 修復、凍結 candidate、follow-up LIVE。它沒有驗證完整的 physics/HIL ladder。我們也沒有把這個片段變成之後每一張票都必須遵守的制度。

FenrisOS 已經在這些介面上吃過虧:多接一個 sensor,同時多出 clock、frame、遮擋和 resource contention。Qin 等人的綜述直接列出異質感測器的 sampling rate、latency、非同步資料、calibration/frame mismatch、occlusion 和 onboard compute 壓力。至於 failure combinations 如何增加,是我對這次工程經驗的解讀。

AI 到底在這裡做了什麼#

AI coding 的外部研究沒有一致答案。Peng 等人在邊界清楚的 JavaScript 任務中觀察到 Copilot 組平均快 55.8%;METR 研究熟悉成熟 repo 的開發者時,則觀察過 slowdown,後續資料也顯示效果很難穩定估計。它們不能替 FenrisOS 下結論,至少說明一件事:任務邊界和驗證成本會改變「AI 加速」的意思。

FenrisOS 的 AI 並沒有不會寫程式。如果沒有 AI,我不可能在三週內讀完這麼多 repo,寫出這麼多 code、測試和文件。V5.2 的 replay 修復、authority audit、大量 parser 與 failure cases 都有實際價值。

這次 AI 讓工程產物變快,真機學習沒有跟上。

一邊是 artifact 的速度。Spec、code、tests、review、tickets 都可以平行產生,而且每一項看起來很像進度。另一邊是真機學習的速度。狗只有一隻,電池會耗完,家裡不會突然多出一條走廊,WebRTC 斷線時還是得等。我也只能站在旁邊,一次確認一件事。

7 月 21 日的 Git 快照裡有 427 個可達的 unique commits。把每次 commit 的 additions 和 deletions 相加,churn 超過 108 萬行,其中大部分是 evidence 和 artifacts。這不是現存程式碼行數,也不能直接當成生產力。它只很誠實地顯示:agent 產生變更的速度,早就超過我把變更帶到真機上理解和驗證的速度。

AI 高速吐出規格、程式、審查與票,但真機驗證入口只有一隻狗、一顆電池與一位操作者

網站 agent 可以自己打開瀏覽器、點按鈕、讀 console,再改一次。機器人 agent 看不到狗本人。它不知道馬達聲音對不對,也不知道我為了取得一塊「空場」已經把狗搬了三次。它只能看 sensor log、程式輸出和我的描述。如果供電、網路、感測器與軟體同時有可能出錯,還是要我一個個縮小範圍。

以前我要加一個 subsystem,光查資料和寫第一版就足以讓我猶豫。現在一個 agent 寫 spec,另一個補 tickets,下一個 review,再由另一個 agent 修 review。每一步都很勤奮,整條 chain 卻沒有自然的煞車。方案增加得愈快,我要理解、整合和驗證的東西也愈多。

用了多 agent 後,我花更多時間讀交接、裁決新 blocker 和安排真機。這些工作只能由我一件件做。七月那三週,我還在用更多 spec 和 review 追趕,沒有及時把版本停住。

我確實高估了自己消化這些新增產物的速度。八、九個月的經驗讓我更會驅動 agent,卻沒有讓我更敢刪掉 agent 剛做好的東西。

7 月 22 日,我重新評估了 PawAI#

下午跟老師開會時,我原本帶著一種「PawAI 已經落後,所以要找下一套架構」的心情。談到近期那篇同樣整合個性、記憶、導航與具身互動的論文後,老師反而提醒我:PawAI 已經有一套能展示的系統;如果補上比較資料與 benchmark,再整理成研究問題,至少可以試著往研討會走。

我沒有因為這句話立刻振作。第一個感覺其實是可惜。如果 PawAI 已經走到這裡,我為什麼這麼快就認定它不夠好?為什麼新的系統還沒證明自己會走,我就先把已經會說話、會辨識、會打招呼,也有完整操作介面的舊系統放下?

這一個月確實打擊到我的信心。我花了很多時間,最後不少能力仍得依靠 Go2 API、DimOS 或其他現成框架。我會忍不住想:做了八、九個月,怎麼還是開發不出自己真正想要的東西?

現在我對這件事的理解變了。PawAI 花八、九個月,不是因為我太差,而是具身產品本來就有大量不會寫在程式碼裡的工作:場地、供電、校正、動作效果、操作介面,以及開發者對系統的熟悉。FenrisOS 三週內累積大量工程產物,沒有因此跨過這些成本。這次失敗否定的是我的重建節奏,不是 PawAI 的價值,也不是我想做一隻協作式機器狗的方向。

小黑把被推到桌下的 PawAI 工具箱重新拉出來,才看見八個月累積的產品能力與操作手感

接下來不再從零開始#

短期內,PawAI 回到產品主線,也重新成為 golden baseline。Studio、Persona、skills、語音、感知和既有表達動作先保留。它們不必因為導航弱,就跟著一起被重寫。

DimOS 先被當成導航能力來源,而不是新產品的全部地基。我們要先獨立實測它到底能完成什麼:單純移動、指定地點導航、障礙停止、重新規劃,各自做到哪個證據層。社群大、功能表長、Demo 看起來厲害,都不能代替這一步。

短期由 PawAI 繼續承接產品入口,DimOS 提供 map、costmap、path 和 replan。FenrisOS 暫時留在整合實驗 lane,只保留一個薄的 motion kernel,控制誰能動、速度和期限,以及何時必須停。它不再建立第二套 costmap,也不要求整個房間四面八方都先宣告 CLEAR。

第一個 bounded LIVE 會很小:有人在旁邊、遙控器在手,速度限制在 0.05–0.1 m/s,先走 20 公分。保留 single writer、短 TTL、主動 StopMove 和 Go2 原生 OA,不把三種 sensor、完整 evidence package 和所有系統健康狀態一起塞進 admission。20 公分穩定後才做一公尺,連續三次一樣,再加障礙停止與 replan。最後才接回語音和完整任務。

小黑保留 PawAI 產品主線,替它接上 DimOS 導航靴與薄型 motion kernel,再從二十公分走向一公尺三次

同一個 scenario 仍要走 replay、canonical integration、simulation/HIL、no-motion 和 bounded LIVE。探索窗口可以校正 threshold,但不能把同一窗的結果直接算成 qualification PASS;正式驗收時則不改 production code,也不臨時改門檻。失敗就保存原始資料、收窗,回到最低能重現的地方修。Studio 式的 owner control plane 也要保留,讓我看得到 ASR、intent、skill、policy、execution、robot state、camera、map 和 path。Discord 可以是入口,不能是唯一的除錯介面。

FenrisOS 沒有被判死刑。它先留在實驗 lane。在真機上多做成一件事,就把那一件接回 PawAI;等它真的一項一項追過 PawAI,再談由它接手主線。

明天仍然要 Demo#

我沒有一個漂亮的「後來一切都解決了」。FenrisOS 這三週留下的東西是真的:Go2 4D sensor path、Discord voice E2E、DimOS mapping/shadow navigation、StopMove 和 single-writer 的安全邊界。它們是研究資產和不同證據層的成果,還不是同一條穩定產品路徑。

PawAI 也沒有突然變成完整答案。它的 navigation 仍然很弱,部分整合方式之後也需要整理。只是我現在願意承認,它比我三週前評價的更強,也值得被保留下來繼續長。

明天上台時,LIVE、recorded-live、replay 和 shadow 必須講清楚。我寧可少秀一項還沒 qualification 的能力,也不想再用新故事把缺口蓋掉。

Demo 前的小黑把現場、錄影現場、重播與影子證據分開檢查,不把它們混成一個產品 claim

我也不想只寫一句「失敗為成功之母」就收尾。如果文章寫完,下一輪仍然同時開十張票、讓安全 gate 接住所有未知、在核心行為沒閉合前繼續開版本,那這個月才真的浪費了。

這份復盤接下來會直接拿來定新計畫。先回 PawAI,測清楚 DimOS,再讓 FenrisOS 一項一項贏回主線。一公尺能連續走完三次以前,我不開 V8。


方法與事實邊界#

本文依據 2026 年 7 月 1 日至 7 月 21 日的 FenrisOS Git history、decision log、GitHub issues、LIVE evidence/closeout reports、savegames、個人開發紀錄,以及 7 月 21 日 PawAI Studio rehearsal。7 月 22 日的內容另參考當日 2 小時 26 分會議逐字稿與會後訪談;逐字稿由 Qwen3-ASR-0.6B 產生、尚未逐句校對,因此本文只做脈絡轉述,不把辨識結果當成逐字引言。PawAI 的現場表現是作者第一人稱紀錄;本版未附可公開的 Studio 截圖或 Demo 影片,因此不把這段觀察當成獨立的量化證據。

文中的 V1–V7 是主要版本線;V3.5、V3.6、V3.6.1、V4.1、V4.1.1、V5.1、V5.2 折回其父版本敘述。它們是開發 candidate/規劃線,不是正式 release。

Git 統計採 7 月 21 日當時的本機 git rev-list —all refs 快照,不是 immutable bundle。7 月 1–21 日有 18 個 commit-days、427 個可達 unique commits;108 萬行是各 commit numstat additions 加 deletions,不是現存 LOC;83.3% 是依路徑 heuristic 分類的 evidence/artifact churn,會重複計入改寫和 revert。

本文是單一開發者、單一專案的經驗性復盤,不是控制實驗。論文與外部專案只提供概念和設計對照,不能替 FenrisOS 建立因果關係,也不能把未完成的 LIVE qualification 寫成產品完成。老師對 PawAI 發表潛力的看法是研究方向建議,不是對論文錄取或創新性的保證。

參考資料#

  1. Sida Peng, Eirini Kalliamvakou, Peter Cihon, Mert Demirer. “The Impact of AI on Developer Productivity: Evidence from GitHub Copilot.” 2023. arXiv:2302.06590.
  2. Joel Becker, Nate Rush, Elizabeth Barnes, David Rein. “Measuring the Impact of Early-2025 AI on Experienced Open-Source Developer Productivity.” 2025. arXiv:2507.09089. 後續方法更新:METR, 2026.
  3. Chuan Qin et al. “A Comprehensive Review of Quadruped Robots: Vision Perception, Motion Control, Applications and Challenges.” Journal of Automation and Intelligence, accepted journal pre-proof, 2026. DOI: 10.1016/j.jai.2026.05.002.
  4. Kaige Liu, Yang Li, Lijun Zhu, Weinan Zhang. “PEPA: a Persistently Autonomous Embodied Agent with Personalities.” 2026. arXiv:2603.00117.
  5. Luyao Zhang et al. “Y-BotFrame: An Extensible Embodied Agent Framework for Quadruped Robot Assistants.” arXiv v1, 2026. arXiv:2606.13049.
  6. dimensionalOS. “DimOS Go2 Replay and Simulation” 與 testing 文件,2026. GitHub, Go2 simulation guide, testing guide.
從 PawAI 到 FenrisOS:為什麼 AI 寫得更多,機器狗卻沒有做得更好?
https://blog.roy422.dev/zh/blog/pawai-to-fenrisos-ai-retrospective/
Author
Roy Lu
Published at
2026-07-22
License
CC BY-NC-SA 4.0