Files
takana/recipes/ia-modelo-chat.toml
Sergio 54bf3e810e ia: el modelo de chat, pineado — Qwen2.5-1.5B-Instruct Q4_K_M (Apache-2.0)
Elegido por tres cosas, y las tres medidas antes de pinearlo: licencia Apache-2.0 (lo que una distro
puede shipear sin letra chica, al revés que Llama-3.2 o Gemma), habla español —se le preguntó qué es
una distribución de GNU/Linux y contestó dos frases correctas— y corre en CPU: 20,1 tokens/s en el
hub sin GPU, 1,04 GiB.

El objeto pineado es un tar que envuelve el .gguf, publicado en el mirror y servido por sha256:
takana extrae toda fuente con `tar` y un GGUF pelado no lo es. Es el camino de firefox-pgo-profile.
La receta anota el sha256 del GGUF DE UPSTREAM (el lfs.oid de HuggingFace, verificado al bajarlo) y
no sólo el del tar nuestro, para que nadie tenga que confiar en nuestro tar. Round-trip verificado:
apartados el caché y el artefacto, el build lo bajó del mirror y selló el mismo ArtifactHash.

Guardián en la receta, porque el fallo es callado: un fichero truncado o un HTML de error renombrado
a .gguf se instala igual y sella en verde. Se comprueban el mágico GGUF y el tamaño.

⚠ Y el modelo de verdad destapó una CARRERA en el guardián del §6.7: el censo de motores contaba en
el instante del cierre — con el de juguete daba 0 y con el de la imagen daba 1, que se lee como fuga
cuando en realidad matar un proceso con un giga mapeado tarda ~1 s. Ahora espera hasta 15 s y anota
cuánto tardó. La rotura a propósito sigue fallando, ahora con el tiempo a la vista.

Falta decidir en qué imágenes se declara (con el motor son ~1,25 GiB por perfil) y pinear el de
embeddings (multilingual-e5-small) para la mitad semántica del §6.3.
2026-09-11 22:41:46 +00:00

71 lines
4.1 KiB
TOML

# ia-modelo-chat — el modelo que contesta en la barra lateral de `atuq` (SDD 26 §6.7).
#
# ══ QUÉ ES ═════════════════════════════════════════════════════════════════════════════════════
# **Qwen2.5-1.5B-Instruct, cuantizado Q4_K_M**: 1.117.320.736 bytes de GGUF. Es el modelo de chat de
# la distro, y entra como los pesos entran en cualquier lado — **fuente pineada por sha256**, no un
# build que lo produzca. Nadie entrena nada acá.
#
# ══ POR QUÉ ÉSTE ═══════════════════════════════════════════════════════════════════════════════
# Tres cosas, y las tres se pueden discutir cambiando un sha256:
#
# · **licencia Apache-2.0**, que es lo que una distro puede shipear sin letra chica. Las
# alternativas obvias (Llama-3.2, Gemma) traen licencias propias con restricciones de uso, y eso
# en una imagen que se distribuye no es un detalle;
# · **habla español**, que es el idioma de quien va a usar esto. Medido antes de pinearlo, no
# supuesto: se le preguntó qué es una distribución de GNU/Linux y contestó dos frases correctas
# en español;
# · **entra en la imagen y corre en CPU**: 1,04 GiB y **20,1 tokens/s** medidos en el hub sin GPU
# (89 tokens en 4,4 s). Un modelo de 7B con la misma licencia daría mejores respuestas y
# quintuplicaría el peso, con la mitad de la velocidad.
#
# ══ POR QUÉ EL TARBALL ES NUESTRO Y LA URL NO RESUELVE ═════════════════════════════════════════
# takana extrae toda fuente con `tar`, y un `.gguf` pelado no es un tar. Así que el objeto pineado es
# un tar que envuelve el fichero, publicado en el mirror de fuentes y servido **por sha256** — el
# mismo camino que `firefox-pgo-profile`. La URL `.invalid` no resuelve a propósito (ADR 0013: la URL
# no entra en `hash_inputs`, sólo el sha256).
#
# La PROCEDENCIA, para que nadie tenga que confiar en nuestro tar:
# upstream https://huggingface.co/Qwen/Qwen2.5-1.5B-Instruct-GGUF
# fichero qwen2.5-1.5b-instruct-q4_k_m.gguf
# sha256 6a1a2eb6d15622bf3c96857206351ba97e1af16c30d7a74ee38970e434e9407e ← del GGUF, no del tar
# Ese sha256 es el que HuggingFace publica como `lfs.oid`, y es el que se verificó al bajarlo.
#
# ⚠ `strip_components = 0`: el tar lleva el fichero en la raíz. Con el default (1) se recorta lo
# único que hay y el install muere con un `cp: cannot stat` que no menciona el recorte.
name = "ia-modelo-chat"
version = "qwen2.5-1.5b-instruct-q4_k_m"
license = "Apache-2.0"
[source]
tarball = "https://no-hay-upstream.invalid/takana/ia-modelo-chat.tar"
sha256 = "2560ee9452a979116ae24278615c51ecced38d2e62288ffe29f4a4bf7ddfc1c6"
strip_components = 0
[build]
compiler = "zig-cc"
[build.phases]
configure = "true"
compile = "true"
install = '''
set -e
mkdir -p /out/usr/share/takana/ia
cp qwen2.5-1.5b-instruct-q4_k_m.gguf /out/usr/share/takana/ia/modelo.gguf
M=/out/usr/share/takana/ia/modelo.gguf
# ── GUARDIÁN: QUE SEA UN GGUF, NO UN FICHERO GRANDE ─────────────────────────────────────────
# El modo de fallo callado acá es el de siempre: un fichero truncado o un HTML de error de 200 K
# renombrado a `.gguf` se instala igual, sella en verde, y lo único que falla es la respuesta —
# cuando ya no hay nadie mirando el build. Se comprueban las dos cosas que un GGUF de verdad tiene:
# el número mágico `GGUF` en los primeros cuatro bytes, y el tamaño.
head -c 4 "$M" | grep -q GGUF || {
echo "!! el fichero instalado no empieza con el mágico GGUF" >&2
head -c 64 "$M" | od -c | head -3 >&2
exit 1
}
n=$(stat -c%s "$M")
test "$n" -gt 900000000 || { echo "!! el GGUF pesa $n bytes: está truncado" >&2; exit 1; }
echo "guardián: GGUF válido — $n bytes"
'''