【從一台 Server 到分散式架構】第 29 篇:用同樣的思維看 ChatGPT——AI 聊天系統架構

前面我們看了 YouTube(大規模讀取)、Uber(即時位置與派單)、Twitter(動態牆的設計取捨)。

最後一個延伸案例是最近最受關注的系統之一:ChatGPT 類的 AI 聊天系統

小明在設計課程平台的 AI 助理時,其實已經碰到了一些相關的問題。但 ChatGPT 這種規模的 AI 聊天系統,還有幾個額外的挑戰。


ChatGPT 的獨特挑戰

相比一般 Web API,AI 聊天系統有幾個特殊性:

  1. 回應是串流的:不是「等一個結果」,是「一個字一個字推給你」
  2. 推理非常耗資源:每次對話都要跑一次 LLM inference,需要 GPU
  3. 多輪對話要記憶:「你剛才說的那個問題」要讓 LLM 知道上下文
  4. 請求之間差異極大:問一句話可能 2 秒回完,問一個複雜問題可能要 30 秒
  5. 同時服務幾千萬用戶:每個用戶的推理請求都要快速進入處理流程

核心架構流程


關鍵設計一:多輪對話的上下文管理

LLM 沒有「記憶」——每次呼叫都是從頭開始的。

要讓 ChatGPT 記得你之前說的話,做法是:每次呼叫時,把完整的對話歷史一起帶進去

第 1 輪:
  送給 LLM:[System Prompt] + [用戶: "你好,我叫小明"]
  LLM 回答:"你好,小明!有什麼可以幫你的?"

第 2 輪:
  送給 LLM:
    [System Prompt]
    + [用戶: "你好,我叫小明"]
    + [AI: "你好,小明!有什麼可以幫你的?"]
    + [用戶: "我叫什麼名字?"]
  LLM 回答:"你叫小明。"

把整段對話歷史帶進去,讓 LLM 「看到」前面說了什麼。

問題:對話歷史越長,Token 越多,推理越慢、越貴。而 LLM 有 Context Window 的上限(例如 128K Tokens)——超過了就要截斷,早期的對話會被「忘掉」。

解法策略

  • 只保留最近 N 輪的完整對話
  • 對超出範圍的歷史做摘要(用 LLM 把前 20 輪摘要成一段話)
  • 搭配 RAG:把用戶提過的重要資訊存入向量庫,需要時再搜出來

對話歷史存在哪裡?

  • 短期:Redis(這輪對話)—— 快速讀取
  • 長期:資料庫(所有歷史對話)—— 用戶重開時可以讀取

關鍵設計二:推理佇列與成本控制

LLM 推理的成本遠高於一般 API 請求,而且資源(GPU)有限。

當用戶同時湧入時,不能讓所有請求都直接打到推理服務——GPU 會被打爆,或者用戶要等很久不知道發生什麼。

解法:推理佇列 + 即時反饋

用戶送出請求
→ 立刻回傳「收到,處理中」(連線建立,SSE 開始等待)
→ 請求進入推理佇列
→ LLM 推理服務從佇列取出,開始處理
→ 生成的每個 Token 透過 SSE 推送給等待的用戶連線

用戶的感受:

  • 送出問題後,幾乎立刻看到「打字中」的指示
  • 文字開始一個個冒出來
  • 即使排隊,也有即時反饋,不是黑屏等待

這和第 17 篇的 WebSocket 結合了第 24 篇的串流回應,是同樣的原理。


關鍵設計三:Prompt 工程與 System Prompt

每個 ChatGPT 的對話,除了用戶輸入,還有一個「System Prompt」——這是給 AI 的角色設定和行為指令,用戶看不到。

System Prompt(例如):
  你是一個課程平台的學習助理。你只回答與課程相關的問題。
  用台灣繁體中文回答。回答要簡潔,不超過 200 字。

System Prompt 的設計很重要:決定 AI 的行為邊界,防止 AI 亂說話或偏離預期。

不同的使用情境(不同的 AI 助理功能)可以有不同的 System Prompt,這讓你可以用同一個 LLM 的 API,提供不同專業方向的 AI 服務。


關鍵設計四:費用控制與防濫用

LLM API 是按 Token 計費的,要防止:

  • 用戶無限制地問問題(浪費費用)
  • 惡意用戶製造大量請求(DoS)

做法:

  1. 每個用戶設配額:例如每天最多 100 次對話、每次最多 2000 Token
  2. Rate Limiting(第 13 篇):每分鐘最多 N 次請求
  3. Token 計數:在送入推理前,計算這次請求 + 歷史大概會用多少 Token,超出配額就拒絕
  4. 付費升級:免費用戶限制配額,付費用戶解鎖更高配額

ChatGPT 的完整架構


小結

ChatGPT 類系統和普通 Web 系統的最大差異在於:

  1. 串流回應:逐 Token 推送,用 SSE 實作(第 24 篇)
  2. 多輪上下文:每次呼叫都把歷史帶進去,要管理長度上限
  3. 推理佇列:GPU 資源有限,用佇列削峰,用即時反饋維持體驗
  4. 費用控制:配額 + Rate Limiting,防止無限制使用

這些元素,在這個系列裡其實都碰過:非同步佇列(第 08 篇)、Redis(第 05 篇)、WebSocket/SSE(第 17、24 篇)、Rate Limiting(第 13 篇)、RAG(第 23 篇)。

AI 系統不是另一個世界,它是同一套分散式架構思維的延伸應用。

下一篇是最後一篇主題文章——我們來看一個實戰情境:開賣和直播的高流量場景,限流、排隊與降級的實戰策略。

相關推薦

2026-04-07
【從一台 Server 到分散式架構】第 31 篇:從面試題反推架構——用本系列思維拆解系統設計考題
「設計一個 URL 短網址服務」「設計一個訊息系統」——系統設計面試問的不是背答案,而是思考方式。這篇整理了一套可以重複使用的面試框架,並用兩道例題示範如何從需求出發,一步步推導出架構、說清楚取捨。
2026-04-06
【從一台 Server 到分散式架構】第 30 篇:限流、排隊與降級實戰——開賣與直播場景
平常流量是 1000 QPS,但「開賣」的那一刻,瞬間湧入 50 萬個請求——系統要怎麼活下來?這篇用課程平台的限量課程開賣和直播開播場景,把第 13 篇學到的限流、降級、熔斷,落地到一個真實的高流量設計,走過每個防護層是怎麼工作的。
2026-04-04
【從一台 Server 到分散式架構】第 28 篇:用同樣的思維看 Twitter——社群動態與時序設計
Twitter 的核心功能看起來很簡單:發推文、看動態、按讚留言。但「動態牆」背後藏著一個棘手的設計問題:你追蹤 200 個人,每個人都可能隨時發文——你打開 App 時,那條時序動態要怎麼快速組出來?這篇來看社群動態系統的兩種策略:推(Fan-out on Write)與拉(Fan-out on Read)。
2026-04-03
【從一台 Server 到分散式架構】第 27 篇:用同樣的思維看 Uber——即時位置與派車系統
Uber 的核心問題看起來簡單:乘客在哪、司機在哪、把最近的司機派過去。但背後有幾個棘手的設計挑戰:海量的司機位置每秒更新、要在幾秒內完成司機配對、派單要公平且不重複。這篇用熟悉的架構思維,拆解 Uber 的即時調度系統。