跳到主要内容

扼杀 AI 流水线吞吐量的预处理瓶颈

· 阅读需 12 分钟
Tian Pan
Software Engineer

某团队构建了一个 RAG 功能,测量端到端延迟后发现慢得无法接受,随即开始优化模型调用。他们尝试了更小的模型、批量请求,并调整了 temperature 和 token 上限。经过两个迭代周期,延迟下降了 15%,但功能依然太慢。他们从未测量过的是:在 LLM 收到任何提示词之前,文本分块和嵌入生成就已经耗费了 600ms。

这种模式在分布式系统中普遍到有了专有名词:优化了错误的组件。在 AI 流水线中,LLM 调用显而易见且易于测量,而其之前的所有环节都是隐形的——除非你主动做埋点,否则根本发现不了——而吞吐量恰恰死在那里。

延迟究竟藏在哪里

典型的生产级 RAG 流水线是这样的:查询到达,进行嵌入,用于搜索向量库,将相关分块拼装成提示词,最后由 LLM 生成响应。工程师倾向于把这理解为"检索 + 生成",并对生成环节做性能分析。

实际的延迟分布远没那么好看。仅查询嵌入在 CPU 上就需要约 85ms——这还是向量搜索开始之前。文档摄入流水线更糟:使用标准工具做 PDF 解析,每页耗时 5–30 秒;即便是快速的专用解析器,每页也稳定在约 6 秒。分块又为每份文档额外增加 100–500ms。元数据富化——提取表格、标题、来源信息——还会在此基础上叠加多轮处理。

在埋点完善的生产系统中,延迟分布通常大致如下:

  • 查询嵌入:占查询路径延迟的 15–25%
  • 向量数据库搜索:5–10%
  • 提示词组装:2–5%
  • LLM 推理(首 token 时间):15–30%
  • LLM 生成:10–40%
  • 网络、编排、序列化:其余部分

模型调用只是诸多因素之一,而且往往不是最大的。然而团队只给模型做埋点,其余部分一片黑暗。

预处理瓶颈的三大类型

并非所有预处理瓶颈都相同,它们分为三类,各有不同的解法。

摄入路径瓶颈最为严重,发生在文档解析、分块、嵌入生成和向量库写入阶段。一项针对 800+ 文档的基准测试发现,仅文档类型一项就能导致解析准确率相差 55 个百分点——法律文档用合适的专用工具可达约 95% 的准确率,而布局复杂的学术论文只有 40–60%。性能影响同样戏剧性:基于前沿 LLM 的解析器每秒只能处理 0.03–0.1 页;而像 Uni-Parser 这样的专用工具在现代 GPU 硬件上可达每秒 20 页。选错工具会让摄入瓶颈恶化一到两个数量级。

嵌入生成往往是大规模摄入的限速步骤。实时嵌入 API 有速率限制,而批量处理 API 没有。那些对批量摄入使用实时嵌入端点的团队——因为和查询时用的是同一个端点,图方便——最终付出了比使用批量 API 高 2–3 倍的成本和慢 5–10 倍的摄入速度。

查询路径瓶颈在查询时出现,直接影响用户侧延迟。查询嵌入和分词在每次请求上都会执行。对大多数西方语言文本,分词快到可以忽略不计。但对于形态丰富的语言或 JSON 等结构化数据格式,分词延迟每次请求可能增加 50–200ms——足以在低延迟 API 中主导整个延迟预算。这一类型最容易让团队猝不及防,因为"嵌入前的文本归一化"不像是热路径。

架构错配瓶颈最为隐蔽,发生在流水线架构是为某种使用模式设计的,却被部署到另一种场景时。最典型的例子:构建了一个同步、阻塞请求的摄入流水线,处理几十份文档没问题,但到了几万份时就成了吞吐量上限。当文档摄入和查询服务争抢同一个计算预算时,任何大型摄入任务都会降低查询延迟。这不是优化问题,而是结构性问题。

先做剖析:找到真正的瓶颈

识别自己属于哪种类型的唯一方法,是显式地追踪每个阶段。这听起来显而易见,但实践中并不常见。大多数团队对模型调用有可观测性(通过服务商 dashboard 或 SDK 层日志),对 HTTP 层有可观测性(通过应用监控),而中间的预处理流水线却往往是黑暗地带。

正确的做法是使用 OpenTelemetry 的按阶段 span。流水线中的每个主要步骤(摄入:解析→分块→嵌入→写入;查询路径:分词→嵌入→搜索→组装)都有自己的 span 并记录耗时。收集第 95 百分位延迟,而不是均值——预处理瓶颈往往在均值出现之前就先体现在尾部延迟上。

读取追踪数据时,需要注意以下几点:

  • CPU 密集型 vs I/O 密集型阶段:如果分块慢,是 CPU 密集型,受益于并行化。如果向量库写入慢,可能是 I/O 密集型,受益于批量处理。
  • 序列化开销:将数据转换为向量数据库期望的格式(例如为 Qdrant 构建批量对象)可能比插入 RPC 本身还慢。这是 CPU 密集型操作,受益于多进程,而非 asyncio。
  • 单文档 vs 单批次计时:两种方式都要报告延迟。一个在单文档看来可接受的阶段,在单批次维度可能因为无法并行化而成为瓶颈。

在获得阶段级数据之前不要优化。确实存在模型调用本来就是瓶颈的情况——但也存在 600ms 的查询嵌入被归咎于"推理慢"的情况。

