Generación de datos sintéticos con la Batch API

Etapa 3 del plan. Se elige la Batch API sobre llamadas sueltas porque cuesta
la mitad y generar un dataset no es sensible a la latencia: es exactamente su
caso de uso. A cambio el trabajo es asincrónico y puede tardar horas, así que
todo el estado vive en disco y es reanudable — matar el proceso, perder la
conexión o reiniciar el servidor no pierde nada ni gasta de nuevo.

Cuatro decisiones que sostienen eso:

- El custom_id se deriva del hash del contenido del pedido. El trabajo queda
  idempotente: re-generar la misma especificación produce los mismos IDs, así
  que lo ya resuelto se reconoce y no se vuelve a pagar.
- Los resultados se indexan por custom_id, nunca por posición. La API los
  devuelve en cualquier orden, y emparejarlos por índice mezcla las respuestas
  en silencio; un dataset mal alineado es peor que uno vacío porque parece
  correcto. El cliente falso de los tests los invierte a propósito.
- Los fallos se registran en errors.jsonl con su motivo en vez de descartarse,
  y --retry-failed reenvía solo esos.
- El prompt de sistema compartido va marcado para caché: es idéntico entre
  miles de pedidos, y a ~0,1x del precio de entrada deja de contar.

Los lotes se persisten después de cada envío y no al final, para que una caída
a mitad de camino no deje lotes huérfanos sin registrar.

El SDK de anthropic se importa de forma perezosa y queda como extra opcional:
el servidor de entrenamiento no lo necesita y el paquete importa sin él.

21 tests nuevos (92 en total), todos contra un cliente falso — lo que hay que
verificar es el harness, no el SDK.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-27 23:26:41 -03:00
parent 1d2fcef4d0
commit 8805b0541b
5 changed files with 419 additions and 18 deletions
+6
View File
@@ -21,6 +21,12 @@ data = [
"fasttext-wheel>=0.9", # filtro de idioma
"datasketch>=1.6", # deduplicación MinHash
]
distill = [
# Solo para generar el dataset SFT (Etapa 3) con la Batch API. No hace falta
# en el servidor de entrenamiento: enlace/data/distill.py importa el SDK de
# forma perezosa para que el paquete funcione sin él.
"anthropic>=0.69",
]
dev = [
"pytest>=8.0",
"ruff>=0.6",