Saltar para o conteúdo principal
A API de Lotes permite que você envie grupos de requisições como um único job processado de forma assíncrona. Isso é útil quando você precisa executar muitas requisições e não precisa de resultados imediatos — por exemplo, executar avaliações, gerar embeddings para um grande conjunto de dados ou classificar conteúdo em massa. As requisições em lote são executadas dentro de uma janela de conclusão de 24 horas e possuem limites de taxa separados e mais altos que as chamadas síncronas da API.

Endpoints suportados

EndpointDescrição
/v1/chat/completionsRequisições de chat completion
/v1/embeddingsGeração de embeddings
/v1/images/generationsGeração de imagens
Todas as requisições em um único lote devem ter como alvo o mesmo endpoint.

Ciclo de vida

Um lote passa pelos seguintes status:
validating → in_progress → finalizing → completed
     ↓            ↓
   failed     cancelling → cancelled
StatusDescrição
validatingO arquivo de entrada está sendo verificado quanto a erros de formato e conteúdo.
failedA validação falhou — o arquivo de entrada contém erros. Verifique batch.errors para detalhes.
in_progressAs requisições estão sendo processadas.
finalizingTodas as requisições foram processadas e os arquivos de saída estão sendo gerados.
completedO lote foi concluído. Baixe os resultados de output_file_id.
cancellingUm cancelamento foi solicitado. Requisições em andamento estão sendo finalizadas.
cancelledO lote foi cancelado. Resultados parciais podem estar disponíveis.
expiredO lote não foi concluído dentro da janela de 24 horas.

Etapa 1 — Preparar o arquivo de entrada

Crie um arquivo JSONL onde cada linha é uma requisição. Cada linha possui quatro campos:
CampoTipoDescrição
custom_idstringSeu identificador para esta requisição. Usado para associar entrada e saída. Deve ser único dentro do arquivo.
methodstring"POST" — o único método suportado.
urlstringO caminho do endpoint — deve corresponder ao endpoint que você declara ao criar o lote.
bodyobjectO corpo da requisição — os mesmos parâmetros que você enviaria para o endpoint síncrono.
{"custom_id": "request-1", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "auto", "messages": [{"role": "user", "content": "Summarize the benefits of batch processing in one sentence."}], "max_tokens": 100}}
{"custom_id": "request-2", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "auto", "messages": [{"role": "user", "content": "What is the capital of France?"}], "max_tokens": 100}}
{"custom_id": "request-3", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "auto", "messages": [{"role": "user", "content": "Explain embeddings in one paragraph."}], "max_tokens": 100}}
Um único lote pode conter até 10.000 requisições.

Etapa 2 — Fazer upload do arquivo de entrada

Faça upload do arquivo JSONL usando a API de Files com purpose: "batch".
import { SDK } from '@meetkai/mka1';

const mka1 = new SDK({
  bearerAuth: `Bearer ${YOUR_API_KEY}`,
});

const file = await mka1.llm.files.upload({
  file: new File([jsonlContent], 'batch_input.jsonl', { type: 'application/jsonl' }),
  purpose: 'batch',
});

console.log(file.id);     // "file_abc123"
console.log(file.status); // "processed"

Etapa 3 — Criar o lote

Passe o ID do arquivo enviado, o endpoint de destino e a janela de conclusão.
const batch = await mka1.llm.batches.create({
  inputFileId: file.id,
  endpoint: '/v1/chat/completions',
  completionWindow: '24h',
});

console.log(batch.id);            // "batch_abc123"
console.log(batch.status);        // "validating" or "in_progress"
console.log(batch.requestCounts); // { total: 3, completed: 0, failed: 0 }
Você também pode anexar metadados para seu próprio rastreamento:
const batch = await mka1.llm.batches.create({
  inputFileId: file.id,
  endpoint: '/v1/chat/completions',
  completionWindow: '24h',
  metadata: {
    description: 'nightly evaluation run',
    run_id: 'eval-2026-03-31',
  },
});

Etapa 4 — Verificar o status do lote

Consulte o lote periodicamente até que ele alcance um status terminal.
const batch = await mka1.llm.batches.get({ batchId: 'batch_abc123' });