异步预处理:将摄入与查询服务解耦

摄入路径瓶颈的结构性修复方案是架构分离。摄入和查询服务应作为独立服务运行,通过队列连接。

在基于队列的摄入流水线中,文档到达时被推送到消息队列(Kafka、RabbitMQ 或云原生替代品)。一个独立的 worker 集群异步消费队列:解析、分块、嵌入、写入——每个步骤都可独立扩展。查询服务只从已填充好的向量库读取,完全不接触摄入流水线,不存在资源竞争。

收益是叠加的。在大量入库或批量导入时,摄入 worker 可以独立扩容,不影响查询延迟。解析步骤的失败不会级联到查询服务。可以重新部署或升级摄入 worker,而无需触碰查询路径。

同样的原则适用于大规模的嵌入生成。处理数百万份文档时,批量嵌入服务(Databricks、SageMaker 及类似平台均提供)比实时嵌入 API 节省 3–5 倍成本,并消除速率限制上限。代价是嵌入可用前会增加延迟,这对大多数摄入工作流是可接受的,对查询路径嵌入(仍实时运行)则无关紧要。

一个不那么显眼的含义:异步摄入要求查询服务能容忍陈旧的嵌入。30 秒前上传的文档可能尚未可搜索。这是否可以接受取决于使用场景。对大多数企业知识库应用而言可以;对实时文档协作则不行。应根据特定产品的延迟需求而非通用场景来设计架构。

多级缓存:最快的预处理是不做预处理

流水线埋点完成、摄入/查询路径解耦之后,缓存是 ROI 最高的优化手段。通用原则:任何随时间稳定、计算成本高昂的预处理结果都应被缓存。

查询嵌入缓存是最容易、回报最高的一层。任何生产应用的用户都会高频重复查询——产品搜索词、常见支持问题、频繁查阅的文档主题。将查询字符串的嵌入向量缓存起来(TTL 30–60 分钟),可以为重复查询消除嵌入调用。生产应用中真实用户的缓存命中率通常达到 30–50%。在 CPU 上每次嵌入 85ms,40% 命中率可将平均查询路径预处理延迟降低约 34ms。

检索结果缓存存储查询嵌入对应的向量搜索结果。对于文档语料稳定的系统,这可以同时消除嵌入调用和向量库查询。失效是难点:文档增加或更新时,缓存的检索结果就会过时。正确的做法是按语料哈希作为缓存键:如果语料自缓存检索以来没有变化,就返回缓存结果。

已解析文档缓存存储解析步骤的中间输出。解析是每份文档中成本最高的预处理步骤,而文档在摄入后极少变化。存储已解析的 AST 或中间表示(而非只存最终分块),允许在不重复解析的情况下重新处理(用不同参数重新分块、用新模型重新嵌入)。这在分块策略仍在调优的迭代实验阶段尤其有价值。

结合嵌入缓存、检索缓存和重排序缓存的多级缓存策略,在查询重叠度较高的工作负载中被测量出最高 80% 的延迟降低,生产环境中典型影响在 40–60% 区间。

实施顺序:先做查询嵌入缓存(低成本,高命中率),再做检索缓存(中等成本,取决于语料稳定性),最后做已解析文档缓存(工程成本最高,对文档密集型工作负载价值最大)。

分块策略的开销

分块策略值得专项关注,因为其影响往往被错误归因。看到 RAG 准确率差的团队通常会归咎于模型或嵌入模型,并投入资源升级两者。在许多情况下,准确率问题出在分块策略上,而非模型——而延迟问题则是他们为修复准确率而采用的昂贵语义分块方案比必要的更慢。

研究证据对默认值给出了明确结论:512 个 token、10–20% 重叠在大量学术文档语料上达到 69% 的准确率。这是正确的起点。语义分块——根据主题转换而非 token 数量对齐边界——在临床决策支持等专业领域能将准确率提升至约 87%,但会增加不可忽视的计算成本。2026 年 1 月的一项分析发现,句子级分块在约 5,000 个 token 以内的准确率与语义分块相当,成本却只有其一小部分。

失败模式:团队以准确率为由推出语义分块,却没有分析其运行时开销,随后发现分块速度比固定大小基线慢 3–5 倍,最终得到一个准确率更高但慢于需求允许范围的流水线。在提交分块策略之前,先在生产文档体量下对其延迟做性能分析。

本周可以做什么

如果你的 AI 流水线有尚未诊断的延迟问题:

  1. 用 OpenTelemetry span 包裹每个预处理步骤,添加按阶段追踪。在得出结论之前,至少收集 100 次真实请求的第 95 百分位计时数据。
  2. 检查你的嵌入调用模式——批量摄入是否在使用实时嵌入端点?切换到批量端点。
  3. 添加查询嵌入缓存——即使是带短 TTL 的简单内存 LRU 缓存,也能暴露真实的缓存命中率,并验证 85ms 的嵌入调用是否在每次请求上都发生。
  4. 如果摄入和查询服务共享计算资源——将它们分离。基于队列的摄入流水线是一次性架构变更,可以消除整整一类资源竞争。

LLM 调用是你能看到的最昂贵的东西。但这并不意味着它是流水线中最昂贵的东西。


预处理瓶颈问题在文献中已有充分记录,但在实践中仍然令团队措手不及,因为模型调用太显眼、太容易测量。解决方案需要先埋点,再调整架构——而埋点恰恰是大多数团队跳过的那一步。

Let's stay in touch and Follow me for more thoughts and updates