← 2026-05-14 📂 All Days 2026-05-16 →

🏗️ 系统设计 / System Design — Day 44

Design a Content Moderation System (内容审核系统)

难度 / Difficulty: Advanced · 阶段 / Phase: Mastery

场景 / Scenario

想象你在 Meta 工作,每天有 5亿条 帖子、图片、视频被上传。你需要构建一个系统,在内容展示给用户之前,自动检测并过滤违规内容(仇恨言论、色情、暴力、虚假信息)。

You're at Meta. 500M pieces of content uploaded daily. Build a system that detects and filters violating content before it reaches users — hate speech, nudity, violence, misinformation.


架构图 / Architecture

Producers [Mobile/Web App] │ ▼ [API Gateway] │ ┌───┴────┐ │ Upload │ ──────────► [Object Storage: S3/GCS] │ Service│ │ └────────┘ [Content Event Bus: Kafka] │ ┌────────────────────┼────────────────────┐ ▼ ▼ ▼ [Text Classifier] [Image/Video ML] [Graph Signals] (BERT/LLM-based) (CNN/Vision model) (user history, reports) │ │ │ └────────────────────┼────────────────────┘ ▼ [Score Aggregator] │ ┌──────────────┼──────────────┐ ▼ ▼ ▼ [Auto-Approve] [Human Queue] [Auto-Remove] score < 0.2 0.2 < s < 0.8 score > 0.8 │ [Moderation Dashboard] (human reviewers) │ [Feedback Loop] (labels → retrain)

核心设计决策 / Key Design Decisions

1. 异步 vs 同步处理 / Async vs Sync

  • 视频不能同步审核(太慢)→ 乐观发布 + 后置过滤
  • 文本可以同步(< 100ms) → 发布前拦截
  • Trade-off: 延迟展示 vs 允许短暂可见

2. 多模型流水线 / Multi-model pipeline

  • 不同内容类型用不同模型(文本/图像/视频/音频)
  • 集成上下文信号:用户举报数、账号年龄、历史违规
  • 模型投票 + 加权分数 → 最终判决

3. 人工审核队列 / Human-in-the-loop

  • 灰色地带内容(score 0.2–0.8)发给人工审核员
  • 目标:每个案例审核时间 < 24h
  • 人工标注数据回流 → 定期重训练模型

4. 上诉机制 / Appeals

  • 被误删内容可申诉 → 触发二次人工审核
  • 降低误杀率(False Positive)对用户信任的损害

为什么这样设计?/ Why This Design?

问题决策原因
5亿/天吞吐量Kafka 异步解耦上传和审核,削峰
高准确性需求多模型融合单一模型误判率高
上下文感知图谱信号同一词在不同用户/背景下含义不同
监管合规可审计日志GDPR/DSA 要求保存决策记录

别踩这个坑 / Common Mistakes

❌ 单模型打天下 — 文本模型看不懂图,图像模型看不懂上下文

❌ 全量同步审核 — 视频审核可能要30秒,用户不会等

❌ 忽略误报(False Positive) — 过度审核会赶走正常用户,比漏审代价更大

❌ 冷启动无数据 — 新平台没有标注数据?用迁移学习 + 小批量人工标注

❌ 不设置上诉通道 — 监管机构(DSA/GDPR)要求平台必须提供申诉机制


关键指标 / Key Metrics

  • Precision/Recall — 误杀率 vs 漏审率(需要业务决定取舍点)
  • Review queue latency — 人工审核积压时间
  • Appeals rate — 用户申诉率(高了说明误判多)
  • Model drift — 定期监控分布漂移(新梗、新表情包)

🧒 ELI5

想象学校里有个自动"坏话检测仪"。它先快速扫一眼所有内容,明显坏的直接删,明显好的直接放,看不准的交给老师手动检查。老师的判断结果再教"检测仪"变聪明。


