Cómo diseñamos nuestro propio sistema LLM: arquitectura, desafíos y aprendizajes

an artificial intelligence illustration on the wall

En este post quiero compartir el recorrido completo que nos llevó a construir un sistema modular de entrenamiento y despliegue de modelos de lenguaje (LLM). Desde el primer diagrama de carpetas hasta una arquitectura funcional con entrenamiento personalizado, inferencia vía API, cliente web y consola, y almacenamiento de feedback para reentrenamiento. Si estás pensando en armar tu propio proyecto LLM desde cero, este camino puede ayudarte a evitar varios tropiezos.

🧱 Planificación inicial: estructura de módulos

Desde el principio decidimos construir el sistema de forma modular y extensible. Definimos los siguientes componentes principales:

  • llm_trainer.py: se encarga del fine-tuning de modelos preentrenados a partir de datos locales.
  • llm_api.py: expone una API REST en FastAPI con endpoints para predicción y recepción de feedback.
  • llm_client.py: cliente web con interfaz HTML/JS que permite generar respuestas desde el modelo.
  • llm_client_line.py: cliente de línea de comandos ideal para testeo y scripts.
  • feedback.sqlite: base de datos local para almacenar respuestas que luego podemos reutilizar para reentrenar.

La estructura de carpetas inicial quedó así:

simpleIA_proyect/
├── app/
│ ├── llm_api.py
│ ├── llm_trainer.py
│ ├── llm_client.py
│ ├── llm_client_line.py
│ ├── templates/
│ └── static/
├── config/
│ └── config.json
├── model_llm/
├── trainer_llm/
│ ├── dialogue/
│ └── knowledge/
├── feedback/
│ └── feedback.sqlite
├── venv/
└── run_llm.sh

🧪 Entrenamiento con llm_trainer.py: dolor, café y ajustes

Uno de los mayores desafíos vino al entrenar modelos con hardware limitado (VPS de 4 GB de RAM sin GPU). Nuestro enfoque inicial se basó en usar modelos como flax-community/gpt-2-spanish y Hugging Face Trainer. Pero pronto nos topamos con errores por falta de memoria, incompatibilidades con el tokenizador y crashes provocados por el sistema operativo:

Killed python3 app/llm_trainer.py

Para solucionarlo:

  • Forzamos el uso de CPU con batch size 1 + gradient_accumulation_steps=4.
  • Desactivamos procesos paralelos en el DataLoader:pythondataloader_num_workers=0
  • Asignamos correctamente el token de padding:pythonif tokenizer.pad_token is None: tokenizer.pad_token = tokenizer.eos_token
  • Y generamos un data collator personalizado:pythonfrom transformers import DataCollatorForLanguageModeling data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)

🔌 La API: llm_api.py

Nuestra API expone dos endpoints:

  • /predict — para solicitar predicciones (respuestas del modelo).
  • /feedback — para almacenar textos útiles para reentrenamiento.

Ejemplo de endpoint de predicción:

@app.post("/predict", response_model=PredictionResponse)
async def predict(request: PredictionRequest):
    return PredictionResponse(generated_text=modelo(request.prompt))

Además configuramos CORS, protección contra errores comunes y base de datos SQLite para almacenar feedback de usuarios.

🌐 Cliente web: llm_client.py con FastAPI y templates

La interfaz web permite al usuario ingresar un prompt y ver una respuesta generada. Conectamos el frontend con /predict a través de JavaScript:

fetch("http://nightslayer.com.ar:8000/predict", {
  method: "POST",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    prompt: textoDelUsuario,
    max_length: 50,
    num_return_sequences: 1
  })
})

Y para almacenamiento de conversaciones:

fetch("/feedback", { ... })

🧠 Modelos usados

Estos fueron los modelos más útiles:

  • flax-community/gpt-2-spanish
  • datificate/gpt2-small-spanish
  • gpt2 y EleutherAI/gpt-neo-125M para pruebas en inglés

Todos compatibles con AutoTokenizer y AutoModelForCausalLM.

💡 Cosas que aprendimos en el camino

  • No subestimes el uso de memoria, incluso con inputs pequeños.
  • La modularidad en diseño salva tiempo a futuro.
  • Aunque el modelo sea grande, se pueden lograr resultados funcionales incluso en servidores básicos.

🚀 ¿Te gustaría colaborar?

