你的 RAG 流水线在标准负载测试中表现出色。p95 延迟看起来很健康,错误率接近于零。然而,用户反馈的回复却在避而不答、引用不存在的文档,或者从六个月前上传的一份白皮书中翻出无关的段落。仪表盘显示一切正常,但实际体验却显示系统已损坏。

这种脱节之所以存在,是因为传统的性能测试是为“请求-响应”系统设计的,而不是为“会思考”的系统设计的。当你向 REST 端点发送一千个并行请求时,你只能了解到服务器是否能保持运行。你无法得知检索层是否抓取了正确的文本块,Prompt 模板是否保留了上下文,或者当向量存储为空时,模型是否会凭空捏造来源。标准的负载测试衡量的是速度,而 RAG 应用要求你衡量的是理解力。

超越状态码 200

典型的 API 负载测试检查三件事:可用性、延迟和吞吐量。它询问服务器是否响应、耗时多久以及能承受多少并发用户。对于 RAG 应用来说,这些数字只是前提条件,而非结论。快速的错误答案仍然是错误答案,而大规模的错误答案比缓慢的答案代价更高。

RAG 为每个请求增加了两个截然不同的阶段。首先,系统将用户问题转化为 Embedding,查询向量存储,并拉取一组上下文分块。其次,它将这些分块塞进 Prompt,将所有内容发送给语言模型,并流式传输回结果。传统的测试通常将这些合并为一个单一的“响应时间”指标。它们将检索引擎和生成器视为一个黑盒。

你需要拆解这个黑盒。如果你的向量数据库在负载下变慢,检索延迟就会上升。LLM 可能仍然响应很快,但它是在基于匆忙抓取的垃圾上下文进行响应。或者,向量搜索保持敏捷,而 LLM 队列却在积压,导致首个 Token 生成时间(TTFT)增加,直到用户盯着闪烁的光标发呆。单一的端到端计时器会掩盖这两种失败。

测试检索层,而不只是数据库

大多数团队运行一个快速的向量搜索基准测试,就认为检索层已经测试过了。该基准测试通常衡量的是数据库针对特定查询返回最近邻的速度。它很少衡量这些最近邻是否真的包含答案。

检索质量会随着负载的变化而发生微妙的偏移。在并发压力下,近似最近邻(ANN)索引的行为可能与隔离状态下不同。在 Notebook 中看起来完美的切片(Chunking)策略,当一万份文档竞争同一个 Embedding 空间时,会开始在边界处导致上下文泄露。在安静环境下能返回理想段落的查询,在索引重建或元数据过滤在请求压力下被剥离时,可能会浮现出误导性的营销幻灯片。

要正确测试这一点,你需要一个 Ground-truth 数据集。策划一些你已经知道应该出现哪些源文档的问题。在不同的并发级别下运行这些问题,并检查预期的分块是否出现在 Top-k 结果中。跟踪命中率,而不仅仅是查询时长。如果你的前五个分块完全错过了关键来源,那么在 LLM 还没“醒来”之前,你的检索流水线就已经失败了。

你还应该对边缘情况进行压力测试。提交在语料库中没有答案的查询。提交可能映射到多个领域的模糊问题。提交超过 Embedding 模型 Token 限制并被静默截断的长问题。观察检索层返回了什么。在每种情况下,失败模式比经过的毫秒数更重要。

当模型悄然“窒息”时

一旦分块到达 LLM,标准的负载测试便会继续撒谎