Week 4 Day 27:系统设计专项 - 3道高频面试题深度准备

💡 系统设计面试不是考你能画多漂亮的图,而是考你能否在模糊需求中做出合理的权衡,并清晰解释为什么。

第一部分:问题驱动

🤔 问题1:系统设计面试,面试官真正在看什么?

引导问题:

  1. 为什么面试官一开始给的需求总是很模糊?
  2. 画完架构图就是结束了吗?
  3. 如果你的方案和面试官心里的"标准答案"不一样,会扣分吗?

答案揭示: 面试官看4件事:

  • 需求澄清能力:能否问出关键的非功能需求(QPS、延迟、一致性)
  • 系统性思维:能否从数据流、控制流、失败模式三个维度思考
  • 权衡意识:能否明确说出"选A牺牲B",而不是假装没有代价
  • 深度追问应对:deep dive一个组件时,能不能讲到数据结构和协议层面

你应该理解: 系统设计没有唯一答案,但有"不合格答案"——比如没估算就设计、没权衡就定方案、没失败模式就上线。


🤔 问题2:Agent系统和传统CRUD系统设计的核心差别是什么?

引导问题:

  1. 一个LLM调用的延迟是多少?(2-10秒)
  2. 一个Agent任务可能要调几次LLM?(5-20次)
  3. 用户愿意等多久?(同步≤30秒,超过就要异步)

答案揭示: Agent系统的4个独特挑战:

  • 长尾延迟:单次请求可能10秒+,需要异步/流式
  • 不确定性:同一输入可能不同输出,难以缓存、难以测试
  • 成本敏感:每次调用都花钱,需要精细化计费和限流
  • 失败模式复杂:LLM幻觉、工具失败、上下文溢出,都要单独设计降级

这4点会贯穿今天3道题的所有权衡。


🤔 问题3:面试的90分钟系统设计,时间怎么分?

标准分配:

5min 需求澄清(最关键!) 5min 规模估算 10min 高层架构(画图) 20min 核心组件深入(面试官引导) 10min 失败模式与扩展 5min 总结+提问

常见错误: 跳过需求澄清直接画图——面试官心里已经扣分了。


第二部分:题1 — 设计Customer Support Copilot

2.1 需求澄清(5分钟)

你要问的问题:

维度 问题 预期答案
用户 谁用?客服Agent还是终端客户? 客服Agent,human-in-the-loop
规模 多少租户?每租户多少客服? 100租户,每租户50-500客服
QPS 峰值QPS? 平均100 QPS,峰值500 QPS
延迟 可接受延迟? 首token <2s,总响应<10s
数据 每租户数据量? 1万-100万文档
隔离 数据严格隔离吗? 是,不同租户绝对不能串数据
工单 需要创建工单吗? 是,Copilot起草,人工审批

2.2 功能需求与非功能需求

功能需求:

  • F1:客服输入客户问题,Copilot基于知识库给出答案建议
  • F2:Copilot可以起草工单(不直接创建)
  • F3:客服看到引用的知识源,可以点击查看原文
  • F4:客服可以反馈(thumbs up/down),用于改进
  • F5:支持中英文

非功能需求:

  • NF1:多租户隔离(数据、计费、限流)
  • NF2:可观测性(每次调用可追溯)
  • NF3:审计(所有对话90天可查)
  • NF4:可用性 99.9%
  • NF5:成本可控(每租户月账单清晰)

2.3 规模估算(Back-of-Envelope)

租户数: 100 每租户客服: 平均100人 总活跃用户: 10,000 日均对话: 每人20次 × 10000 = 200,000 对话/天 平均QPS: 200000 / 86400 ≈ 2.3 QPS(日均) 峰值QPS: 日均 × 5 = 12 QPS(不算高,但LLM调用贵) 每对话平均: 3-5次LLM调用(思考+检索+生成) 日LLM调用: 200000 × 4 = 800,000 次/天 每次LLM成本: $0.01 日成本: $8,000 月成本: $240,000(所以精细化计费很重要) 知识库: 每租户10万chunks × 100 = 1000万chunks 向量维度: 1536 向量总大小: 10^7 × 1536 × 4B ≈ 60GB

