亿级文档批量生成 Embedding,离线任务怎么设计?

第 1218 题 约 2 分钟读完

本文目录
  1. 面试怎么回答
  2. 先估算
  3. 任务设计
  4. 容错和断点续跑
  5. 增量和更新
  6. 成本优化

面试怎么回答

我会先估算总 Token 数,决定用外部 API 还是自建 GPU、需要多少并发。任务按文档 ID 哈希切成几千个分片,用 Spark 或 Ray 并行处理,自建模型时每个 GPU worker 只加载一次模型,批量推理并把长度相近的文本放一批减少填充;调 API 时控制速率、限流退避,能用批处理接口就用。结果连同片段 ID 和模型版本写入表文件,最后批量导入向量库建索引。容错上每个分片记录状态、失败单独重试,写入按片段 ID 幂等,异常数据进错误表。之后用内容哈希做增量,只算新增和修改的。成本上先对相同片段去重、过滤无信息量的片段,监控吞吐、GPU 利用率和每百万 Token 成本。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

知识库要上线,需要把 2 亿个文本片段批量生成向量。用一个 Python 脚本循环调用 Embedding 接口,算了一下要跑三周。面试官问这题,想看你能不能把它当成一个大数据批处理任务来设计:并行、吞吐、容错、成本。

先估算

  • 2 亿个片段,平均 300 Token,总共 600 亿 Token;
  • 如果调用外部 API:按 Token 计费,还有速率限制(每分钟请求数和 Token 数);
  • 如果自建 GPU 推理:单卡每秒能处理多少 Token,需要多少卡、多少小时。

估算决定了方案:调 API 还是自建、需要多少并发。

任务设计

  1. 数据分片:按文档 ID 哈希分成几千个分片,每个分片是一个独立的处理单元;
  2. 并行执行:用 Spark、Ray 这类分布式框架调度。自建模型时,每个 GPU worker 加载一次模型,持续处理分片,不要每个分片重新加载;
  3. 批处理:每次推理送一批(比如 64 或 128 条),提高 GPU 利用率;把长度相近的文本放在一个批次里,减少填充浪费;
  4. 调用外部 API 时:控制并发和速率,遇到限流指数退避;能用批处理接口(Batch API)就用,通常更便宜;
  5. 结果写入:向量和片段 ID、模型版本一起写入表(Parquet、Lance 等),而不是直接一条条写在线向量库;最后再批量导入向量库构建索引。

容错和断点续跑

  • 每个分片完成后记录状态,失败的分片单独重试;
  • 写入幂等:同一个片段 ID 重复计算时覆盖,不会产生重复;
  • 遇到异常数据(超长文本、乱码)记录到错误表,不让一条坏数据卡住整个分片。

增量和更新

  • 后续只处理新增和修改的片段:用内容哈希判断是否需要重新计算,没变的直接复用;
  • 模型升级时才需要全量重算。

成本优化

  • 去重:完全相同的片段只算一次(模板、免责声明常常大量重复);
  • 过滤:太短、没有信息量的片段不需要向量化;
  • 自建模型时用合适的精度(比如 FP16),在离峰时段使用空闲 GPU;
  • 监控每百万 Token 的成本和吞吐,找出瓶颈(GPU 利用率低往往是数据读取或批次太小导致的)。