console.log(batch.status);                // "completed"
console.log(batch.requestCounts.completed); // 3
console.log(batch.requestCounts.failed);    // 0
console.log(batch.outputFileId);           // "file_xyz789"
Aqui está um helper de polling que aguarda a conclusão do lote:
async function waitForBatch(batchId: string, timeoutMs = 120_000) {
  const terminal = ['completed', 'failed', 'cancelled', 'expired'];
  const start = Date.now();

  while (Date.now() - start < timeoutMs) {
    const batch = await mka1.llm.batches.get({ batchId });
    if (terminal.includes(batch.status)) return batch;
    await new Promise((r) => setTimeout(r, 2000));
  }

  throw new Error(`Batch ${batchId} did not complete within ${timeoutMs}ms`);
}

const completed = await waitForBatch(batch.id);

Etapa 5 — Baixar os resultados

Quando o lote estiver completed, baixe o arquivo de saída. Ele é um arquivo JSONL onde cada linha contém o custom_id que você forneceu, a resposta e qualquer erro.
const stream = await mka1.llm.files.content({ fileId: completed.outputFileId! });
const reader = stream.getReader();
const chunks: Uint8Array[] = [];
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  chunks.push(value);
}
const text = new TextDecoder().decode(Buffer.concat(chunks));

const results = text
  .split('\n')
  .filter((line) => line.trim())
  .map((line) => JSON.parse(line));

for (const result of results) {
  console.log(`${result.custom_id}: status=${result.response.status_code}`);
  console.log(`  body:`, result.response.body);
}
Cada linha no arquivo de saída tem esta estrutura:
{
  "id": "response_abc123",
  "custom_id": "request-1",
  "response": {
    "status_code": 200,
    "request_id": "req_abc123",
    "body": { "...": "same shape as the synchronous endpoint response" }
  },
  "error": null
}
Se uma requisição falhou, response é null e error contém os detalhes:
{
  "id": "response_def456",
  "custom_id": "request-2",
  "response": null,
  "error": {
    "code": "processing_error",
    "message": "The request could not be processed."
  }
}
Se alguma requisição falhou, o lote também fornece um error_file_id contendo apenas as entradas que falharam.

Cancelar um lote

Cancele um lote que ainda está em andamento. Requisições que já foram concluídas permanecem na saída.
const cancelled = await mka1.llm.batches.cancel({ batchId: 'batch_abc123' });
console.log(cancelled.status); // "cancelling"
O lote transiciona para cancelling enquanto as requisições em andamento são finalizadas, e depois para cancelled.

Listar lotes

Recupere todos os lotes da conta atual, do mais recente ao mais antigo. Suporta paginação.
const page = await mka1.llm.batches.list({ limit: 20 });

for (const batch of page.data) {
  console.log(`${batch.id}: ${batch.status} (${batch.requestCounts?.completed}/${batch.requestCounts?.total})`);
}
Use o parâmetro after com um ID de lote para paginar os resultados.

Exemplo: embeddings em lote

O mesmo fluxo funciona para embeddings. Altere o url em cada linha JSONL e o endpoint ao criar o lote.
{"custom_id": "embed-1", "method": "POST", "url": "/v1/embeddings", "body": {"model": "auto", "input": "The quick brown fox"}}
{"custom_id": "embed-2", "method": "POST", "url": "/v1/embeddings", "body": {"model": "auto", "input": "jumps over the lazy dog"}}
const file = await mka1.llm.files.upload({
  file: new File([jsonlContent], 'embed_batch.jsonl', { type: 'application/jsonl' }),
  purpose: 'batch',
});

const batch = await mka1.llm.batches.create({
  inputFileId: file.id,
  endpoint: '/v1/embeddings',
  completionWindow: '24h',
});

const completed = await waitForBatch(batch.id);
const stream = await mka1.llm.files.content({ fileId: completed.outputFileId! });
// ... read stream as shown in Step 5

Erros de validação

Se o arquivo de entrada tiver problemas de formatação, o lote passa imediatamente para failed. Causas comuns:
  • JSON inválido — uma linha não é um JSON válido.
  • Campos ausentes — uma linha está sem custom_id, method, url ou body.
  • Método incorretomethod deve ser "POST".
  • URL incompatível — o url em uma linha não corresponde ao endpoint declarado ao criar o lote.
  • custom_id duplicado — cada custom_id deve ser único dentro do arquivo.
Verifique batch.errors.data para as mensagens de erro específicas e números de linha.
const batch = await mka1.llm.batches.get({ batchId: 'batch_abc123' });

if (batch.status === 'failed' && batch.errors) {
  for (const err of batch.errors.data ?? []) {
    console.log(`Line ${err.line}: [${err.code}] ${err.message}`);
  }
}

Veja também