2.4 高层架构图

flowchart TB
    Client[客服Web/桌面端]
    Gateway[API Gateway<br/>认证/限流/路由]
    
    subgraph Runtime[Agent Runtime]
        Orch[Orchestrator<br/>编排器]
        Plan[Planner]
        Exec[Executor]
        Mem[Memory Store]
    end
    
    subgraph RAG[RAG Service]
        Embed[Embedding Service]
        VDB[(Vector DB<br/>Qdrant)]
        Rerank[Reranker]
    end
    
    subgraph Tools[Tool Gateway]
        Ticket[Ticket Tool<br/>draft only]
        Search[Search Tool]
        Profile[Customer Profile]
    end
    
    subgraph Infra[Infra]
        Queue[(Message Queue<br/>Kafka)]
        Audit[(Audit Log<br/>S3+ClickHouse)]
        Meter[(Metering DB)]
    end
    
    LLM[LLM Provider<br/>OpenAI/Anthropic]
    
    Client -->|SSE stream| Gateway
    Gateway --> Orch
    Orch --> Plan
    Plan --> Exec
    Exec --> RAG
    Exec --> Tools
    Exec --> LLM
    Exec --> Mem
    Orch -->|events| Queue
    Queue --> Audit
    Queue --> Meter
    Tools -.draft.-> Ticket

2.5 关键组件深入

组件1:API Gateway

职责:

  • JWT认证(提取tenant_id、user_id)
  • 限流(per-tenant + per-user)
  • 路由到对应region的Runtime
  • SSE/WebSocket连接管理

关键设计:tenant_id打在每个下游请求的context里,零信任——下游永远重新校验。

func (g *Gateway) Auth(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        claims, err := g.jwt.Verify(r.Header.Get("Authorization"))
        if err != nil {
            http.Error(w, "unauthorized", 401)
            return
        }
        ctx := context.WithValue(r.Context(), "tenant_id", claims.TenantID)
        ctx = context.WithValue(ctx, "user_id", claims.UserID)
        next.ServeHTTP(w, r.WithContext(ctx))
    })
}

组件2:Agent Runtime

核心循环(ReAct模式):

输入 → Plan(决定下一步) → Act(调tool或LLM) → Observe → 判断是否结束 → 循环

关键问题: 循环会不会无限?

  • 设置max_iterations(默认10)
  • 设置总超时(30秒)
  • 每步写入trace,异常时kill掉

组件3:RAG Service

数据流:

查询 → 改写(HyDE可选) → Embedding → Vector Search(filter: tenant_id) → Rerank(cross-encoder) → 取Top 5 → 拼prompt

多租户隔离的实现:

  • 方案A:每租户独立collection(强隔离,但租户数多了运维复杂)
  • 方案B:共享collection + metadata filter(弹性好,但filter必须强制)
  • 推荐: 方案B,但在query层强制注入tenant_id filter,代码review必检
// 强制tenant过滤,不给调用方选择
func (r *RAG) Search(ctx context.Context, query string) []Chunk {
    tenantID := ctx.Value("tenant_id").(string)
    filter := qdrant.Filter{
        Must: []qdrant.Condition{
            {Key: "tenant_id", Match: tenantID}, // 硬编码
        },
    }
    return r.client.Search(ctx, query, filter)
}

组件4:Tool Gateway

为什么独立?

  • 工具可能有副作用(创建工单、发邮件),必须统一审计
  • 不同工具权限不同,统一鉴权
  • 方便添加human-in-the-loop

Draft-then-Confirm模式:

Agent调用CreateTicket → Tool Gateway → 返回draft_id(未真正创建) → 客服看到draft → 点击确认 → Tool Gateway真正创建

