批量向量化的性能优化
demo 里我们一次性把 5 个 chunk 传给 API,实际项目中可能有几万甚至几十万个 chunk。一次全传过去不现实(API 有请求大小限制),一个一个传又太慢。
2.1 分批处理
最基本的优化:把 chunks 分成固定大小的批次,逐批调用 API。
java
/**
* 分批向量化
*
* @param texts 所有待向量化的文本
* @param batchSize 每批的大小(建议 20~50)
* @return 所有文本的向量
*/
public List<double[]> embedInBatches(List<String> texts, int batchSize) throws Exception {
List<double[]> allEmbeddings = new ArrayList<>();
for (int i = 0; i < texts.size(); i += batchSize) {
int end = Math.min(i + batchSize, texts.size());
List<String> batch = texts.subList(i, end);
System.out.printf("向量化进度:%d/%d%n", end, texts.size());
List<double[]> batchEmbeddings = embed(batch);
allEmbeddings.addAll(batchEmbeddings);
// 简单的限流:每批之间等一下,避免触发 API 的速率限制
if (end < texts.size()) {
Thread.sleep(200);
}
}
return allEmbeddings;
}
2.2 并发控制
分批处理是串行的,如果 API 支持并发,可以用多线程加速:
java
import java.util.concurrent.*;
/**
* 并发批量向量化
*/
public List<double[]> embedConcurrently(List<String> texts, int batchSize,
int maxConcurrency) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(maxConcurrency);
List<Future<List<double[]>>> futures = new ArrayList<>();
for (int i = 0; i < texts.size(); i += batchSize) {
int start = i;
int end = Math.min(i + batchSize, texts.size());
List<String> batch = texts.subList(start, end);
futures.add(executor.submit(() -> embed(batch)));
}
List<double[]> allEmbeddings = new ArrayList<>();
for (Future<List<double[]>> future : futures) {
allEmbeddings.addAll(future.get());
}
executor.shutdown();
return allEmbeddings;
}
2.3 错误重试
网络请求难免会失败,加一个简单的重试机制:
java
/**
* 带重试的 embed 方法
*/
public List<double[]> embedWithRetry(List<String> texts, int maxRetries) throws Exception {
Exception lastException = null;
for (int attempt = 1; attempt <= maxRetries; attempt++) {
try {
return embed(texts);
} catch (Exception e) {
lastException = e;
System.err.printf("第 %d 次调用失败:%s,%s%n",
attempt, e.getMessage(),
attempt < maxRetries ? "准备重试..." : "已达最大重试次数");
if (attempt < maxRetries) {
// 指数退避:第 1 次等 1 秒,第 2 次等 2 秒,第 3 次等 4 秒
Thread.sleep(1000L * (1 << (attempt - 1)));
}
}
}
throw new RuntimeException("向量化失败,已重试 " + maxRetries + " 次", lastException);
}