📚 References

  • https://engineering.fb.com/2020/08/07/ml-applications/hate-speech/
  • https://transparency.fb.com/enforcement/
  • https://blog.youtube/inside-youtube/youtube-content-id/
  • https://aws.amazon.com/rekognition/content-moderation/

💻 算法 / Algorithms — Day 44

#143 Reorder List 🟡 Medium — Linked List Pattern (4/11)

🔗 LeetCode #143 · 📹 NeetCode Solution


🧩 链表技巧模式 (4/11) — building on the template from Day 41 (Reverse Linked List)

今天的题是链表模式的综合题 — 同时用到找中点、反转链表、合并三个技巧。


题目 / Problem

给定链表 `1 → 2 → 3 → 4 → 5`,就地重排为 `1 → 5 → 2 → 4 → 3`。

规律:把后半段倒过来,然后和前半段交叉合并。

Given linked list `1→2→3→4→5`, reorder in-place to `1→5→2→4→3`.

现实类比 / Real-World Analogy

排队等电影票:前半队人保持原位,后半队人调头,然后两队交替插队合并。

Like a theater line: keep the first half in order, reverse the second half, then interleave them.


如何映射到模版 / Mapping to Template

这道题是三步走,每一步都来自同一个链表工具箱:

Step 1: 找中点 (Fast-Slow Pointers)
Step 2: 反转后半段 (Reverse Template)  
Step 3: 交叉合并 (Merge Template)
from typing import Optional

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

def reorderList(head: Optional[ListNode]) -> None:
    if not head or not head.next:
        return

    # Step 1: Find middle using fast-slow pointers
    slow, fast = head, head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
    # slow is now at the middle

    # Step 2: Reverse the second half
    prev, curr = None, slow.next
    slow.next = None  # Cut the list in half
    while curr:
        nxt = curr.next
        curr.next = prev
        prev = curr
        curr = nxt
    # prev is now the head of reversed second half

    # Step 3: Merge two halves by interleaving
    first, second = head, prev
    while second:
        tmp1, tmp2 = first.next, second.next
        first.next = second
        second.next = tmp1
        first = tmp1
        second = tmp2
**执行追踪 / Trace:** `1→2→3→4→5`
After Step 1: slow=3, list: 1→2→3 | 4→5 After Step 2: second half reversed: 5→4 After Step 3 (iter 1): 1→5→2→... second=4 After Step 3 (iter 2): 1→5→2→4→3 Result: 1→5→2→4→3 ✓

复杂度 / Complexity: Time O(n) · Space O(1)


与同模式题目的对比 / Variations in this Pattern

题目用到的技巧
#206 Reverse Linked List反转
#21 Merge Two Sorted Lists合并
#141 Linked List Cycle快慢指针(环检测)
#143 Reorder List ← 今天找中点 + 反转 + 合并 (三合一)
#19 Remove Nth From End快慢指针(间距k)

今天的关键洞察: Reorder List 是链表模式的"Boss题"——它不引入新技巧,而是要求你在一题中正确地组合三个已知工具,且顺序和边界条件不能出错。


举一反三 / Pattern Connections

  • 这道题的 Step 2 = #206 Reverse Linked List 的完整实现
  • Step 3 的 interleave 逻辑 ≈ #21 Merge Two Sorted Lists,但没有顺序比较
  • 下一题 #19 Remove Nth From End 只需 fast-slow 找位置,是这个模式的简化版

🧒 ELI5

把一列火车从中间切成两截,后半截倒过来,然后把两截一节一节交替拼接。


📚 References

  • https://leetcode.com/problems/reorder-list/
  • https://neetcode.io/problems/reorder-linked-list
  • https://cs.stackexchange.com/questions/11349/what-is-a-linked-list-in-data-structures

🗣️ 软技能 / Soft Skills — Day 44

决策力 / Decision Making (Staff Level)

"Tell me about a time you had to make a decision that was right for the company but unpopular with your team"


为什么这道题重要 / Why This Matters