组件5:Audit

三层存储:

  • 热数据(近7天):ClickHouse,支持查询
  • 温数据(7-90天):S3 + Athena
  • 冷数据(>90天):Glacier或删除(按合规)

每条记录:

{
  "trace_id": "...",
  "tenant_id": "...",
  "user_id": "...",
  "timestamp": "...",
  "event_type": "llm_call|tool_call|rag_query",
  "input_hash": "...",  // 敏感数据不存原文
  "output_hash": "...",
  "tokens_in": 1234,
  "tokens_out": 456,
  "cost_usd": 0.012,
  "latency_ms": 1234
}

2.6 关键权衡

维度 选项A 选项B 推荐 原因
响应模式 同步REST SSE流式 SSE LLM首token快,流式体验好
租户隔离 独立DB 共享DB+filter 共享DB 100租户独立DB太贵
工单创建 直接创建 Draft+Confirm Draft 人类审批是核心价值
一致性 强一致 最终一致 最终一致 对话历史、计费都可容忍秒级延迟
Embedding 租户共享模型 租户fine-tune 共享 成本考量,企业版再定制

2.7 失败模式

故障 影响 降级策略
LLM Provider挂了 核心功能失效 切换到备用provider(Anthropic↔OpenAI)
Vector DB慢 检索超时 降级到关键词搜索
单租户流量爆发 影响其他租户 per-tenant限流 + 隔离队列
Agent无限循环 成本爆炸 max_iterations + budget cap

第三部分:题2 — 设计Enterprise Agent Platform

3.1 与Copilot的区别

维度 Copilot Agent Platform
用户 特定角色(客服) 开发者构建任意Agent
Agent数量 1个 N个,多Agent协作
定制性 高(prompt、tools、模型都可配)
类比 Salesforce AWS Lambda + MCP

核心挑战: 从"做好一个Agent"变成"做一个让别人做Agent的平台"。

3.2 核心能力(平台化)

四大支柱:

  1. Agent注册与市场

    • 开发者上传Agent定义(prompt、tools、模型)
    • 平台审核、签名、发布
    • 企业内部"Agent市场"
  2. 多Agent编排

    • Agent间通信协议(A2A或MCP)
    • 调度器决定谁先谁后
    • 支持顺序、并行、条件分支
  3. Runtime隔离

    • 每个Agent运行在独立容器/进程
    • 资源配额(CPU、内存、LLM budget)
    • 故障隔离
  4. SLA保证

    • 平台级:99.9%可用
    • Agent级:每个Agent自报延迟、成功率
    • 订阅方根据SLA选Agent

3.3 架构图

flowchart TB
    Dev[开发者] -->|上传Agent Bundle| Reg[Agent Registry<br/>审核+签名]
    Reg --> Market[Agent Marketplace]
    
    User[终端用户] --> Portal[Platform Portal]
    Portal --> Market
    
    Portal --> Orch[Multi-Agent Orchestrator]
    Orch --> Scheduler[Scheduler]
    Scheduler --> Pool[Agent Worker Pool]
    
    subgraph Pool
        W1[Agent A Container]
        W2[Agent B Container]
        W3[Agent C Container]
    end
    
    Pool --> Bus[Event Bus<br/>Agent间通信]
    Pool --> Tools[Shared Tool Gateway]
    Pool --> LLMGW[LLM Gateway<br/>路由+计费]
    
    LLMGW --> Providers[OpenAI/Anthropic/本地]
    
    Pool --> Obs[Observability<br/>Traces+Metrics+SLA]
    Obs --> SLAEngine[SLA Engine]
    SLAEngine -.熔断.-> Scheduler

3.4 Agent注册中心

Agent Bundle格式(类似Helm Chart):

name: finance-analyzer
version: 1.2.0
author: acme-corp
description: Analyze financial reports
entrypoint: agent.main
runtime: python-3.11
resources:
  cpu: 500m
  memory: 512Mi
  llm_budget_per_call: 0.10 USD
