vatt'ghern jaskier's ballads
本文 2 個互動圖表在手機上以重點摘要呈現,互動版請以桌面瀏覽器開啟。

你下載一份號稱 Apache-2.0 的開源 model,拿去 fine-tune 出產品。三個月後法務問你:訓練資料是哪個模型生的?那個模型的 distillation 又是從誰蒸出來的?你答不出來——不是因為偷懶,是因為這條鏈根本沒有任何一份文件完整記過。

invisible dependency,從零講起——你的模型到底建在誰之上

完這篇你會知道一件事:一個現代 LLM 的「依賴」早就不是 requirements.txt 那種看得見、列得出的東西。它藏在「我用 model A 生了一批合成資料」「我用 model B 過濾語料」「我用 model C 當 judge 篩 response」這些訓練決策裡,而且這些選擇本身又遞迴地依賴別人的選擇。一篇 arxiv 論文(Sanjay Adhikesaven、Haoxiang Sun、Sewon Min,Which Models Are Our Models Built On?)給這種看不見的傳遞性影響取了個名字——invisible dependency——並做了一個 agentic 系統把它挖出來。這篇文章從「為什麼依賴會看不見」講起,到怎麼把它形式化成一張圖,最後落到一個你下週可能就會遇到的問題:你要選的那個 base model,背後到底牽連了誰。

四種「用模型」——依賴從哪裡偷偷長出來

先把場景攤開。傳統的軟體依賴很誠實:你 import 一個 library,它寫在 manifest 裡,工具掃得到,授權條款查得到。LLM 的訓練不是這樣。論文開頭那句把現況講得很白:「Modern LLM training pipelines increasingly rely on other models to generate data, filter corpora, judge outputs, and guide development decisions.」

拆開看,這是四個不同的「用模型」動作,每一個都讓另一個模型的影響滲進你最終的 weights:

  • generate data——你讓一個既有模型生成合成訓練資料。那個模型的偏好、風格、甚至它自己訓練時吃過的東西,都被蒸進你的 corpus。
  • filter corpora——你用一個 classifier 或 LLM 去判斷哪些語料留、哪些丟。留下來的分布由那個過濾模型的判斷塑形。
  • judge outputs——你用一個 model 當 judge,替 RLHF 或 evaluation 打分。被它打高分的方向,就是你的模型被推去的方向。
  • guide development decisions——更隱晦的一種:你在開發過程中參考另一個模型的行為來決定架構、超參、資料配比。

關鍵在於,這四種動作沒有一個會留下 import 那樣的硬痕跡。資料生完,生它的模型不在你的 repo 裡;語料過濾完,過濾器不會被一起 release;judge 打完分,留下的只是被它塑形過的 reward 訊號,不是 judge 本身。可是它的影響已經 baked in 了。這就是「invisible」的第一層意思——影響真實存在於最終的 weights 裡,紀錄卻不在你手上的任何一個檔案裡。傳統依賴掃描工具到這裡完全失效,因為它們掃的是 build 時的 link,而這些模型的影響發生在更早、更上游的 data 與 decision 階段,根本沒有 link 可掃。

對照一下就更清楚這個落差有多大。一個 npm 套件的依賴鏈,你跑 npm ls 就能完整列出,每個節點有明確的名字、版本、license,工具替你算傳遞閉包。LLM 沒有對應的東西——沒有一個 llm ls 會告訴你「這個 checkpoint 的訓練資料是 model X 生的,X 的對齊資料又是 model Y judge 的」。整個產業在用模型造模型,卻沒有任何一個 lockfile 在記這件事。論文要做的,本質上就是事後把這個不存在的 lockfile 重建出來。

而且這些角色是異質的。「A 用 B 生資料」和「A 用 B 當 judge」是兩種完全不同的依賴關係,帶來的義務與風險也不同——前者把 B 的內容與 license 蒸進 A,後者把 A 的訓練方向綁上 B 的偏好。論文後面要解決的一個核心問題,就是怎麼用同一套形式把這些不同角色的邊統一表示,而不是粗暴地全部標成「A 依賴 B」。下面這張圖把四種角色並排,每一條邊都標出它在 pipeline 裡扮演的 operation——這正是論文所謂 operation-centered relationship 的直覺。

upstream model B your model A generate data filter corpora judge outputs guide decisions 同一對 (B → A),四條邊各記不同 operation——這就是 operation-centered relationship 沒有一條會出現在 A 的 requirements 或 release manifest 裡
四種角色帶來的義務不同:generate data 可能把上游 license 一起繼承,judge outputs 則把 train 與 evaluation 綁在一起。論文用 operation-centered relationship 統一表示這些異質的邊。

遞迴與散落——為什麼人追不動這條鏈

