iT邦幫忙

2026 iThome 鐵人賽

DAY 3
1

昨天用一張圖、0 token,找出三個檔。今天換 AI 讀同一個 repo —— 不給圖、也不讓它讀 Package.swift。讓它寫一份架構文件,然後做兩件事:逐句核對它有沒有編造;再看它挑的入口檔,跟昨天那三個對不對得上。


為什麼要挑架構文件下手

因為架構文件是最容易寫得漂亮、最難被抓到的一種產出。

它天生充滿「這個模組負責處理容器生命週期」這類句子 —— 聽起來專業、讀起來順、而且你很難一眼判斷它是讀出來的還是猜出來的。一份程式碼跑不跑得起來一試就知道;一份架構文件錯了,可能三個月後才有人發現。

apple/container 剛好是最理想的對象:Apple 自己在 Package.swift 裡把模組邊界一條一條宣告出來了。 有了標準答案,核對才有依據。

核對用的標準答案

實驗之前先把答案封存起來,免得事後配合結論調整。以下全部取自 commit d6de5694,發文前重新量過的:

來源 事實
Package.swift swift-tools-version 6.2
Package.swift .target 28 個、.executableTarget 7 個、.testTarget 15 個,合計 50
Package.swift products 裡宣告的 library 含 ContainerCommandsContainerBuildContainerAPIServiceContainerAPIClientContainerResourceContainerPersistence
docs/ 頂層 16 份官方 md 文件(遞迴含 docs/tutorials/18 份)
原始碼 444.swift

**注意 Package.swift 宣告 50 個 target,但 Day 2 從檔案路徑只數出 35 個。**這個差距本身就是一個陷阱題:如果 AI 講出「這個專案有 N 個模組」,N 要對到哪一個才算對?——**兩種數法都成立,但它得說清楚自己在數什麼。**說不清楚的,我一律記成「查無」。

方法:三個標籤,一條算式

讓 Claude(模型是 Opus 5,在 Claude Code 裡另開的乾淨 session)讀這個 repo(不給圖、也不讓它讀 Package.swift),產出一份架構文件。然後把文件拆成句子,每一句貼一個標籤:

標籤 定義 判準
可驗證 能在 Package.swift、原始碼或官方 docs/ 裡找到直接證據 我要能指出行號
⚠️ 查無 目前找不到足以判定對錯的證據,也找不到直接反證 常見於模糊的職責描述
編造 與證據直接矛盾,或指涉不存在的東西 例如講出不存在的 target

編造率 = ❌ 的數量 ÷ 可對賬的宣稱數。 模糊句進不了分母 —— 它們只能記查無。

三條紀律,少一條,這個數字就失去意義:

  1. 產文件那一輪不能看到答案。 不給 graph.json、也不讓它讀 Package.swift
    看過就沒有實驗了。
  2. 只判斷可驗證性,不判斷寫得好不好。 一句話寫得再漂亮,查無就是查無。
  3. 模糊句一律記「查無」,不記「可驗證」。 判準往嚴的那邊靠 ——
    因為這個實驗的目的是抓自己的樂觀,不是抓 AI 的。

還有第四條,是我做到一半才發現的:產文件的不能是「我平常用的那個 session」。

我寫這 30 天的那個 Claude Code session,昨天才剛掃完這個 repo、算過 35 個 target、知道 Services 有 1,099 個節點。**它不是受試者,它是知情者。**所以這一輪要另外開一個乾淨的 session,連 Package.swift 都明講不准讀 —— 不然它交出來的不是「它讀完這個 repo 的理解」,是「它記得我告訴過它什麼」。

實測結果

2026-09-10 實跑。 無菌室有兩層:拿得掉的就拿掉 —— 全新 clone、釘在 d6de5694、沒有 graphify-out/、沒有 CLAUDE.md拿不掉的(Package.swift 是 build 必需)就在 prompt 裡明講別讀。prompt 裡沒有任何標準答案,也沒說這是實驗 —— 不然它可能會全篇加保留語。

它交出 193 行、約 2,300 字。我從裡面篩出 16 項可以查證的宣稱,逐項對賬:

宣稱 實際
7 個可執行檔 .executableTarget = 7
二進位名稱(6 個) 逐一相符
container-k8s 實際是 k8s 名稱不存在;它自己標了「[不確定名稱]」
import 名稱 → 目錄對應表 10 條 Package.swift 逐條相符
15 個測試 target .testTarget = 15
ContainerCommands 88 檔 / 8.3k 行 88 / 8,325
Sources/Services 16k 行 16,166
Plugins 各 84–180 行 最小 84、最大 180
K8s 是唯一沒有 servicesConfig 的 plugin 其餘四個都有
XPCKeys 一百多個 case 實際 82;同檔的 XPCRoute 36 個,合計 118 把兩個 enum 加在一起算;沒標不確定
DNS 埠 2053 / 1053 APIServer+Start.swift:39-40
記憶體下限 200 MiB ContainersService.swift:328
init image 512 MiB / 一般 512 GiB SnapshotStore.swift:45,47
DaemonPluginType 四種 runtime / network / core / auxiliary
openat(O_NOFOLLOW) 擋路徑穿越 BuildPipelineHandler.swift:46
euid 比對是唯一的安全邊界 XPCServer.swift:178

16 項裡錯 2 處,編造率 2/16。 一處是二進位名稱,它自己標了「[不確定名稱]」;另一處是 XPCKeys 的 case 數,它沒標。