Este proyecto está disponible en GitHub y estamos abiertos a issues, sugerencias, PRs y adaptaciones. Queremos que esta base sirva tanto para desarrolladores curiosos como para equipos que necesiten una infraestructura LLM funcional y personalizable.

👉 Visitar el repositorio

#IA #LLM #Python #FastAPI #HuggingFace #GPT2 #APIrest #NLP #DesarrolloWeb #InteligenciaArtificial #OpenSource #Tokenizers #FineTuning #Devlog

Solución a los errores “Out of Memory”: Creando un archivo swap en tu VPS

Durante mis recientes experimentos con un sistema LLM en Python, me encontré con un problema recurrente: el proceso de entrenamiento se terminaba abruptamente con un error de Out of Memory, y el sistema lo mataba automáticamente. La solución pasó por habilitar un archivo swap en mi VPS —algo que, por defecto, no estaba configurado— permitiéndome proporcionar un “colchón” de memoria y evitar esos infortunados kills.

En esta entrada te muestro mi solución a este inconveniente, presentándote un sencillo script en Bash que crea un archivo swap de forma automática. A continuación, te explico paso a paso cómo funciona y por qué puede marcar la diferencia en tus proyectos:

¿Por qué es importante el swap en un VPS?

Al trabajar en proyectos de inteligencia artificial, sobre todo durante el entrenamiento de modelos intensivos, es vital tener una gestión de memoria robusta. Sin un archivo swap, el sistema tiene un límite estricto de RAM, lo que puede provocar que procesos de alta demanda sean terminados súbitamente. Implementar un swap proporciona una extensión a la memoria física, dando tiempo extra a los procesos antes de que se alcance un fallo crítico.

El script paso a paso

A continuación, te dejo el script en Bash que puedes utilizar para crear y activar el archivo swap. La idea es asignar un tamaño definido (en este ejemplo, 2GB), configurarlo con los permisos correctos y activarlo:

#!/bin/bash
# Variables
SWAPFILE="/swapfile"
SIZE="2G"  # Puedes ajustar el tamaño según tus necesidades

echo "Creando un archivo swap de tamaño $SIZE en $SWAPFILE..."

# Crear el archivo swap usando fallocate
sudo fallocate -l $SIZE $SWAPFILE

# Configurar los permisos: solo root debe tener acceso
sudo chmod 600 $SWAPFILE

# Formatear el archivo como swap
sudo mkswap $SWAPFILE

# Activar el swap creado
sudo swapon $SWAPFILE

echo "¡Archivo swap creado y activado exitosamente!"

# Agregar la configuración al fstab para que se monte automáticamente en cada reinicio
echo "$SWAPFILE none swap sw 0 0" | sudo tee -a /etc/fstab

echo "Configuración añadida a /etc/fstab para persistencia."

¿Cómo utilizar el script?

  1. Copia el código en un archivo de tu VPS, por ejemplo crear_swap.sh.
  2. Asigna permisos de ejecución: chmod +x crear_swap.sh
  3. Ejecuta el script con privilegios de superusuario: sudo ./crear_swap.sh

Con estos simples pasos, tu VPS estará mejor preparado para manejar procesos intensivos sin riesgos inmediatos de quedarse sin memoria.

Implementar esta solución no solo te ayudará a evitar esos molestos kills del sistema, sino que además te permitirá centrarte en lo verdaderamente innovador: experimentar y mejorar tus modelos de LLM sin interrupciones inesperadas. ¿Te animas a probarlo en tu VPS? ¡Comparte tus experiencias!

Si te interesa conocer más sobre mejoras en la gestión de recursos en sistemas Linux o tienes alguna duda sobre el script, seguimos la conversación en los comentarios. Además, en próximos post profundizaré en otras técnicas de optimización para entrenamientos de LLMs y cómo integrar estas soluciones en flujos de trabajo automatizados.

¿Qué otros temas te gustaría ver? Estoy preparando contenido sobre Dockerización de ambientes de desarrollo y CI/CD en proyectos de IA. ¡Mantente atento!

Happy coding y a seguir optimizando tus proyectos.

#Linux #Bash #VPS #Script #Swap #InteligenciaArtificial #LLM #OutOfMemory #DesarrolloTech

Utilizando el teclado en VB.net, forma de detectar pulsado de teclas.

abstract business code coder

Volvemos nuevamente con la codificacion para principiantes, en vb.net

Aquí te dejo un ejemplo de cómo podrías verificar qué tecla se presionó dentro de un TextBox y realizar una función en consecuencia en Visual Basic .NET:

Private Sub TextBox1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles TextBox1.KeyPress
    If e.KeyChar = "a" Then
        'Realizar la función correspondiente al presionar la tecla "a"
        MsgBox("Presionaste la tecla 'a'")
    ElseIf e.KeyChar = "b" Then
        'Realizar la función correspondiente al presionar la tecla "b"
        MsgBox("Presionaste la tecla 'b'")
    Else
        'Realizar la función correspondiente al presionar cualquier otra tecla
        MsgBox("Presionaste una tecla diferente")
    End If
End Sub

En este ejemplo, se utiliza el evento KeyPress del TextBox para detectar qué tecla se presionó. Dentro del evento, se utiliza una estructura condicional If-ElseIf-Else para verificar qué tecla se presionó y realizar una función correspondiente.

En el ejemplo, si se presiona la tecla “a”, se mostrará un mensaje con el texto “Presionaste la tecla ‘a'”, si se presiona la tecla “b”, se mostrará un mensaje con el texto “Presionaste la tecla ‘b'” y si se presiona cualquier otra tecla, se mostrará un mensaje con el texto “Presionaste una tecla diferente”.

Para detectar si se ha presionado la tecla F1 o una combinación de teclas como Ctrl + F1, puedes utilizar el evento KeyDown en lugar del evento KeyPress. El evento KeyDown permite detectar la pulsación de teclas especiales y combinaciones de teclas.

A continuación, te muestro un ejemplo de cómo podrías hacerlo:

Private Sub TextBox1_KeyDown(sender As Object, e As KeyEventArgs) Handles TextBox1.KeyDown
    If e.KeyCode = Keys.F1 AndAlso e.Modifiers = Keys.None Then
        ' Realizar la función correspondiente al presionar la tecla F1
        MsgBox("Presionaste la tecla F1")
    ElseIf e.KeyCode = Keys.F1 AndAlso e.Modifiers = Keys.Control Then
        ' Realizar la función correspondiente al presionar Ctrl + F1
        MsgBox("Presionaste Ctrl + F1")
    End If
End Sub

En este ejemplo, se utiliza el evento KeyDown del TextBox para detectar si se ha presionado la tecla F1 o la combinación de teclas Ctrl + F1. Dentro del evento, se utiliza una estructura condicional If-ElseIf para verificar qué tecla se presionó y realizar una función correspondiente.

En el ejemplo, si se presiona la tecla F1 sin presionar ninguna tecla adicional, se mostrará un mensaje con el texto “Presionaste la tecla F1”. Si se presiona la tecla F1 junto con la tecla Ctrl, se mostrará un mensaje con el texto “Presionaste Ctrl + F1”.

Despues a cada presión de tecla se le asigna las funcione que quieren que realizar.

Además de los eventos KeyPress y KeyDown, que te mostré en los ejemplos anteriores, VB.NET también proporciona el evento KeyUp, que se activa cuando se suelta una tecla. Este evento puede ser útil si necesitas detectar cuando se ha dejado de presionar una tecla específica.

Además, VB.NET también proporciona la clase SendKeys, que te permite simular la pulsación de teclas desde tu código. La clase SendKeys te permite enviar pulsaciones de teclas a una aplicación externa o a tu propia aplicación, y también puedes simular combinaciones de teclas, como Ctrl + C para copiar, o Alt + F4 para cerrar una ventana.

A continuación, te muestro un ejemplo de cómo podrías utilizar la clase SendKeys para simular la pulsación de teclas en VB.NET:

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    ' Simular la pulsación de la tecla "A"
    SendKeys.Send("A")
End Sub

En este ejemplo, se utiliza el método Send de la clase SendKeys para enviar una pulsación de tecla al sistema. En este caso, se envía la tecla “A”.

También puedes utilizar la clase SendKeys para simular combinaciones de teclas, como Ctrl + C para copiar. A continuación, te muestro un ejemplo de cómo podrías hacerlo:

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    ' Simular la pulsación de la combinación de teclas "Ctrl + C"
    SendKeys.Send("^C")
End Sub

En este ejemplo, se utiliza el carácter “^” para indicar que se está presionando la tecla Ctrl, seguido de la letra “C” para indicar que se está presionando la tecla C.

Ten en cuenta que la clase SendKeys puede ser muy poderosa, por lo que debes tener cuidado al utilizarla. Asegúrate de entender completamente cómo funciona antes de utilizarla en tu código.