本文整理了大模型面试中常见的系统设计问题,包括LLM推理服务、RAG系统、Agent系统等典型场景,涵盖架构设计原则和性能优化考量。
功能性需求:
非功能性需求:
整体分层架构:
┌─────────────┐
│ CDN/Nginx │ 负载均衡 / 静态资源
└──────┬──────┘
↓
┌─────────────┐
│ API网关 │ 认证限流日志
└──────┬──────┘
↓
┌─────────────┐
│ 推理服务池 │ 多个推理Worker实例
└──────┬──────┘
↓
┌─────────────┐
│ GPU计算资源│ 模型加载 + 前向计算
└─────────────┘| 部署方式 | 适用场景 | 优缺点 |
|---|---|---|
| 单GPU单模型:一张卡放一个模型 | 大模型(70B+),吞吐量要求不高 | 简单稳定,GPU利用率可能不够满 |
| 单GPU多模型:一张卡放多个小模型(7B以下) | 小模型,高并发场景 | 提高GPU利用率,需要做好显存管理 |
| 多GPU张量并行:一个模型切到多张卡 | 大模型单卡放不下 | 推理延迟低,需要多卡互联 |
KV缓存优化:
连续批处理(Continuous Batching):
量化:
算子优化:
优势:
需要监控这些关键指标:
| 层面 | 要点 |
|---|---|
| 架构 | 分层设计,负载均衡,无状态推理服务 |
| 计算 | KV缓存优化,连续批处理,量化,算子融合 |
| 调度 | 动态批处理,提高GPU利用率 |
| 可用性 | 多实例,健康检查,弹性伸缩 |
| 监控 | TTFT、TPOT、吞吐量、GPU利用率 |
功能性需求:
非功能性需求:
┌─────────────┐
│ 用户问题 │
└──────┬──────┘
↓
┌─────────────┐
│ Query优化 │ 改写/扩展/纠错
└──────┬──────┘
↓
┌─────────────┐
│ 向量召回 │ 向量库TOPK召回
│ 关键词召回 │ BM25召回
└──────┬──────┘
↓
┌─────────────┐
│ 重排序 │ CrossEncoder重排
└──────┬──────┘
↓
┌─────────────┐
│ Prompt拼接 │ 问题+检索结果
└──────┬──────┘
↓
┌─────────────┐
│ LLM生成回答 │
└──────┬──────┘
↓
┌─────────────┐
│ 后处理+引用 │ 整理回答+标注来源
└─────────────┘离线文档处理流程:
文档上传 → 文本清洗 → 智能分块 → Embedding向量化 → 存入向量库常见方法:
经验值:
多路召回融合:
为什么需要多路?
| 向量库 | 特点 | 适用场景 |
|---|---|---|
| FAISS | Facebook开源,性能好,可本地部署 | 中小规模数据,离线使用 |
| Chroma | 轻量,易用,Python开发 | 原型开发,小数据量 |
| Weaviate | 功能全,支持多模态,云原生 | 生产环境,需要扩展性 |
| Milvus/Zilliz | 分布式,高可用,生产级 | 大规模数据,生产环境 |
| PGVector | PostgreSQL扩展,不用额外组件 | 已有PG,数据量不大 |
问题1:召回了不相关的文档怎么办?
问题2:回答引用了错误的来源怎么办?
问题3:文档太长,超过LLM上下文窗口怎么办?
问题4:RAG怎么评估效果?
功能性需求:
非功能性需求:
┌─────────────────────────────────────────────┐
│ 用户输入 │
└────────────┬────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ 任务理解 + 意图识别 │
└────────────┬────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ 规划(Planning) │
│ - 任务拆解成多步 │
│ - 决定下一步调用什么工具 │
└────────────┬────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ 工具调用(Tool Calling) │
│ - 参数提取 │
│ - 调用外部工具/API │
└────────────┬────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ 观察(Observation) │
│ - 获取工具返回结果 │
└────────────┬────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ 反思 + 判断是否完成 │
│ → 完成:整合结果输出给用户 │
│ → 未完成:回到规划下一步 │
└────────────┬────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ 最终回答 │
└─────────────────────────────────────────────┘工具描述格式(给大模型看):
示例:
1{
2 "name": "search",
3 "description": "搜索互联网获取实时信息,当你不知道答案或者需要最新新闻时事的时候使用",
4 "parameters": {
5 "query": {
6 "type": "string",
7 "description": "搜索关键词"
8 }
9 }
10}工具注册机制:
常见规划方法:
| 方法 | 特点 | 适用场景 |
|---|---|---|
| ReAct | Reasoning + Acting,每次一步,思考→行动→观察循环 | 大多数场景,实现简单稳定 |
| Chain-of-Thought | 一步步思考,输出推理过程 | 数学推理、逻辑题 |
| Tree-of-Thought | 探索多条推理路径,择优选择 | 复杂推理,正确率要求高 |
| Plan-and-Execute | 先做整体计划,再一步步执行 | 复杂长任务 |
工程建议:ReAct最容易实现,稳定性也不错,先从ReAct开始,满足大多数需求。
Agent多轮推理会不断增加上下文长度,需要处理:
如果需要多个Agent协作完成任务:
典型架构:
通信方式:
功能性需求:
非功能性需求:
┌─────────────┐
│ 前端控制台 │
└──────┬──────┘
↓
┌─────────────┐
│ API服务 │ 任务提交/查询/监控
└──────┬──────┘
↓
┌─────────────┐
│ 任务调度器 │ 排队 + GPU分配
└──────┬──────┘
↓
┌─────────────┐
│ 训练Worker │ 拉取任务 → 数据预处理 → 启动训练
└──────┬──────┘
↓
┌─────────────┐
│ GPU集群 │ 实际训练计算
└──────┬──────┘
↓
┌─────────────┐
│ 模型存储 │ 保存训练好的LoRA权重/全量权重
└─────────────┘调度策略:
监控:每个任务的GPU利用率、显存占用、训练loss实时采集显示
| 方法 | 显存需求 | 适合场景 |
|---|---|---|
| Full Fine-tuning | 高,需要多卡 | 数据量大,追求最佳效果 |
| LoRA | 低,单卡就能调大模型 | 大多数场景,快速迭代 |
| QLoRA | 更低,4bit量化,单卡调70B | 资源有限,效果接近全微调 |
无论什么系统,都需要从这几个维度考虑性能优化:
大模型系统设计题核心考察:
记住:没有完美的架构,只有适合场景的架构。设计师的工作就是根据需求和资源,做出最合适的选择。