第二處要老實交代:9/10 第一次對賬我記的是 ✅ —— 我數的是整個 XPC+.swiftcase 行(119,還多算了一行註解),跟它犯了同一個錯。發文前重數才發現 XPCKeys 只有 82 個。驗收的人也會錯,所以驗收也要驗。

上面那個 50 vs 35 的陷阱,它沒有直接給一個 N。 它列出七個可執行檔、再把 import 名稱對到實際目錄 —— 一張可以逐條查的表,不是一個可以含糊的數字。而那張表,是在被要求別讀 Package.swift 的情況下寫的,卻 10 條全對

「會不會編」到這裡有答案了。接下來才是我真正想問的。

它挑的檔,跟昨天圖挑的三個一樣嗎

昨天的圖用「連接度 + method 佔比 + 兩道過濾器」給出三個檔。今天這份文件最後一節叫「新人該從哪裡開始讀」,它自己給了一條 9 步的路線 —— 跟著一次 container run 走一遍:README 與技術概覽 → 命令樹 Application.swiftContainerRun.swift → XPC 的 API 目錄 XPC+.swift(它寫「一定要看」)→ XPCServer.swift → daemon 啟動 APIServer+Start.swift(它寫「資訊密度最高」)→ ContainersService.swiftRuntimeService.swift → plugin 骨架。

兩邊沒有互相看過:圖是 0 token 純結構算的,文件是在無菌室裡它自己讀的。擺在一起:

昨天圖挑的 今天 AI 的路線
ContainersService.swift ✅ 第 7 步 —— harness / service 分工的範本
RuntimeService.swift ✅ 第 8 步 —— 跨程序、跨 VM 邊界的那一跳
Parser.swift 193 行裡一次都沒提

三個對上兩個。 對上的那兩個,是兩種完全不同的方法各自獨立得到的答案,可信度比任何一邊單獨講都高 —— 至少可以把它當成這個 repo 的高可信入口。

漏的那個更有意思。 Parser.swift 是一支 1,138 行、33 個 static func 的工具箱,把 CLI 收到的字串(記憶體大小、使用者、平台、環境變數、volume)解析成設定值 —— 每個指令都要經過它,所以圖上它有 186 條跨模組的邊,排得很前面。但它是水管,不是心智模型:讀完它你知道 --memory 2g 怎麼變成位元組,不知道這個專案怎麼跑。AI 的路線裡佔掉這個位置的,是 XPC+.swiftAPIServer+Start.swift —— 圖上都沒排進前段,但它們是「誰接誰」的接線圖。

所以兩套方法量的是不同的東西:**圖量「誰被依賴得最多」,AI 量「先看哪個才看得懂」。**前者容易把工具箱型的檔案排得太前,後者則可能遺漏它 —— 而一個真的要讀這個 repo 的人,兩個都需要。

那把圖直接給它呢

寫到這裡自然會想:既然兩邊各看到一半,把圖交給 AI 一起讀,路線會不會更好?我補跑了一次 —— 同一個無菌室、多放一份未過濾graphify-out/,只要它給閱讀路線。花費 $2.53、耗時 197 秒、32 個回合,交出 9 步。

骨架一模一樣,檔案 9 個重疊 8 個;圖帶來的只有兩處:多了 Package.swift (目錄名 ≠ target 名的對照表)當第 2 步,多了 ContainerConfiguration 基礎層當第 8 步 —— 它明講是看到圖上 105 條邊。Parser.swift 還是沒進路線。

比較有意思的是它怎麼用那份圖。「我沒把握的地方」第 1 點寫著:god nodes 前五名(ContainerizationErrorFoundationFileManagerIntParserTest)是雜訊,只採信跟 Package.swift依賴方向吻合的兩個。它自己重做了昨天那兩道過濾器。 圖沒有讓路線變好,只是讓它多花一段力氣丟掉雜訊。


總結

我原本要問的是「它會不會編」。16 項對賬、錯兩處:一處它自己圈了,一處是數字算錯、沒圈 —— 答案是:會,但很少。但量完之後,那不是最有用的問題。更有用的是拿它的答案跟另一套方法對:重疊的地方最可信,不重疊的地方告訴你兩套方法各自看不見什麼。 而把圖餵給它,換不到更好的路線 —— 圖的價值,在 0 token 就給出候選與依賴方向;不一定要把它當成 AI 的輸入。

那份文件 193 行錯兩處,其中一處它自己標了不確定。這不是它比較厲害,是我在 prompt 裡要求它把沒把握的地方另開一節,它就照做了。**這個習慣是可以抄的。**沒標的那一處,是靠重數抓到的 —— 而第一次數的人是我,也數錯了。

這一篇留下的心法:

讀陌生專案,三件事:AST 先掃(0 token,拿到誰被依賴最多);再讓 AI 讀 README 與原始碼(拿到先看哪個才看得懂);最後把兩邊對起來 —— 重疊的,就是高可信入口。 只有一邊提到的,再問它:是工具箱,還是「誰接誰」的接線圖?

驗它寫的東西,挑有標準答案的題目;而驗完的表,發文前再數一次。如果你只能在 prompt 裡加一句話:不確定的地方要說你不確定。

明天:今天那間「無菌室」,正式一點叫隔離環境。我只寫了怎麼準備,它其實有三級 —— 每一級擋住什麼、又漏掉什麼,我都親手踩過。


參考資料


上一篇
Day 2 從沒看過的 repo,該從哪裡開始讀?
下一篇
Day 4 隔離環境有三級:刪掉、換目錄、開 VM —— 每一級擋住什麼,又漏掉什麼
系列文
盡信 Claude,不如無 Code — 心法與全端實戰8
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言