← 2026-07-01 📂 All Days 2026-07-03 →

🔄 复习日 / Review Day — Day 80

📊 NeetCode: 64/150 · SysDesign: 63/40 · Behavioral: 63/40 · Frontend: 37/50 · AI: 31/30
🔥 3-day streak!

今天是复习日!回顾过去4天的内容 (Days 76–79)。

涵盖主题 / Topics covered:

  • 🏗️ System Design: AI Chatbot Platform (ChatGPT-scale)
  • 💻 Algorithms: Trie (Add/Search Words + Wildcard), Word Search II, Kth Largest in Stream (Heap)
  • 🐍 Python Craft: Context Managers, Connection Pooling, Retry with Backoff
  • 🤖 AI: AGI Debates, Emerging Architectures, AI News

📝 Quick Quiz — 3 Mini-Reviews

Q1: [🏗️ System Design] — AI Chatbot Platform

Question: In a ChatGPT-scale AI chatbot, why do you need a streaming gateway layer separate from the LLM inference backend — and what problem does it solve for clients?

<details><summary>显示答案 / Show Answer</summary>

LLM inference is slow to start but generates tokens incrementally. Without streaming, clients would wait 10–30s for the full response, causing timeouts and terrible UX.

The streaming gateway (e.g., nginx + SSE or WebSocket proxy) solves this by:

  1. Forwarding tokens as they're generated — clients start rendering within milliseconds
  2. Buffering backpressure — if the client is slow (mobile, weak connection), the gateway queues tokens without stalling the GPU inference worker
  3. Session affinity — routes a user's follow-up message to the same conversation state (message history, system prompt)

Key tradeoff: Stateless HTTP is easier to scale, but SSE/WebSocket connections are stateful. You typically pin a user session to a gateway pod and rely on horizontal scaling at the inference tier.

</details>


Q2: [💻 Algorithms] — Word Search II (Trie + Backtracking)

Question: Word Search II uses a Trie instead of a Set for the word list. In one sentence, explain why the Trie is strictly better than checking if word_so_far in word_set at each DFS step.

<details><summary>显示答案 / Show Answer</summary>

A Trie lets you prune entire DFS branches early: if no word in the list starts with the current prefix, you immediately stop exploring that direction — with a plain set, you'd have no way to know this and would explore all paths regardless.

Concrete example: Grid is 5×5, words = ["abc", "abd"]. With a Trie, once you're at a cell where the current path is "xyz...", you check trie.root.children and find no "x" node → prune immediately. With a set, you'd continue DFS forming "xyzqr..." and only fail at the full word check.

Template reminder:

def findWords(board, words):
    trie = Trie()
    for w in words: trie.insert(w)
    
    def dfs(node, r, c, path):
        if node.word:  # found a complete word
            res.add(path)
            node.word = False  # avoid duplicates
        tmp, board[r][c] = board[r][c], '#'  # mark visited
        for dr, dc in [(0,1),(0,-1),(1,0),(-1,0)]:
            nr, nc = r+dr, c+dc
            if 0<=nr<rows and 0<=nc<cols and board[nr][nc] in node.children:
                dfs(node.children[board[nr][nc]], nr, nc, path+board[nr][nc])
        board[r][c] = tmp  # restore
    ...

Critical optimization: Delete matched words from the Trie (node.word = False) to avoid re-adding duplicates and to enable Trie pruning after a word is found.

</details>


Q3: [🐍 Python Craft] — Retry with Backoff + Connection Pooling

Question: You're building a service that calls an external API. You have both connection pooling and retry with exponential backoff available. A request fails with a ConnectionResetError. In what order should these two mechanisms handle it, and why?

<details><summary>显示答案 / Show Answer</summary>

Order: retry logic wraps the pool, not vice versa.

  1. Connection pool handles acquiring/releasing connections efficiently (reuse TCP connections, manage pool size). When a ConnectionResetError happens, the pool should discard that broken connection (not return it to the pool).
  2. Retry with backoff then kicks in at the call-site level: it re-attempts the full operation (which will now request a fresh connection from the pool).
# Correct layering
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=1, max=10))
def call_external_api():
    with pool.get_connection() as conn:  # pool is INSIDE the retry
        return conn.request("GET", "/endpoint")

Why not the reverse? If retry logic were inside the pool's connection acquisition, you'd retry getting a pooled connection — which doesn't help if the remote server is actually down. You need to retry the business operation, not just the connection handshake.

Key tenacity patterns:

  • stop_after_attempt(3) — max retries
  • wait_exponential(multiplier=1, min=1, max=10) — 1s, 2s, 4s, 8s, 10s...
  • retry=retry_if_exception_type(ConnectionError) — only retry transient errors, NOT ValueError or auth failures

</details>


💡 复习巩固记忆,螺旋式上升。

📅 明天继续新内容!