Files
msaldain 179062a5d4 Búsqueda web con DuckDuckGo, sin API key
Primera tool del agente. No depende del modelo, así que se puede usar y
verificar de punta a punta antes de que exista el modelo propio.

Sobre el endpoint: la API oficial de DuckDuckGo ("Instant Answer") no sirve
para esto — responde definiciones y fichas de entidades, y para una consulta
normal devuelve 200 con el cuerpo vacío. Los resultados web reales solo están
en el endpoint lite, que no es una API con contrato: el HTML puede cambiar y
hay límite de tasa. Por eso el backend está detrás de una interfaz y queda
implementado también SearxNG autoalojado, que es un cambio de una línea de
config cuando haga falta.

Decisiones:

- Presupuesto de contexto explícito: con seq_len 2048 los resultados compiten
  con la memoria recuperada y el turno del usuario, así que se devuelven cinco
  recortados en vez de diez completos.
- Las redirecciones /l/?uddg= se desenvuelven al destino real: guardarlas
  ensuciaría la memoria episódica, donde dos búsquedas a la misma página
  parecerían páginas distintas.
- Caché con TTL, que es de comportamiento y no de rendimiento: en una casa las
  mismas preguntas se repiten muchas veces por día.
- Sin resultados devuelve "Sin resultados." en vez de vacío, para que el modelo
  pueda decir que no encontró nada en lugar de inventar.

Se quitan Brave y Tavily de .env.example: ya no hay credenciales que gestionar
ni un tercero al que informarle qué busca la familia.

23 tests nuevos (71 en total), contra una respuesta real guardada como fixture:
el parser es lo que se rompe cuando cambia el markup, y tiene que fallar en la
suite y no en producción. Ningún test sale a internet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 23:15:13 -03:00

103 lines
3.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ENLACE
Modelo de lenguaje propio, entrenado desde cero, para asistencia general y
familiar en español. No es fine-tuning de un modelo existente: tokenizer, datos
y pesos son propios.
El plan completo — etapas, presupuestos de cómputo, arquitectura de datos y
criterios de verificación — está en `docs/PLAN.md`.
## Estado
Etapa 0 (entorno y validación del stack) implementada y verificada:
- Capa de configuración validada, con composición por capas y perfiles de hardware.
- Arquitectura del modelo: RMSNorm, SwiGLU, RoPE, GQA, QK-norm, z-loss.
- Entrenador con WSD, precisión mixta, acumulación de gradiente y **reanudación exacta**.
- Cargadores de datos: bytes (smoke test) y shards `uint16` (corpus real).
Primera tool del agente (Etapa 4), que no depende del modelo y ya funciona:
- Búsqueda web con DuckDuckGo, **sin API key ni cuenta en ningún servicio**.
```bash
.venv/bin/python -m enlace.agent.tools.search "que es home assistant"
```
71 tests, incluido el de reanudación exacta.
Pendiente: Etapa 1 en adelante (corpus, tokenizer, pretraining, post-training,
agente, bases del sistema, memoria, snapshots).
## Puesta en marcha
```bash
python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"
scripts/prepare_smoke_data.sh # texto en español de dominio público
.venv/bin/python -m enlace.train.train configs/runs/smoke-cpu.yaml
scripts/test.sh
```
En el servidor con GPU, por SSH (ver `.env.example`):
```bash
scripts/remote.sh sync
scripts/remote.sh run configs/runs/smoke-2060.yaml # smoke test, ~10 min
scripts/remote.sh run configs/runs/pretrain-2060.yaml # pretraining, 1-2 días
scripts/remote.sh logs
```
Toda corrida larga arranca bajo `tmux`: cortar el SSH no mata el entrenamiento.
## Configuración
Ningún hiperparámetro vive en el código. Las configs se componen por capas:
```yaml
# configs/runs/pretrain-2060.yaml
include:
hardware: hardware/turing-2060.yaml # dtype, backend de atención, batch
model: model/tiny-50m.yaml # capas, dimensiones, contexto
train: train/pretrain.yaml # LR, schedule, intervalos
data: data/corpus.yaml # de dónde salen los tokens
```
Overrides puntuales desde la línea de comandos, para probar variantes sin editar
archivos:
```bash
.venv/bin/python -m enlace.train.train configs/runs/smoke-cpu.yaml train.seed=99
```
Una config inválida falla al arrancar con un mensaje concreto, no a las tres
horas de entrenamiento.
## Hardware
El perfil de hardware es la única capa que cambia al migrar de placa.
| Perfil | Placa | dtype | Atención | Notas |
|---|---|---|---|---|
| `turing-2060` | RTX 2060 12 GB (sm_75) | float16 + GradScaler | mem_efficient | Turing no soporta bfloat16 ni FlashAttention-2 |
| `blackwell-5090` | RTX 5090 32 GB (sm_120) | bfloat16 | flash | Requiere PyTorch ≥ 2.7 con CUDA 12.8 |
| `cpu` | — | float32 | math | Solo desarrollo y tests |
`enlace/train/backends.py` es el único archivo del entrenamiento que conoce
diferencias entre placas, y valida el perfil contra la GPU real antes de
empezar: pedir bfloat16 en Turing falla de inmediato en vez de degradarse en
silencio.
## Estructura
```
enlace/config/ Esquemas pydantic y composición de YAML
enlace/model/ Transformer decoder-only y selección de backend de atención
enlace/train/ Bucle, schedules, checkpointing, detección de hardware
enlace/data/ Cargadores con reanudación exacta
configs/ hardware × model × train × data, compuestos en configs/runs/
scripts/ Utilidades: remote.sh, test.sh, prepare_smoke_data.sh
tests/ Suite completa; test_resume.py es el crítico
```