如果依賴只有一層,問題還算可控:你查一下生資料用的是哪個模型,記下來就好。麻煩在於它是遞迴的。論文這句講得很精準:「These dependencies are recursive: a model may depend on an upstream artifact whose own dependencies are documented only in separate releases and artifacts.」

翻成白話:你依賴的上游 artifact,它自己也有依賴,而那些依賴只記在它自己那份獨立的 release 和 artifact 文件裡。你要往上追一跳,得去翻另一份 model card;再追一跳,又是另一份 repo 的 README、另一個版本的 technical report。每一跳的線索都散在不同地方,格式不一、命名不一、版本對不上。沒有任何一份文件試圖記錄整條鏈——每個作者只記自己這一層用了什麼,不記、也不可能記他用的東西底下又牽連了誰。

遞迴和散落這兩個性質會互相放大。如果鏈是遞迴但集中在一份文件,人還追得動;如果是散落但只有一層,人也追得動。偏偏它兩者都有:深度上是遞迴的,廣度上每一跳又散在不同產物裡。深度乘以散落,就是論文說的 complexity——它不是線性增長,是每往上一跳,要查的文件來源、要對齊的命名分歧、要處理的版本歧義都成倍堆疊。到了第三、第四跳,一個人類分析師要同時在腦子裡維護的「這個 codename 到底指誰」的對照表,就已經超載了。

論文用了一個很重的詞來形容後果:「the full dependency structure is fragmented across heterogeneous public artifacts, with complexity and recursive depth far outpacing humans' ability to trace.」complexity 和 recursive depth 已經超過人能手動追的範圍。這不是「很麻煩」,是「人力上不可行」。

這就是為什麼作者做的是一個 agentic 系統而不是一張查表。它的定義句是:「We introduce ModSleuth, an agentic system that recursively reconstructs LLM dependency graphs from public artifacts with source-grounded evidence.」三個動詞值得各別停一下——recursively(一跳一跳往上爬,追到沒有更上游為止)、reconstructs(重建,因為沒有現成的完整圖,只有散落的碎片)、source-grounded(每條邊都要有出處證據,不是猜的)。

為什麼非得是 agentic?因為每往上一跳,下一步要去哪裡找線索、找到的東西要怎麼解讀,都不是固定流程。這一跳的線索可能在 model card 的一句話裡,下一跳的線索可能藏在一個 GitHub repo 的 config 檔,再下一跳又要去比對兩份 technical report 的措辭才能確認是不是同一個 artifact。這種「讀一點、判斷一下、決定下一步往哪查」的迴圈,正是 agent 擅長而固定 pipeline 做不到的。一個寫死的 scraper 只能抓它被教過的格式;遞迴依賴的麻煩恰恰是每一層格式都不一樣。

下面這個 widget 把「遞迴 + 散落」的後果做成可操作的東西。這是一張示意的依賴圖(節點與邊是 schematic,不是論文公布的真實數值),用 force-directed 佈局自己排開。你可以抓住任何一個節點拖動,看整張網怎麼牽連;更重要的是點任一個上游節點按「移除」,看有多少下游 release 的依賴邊跟著斷掉——一個上游 artifact 的 reach,往往比直覺深得多。

點一個節點,拖動可重排
示意依賴圖(節點 / 邊為 schematic,非論文公布數值)。三個下游 release(深色)各自往上依賴若干 upstream artifact;遞迴往上還有更上游的來源。拖動感受牽連,移除上游節點看連帶斷裂的依賴數。

示意依賴圖(節點 / 邊為 schematic,非論文公布數值)

拔掉一個上游 artifact,斷的常不只直接那條邊——順著遞迴往下,一整片下游 release 跟著塌,比直覺深。

難點不是 parsing——是「什麼才算一條依賴」

到這裡你可能以為,這就是個資訊抽取(information extraction)問題:寫個夠強的 agent 去爬 model card、讀 technical report、把「我們用了 X」這種句子抓出來,連成圖就好。論文的發現恰恰相反,而且這是全篇最反直覺的一句:「the primary challenge is no longer information extraction, but defining what constitutes a dependency and reconciling artifact references across inconsistent documentation.」

主要難點不再是抽資訊,而是兩件更基礎的事——定義什麼算一條依賴,以及調和彼此不一致的 artifact 引用。

