iT邦幫忙

2026 iThome 鐵人賽

DAY 11
0

一、回到我們熟悉的 Client-Server 架構

(這節是給菜鳥的,老鳥可以直接跳到第 2 節了 XDD)

從系統設計的角度看,本質上跟 AI 聊天的過程,依然是我們再熟悉不過的 Client-Server 的模式。(很像廢話,但有時候魔法用著用著,確實會忘記他跟你所認知的或是你正在開發的架構,有很多東西是一樣的,沒那麼可怕~)

https://ithelp.ithome.com.tw/upload/images/20260924/20183607durkV0kTq1.png

這張圖當然只是個示意,實際背後系統架構的複雜度,肯定遠遠不止這些,畢竟功能也遠遠不止這些。

如果拆開來看兩邊各自要做的事情:

  • Client 端(使用者 / 應用程式 / Agent):
    在 Client 這端主要負責就是管理對話的上下文(Context)、把參考資料和 System Prompt 組織成符合 API 格式的文字,透過發送 Request 與伺服器溝通;如果是具備工具調用(Tool Calling)能力的 Agent,甚至還得在本地端負責執行指令或讀寫檔案,把結果再整理然後再發一次 Request。透過這樣反覆執行,形成了我們與 AI 聊天的整個過程。但無論功能多複雜,退回到底層最基本的動作,其實就是:把當前要講的話打包成一段 Prompt,送出 Request。

  • Server 端(Model Provider / Local Model):
    伺服器也同樣是一整套龐大的分散式系統。除了我們這幾天聊的幾十層 Transformer 模型計算,它還得處理 API 路由、排隊調度、資料儲存、以及我們後面會聊到的快取機制。而它的核心任務也很明確:接收這串 Prompt,在 GPU 裡跑完模型計算,再把生成的文字一個字一個字串流吐回給 Client。

簡單區分了兩者的分工與邊界,我們繼續來看一下工程師是怎麼設計與運用模型,實作出這種可以跟你對話,還能記住你說過的話的聊天系統。

(沒錯!這是系統設計!不是 AI!抱歉有點敏感 XDD 我只是想表達很多人時常在讚嘆 AI 的同時貶低軟體工程師,但其實有很多讚嘆 AI 的點,不見得都是 AI 的功勞,而是軟體工程師與產品們的設計跟決策)


二、兩大階段:Prefill 與 Decode

當 Server 收到 Client 送來的長篇 Prompt 時,不是像我們前幾天那樣單純把一大段 Prompt 丟到模型,吐出結果。這裡分成了兩個不同的階段:Prefill 與 Decode:

小故事:曾經在 ChatGPT 剛出來的時候,我跟同事曾討論過「為什麼 AI 都記得住我們講過的內容?」這問題放到現在可能沒什麼,大家都知道一次會送一大包,但畢竟當時剛出來嘛。那時的我很天真地覺得「每次發過去都會 fine-tune 模型參數,每個 session 都是個別 tune 過的 model,所以才都記得住我們的聊天記錄」。現在想想這想法有夠荒唐哈 XDD

階段一:Prefill 階段(理解上下文脈絡)

首先,我們要先理解一件事,當我們在一個 session 中跟 AI 對話時,每一次的 Request 不是只有把我們這輪的對話內容發給模型,而是整個 session 裡面所有的歷史紀錄(當然有 Compact 後就是從 Checkpoint 到最新的輸入之間所有的內容)。對,模型的 Input Token 就是這麽大包!絕對不是「我吃蘋果」這種很短的句子~

幾天前的我們,可能還比較難想像這個階段的目的。但 Day07 提到了現在很多在使用的 LLM,採取的是「Decoder-Only」的策略,所以我們已經沒有 Encoder 了,理解上下文的工作也全部都在 Decoder 身上。Client 送來的 Prompt 通常是一大段文字(幾百字、幾千字,甚至包含整份程式碼以及厚厚的 System Prompt),因此,這個階段的目的是要先讓模型 「理解傳過來的 Prompt 內容到底在做什麼」。

所以在這個階段,模型做的事情就是 「一次性消化整批輸入內容然後理解上下文關係」:

  • 模型把這上千個 Token 平行(Parallel) 一口氣灌進 GPU。
  • 輸入文字被切成 Token 灌進 GPU 後,所有的輸入字同時進行我們前幾天講過的 Embedding -> 多層 Self-Attention 計算。
  • 彼此之間同時比對注意力(QKV),搞懂這整段 Prompt 的上下文脈絡。

工程特性:算力密集(Compute-Bound)
這時候 GPU 裡的幾萬個運算核心全速工作,把算力用在進行大規模的矩陣乘法。


階段二:Decode 階段(文字接龍)

讀完並理解整段 Prompt 之後,模型可以開始透過計算好的上下文資訊(KV),不斷玩「文字接龍」,就像我們平常在介面上看到的「打字機效果」。

這個階段,完全回歸到 自回歸模型(Autoregressive) 的本質(還記得它嗎?在 Day 07 XDD)
「每一次模型輸入然後前向傳播,就只負責猜出『下 1 個 Token』!然後把生成的 Token 再放到 Input 再生成下一個字」

  1. 在 Prefill 階段理解的上下文資訊(KV)時,其實最後已經猜出第 1 個字(例如:「我」);
  2. 概念上把「我」追加到剛剛的上下文尾端,透過最新的 Token 配合上下文資訊,再猜出第 2 個字(例如:「是」);
  3. 把「是」再追加進去,猜出第 3 個字……
  4. 如此循環往復,一個字接一個字串流吐回給 Client,直到模型猜出結束符號,整場推論才宣告結束。

工程特性:記憶體頻寬密集(Memory-Bound)
在這個階段,模型跑完整個神經網路,僅僅只是為了生出 1 個 Token。但為了算這 1 個 Token,GPU 卻必須把整個幾十 GB 的模型權重,從 GPU 顯存完整搬進運算核心跑一輪!這時候算力根本用不滿,真正的效能瓶頸全卡在 GPU 顯存搬移的頻寬上。


三、兩大階段的運作時序

把剛才聊到的 Client-Server 與兩大階段串連起來,整個現代 LLM 推論的運作過程類似這樣:

https://ithelp.ithome.com.tw/upload/images/20260924/20183607oW7xgvGETL.png

在使用 AI Agent 時,會有兩個不同指標來表示體感上的延遲:

  • 首字延遲(TTFT, Time To First Token):就是 Server 在跑 Prefill 階段 的時間。輸入的文章越長,模型理解的時間就越久。
  • 每秒生成字數(TPS, Tokens Per Second):就是 Server 在跑 Decode 階段 的速度。取決於 GPU 頻寬能多快把權重搬完一次來產生一個字。

每一次的 Decode(生出一個 Token) 或是 每一輪對話(Request),如果都要 Prefill 計算的話,整台伺服器就等於一直在把上下文重新理解一次,顯然是一筆非常大的計算開銷。還記得 昨天 的問題嗎?「頭髮、眼睛、鼻子的邊界(K)與畫面(V)在「嘴巴」比對時,是不是可以重複利用呢?」確實可以!這又是一次漂亮的設計,將整體運算的時間及成本,以及你的 Token 花費大大降低的設計,KV Cache。

明天就來聊聊這東西是啥吧!


參考資料


上一篇
Day 10 | 少年 Token 的奇幻漂流(終):淺出 Self-Attention
下一篇
Day 12 | 明天,我要和昨天的 Token 約會(上):KV Cache
系列文
在贏家書寫歷史之前:我所看見的 AI,與一位工程師共舞著 共 16 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言