Week 4 Day 27:系统设计专项 - 3道高频面试题深度准备
💡 系统设计面试不是考你能画多漂亮的图,而是考你能否在模糊需求中做出合理的权衡,并清晰解释为什么。
第一部分:问题驱动
🤔 问题1:系统设计面试,面试官真正在看什么?
引导问题:
- 为什么面试官一开始给的需求总是很模糊?
- 画完架构图就是结束了吗?
- 如果你的方案和面试官心里的"标准答案"不一样,会扣分吗?
答案揭示:
面试官看4件事:
- 需求澄清能力:能否问出关键的非功能需求(QPS、延迟、一致性)
- 系统性思维:能否从数据流、控制流、失败模式三个维度思考
- 权衡意识:能否明确说出"选A牺牲B",而不是假装没有代价
- 深度追问应对:deep dive一个组件时,能不能讲到数据结构和协议层面
你应该理解:
系统设计没有唯一答案,但有"不合格答案"——比如没估算就设计、没权衡就定方案、没失败模式就上线。
🤔 问题2:Agent系统和传统CRUD系统设计的核心差别是什么?
引导问题:
- 一个LLM调用的延迟是多少?(2-10秒)
- 一个Agent任务可能要调几次LLM?(5-20次)
- 用户愿意等多久?(同步≤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 核心能力(平台化)
四大支柱:
-
Agent注册与市场
- 开发者上传Agent定义(prompt、tools、模型)
- 平台审核、签名、发布
- 企业内部"Agent市场"
-
多Agent编排
- Agent间通信协议(A2A或MCP)
- 调度器决定谁先谁后
- 支持顺序、并行、条件分支
-
Runtime隔离
- 每个Agent运行在独立容器/进程
- 资源配额(CPU、内存、LLM budget)
- 故障隔离
-
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
注册流程:
- 上传bundle
- 静态扫描(prompt注入检测、恶意代码)
- 沙箱跑测试集
- 签名、发布
- 订阅者按版本绑定
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:
- 平台SLA:Gateway、调度器可用性
- Agent SLA:Agent自报(和实测对比)
- 端到端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 核心功能
- Document API:上传PDF/markdown/HTML,自动解析+chunking+embedding+存储
- Query API:输入问题,返回Top-K chunks
- Ingestion Pipeline:异步处理大文档
- 多租户数据隔离
- 按量计费(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 |
平台产品的核心承诺 |
第六部分:自测清单
第七部分:作业
任务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天做的项目。