โ† 2026-06-24 ๐Ÿ“‚ All Days 2026-06-26 โ†’

๐Ÿ—๏ธ ็ณป็ปŸ่ฎพ่ฎก / System Design โ€” Day 61

่ฎพ่ฎก AI ่Šๅคฉๅนณๅฐ๏ผˆChatGPT ่ง„ๆจก๏ผ‰

Design an AI Chatbot Platform (ChatGPT-scale)

โฑ๏ธ ้ข„่ฎก้˜…่ฏปๆ—ถ้—ด / Estimated read time: 3 min


๐ŸŽฏ ็œŸๅฎžๅœบๆ™ฏ / Real-World Scenario

ๆƒณ่ฑกไฝ ๅœจ OpenAI ๅทฅไฝœ๏ผŒ้œ€่ฆ่ฎพ่ฎกไธ€ไธชๆฏๅคฉๅค„็† 1 ไบฟๆฌกๅฏน่ฏ่ฏทๆฑ‚็š„ AI ่Šๅคฉ็ณป็ปŸใ€‚็”จๆˆทๅ‘ไธ€ๆกๆถˆๆฏ๏ผŒๅ‡ ็ง’ๅ†…ๅฐฑๆ”ถๅˆฐๆตๅผๅ›žๅคโ€”โ€”่ƒŒๅŽ็ฉถ็ซŸๅ‘็”Ÿไบ†ไป€ไนˆ๏ผŸ

Imagine you're at OpenAI, designing a system handling 100 million conversation requests per day. A user sends a message and gets a streamed response within seconds โ€” what's happening under the hood?


๐Ÿ›๏ธ ๆžถๆž„ๅ›พ / Architecture Diagram

User Browser / Mobile App โ”‚ WebSocket / SSE โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ API Gateway โ”‚ โ”‚ (Auth, Rate Limiting, Session Routing) โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ–ผ โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Chat Serviceโ”‚ โ”‚ Streaming Proxy โ”‚ โ”‚ (FastAPI) โ”‚ โ”‚ (SSE/WebSocket) โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ–ผ โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Context Svc โ”‚ โ”‚ LLM Inference โ”‚ โ”‚ (Redis TTL) โ”‚ โ”‚ Cluster โ”‚ โ”‚ โ”‚ โ”‚ (vLLM / TGI) โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”Œโ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”โ”‚ โ”‚ โ”‚ โ”‚GPUโ”‚ โ”‚GPUโ”‚ โ”‚GPUโ”‚โ”‚ โ–ผ โ”‚ โ””โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”˜โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ Conversationโ”‚ โ”‚ โ”‚ DB โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ (Postgres) โ”‚ โ”‚ Model Registry โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ (S3 + weights) โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โš–๏ธ ๆ ธๅฟƒๆƒ่กก / Key Tradeoffs

ไธบไป€ไนˆ็”จ SSE๏ผˆServer-Sent Events๏ผ‰่€Œ้ž WebSocket๏ผŸ

  • SSE ๆ˜ฏๅ•ๅ‘ๆต โ†’ ๆœๅŠก็ซฏๆŽจ้€ token ๆ›ด็ฎ€ๅ•
  • WebSocket ้œ€่ฆๅŒๅ‘้€šไฟก โ†’ ่Šๅคฉๅœบๆ™ฏไธๅฟ…่ฆ
  • SSE ๅคฉ็„ถๆ”ฏๆŒ HTTP/2 ๅคš่ทฏๅค็”จ

Why SSE over WebSocket? SSE is one-directional โ€” perfect for streaming tokens. WebSocket adds bidirectional complexity you don't need here. SSE also works seamlessly with HTTP/2 multiplexing.

ไธบไป€ไนˆ็”จ Redis ๅญ˜ๅฏน่ฏไธŠไธ‹ๆ–‡๏ผŸ

  • LLM ๆ˜ฏๆ— ็Šถๆ€็š„๏ผšๆฏๆฌก้ƒฝ่ฆไผ ๅฎŒๆ•ด history
  • ็”จๆˆทๅนณๅ‡ๅฏน่ฏ 10-20 ่ฝฎ๏ผŒtoken ้ข„็ฎ—ๆœ‰้™
  • Redis TTL = 30min ่‡ชๅŠจ่ฟ‡ๆœŸ๏ผŒไธๅ †ๅžƒๅœพ

