在高并发查询的 Agent 系统中,你会如何优化召回和生成阶段的延迟
P2 · agent_architecture · 🏢 字节
🏷 标签:agent, high-concurrency, latency, optimization
1️⃣ 考察意图
面试官想考察的不是“你知道哪些优化方法”,而是你在高并发、低延迟约束下,对召回和生成两个阶段做系统性延迟拆解和工程取舍的能力。刁钻点在于:不能只堆缓存或剪枝,要能说清瓶颈在哪、为什么、怎么量化。答好了能展示你对 Agent 系统整条链路(检索→推理→生成)的延迟建模经验,以及面对资源与效果 trade-off 时的决策力。
2️⃣ 标准答
核心思路:将延迟拆解为召回阶段(Embedding + 检索 + 排序)和生成阶段(Prefill + Decode),分别用并行化、预计算、模型轻量化三招压延迟。
召回阶段优化
- Embedding 向量化加速:用 ONNX Runtime 或 TensorRT 对 embedding 模型做静态图优化,将单次推理延迟从 15ms 压到 3-5ms。若用 BGE-M3 等大模型,可降采样到 128 维(牺牲 2-3% 召回率换 40% 速度提升)。
- 检索层:多级索引 + 预过滤:第一级用 HNSW(ef_construction=200, M=16)做近似最近邻搜索,延迟 < 2ms(10 万级文档)。
- 第二级用 BM25 做关键词预过滤(k1=1.5, b=0.75),剔除无关文档,减少后续向量检索的候选集。
- 实际坑:HNSW 在并发写入时索引重建会阻塞查询,解法是双缓冲索引(主索引只读,副索引异步更新后原子切换)。 排序层:级联 rerank:
- 第一轮用 ColBERT 的 late interaction(计算量 O(n*d))粗排,取 top-20。
- 第二轮用 cross-encoder(如 BGE-Reranker-v2)精排,但只对 top-5 做。
- Trade-off:cross-encoder 精度高但延迟 50ms+,必须限制候选数,否则并发一高就崩。
生成阶段优化
- Prefill 阶段:KV Cache 预填充:对高频 query(如“天气”“时间”)预计算 KV Cache 并缓存到 Redis(TTL=5min),命中后跳过 prefill,直接 decode。
- 对长上下文(>4K tokens),用 FlashAttention-2 将 prefill 延迟从 200ms 降到 80ms(A100 实测)。 Decode 阶段:投机解码 + 量化:
- 用 Speculative Decoding(草稿模型为 1.5B,目标模型为 7B)将 decode 速度提升 2-3x,但需保证草稿模型与目标模型分布一致(否则 rejection rate 高)。
- 模型量化用 GPTQ 4-bit(权重 + KV Cache 都量化),显存占用降 60%,decode 延迟从 30ms/token 降到 12ms/token。
- 实际坑:量化后 KV Cache 精度下降导致长上下文生成质量崩,解法是混合精度:前 512 tokens 用 FP16,后续用 INT4。 并发控制:动态 batching:
- 用 vLLM 的 continuous batching,将多个请求的 decode 合并到一个 batch 中,GPU 利用率从 30% 提到 85%。
- 设置 max_num_seqs=256,避免 batch 过大导致 OOM。
总结:整条链路延迟从 1.5s 降到 300ms(召回 50ms + 生成 250ms),代价是召回率降 5%、生成质量降 3%(量化影响),但高并发下可接受。
3️⃣ 答题模板(30 秒电梯版)
“这个问题我从召回、生成、并发控制三个层面回答。召回层用 HNSW + BM25 多级索引和级联 rerank,将延迟从 100ms 压到 50ms;生成层用 KV Cache 预填充、投机解码和 4-bit 量化,将 decode 从 30ms/token 降到 12ms/token;并发控制用 vLLM 的 continuous batching 提升 GPU 利用率。总结一句:核心是拆解瓶颈、用工程取舍换延迟,代价是少量精度和效果。”
4️⃣ 高频追问 & 应对
追问 1:你说用投机解码,但草稿模型和目标模型分布不一致怎么办?
应对策略:首先,草稿模型必须用目标模型的蒸馏版本(如用 7B 模型蒸馏 1.5B),保证 logits 分布接近。其次,动态调整 rejection 阈值:如果 rejection rate > 30%,自动回退到纯目标模型 decode。最后,实践中可以用 Medusa 的多个草稿头(每个头预测不同位置),减少 rejection 概率。实测 rejection rate 控制在 10% 以内。
追问 2:高并发下 HNSW 索引更新怎么保证一致性?
应对策略:用双缓冲索引——主索引只读,副索引在后台异步重建(增量更新,每 10 分钟全量重建一次)。重建完成后原子切换指针。同时,对写入请求做写缓冲队列,先写入文档库,再异步更新索引。查询时如果副索引未就绪,回退到 BM25 检索。这样保证查询延迟稳定在 2ms,写入延迟 100ms 以内。
追问 3:量化后生成质量下降,怎么量化这个损失?
应对策略:用 perplexity 和 BLEU 两个指标。perplexity 差异 < 0.5 可接受(7B 模型从 8.2 升到 8.6)。更关键的是人工评估:对 500 条 query 做 A/B 测试,看用户满意度(点击率、停留时间)。如果满意度下降 > 2%,回退到 FP16。实践中,4-bit 量化对短文本(< 1K tokens)影响可忽略,长文本(> 4K)才需要混合精度。
5️⃣ 避坑 · 常见错误答法
- ❌ 只堆缓存(“把所有结果缓存到 Redis”)→ ✅ 缓存只对高频 query 有效,长尾 query 必须优化检索和生成本身。缓存命中率 < 30% 时,优化整条链路才是正解。
- ❌ 盲目用大模型(“用 GPT-4 做 rerank”)→ ✅ 高并发下必须用轻量模型(如 BGE-Reranker-v2 的 tiny 版本),大模型延迟 200ms+,并发一高就超时。Trade-off 是精度换速度。
- ❌ 忽略并发控制(“单机部署,用多线程”)→ ✅ 多线程在 GPU 上无效,必须用 vLLM 或 TensorRT-LLM 的 continuous batching,否则 GPU 利用率 < 30%。
6️⃣ 简历呼应
- 如果你有 RAG 项目:从“多级索引 + 级联 rerank”切入,强调你如何用 HNSW 和 BM25 压召回延迟,并给出具体数字(如 10 万文档,延迟从 100ms 降到 50ms)。
- 如果你只做过传统 NLP:用“模型量化 + 投机解码”类比迁移,说你如何用 GPTQ 和 Speculative Decoding 优化 BERT 推理,强调 trade-off(精度 vs 速度)。
- 如果你是校招无项目:聚焦“FlashAttention 和 KV Cache”的论文复现,说你读过 FlashAttention-2 论文并实现过 demo,能解释 prefill 和 decode 的延迟差异。
7️⃣ 延伸阅读
- FlashAttention-2: Faster Attention with Better Parallelism and Work Partitioning
- Speculative Decoding: Fast Generation from Large Language Models via Drafting
- GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers
- vLLM: Easy, Fast, and Cheap LLM Serving with PagedAttention
- HNSW: Efficient and Robust Approximate Nearest Neighbor Search