Staff/Principal 工程师必须做的一件事:代表公司,而不只是代表团队。

面试官想看的是:你能否在团队不满的情况下,仍然清晰地论证和执行正确的决定——然后重建信任。

This question separates Staff+ engineers from Senior ones. It's not about being a pushover or a dictator — it's about principled decision-making under social pressure and bringing people along afterward.


STAR 拆解 / STAR Breakdown

Situation 背景

  • 设置具体场景:技术栈迁移?裁撤某个子系统?推迟一个团队心爱的功能?
  • 例:团队自建了一套内部监控工具,用了两年,但公司决定全面迁移到 Datadog。

Task 任务

  • 你的角色是什么?为什么决策权落到你这里?
  • 例:你是负责可观测性平台的 Staff Engineer,需要执行这个迁移决定。

Action 行动

  • 你如何沟通这个决定?
  • 你如何处理团队的抵触?
  • 你如何保护团队的利益(保留知识、平滑迁移)?

Result 结果

  • 量化成果:迁移完成时间、覆盖率、事故减少率
  • 团队关系的修复

❌ 差回答 vs ✅ 好回答

❌ 差回答:

"团队不太高兴,但我告诉他们这是公司的要求,最终大家还是执行了。"

问题:没有展示沟通能力,没有展示对团队感受的理解。

✅ 好回答:

"团队花了18个月构建这套工具,对它有很强的归属感。我首先主动聆听每个人的顾虑——有人担心职业发展(自建工具的经验还有用吗?),有人担心迁移期的on-call负担。我把这些顾虑带进和VP的讨论,争取到3个月的过渡期和专门的迁移资源。在团队内部,我明确说:'我不同意放弃我们自建的努力,但我认同标准化对公司长期更好,所以我们的目标是让迁移成为一个成功的项目,而不是被强加的负担。'最终迁移比计划提前完成,两名工程师因为主导迁移获得了晋升认可。"

Senior vs Staff 差异 / Seniority Signals

维度SeniorStaff+
视角团队层面组织/公司层面
决策依据技术正确性技术 + 商业 + 人
冲突处理尝试说服设计决策框架,建立对齐
结果导向功能完成团队信任 + 业务指标

关键要点 / Key Takeaways

  1. 先倾听,再决定 — 即使结果不变,过程中被听见很重要
  2. 区分"我不同意"和"我不会执行" — 可以保留不同意见,但仍然全力执行
  3. 保护团队利益是你作为 leader 的职责,即使决定来自上面
  4. 重建信任靠的是执行结果,而不是事前承诺

🧒 ELI5

班级要换教室,你不想搬但校长说必须搬。好的做法:听同学的抱怨,帮大家一起打包,争取更多搬家时间,把新教室布置得比以前更好。最后大家都觉得你是个靠谱的组长。


📚 References

  • https://www.lennysnewsletter.com/p/how-to-have-hard-conversations
  • https://www.amazon.com/Radical-Candor-Kim-Scott/dp/1250235375
  • https://staffeng.com/guides/work-on-what-matters/

🎨 前端 / Frontend — Day 44

Next.js Middleware, Auth, & Protected Routes


场景 / Real Scenario