Why Redis for conversation context? LLMs are stateless โ€” you must send the full history every request. Redis with TTL handles the limited context window budget and auto-expires stale sessions.

ๆŽจ็†้›†็พคๅฆ‚ไฝ•ๆ‰ฉๅฎน๏ผŸ

  • vLLM ็š„ PagedAttention๏ผšGPU KV Cache ๅˆฉ็”จ็އ +3x
  • ่ฏทๆฑ‚่ทฏ็”ฑๆŒ‰ session affinity๏ผˆๅŒ session โ†’ ๅŒ GPU ่Š‚็‚น๏ผŒๅ‡ๅฐ‘ KV cache miss๏ผ‰

How do you scale inference? vLLM's PagedAttention gives 3x better GPU memory utilization. Route by session affinity โ€” same session to same GPU node minimizes KV cache misses.


โŒ ๅธธ่ง่ฏฏๅŒบ / Common Mistakes

ๅ‘ 1๏ผšๅฏน่ฏ Context ๆฒกๆœ‰ๆˆชๆ–ญ็ญ–็•ฅ

  • LLM ๆœ‰ๆœ€ๅคง context window๏ผˆๅฆ‚ 128K tokens๏ผ‰
  • ่ถ…้™็›ดๆŽฅๆŠฅ้”™๏ผŒ่ฆๅฎž็Žฐ sliding window ๆˆ– summary ๅŽ‹็ผฉ

Trap 1: No context truncation strategy. LLMs have max context windows. You need a sliding window or summary compression before you hit the limit.

ๅ‘ 2๏ผšๆฒกๆœ‰่ฏทๆฑ‚ๆŽ’้˜Ÿๅฏผ่‡ด GPU OOM

  • ๅนถๅ‘ๅคง้‡ๆŽจ็†่ฏทๆฑ‚ โ†’ GPU ๅ†…ๅญ˜็ˆ†็‚ธ
  • ๆญฃ็กฎๅšๆณ•๏ผšinference queue + backpressure

Trap 2: No request queuing leads to GPU OOM. Concurrent requests overwhelm GPU memory. Add an inference queue with backpressure.

ๅ‘ 3๏ผšๆฏๆฌก้ƒฝ้‡ๆ–ฐๅŠ ่ฝฝๆจกๅž‹ๆƒ้‡

  • ๆƒ้‡ไธ€ๆฌกๅŠ ่ฝฝ๏ผŒๅธธ้ฉป GPU
  • ็”จ Model Registry๏ผˆS3๏ผ‰็ฎก็†็‰ˆๆœฌ๏ผŒ็ƒญๆ›ดๆ–ฐ

Trap 3: Reloading model weights per request. Weights should be loaded once, resident on GPU. Use a Model Registry for version management with hot-reload.


๐Ÿ“š ๅ‚่€ƒ่ต„ๆ–™ / References

  1. vLLM: PagedAttention for Efficient LLM Serving
  2. OpenAI API Streaming Docs
  3. Designing ML Systems โ€” Chip Huyen

๐Ÿง’ ELI5

ๅฐฑๅƒไธ€ไธช่ถ…็บงๅฟซ็š„ๆ‰“ๅญ—ๅ‘˜๏ผš

ไฝ ้—ฎ้—ฎ้ข˜ โ†’ ๅŠฉๆ‰‹่พนๆƒณ่พนๆ‰“ โ†’ ไฝ ๅฎžๆ—ถ็œ‹ๅˆฐๆฏไธชๅญ—ๅ‡บ็Žฐใ€‚

่ƒŒๅŽๆœ‰ๅพˆๅคš็”ต่„‘๏ผˆGPU๏ผ‰่ฝฎๆตๅธฎๅฟ™ๆ‰“ๅญ—๏ผŒ

่ฟ˜ๆœ‰ไธ€ไธช"่ฎฐๅฟ†ๆœฌ"่ฎฐไฝไฝ ไปฌ่Š่ฟ‡ไป€ไนˆใ€‚

*Like a super-fast typist: you ask a question โ†’ the assistant types while thinking โ†’ you see each word appear in real time. Behind the scenes, many computers (GPUs) take turns "typing," and a "memory notebook" (Redis) remembers your conversation history.*