第一件,「什麼算依賴」,不像聽起來那麼好定。如果 A 用 B 生了 1% 的訓練資料,算依賴嗎?如果 A 只在開發初期看了 B 的行為,後來沒用,算嗎?如果 B 是用來過濾掉壞資料、最後留下的語料反而跟 B 沒直接關係,算嗎?這些都是邊界案例,而依賴圖的價值高度取決於你怎麼劃這條線。抓得太寬,圖會爆炸成一團弱關聯的亂麻,每個模型都「依賴」幾乎所有模型,圖就失去資訊量,等於沒建;抓得太嚴,又會漏掉真正會帶來 license 義務和 evaluation 污染的傳遞邊,等於白建。這條界線要靠形式化來劃,而且要劃得讓 agent 能機械地、一致地套用,不能每條邊都靠人臨場判斷。

第二件,「調和不一致文件」,是現實世界的髒活。同一個 artifact 在不同 release 裡可能叫不同名字、掛不同版本號、放在不同 repository。文件 A 說它用了「our internal reward model」,文件 B 把同一個東西寫成具體版本號,文件 C 又只給了個 codename。要把這些指向同一實體的引用認出來、對齊起來,才不會把一個 artifact 拆成三個節點、或把三個不同 artifact 併成一個。這件事為什麼難在於:認錯一個身分,整張圖的拓樸就錯了——你會憑空多出一條不存在的依賴,或漏掉一條真實的。而判斷「這兩個名字是不是同一個東西」往往沒有權威答案可查,只有散落的旁證,要靠交叉比對版本時間、repo 結構、文件描述才能下結論。這正是 agentic 系統比規則式 parser 強的地方——它能讀上下文做這種模糊比對。

論文用一套形式化同時解這兩件事:「a formalization that distinguishes direct and indirect dependencies, represents heterogeneous pipeline roles through operation-centered relationships, and resolves artifact identities across names, versions, and repositories.」三個部分對應三個難題——

// 形式化的三個部分(對照論文 abstract)

direct vs indirect
  // A 直接用 B(direct)
  // A 用 B,而 B 又用 C ⇒ A 對 C 是 indirect
  dep(A, B, op)                // direct:一條 operation-centered 邊
  reaches(A, C) = ∃ path A → … → C   // indirect:傳遞閉包上的可達

operation-centered relationship
  // 邊不是布林的「有沒有依賴」,而是帶角色
  op ∈ { generate-data, filter-corpora, judge-outputs, guide-decisions }

