引擎如何與你帶來的任何模型對話
帶任何你想帶的模型來。RakuAI 的 AI 層是介面,不是匯入——所以模型市場儘管每季為誰最強鬧一次脾氣,你的引擎永遠不必在乎。
這個週末有人問了我一個尖銳的問題。「如果 AI 是你引擎內部的執行時期原語,那引擎就被鎖死在你當初接進去的那個模型上。下次模型供應商一動,你就得重寫引擎。」
合理的顧慮。而且是錯的,但合理。
執行時期裡的 AI 原語不是某個特定模型。它是一個介面。五個各自獨立的子系統,各有自己的 C API,引擎的其餘部分都能對其定址,而不需要任何人知道是哪個模型、哪組權重、哪條推論路徑在產生答案。模型住在介面後面。呼叫端住在介面前面。兩者之間的契約小巧、穩定,而且刻意愚笨。
這篇文章講的就是那條邊界是怎麼畫的,以及為什麼畫下它之後,我持續從中得到愈來愈多的價值。
「AI 原語」實際指的是什麼
我們執行時期裡的 AI 層不是一個東西。是五個。
- 行為樹。確定性執行層。在意圖確定之後,告訴代理該做什麼。
- 導航網格與尋路。「我要怎麼在這個空間中移動」的那一層。
- 群眾模擬。「許多代理如何互相避讓、並在一起表現得連貫」的那一層。
- 感官系統與感知。「代理觀察到什麼」的那一層。
- 決策樹與複雜 AI 邏輯。「基於我所知的一切,我想做什麼」的那一層。
每一個都是自己的子系統。每一個都以自己的 DLL 出貨。每一個都有公開的 C API。沒有任何一個匯入特定模型。它們全都透過各自的介面與引擎的其餘部分對話,彼此之間也以同樣的方式對話。
當一個 .raku 體驗檔寫著 "ai_behavior": "strafe",它不是在指名一個模型。它是在指名一個已註冊的行為。執行時期解析這個字串。字串對應到一個實作。這個實作可以是行為樹、決策樹、學習到的策略,或是手寫的啟發式。呼叫端不知道。檔案不知道。實作可以被更換,而兩者都不必動。
這就是整個戲法。
模型管理層是它自己的子系統
當我們需要在執行時期內做真正的機器學習推論時,我們並沒有把它硬栓進上面五個子系統之一。我們加了第六個關注點,帶著自己的 API 表面:模型管理。
// Roughly what the surface looks like, simplified for the post.
RakuModelHandle raku_ai_load_model(const char* model_id, RakuModelOptions opts);
RakuInferenceResult raku_ai_infer(RakuModelHandle h, const RakuTensor* input);
void raku_ai_unload_model(RakuModelHandle h);
想呼叫模型的行為樹節點,走的是這個 API。不是匯入某家供應商的 SDK。不是連結到某個特定的執行環境。而是向模型管理子系統要一個控制代碼,然後使用它。
這意味著模型管理子系統是整個程式碼庫裡唯一知道特定模型格式、供應商或推論框架的地方。引擎其他任何地方看到的都是控制代碼與張量。換一個模型。換一個執行環境。換一個供應商。其他什麼都不必改。
這是毫不光鮮的基礎設施工作。它也是讓我們在 AI 生態系每季為「哪個模型是新霸主」鬧脾氣時,不必恐慌的原因。
這條邊界也保護了檔案格式
看看任何 .raku 體驗檔開頭的 ai 區塊。它有這樣的鍵:
"ai": {
"dda_enabled": true,
"target_flow_state": 0.7,
"profiler_mode": "active"
}
沒有一個是在指名模型。它們指名的是能力。「動態難度調整是開的。執行時期應該以 0.7 的心流狀態為目標。分析器是啟用的。」由執行時期決定要動用哪些子系統來交付這些能力。如果本季的正確答案是行為樹,那跑的就是行為樹。如果下一季變成一個小型裝置端模型,檔案不必改。
你在系統裡畫下的每一條介面邊界,都是未來能在不弄壞呼叫端的前提下發生變化的地方。我們在一開始就積極地把它們畫好了。現在正在花用當時存下的紅利。
為什麼這件事愈來愈重要,而不是愈來愈不重要
三個理由。
其一。模型市場一直在動。去年最強的模型是今年最貴的那個。今年最強的是明年過時的那個。把模型供應商硬編碼進引擎的團隊,到現在已經做過兩三次那個整合了。把模型管理介面擋在中間的團隊,只做過一次。
其二。裝置端比以前更重要。這個介面讓我們可以用同一個 ai_behavior: "strafe",在開發時打伺服器端模型、在正式環境打裝置端模型。呼叫端不知道。這種彈性是裝置端推論能在不重寫體驗層的情況下可行的唯一原因。
其三。開發迴圈中的 AI 助手受益於乾淨的邊界。當我請助手新增一個行為時,它必須遵守的契約就是已註冊行為的介面。而不是一團糾纏的供應商 SDK。介面愈乾淨,助手產出正確程式碼的速度愈快,我這邊的審查成本也愈小。
這件事難在哪裡
誠實的成本。
介面設計比實作花的時間更長。跳過介面步驟、直接寫能動的版本,誘惑是真實的。要抵抗。你在這裡抄的每一條捷徑,日後需要更換實作時都要償還。
你必須對放進介面的東西有紀律。每一個參數都是一份不容易打破的契約。加得比你以為需要的更少。等第二個使用情境來告訴你什麼才是真正通用的。AI 介面的第一版有五個後來證明不屬於那裡的參數。事後移除它們很痛苦。
已註冊的行為需要版本管理。當 "strafe" 在某一版執行時期裡是一個意思、在下一版裡是稍微不同的意思時,呼叫端是透過遊戲性回歸才發現的。我們為行為加上版本,並把 .raku 檔釘選到執行時期版本。這很煩。這是必要的。
有時候你確實想要那個依賴。這是異端的一條。確實存在某些情況:某個特定模型有某項特定能力,是任何泛用介面都表達不了的。誠實的做法是擴充介面、讓那項能力變得泛用,而不是把模型洩漏進呼叫端。我們不只一次逮到自己想抄那條捷徑。
架構上的論證很直接。AI 是執行時期原語。驅動它的檔案格式指名的是能力,不是模型。執行時期把能力解析到當下負責交付它們的子系統。三層之間的接線就是介面。介面小巧、穩定,而且刻意愚笨。
整篇文章就是這樣。
回去繼續蓋。
帶上你的模型。介面在等著。
RakuAI 透過控制代碼與張量和任何模型對話——開發時在伺服器端,正式環境在裝置端,呼叫端永遠察覺不到差別。看看你的權重如何接進一個為撐過模型市場更迭而打造的空間執行時期。