tools_required:
  - ticker_lookup
  - pdf_parser
models_supported:
  - gpt-4
  - claude-3-sonnet
sla:
  p50_latency_ms: 3000
  p99_latency_ms: 10000
  success_rate: 0.99

注册流程:

  1. 上传bundle
  2. 静态扫描(prompt注入检测、恶意代码)
  3. 沙箱跑测试集
  4. 签名、发布
  5. 订阅者按版本绑定

3.5 多Agent编排

编排DSL(类似LangGraph):

workflow: customer-research
steps:
  - id: fetch_profile
    agent: profile-agent
    input: "{{ customer_id }}"
  - id: analyze_sentiment
    agent: sentiment-agent
    input: "{{ fetch_profile.output }}"
    parallel_with: [fetch_history]
  - id: fetch_history
    agent: history-agent
  - id: summarize
    agent: summarizer
    depends_on: [analyze_sentiment, fetch_history]

关键权衡:

  • 静态DAG vs 动态路由:静态好调试,动态灵活。建议:主流程DAG,子步骤可动态。
  • 同步调用 vs 消息总线:延迟敏感用同步,解耦用总线。

3.6 SLA保证

三层SLA:

  1. 平台SLA:Gateway、调度器可用性
  2. Agent SLA:Agent自报(和实测对比)
  3. 端到端SLA:用户感知的总延迟

熔断机制:

if agent.RecentErrorRate() > 0.1 {
    scheduler.MarkUnhealthy(agent)
    // 自动路由到备份Agent或降级
}

第四部分:题3 — 设计RAG-as-a-Service

4.1 产品定位

"RAG版的Stripe" —— 开发者只管上传文档+调query API,不管向量存储、embedding、reranker。

目标客户:

  • 中小企业,没有ML团队
  • 需要RAG但不想维护Qdrant

4.2 核心功能

  1. Document API:上传PDF/markdown/HTML,自动解析+chunking+embedding+存储
  2. Query API:输入问题,返回Top-K chunks
  3. Ingestion Pipeline:异步处理大文档
  4. 多租户数据隔离
  5. 按量计费(ingestion按页数,query按次)

4.3 架构

flowchart LR
    Customer[客户应用] -->|POST /docs| IngAPI[Ingestion API]
    Customer -->|POST /query| QueryAPI[Query API]
    
    IngAPI --> Queue[(Task Queue<br/>SQS)]
    Queue --> Workers[Ingestion Workers]
    
    Workers --> Parser[Parser<br/>PDF/MD/HTML]
    Workers --> Chunker[Chunker]
    Workers --> Embedder[Embedder<br/>批量]
    Workers --> VDB[(Vector DB<br/>per-tenant)]
    
    QueryAPI --> Router[Tenant Router]
    Router --> VDB
    Router --> Rerank[Reranker]
    
    Workers --> Meter[(Metering)]
    QueryAPI --> Meter
    Meter --> Billing[Billing Engine]
    Billing --> Stripe[Stripe]

4.4 多租户数据隔离

三种方案对比:

方案 隔离强度 成本 运维 适用
独立集群 最强 最高 最重 企业大客户
共享集群+独立collection 主流
共享collection+metadata filter 免费/小客户

推荐分层:

  • Free tier:共享collection + filter
  • Pro tier:独立collection
  • Enterprise:独立集群 + VPC

4.5 Ingestion Pipeline

为什么必须异步?

  • 大PDF解析可能几分钟
  • Embedding API有rate limit,批量处理更划算
  • 失败可重试

Pipeline设计:

Upload → 落S3 → 写DB记录(status=pending) → 发SQS消息 → Worker消费 → Parse → Chunk → Embed(batch 100) → Upsert到VDB → 更新status=done → 通知webhook