artifact identity resolution
  // 把散落的引用對齊到同一實體
  resolve("internal RM", "rm-v2", repo/xyz#rm) → 同一個 artifact_id

direct 與 indirect 的區分是整套形式化的承重牆。你直接用的那個模型,license 你大概會去看;但它的上游、上游的上游帶來的義務,是 indirect 依賴——而那才是文章開頭法務問題的真正麻煩所在。下面這個 widget 讓你拖一個「往上追幾跳」的 hop-depth,看 indirect 依賴怎麼隨深度擴散。

depth 1 · direct only
左 = 你的 release · 往右每一層是再上一跳的上游
示意傳遞閉包(schematic)。depth 1 只看你直接用的;每加一跳,被你 indirect 依賴、因而可能帶 license 義務的上游 artifact 數量擴大。multi-hop license obligation 的風險就藏在右邊那幾層。

示意傳遞閉包(schematic)

只看 direct 依賴約背 2 條義務;往上追幾跳,傳遞閉包上的 artifact 快速膨脹——義務住在你沒直接碰過的上游節點。

把 hop-depth 從 1 拉到 4,你看到的不只是節點變多——是「你要負責的範圍」隨深度擴大。direct 依賴你會盡職去查,indirect 依賴卻是你從沒直接碰過、卻仍可能背著義務的那些節點。論文要 source-grounded 地把這整個傳遞閉包重建出來,靠的就是這套把 direct / indirect 明確分開的形式化。

四個 release,1,060 條邊——圖一旦建起來,看見了什麼

形式化講完,論文把 ModSleuth 實際跑了一遍。worked example 的數字很具體:「Applying ModSleuth to four public-artifact-rich LLM releases, we recover 1,060 source-verified dependencies and construct large-scale dependency graphs of modern LLM development.」

四個「public-artifact-rich」的 LLM release——也就是公開產物夠多、足以重建依賴的那種——挖出 1,060 條 source-verified 依賴。每條都有出處,不是 agent 腦補的。論文沒有點名是哪四個 release,所以這裡也不替它編模型名;重點是量級:光是四個釋出,傳遞性的依賴就堆到四位數,這正好印證前面「人追不動」的說法。平均一個 release 攤到兩百多條依賴邊,沒有任何一個人能在腦子裡維護這個規模的圖,更別說每條還要附上出處。source-verified 這個限定詞值得再強調一次——它不是 agent 推測「應該有」這條依賴,而是每一條都能指回某個公開產物裡的具體段落。這讓圖可以被第三方複查,而不是又一個要你信的黑箱結論。

而圖的價值不在「邊很多」,在於它讓四類本來看不見的東西浮出來。論文列得很清楚:「These graphs reveal multi-hop license obligations, train-evaluation coupling, discrepancies between released and training-time artifacts, and documentation inconsistencies that would otherwise be difficult to uncover.」下面這張表把這四類攤開,逐一說它是什麼、為什麼會咬到你。

點欄位標題排序 · 3 欄 × 4 列

圖揭露的東西 它是什麼 為什麼咬到你
multi-hop license obligation license 義務沿著 indirect 依賴傳遞,跨越你沒直接碰過的多個上游 artifact。 你以為合規的 release,可能背著上游某一跳的條款;只看直接依賴會漏掉。
train-evaluation coupling 同一個(或同源的)模型,既參與了訓練、又出現在 evaluation 路徑上。 train 與 eval 不獨立,benchmark 分數可能被污染,你高估了真實能力。
released vs training-time discrepancy 公開 release 的 artifact,跟訓練當下實際用的 artifact 對不上。 你照 release 文件復現,行為跟原作者訓練時不一樣,debug 找不到根因。
documentation inconsistencies 不同文件對同一依賴的描述彼此矛盾——名稱、版本、角色不一致。 你信哪份文件都可能錯;要對齊才知道真相,這正是 artifact identity resolution 要解的。
四類 finding 對應 abstract 列出的四項。共同點:單看任何一份 release 文件都看不出來,要把整張依賴圖拼起來才會顯形。

這四類裡,train-evaluation coupling 對日常最致命。你看到某個 release 在 benchmark 上漂亮的分數,卻沒看到它的 judge model 或合成資料來源,跟它拿去評測的 model 同源——train 與 eval 的獨立性破了,分數的可信度跟著破。這種污染特別陰險,因為它不需要任何人作弊:作者可能完全善意地用了業界最常見的那個 judge model,而那個 judge 剛好也滲進了 benchmark 的構造或評分,coupling 就在沒人察覺的情況下成立了。單看 benchmark 報告永遠看不出來,因為報告只列分數,不列分數背後的依賴。依賴圖把這條 coupling 顯形,你才有機會把它從「能力提升」裡扣掉,還原一個比較誠實的能力估計。

released vs training-time discrepancy 則是另一種會默默浪費你時間的東西。你照公開 release 的 artifact 去復現論文行為,怎麼調都對不上——不是你做錯,是作者訓練當下用的 artifact 跟最後 release 出來的版本本來就有落差,可能是某個中間 checkpoint、某個沒一起公開的過濾器。沒有依賴圖,你會在自己的程式碼裡找一個根本不在你這邊的 bug。圖把「released 的」與「training-time 用的」這兩個 artifact 分成兩個節點、標出落差,你才知道該停止 debug 自己、轉去質疑復現前提。

你下週選 base model 時,這張圖怎麼用

把這套東西落到實務。論文最後一句交代了交付物:「We release ModSleuth and the resulting dependency graphs to support transparent analysis of the increasingly complex ecosystems underlying modern LLMs.」系統和挖出來的依賴圖都開源——這不是一篇只給你看結論的論文,它把工具給你了。

對三種人這張圖直接可用。要選 base model 的工程師,可以在 fine-tune 之前先看它的 indirect 依賴鏈,把 multi-hop license obligation 查清楚,免得三個月後才被法務問倒——文章開頭那個場景,本來就是因為沒有圖才答不出來。做合規盡職調查的,多了一個 source-grounded 的依據——每條邊都有出處,不是憑 model card 的一面之詞,真要上法庭或過審計,這種可回溯的證據鏈遠比「我們相信它是乾淨的」有份量。要評估 benchmark 數字的,可以拿 train-evaluation coupling 當折扣係數,判斷一個漂亮分數有多少是真本事、多少是評測污染,避免照著被污染的排行榜做選型決策。

當然也要誠實地看它的邊界。ModSleuth 只能重建「public-artifact-rich」的 release——公開產物不夠的閉源模型,沒有足夠線索可爬。它重建的是「文件記載的依賴」,記載本身有漏,圖就有漏;它能抓出文件之間的不一致,但抓不出所有人都沒寫進文件的那條依賴。換句話說,它把「散落但存在的紀錄」拼成圖,沒辦法把「從來沒被記下來」的影響變出來。即便如此,能把四個 release、1,060 條傳遞邊 source-grounded 地攤在你面前,已經把這個生態系從「人力不可追」拉回「工具可查」。

The model:你的模型不是建在一份 requirements.txt 上,是建在一張沒人完整畫過的依賴圖上——invisible dependency 就是那些影響已經進了你的 weights、紀錄卻散在別人 release 裡的邊。先把圖建起來,才知道自己到底站在誰的肩膀上。