Cadena de búsqueda con respaldo. DuckDuckGo sigue de primario porque no exige
credenciales: en el camino habitual ningún tercero se entera de qué busca la
familia. Pero su endpoint lite no es una API con contrato, así que cuando
limite por tasa o cambie el HTML, Brave responde.
Dos matices del encadenado:
- Cero resultados NO dispara el respaldo. Si el primario respondió bien y no
encontró nada, esa es la respuesta correcta; encadenar gastaría cuota y
devolvería resultados peores. Solo se avanza ante un error real.
- La cadena recuerda quién respondió: al depurar una respuesta rara, lo
primero que hay que saber es de dónde salió.
Un respaldo sin credencial falla al arrancar y no en la primera consulta —
que es justo cuando el primario ya falló y el respaldo tiene que funcionar.
Aparte, verificando torch en la 2060 apareció un defecto real en backends.py:
torch.cuda.is_bf16_supported() usa including_emulation=True por defecto, así
que devuelve True en Turing, donde bf16 no existe en silicio. La guardia no
habría atrapado el perfil de la 5090 corriendo en la 2060: el entrenamiento
seguía, emulado y silencioso. Medido en la placa: 4,49 ms por matmul en bf16
contra 1,75 ms en fp16, unas 2,6x más lento. Ahora se consulta con
including_emulation=False, con respaldo por compute capability.
11 tests nuevos (113 en total).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Base del proyecto ENLACE: un modelo de lenguaje propio entrenado desde cero,
en español, para asistencia general y familiar. El plan completo está en
docs/PLAN.md.
Esta etapa establece el andamiaje y lo verifica de punta a punta:
- Configuración por capas (hardware × model × train × data) validada con
pydantic. Ningún hiperparámetro vive en el código y una config inválida
falla al arrancar, no a las tres horas de entrenamiento.
- Perfiles de hardware que aíslan el salto de GPU: la RTX 2060 (Turing) no
soporta bfloat16 ni FlashAttention-2, así que entrena en float16 con
GradScaler y backend mem_efficient; el perfil de la 5090 ya está escrito.
backends.py valida el perfil contra la GPU real antes de empezar.
- Transformer decoder-only estilo Llama: RMSNorm, SwiGLU, RoPE, GQA,
embeddings atados, QK-norm y z-loss. Los dos últimos son lo que mantiene
estable el entrenamiento en float16.
- Entrenador con schedule WSD, acumulación de gradiente, precisión mixta,
checkpointing atómico y reanudación exacta.
- Cargadores de datos con estado serializable: bytes para el smoke test y
shards uint16 para el corpus real.
48 tests, entre ellos el crítico: reanudar desde un checkpoint reproduce los
pesos de una corrida ininterrumpida, parámetro por parámetro.
Verificado en CPU: 300 pasos sobre texto en español, loss 3.07 -> 1.63.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>