你在做一个 SaaS dashboard,需要把 /dashboard/* 全部保护起来 — 没登录的用户重定向到 /login,同时还要在 Edge 运行(速度快,不走 Node.js runtime)。

You're building a SaaS dashboard. Protect all /dashboard/* routes — redirect unauthenticated users to /login. Must run at the Edge for low latency.


Next.js Middleware 核心概念 / Core Concept

Middleware 在请求到达页面之前在 Edge 运行,可以:

  • 重定向 / Rewrite URL
  • 修改请求/响应 headers
  • 读取 Cookie(做认证检查)

Middleware runs before the page renders, at the Edge (Cloudflare Workers/Vercel Edge) — no cold starts, ~1ms overhead.


代码示例 / Code Snippet

// middleware.ts (root of project, NOT inside /app or /pages)
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl

  // Read session token from cookie (JWT or session cookie)
  const token = request.cookies.get('session-token')?.value

  // Protected route check
  const isProtectedRoute = pathname.startsWith('/dashboard') ||
                           pathname.startsWith('/settings') ||
                           pathname.startsWith('/api/user')

  if (isProtectedRoute && !token) {
    // Redirect to login, preserve original URL for post-login redirect
    const loginUrl = new URL('/login', request.url)
    loginUrl.searchParams.set('from', pathname)
    return NextResponse.redirect(loginUrl)
  }

  // Already logged in, trying to access /login → redirect to dashboard
  if (token && pathname === '/login') {
    return NextResponse.redirect(new URL('/dashboard', request.url))
  }

  return NextResponse.next()
}

// IMPORTANT: Control which paths trigger this middleware
export const config = {
  matcher: [
    // Match all except static files, images, favicon
    '/((?!_next/static|_next/image|favicon.ico|public).*)',
  ],
}

猜猜这段代码的行为 / Quiz

// User visits /dashboard/settings without a session cookie
// What happens?
const from = '/dashboard/settings'
// loginUrl becomes: /login?from=%2Fdashboard%2Fsettings

用户访问 /dashboard/settings,没有 session-token cookie,会跳转到哪里?

  • A: /login
  • B: /login?from=/dashboard/settings
  • C: 403 页面
  • D: 什么都不发生,正常渲染

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

B — /login?from=%2Fdashboard%2Fsettings

Middleware 重定向并把原始路径编码到 from 参数。登录成功后可读取 from 参数并重定向回用户原本要访问的页面。

</details>


❌ 常见错误 vs ✅ 正确做法

❌ 错误:在 Middleware 里做数据库查询

// DON'T: DB calls are expensive and Middleware runs on every request
const user = await db.findUser(token) // ❌ Slow, can't use Node.js DB clients at Edge

✅ 正确:只做轻量 JWT 验证

// DO: Verify JWT signature (CPU-only, ~0.1ms)
import { jwtVerify } from 'jose'
const { payload } = await jwtVerify(token, secret)
// Full user data fetch happens in the page/API route itself

❌ 错误:把所有路由都加进 matcher

matcher: ['/:path*'] // ❌ Runs on static assets too, wasteful

✅ 正确:排除静态资源

matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'] // ✅

用 / 不用 Middleware 的判断框架

用 Middleware 当:

  • 需要在 Edge 做快速重定向(认证、地区重定向)
  • A/B 测试路由分发
  • 修改请求 headers(添加 correlation ID)

不用 Middleware 当:

  • 需要数据库查询 → 放在 Server Component 或 API Route
  • 需要 Node.js 原生模块 → Middleware 只能用 Web APIs
  • 复杂业务逻辑 → Middleware 应该保持轻量

🧒 ELI5

Middleware 就是门卫。你要进公司大楼(访问页面),门卫先检查你有没有工牌(session cookie)。没有工牌直接叫你去前台登记(/login)。有工牌直接放行,不用每次都去找HR确认你是不是员工。


📚 References

  • https://nextjs.org/docs/app/building-your-application/routing/middleware
  • https://nextjs.org/docs/app/api-reference/file-conventions/middleware
  • https://www.youtube.com/watch?v=LdM5oFRPVkk (Vercel: Middleware Deep Dive)
  • https://github.com/nextauthjs/next-auth (production auth solution)

🤖 AI — Day 44

量化 / Quantization — Running Large Models on Small Hardware

模式 / Mode: CONCEPT · 类别 / Category: Deployment

直觉解释 / Intuitive Explanation

想象你有一张超高清4K照片(32位色彩),但你只需要在手机上显示缩略图。如果你把每个像素从32位精度压缩到8位,文件大小变成1/4,肉眼几乎看不出差别。

量化(Quantization) 对神经网络做的是同样的事:把模型权重从32位浮点数(float32)压缩成8位整数(int8)甚至4位(int4),让大模型能跑在消费级GPU甚至CPU上。

Think of it like compressing a 4K photo to a thumbnail. Quantization takes a neural network's weights from 32-bit floats (float32) down to 8-bit integers (int8) or even 4-bit (int4). The model gets ~4x smaller with minimal quality loss.


原理 / How It Works

核心思想: 大部分神经网络权重的值分布在一个有限范围内,不需要32位精度。

float32: ████████████████████████████████  (4 bytes/value)
float16: ████████████████                  (2 bytes/value)  
int8:    ████████                          (1 byte/value)
int4:    ████                              (0.5 bytes/value)

量化的数学 / The Math:

# Map float range [min, max] → int range [0, 255] scale = (max_val - min_val) / 255 zero_point = -min_val / scale # Quantize q = round(x / scale + zero_point) # Dequantize (during inference) x_approx = (q - zero_point) * scale

主流方法 / Common Methods:

方法时机精度损失实现难度
PTQ (Post-Training Quantization)训练后中等简单
QAT (Quantization-Aware Training)训练中最小复杂
GPTQ训练后,逐层优化小中等
GGUF/llama.cppCPU 推理专用小开箱即用

实际影响 / Real-World Impact

Llama 3 70B 示例:

float32: 70B × 4 bytes = 280 GB → 需要 4× A100 (每张$10,000+) float16: 70B × 2 bytes = 140 GB → 需要 2× A100 int8: 70B × 1 byte = 70 GB → 单张 H100 (80GB) int4: 70B × 0.5byte = 35 GB → 两张 4090 (各 24GB) ← 普通人能买到!

可运行代码 / Runnable Python Snippet

# pip install transformers bitsandbytes accelerate
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
import torch

# Load a model in 4-bit quantization (requires bitsandbytes)
model_id = "meta-llama/Meta-Llama-3-8B-Instruct"

quantization_config = BitsAndBytesConfig(
    load_in_4bit=True,              # Enable 4-bit quantization
    bnb_4bit_compute_dtype=torch.float16,  # Compute in fp16 for speed
    bnb_4bit_use_double_quant=True, # Nested quantization for extra savings
    bnb_4bit_quant_type="nf4",      # NF4 = better for normally distributed weights
)

tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    quantization_config=quantization_config,
    device_map="auto",  # Automatically distribute across available GPUs
)

# Model loads in ~5GB instead of ~32GB for 8B params
inputs = tokenizer("Explain quantization in one sentence:", return_tensors="pt").to("cuda")
output = model.generate(**inputs, max_new_tokens=50)
print(tokenizer.decode(output[0], skip_special_tokens=True))

量化 vs 其他压缩技术 / Quantization vs Other Compression

技术做什么适合场景
量化 (Quantization)降低数值精度推理加速,内存节省
剪枝 (Pruning)删除不重要的权重结构化稀疏
蒸馏 (Distillation)小模型学大模型行为需要更小的模型
LoRA低秩适配微调训练时参数高效

量化 + LoRA = QLoRA — 先量化再微调,微调大模型的标准方案。


🧒 ELI5

量化就像用铅笔画画:原来用的是超级精细的彩色笔(float32),效果很好但很贵很重。量化后改用粗铅笔(int4),画出来虽然没那么细腻,但99%的人看不出区别,而且可以带回家画(在消费级硬件上运行)。


📚 References

  • https://huggingface.co/docs/transformers/quantization
  • https://github.com/TimDettmers/bitsandbytes
  • https://github.com/ggerganov/llama.cpp (GGUF格式,CPU推理)
  • https://arxiv.org/abs/2305.14314 (QLoRA论文)
  • https://pytorch.org/docs/stable/quantization.html

Attention Heatmap

When the model processes it, it attends most strongly to animal.

Theanimaldidntcrossthestreetbecauseitwastootired
it →