关键细节:

  • 幂等性:doc_id + chunk_index作为主键,重试不重复
  • 分阶段提交:每阶段完成写一次status,便于断点续传
  • 死信队列:重试3次失败的任务人工介入

4.6 计费模型

Ingestion: $0.01 / page (parsed) $0.02 / 1000 embedding tokens Storage: $0.10 / GB-month Query: Free tier: 1000次/月 Pay: $0.001 / query Rerank: +$0.002 / query

计费数据流:

  • 每次API调用写一条metering event
  • 聚合服务按小时/天汇总
  • 月末生成账单

4.7 关键权衡

维度 权衡 决策
Embedding模型 自研 vs OpenAI 初期OpenAI,后期自研降成本
Chunking策略 自动 vs 用户可配 自动+可选override
一致性 写后立即可查 vs 最终一致 最终一致(通常30秒内)
Reranker 必选 vs 可选 可选(收费)

第五部分:关键概念总结

概念 3道题都涉及 为什么重要
多租户隔离 所有题 企业级系统的生死线
异步 vs 同步 所有题 LLM延迟决定的
计费/Metering 所有题 成本可控是生存前提
失败降级 所有题 LLM不稳定,备胎必备
审计/可观测 所有题 合规 + debug
Tool Gateway Copilot/Platform 副作用统一管控
SLA Platform/RaaS 平台产品的核心承诺

第六部分:自测清单

  • 我能在5分钟内做规模估算(QPS、存储、成本)
  • 我能解释同步vs异步的权衡并举例
  • 我能说出多租户隔离的3种方案及权衡
  • 我能画出Customer Copilot的完整架构图
  • 我能解释为什么工单要Draft-then-Confirm
  • 我知道Agent Platform和Copilot的4个本质区别
  • 我能设计一个异步Ingestion Pipeline并说明幂等性如何保证

第七部分:作业

任务1:白板练习

找一面白板(或纸),不看答案,从0画出Customer Support Copilot架构,限时20分钟。录音讲解。

任务2:规模估算练手

给定条件(假设1000租户、日活10万),重新算Copilot的:

  • 日LLM调用次数
  • 月成本
  • 向量存储大小
  • 需要几台Embedding Worker

任务3:权衡论证

写一份500字的分析:如果让你为Customer Copilot选同步REST还是SSE,你选哪个?为什么?有什么前提?

任务4:deep dive准备

从3道题各挑一个组件(推荐:RAG Service、Multi-Agent Scheduler、Ingestion Pipeline),各准备一份10分钟的深度讲解(包括数据结构、伪代码、失败模式)。


第八部分:常见问题解答

Q1: 面试时画图用什么工具? A: 白板 > 画板软件(Excalidraw)> 口头描述。面试官希望看到你一边讲一边画的过程,而不是拿现成图。

Q2: 需求澄清该问几个问题? A: 5-8个,覆盖4个维度:用户/规模/SLA/数据。问太多显得犹豫,太少显得草率。

Q3: 如果面试官说"假设你可以用任何技术",要列多少候选? A: 每个关键组件说2个候选 + 选择理由。例如:"向量DB我考虑Qdrant和Pinecone,选Qdrant因为自部署灵活、支持per-collection metadata filter,符合我们多租户需求。"

Q4: 被追问到不会的细节怎么办? A: 诚实 + 推理。"这块我没做过生产级,但基于XX原理,我会这样设计..." 比装懂好太多。

Q5: Copilot和Agent Platform哪个更可能考? A: Staff及以下更可能考Copilot(具体产品);Staff+更可能考Platform(平台抽象)。但准备好两个都有利无害。


下一步:Day 28 项目包装

明天我们把30天做的东西,包装成能在面试30秒内打动人的故事。

  • 30秒/2分钟/5分钟三个版本的项目介绍
  • GitHub README模板
  • LinkedIn发文
  • 面试自我介绍

准备问题: 用一句话描述你这30天做的项目。