DLLM. Modelos de lenguaje con difusión.

En el mundo de la inteligencia artificial, escuchar que algo puede revolucionarlo todo es casi rutina. Sin embargo, esta innovación realmente podría marcar un antes y un después en cómo funcionan los modelos de lenguaje: los Modelos de Lenguaje con Difusión (Diffusion LLMs).

Puedes ver el vídeo para más información

¿Qué es un modelo de difusión?

Para entender esta nueva idea, hay que mirar atrás. Los modelos de difusión clásicos, como Stable Diffusion, se entrenan para limpiar ruido de imágenes de forma progresiva, guiados por un texto (prompt). Este proceso ocurre en el espacio latente y es dirigido por una red llamada UNet.

Todo cambió cuando se sustituyó esa UNet por un transformer, el mismo tipo de arquitectura que usan los modelos de lenguaje actuales. Así nació un nuevo enfoque: enseñar a transformers a eliminar ruido. ¿La clave? Estos modelos pueden generar contenido de manera no secuencial.

¿Y si aplicamos esta idea al texto?

Aquí está lo revolucionario. En vez de generar texto palabra por palabra (como hacen los LLMs tradicionales), los modelos de lenguaje con difusión generan todo el texto a la vez. Todas las palabras influyen en las demás desde el inicio, una forma más parecida a cómo pensamos los humanos.

Al no poder crear tokens de texto con ruido se crea una máscara con una entrada para token, que indica si el token es válido (desenmascarado) o ruidoso (en mascarado). Técnicamente, el proceso comienza con todos los tokens del texto enmascarados. Luego, en varias iteraciones, el modelo va desenmascarando aquellos tokens que considera más probables. Incluso puede volver a enmascarar tokens ya revelados para mejorar la coherencia general.

¿Qué modelos existen hoy?

Actualmente hay tres modelos destacados que usan esta técnica:

  1. Mercury (Inception Labs)
    Especializado en generación de código. Es privado. Presume de su velocidad generando código frente a los LLM clásicos.
  2. LLaDA 8B
    Un modelo open source con 8.000 millones de parámetros. Tiene versión base e instruct (esta última preparada para seguir instrucciones, como en un chat). LLaDA utiliza un transformer bidireccional y un proceso iterativo de enmascarado y desenmascarado. Curiosamente, el número de iteraciones es fijo, sin importar la longitud del texto, lo que puede suponer ventajas en velocidad, aunque también plantea retos con textos largos.
  3. Block Diffusion
    Una propuesta híbrida: aplicar el proceso de difusión por bloques de tokens. Dentro de cada bloque se aplica la lógica de difusión; entre bloques, se mantiene una estructura más parecida a los LLM clásicos. Aunque esta implementación es conservadora (usa bloques pequeños y sin que se puedan volver a enmascarar tokens), tiene un gran potencial, especialmente si se amplía a párrafos u otras unidades mayores.

Pros y contras:

Los modelos de lenguaje con difusión (DLLM) presentan algunas ventajas claras frente a los LLM tradicionales. Al generar todo el texto a la vez en lugar de palabra por palabra, los DLLM pueden lograr una mayor coherencia global, ya que todas las palabras se ajustan mutuamente durante el proceso. Esto se acerca más a cómo razonamos y escribimos los humanos. Además, al tener un número fijo de iteraciones, pueden ser más rápidos en tareas cortas y permiten un razonamiento más flexible en el espacio latente. Sin embargo, también tienen limitaciones: su entrenamiento y optimización todavía están en fases tempranas, carecen de las mejoras acumuladas que ya existen para los LLM, y su rendimiento puede degradarse con textos largos. Además, es más difícil reutilizar cálculos entre iteraciones, lo que puede afectar a su eficiencia en comparación con los modelos tradicionales altamente optimizados.

¿Qué futuro tienen?

Estos modelos podrían integrarse mejor en sistemas multimodales (que combinan texto, imagen, sonido…) y ofrecen nuevas posibilidades para tareas complejas como el razonamiento. Eso sí, todavía estamos dando los primeros pasos. Los LLMs tradicionales están muy optimizados, y cambiar de paradigma implica reaprender muchos procesos.

Un dato curioso: los creadores de LLaDA observaron que el modelo a veces puede generar la respuesta correcta antes de completar todo el razonamiento. Los tokens aún enmascarados ya contienen información útil, lo que sugiere que el razonamiento está ocurriendo en un plano latente.

¿Qué es el Vibe Coding y cómo hacerlo bien?

Hoy quiero confesaros algo. Cuando empecé a planear este contenido, pensaba criticar el vibe coding. Sin embargo, tras reflexionar un poco, me he dado cuenta de que el problema no es la técnica en sí, sino cómo se aplica. De hecho, el vibe coding puede ser una herramienta muy útil si se usa correctamente. Así que, en vez de criticarlo, hoy os voy a contar cómo sacarle partido, tanto si tenéis mucha experiencia programando como si estáis empezando.

¿Qué es el Vibe Coding?

El término vibe coding viene a significar «programar por vibras». Imaginad al protagonista de El Gran Lebowski programando: te sientas con una IA, le pides algo, ajustas lo que genera, vuelves a pedir cambios… todo de forma informal. ¿Funciona? Bueno, depende del tipo de proyecto que quieras desarrollar.

Hay quienes dicen que ya no necesitamos programadores, solo ideas y una IA. Pero como alguien que lleva más de 20 años en esto, os aseguro que esa frase la he escuchado muchas veces antes: con la programación visual, los generadores automáticos, el low code, y ahora con la inteligencia artificial. Y aquí sigo, picando líneas y líneas de código para poner un botón.

Origen del término y su auge

El término fue popularizado por Andrej Karpathy, un experto en IA que ha trabajado para Tesla y OpenAI. En uno de sus tweets hablaba maravillas del vibe coding… pero matizaba: lo ve útil para webs o proyectos de fin de semana, no para montar un SaaS (Software as a Service).

Además, el auge del vibe coding viene de la mejora brutal en los modelos de lenguaje. Ahora son capaces de programar un Tetris, un Comecocos o un Snake y estos ejemplos resultan impresionantes para la mayoría de la gente, pero hay que tener en cuenta que literalmente son ejercicios que se realizan en clase mientras estudias informática. Un proyecto real puede tener cientos de miles de líneas de código y muchos más retos.

Programar es mucho más que escribir código

Pensad en esto: aunque la IA os haga un SaaS que parece funcional, ¿habéis pensado en temas como la protección de datos? ¿La gestión de compras y devoluciones? ¿Compatibilidad en distintos dispositivos? ¿Pruebas? ¿Seguridad? Programar es mucho más que escribir código.

Por eso, si quieres montar algo serio, rodéate de expertos. Y no te fíes de campañas virales que prometen miles de dólares al mes con juegos feos hechos por IA. Incluso quienes presumen de usar vibe coding al 100%, terminan permitiendo modificaciones humanas.

Cómo usar el Vibe Coding correctamente

Si quieres aplicar esta técnica de forma eficaz, aquí tienes los pasos clave:

  1. Elige bien tus tecnologías. Cuanto mejor las conozcas, más fácil será guiar a la IA.
  2. Evalúa si realmente necesitas una app. A veces una hoja de cálculo basta.
  3. Control de versiones. Usa Git o, si no sabes, guarda cada versión generada con fecha.
  4. Haz una lista de funcionalidades. Divide tu app en versiones y fases claras.
  5. Crea una arquitectura limpia. Separar controladores, servicios y datos te permitirá delegar mejor a la IA.
  6. Desarrolla por tareas. Describe cada una en un prompt, revisa el resultado, testea y guarda.
  7. Pon límites a la IA. Si una tarea no se resuelve tras varios intentos, decide si continuar o revertir.
  8. Automatiza donde puedas. Pero también aprende cuándo intervenir a mano.

El flujo de trabajo en Vibe Coding: paso a paso

Una de las claves para que el vibe coding funcione realmente bien es organizarse con un flujo claro. No se trata solo de pedirle cosas a la IA y esperar milagros, sino de establecer un proceso iterativo y controlado. Este sería un flujo básico que puedes seguir:

1. Crear una lista de tareas

Antes de escribir ni una línea de código, define qué funcionalidades debe tener tu aplicación. Divide esas funcionalidades en tareas pequeñas y manejables. Por ejemplo:

  • Mostrar lista de usuarios
  • Añadir nuevo usuario
  • Validar email al registrarse

Esta lista puede estar escrita por ti o generada inicialmente con ayuda de una IA.

2. Redactar prompts para cada tarea

Para cada una de esas tareas, redacta un prompt claro que describa lo que quieres. Sé específico.

Puedes añadir condiciones, estructuras de datos, objetos o interfaces previamente definidas.

3. Evaluar si el código generado funciona

Una vez la IA te devuelve el código:

  • Si es un lenguaje compilado: comprueba si compila y arranca.
  • Si es interpretado: simplemente ejecútalo y observa si arranca correctamente.

4. Corregir errores si no funciona

Si da error, copia ese error y pásaselo a la IA junto con el código.

La IA intentará corregirlo. Puedes repetir este paso varias veces, pero pon un límite de intentos para no quedarte atrapado en un bucle infinito.

5. Testear el código

Cuando el código ya «funciona», toca comprobar si hace lo correcto.

  • Ideal: tener tests automáticos definidos.
  • Alternativa: probar a mano, pero siempre siguiendo un guión claro de qué debería pasar.

6. Guardar versiones que funcionen

Cada vez que una funcionalidad funciona y pasa los tests, guárdala.

  • Si usas Git, haz un commit.
  • Si no sabes usar Git, guarda el archivo en una carpeta con fecha/nombre descriptivo.

Esto es importante porque la IA, a veces, rompe cosas que antes funcionaban y luego no sabe repararlas. Tener una versión estable te permite comparar y recuperar fácilmente.

7. Si no se puede resolver una tarea…

A veces la IA no logra resolver una tarea, por más intentos que hagas.

En ese caso, tienes dos opciones:

  • Guardar el progreso parcial si la app sigue funcionando. Aunque sea de forma incorrecta
  • Revertir a una versión anterior y dejar esa tarea para después.

La idea es no frenar todo el proyecto por una sola parte atascada.

Un ejemplo real

En mi día a día, uso un sistema híbrido: tengo un motor de plantillas que genera parte del código con IA y parte de forma clásica. Desde SQL hasta controladores web, todo está dividido por capas, lo que me permite testear fácilmente y generar componentes reutilizables.

Eso sí, hay límites: en el frontend, por ejemplo, todavía no logro que la IA respete del todo los estilos y convenciones, así que prefiero crear esqueletos básicos que luego el programador humano completa.


Conclusión

El vibe coding no es magia, pero tampoco es humo. Si se hace bien, puede acelerar el desarrollo, sobre todo para tareas repetitivas o proyectos pequeños. Pero para crear productos reales, sólidos y mantenibles, hace falta mucho más que IA: hace falta conocimiento, planificación y buen criterio.

¿Te animas a probarlo?

Brain2Qwerty ¿Teclear con la mente?

Hace poco Meta anunció un proyecto donde había conseguido leer directamente de la mente de 35 voluntarios que teclas iban a pulsar en el teclado.

Los resultados son sorprendentes, una tasa de acierto del 80%

Si deseas ampliar el contenido de este post puedes ver este vídeo.

¿Pero como de real es eso de leer teclas de mente de una persona?

Y es que lo de «leer la mente» suena mejor que decir que leyeron la corteza neuromotora para saber que movimientos se ordenaban a los dedos. Para leer estas señales del cerebro probaron con dos técnicas no invasivas:

  • EEG: Electroencefalografía, leer las señales eléctricas del cerebro.
  • MEG: Magnetoencefalografía, leer los campos magnéticos que causan las señales eléctricas en el cerebro.

El problema de leer señales biológicas de forma no invasiva es la pésima relación señal ruido. Básicamente la señal está envuelta en un montón de ruido que índuce errores e incertidumbre en su lectura.

En este caso los resultados fueron mucho mejores con MEG que con EEG, lo cuál es una lastima porque EEG es un sistema más asequible y “simple” que MEG.

El proceso de captura de datos :

La tarea de cada voluntario consistía en tres pasos: Leer, esperar, escribir.

  • Cada usuario leía una frase de un monitor
  • Después se mostraba en la pantalla una cruz negra al desaparecer de pantalla empezaba la tercera fase
  • En pantalla se mostraba un cuadrado girando mientras los usuarios escribían la frase en un teclado

Todo este proceso se hace para asegurarse de que la información procede de las “ordenes de teclear” y no por ejemplo de lo que están viendo los ojos.

Hay ciertas peculiaridades en el texto, para evitar que una letra fuera más de una pulsación (lo que complicaría el procesado de datos). Todo eran letras mayúsculas, sin tildes, diéresis y por algún motivo sin Ñ (¿Saben los americanos que tenemos una letra Ñ en el teclado?)

Cada sentencia era grabada y almacenada para luego poder ser procesada por la IA.

Arquitectura de la IA

La IA se compone de tres módulos que trabajan con un sentencia completa.

Modulo Convolucional

Se compone de cuatro partes, con las siguientes tareas:

  • Codificar la posición espacial de cada sensor
  • Adapta los datos a cada usuario
  • Modulo convolucional (combina los datos de varios sensores próximos)
  • Agrupación temporal

Transformer

Toma los datos del modelo anterior y calcula cual es la probabilidad (realmente no es la probabilidad son los logits, para los que sepáis de que hablo) de que sea cada carácter. Su función es integrar el contexto de la frase dentro de las predicciones.

Modelo de lenguaje:

Nada que ver con los LLMs, simplemente modela la relación estadística existente entre los caracteres (usando 9grams). Esto sumado a las datos del paso anterior nos da como resultado la sentencia escrita (si todo sale bien).

El resultado es tan bueno que puede llegar a corregir errores reales de tecleo del voluntario.

Teclear con la mente.

Aunque la idea de usar la mente para escribir un texto puede resultar muy atractiva, está lejos de ser la realidad de este sistema. Hay muchos “peros”.

A nivel de datos:

  • Solo 35 personas. Poca variedad. Sin ningún tipo de lesión.
  • Mecanógrafos expertos. Señal limpia, sin dudar a la hora de pulsar una tecla y pocos errores.
  • Entorno clínico, controlado. Sin distracciones. Ni ruido ambiente.

Cómo a nivel práctico :

  • Una máquina de resonancia magnética necesita un entorno clínico o de laboratorio con muchas restricciones.
  • Se trabaja sobre datos grabados, sentencias completas. No carácter a carácter.
  • Letras limitadas

¿Es un paso prometedor? Lo es. Significa que podremos teclear con la mente. Por ahora no, pero si algún día podemos será gracias a estudios como este.

Convierte texto a audio con Kokoro-82M

Kokoro-82M es un nuevo modelo de texto a voz que permite fácilmente y con pocos recursos convertir de texto a voz en varios idiomas:

🇪🇸 ‘e’ => Spanish es
🇫🇷 ‘f’ => French fr-fr
🇮🇳 ‘h’ => Hindi hi
🇮🇹 ‘i’ => Italian it
🇧🇷 ‘p’ => Brazilian Portuguese pt-br
🇺🇸 ‘a’ => American English
🇬🇧 ‘b’ => British English
🇯🇵 ‘j’ => Japanese
🇨🇳 ‘z’ => Mandarin Chinese

Entre ellos el español, lo cual no es tan habitual como cabria esperarse por su número de hablantes.

Su uso es realmente sencill, para instalarlo basta con seguir los siguientes pasos.

Lo primero es instalar kokoro y soundfile:

pip install  kokoro soundfile

También necesitaremos instalar espeak-ng, la forma de instarlo variará según el sistema operativo que tengamos:

  • Para Windows podemos descargar la última versión aquí
  • Para Linux eligen según tu distribución:
sudo apt-get install espeak-ng

sudo yum install espeak-ng

sudo pacman -S espeak-ng

Ahora nos queda escribir un poco de código en Python

from kokoro import KPipeline
import soundfile as sf

pipeline = KPipeline(lang_code='es') # lang_code del idioma

text = 'Hola, bienvenidos a construyendo a Chispas.'

# Voces:
# ef_dora Femenino
# em_alex Masculino
# em_santa Masculino
generator = pipeline(
    text, voice='em_santa', # cambia la voz aqui
    speed=1, split_pattern=r'\n+'
)

for i, (gs, ps, audio) in enumerate(generator):
    print(i)    # indice
    print(gs) # grafemas (texto)
    print(ps) # fonemas    
    sf.write(f'{i}.wav', audio, 24000)

También permite generar el audio desde los fonemas:

from kokoro import KPipeline
import soundfile as sf

pipeline = KPipeline(lang_code='es') # lang_code del idioma

phonemes = "ˈola, bjˌembenˈiðos a kˌonstɾujjˈɛndo a ʧˈispas."

# Voces:
# ef_dora Femenino
# em_alex Masculino
# em_santa Masculino
generator = pipeline.generate_from_tokens(
    tokens=phonemes,
    voice="ef_dora",
    speed=1.0
)

for i, (gs, ps, audio) in enumerate(generator):
    print(i)    # indice
    print(gs) # grafemas (texto)
    print(ps) # fonemas    
    sf.write(f'{i}.wav', audio, 24000)

¿Cómo es posible que un modelo tan pequeño funcione relativamente bien? Puedes verlo en el siguiente vídeo.

¿Qué estrategias se usan en IA para alcanzar la AGI?

Realmente no tenemos existe una definición formal de que es la AGI así que no tenemos un objetivo claro para llegar a ella. La forma en que actualmente tratamos de aproximarnos a ella es a través de los benchmarks (que como ya vimos que tiene sus propios problemas). Cada vez que se supera un benchmark aparece otro que sube el listón.

De hecho ya han sido varias las pruebas superadas que se suponía nos llevaban a la AGI:

  • Ganar al ajedrez
  • Ganar al go
  • Superar el test de Turing
  • Demostraciones matemáticas

Y aquí seguimos sin nada que podamos considerar AGI.

Principalmente hay tres caminos que se mezclan:

  • Agentes: combinar varios modelos de lenguajes expertos en diferentes tareas.
  • LLM + entrenamiento: entrenar a un modelo de lenguaje para mejorar sus capacidades de razonamiento.
  • LLM + algoritmos clásicos: el modelo de lenguaje genera múltiples caminos de razonamiento y se usan algoritmos clásicos para elegir cual se desarrolla.

No son tres caminos independientes si no que se pueden combinar para mejorar el sistema.

Además estos modelos pueden usar las siguientes

  • Ingeniería de prompts.
  • RAG
  • Uso de herramientas (function calling)
  • Generación y ejecución de código

No basta con conseguir la AGI, no todo es inteligencia:

  • Comprensibles. No basta con que la respuesta sea correcta, tiene que estar claramente explicada para que sea comprensible. Por como funcionan los modelos de lenguaje esta explicación debe de producirse durante la generación de la respuesta. No puede producirse a posteriori. Ahora mismo lo que hay es un galimatías caótico. (un ejemplo clásico es ¿Cuál es el secreto de la vida el universo y todo lo demás?)
  • Confiables. Tenemos que poder confiar en la respuesta de estos modelos, ahora mismo las alucinaciones hacen que no podamos confiar en ellos plenamente. Está relacionado con el punto anterior ya que si podemos comprender el “porqué” de la respuesta podemos aprender a detectar las respuestas erróneas.
  • Razonamiento general: Es capaz de enfrentar problemas de todo tipo y crear estrategias para resolverlos. Un ser humano inteligente no es aquel que sabe la solución a un problema, es el que puede usar sus recursos para hallarla o aproximarse.
  • Coste asumible: Estos modelos tienen que funcionar en una escala realista. Se estima que a O3 superar el test ARC-AGI le costó más de un millón de dólares. Por mucho menos puedes contratar a un grupo de expertos humanos. La necesidad de potencia de cálculo, recursos como la RAM y tiempo puede disparar el precio de estos modelos.

Agentes:

Como ingeniero es mi solución favorita.

En lugar de un único modelo usa varios modelos diferentes colaborando en un flujo de trabajo para hallar la solución. Esto permite modelos más pequeños especializados en ciertas tareas.

Pueden lanzarse varios flujos de trabajo en paralelo afrontando el problema desde distintos puntos de vista.

Ventajas:

  • Modelos especializados y más pequeños
  • Modelos más fáciles de entrenar
  • Es fácil integrar diversas fuentes de datos y herramientas
  • Es más entendible.
  • Muy flexible.
  • No es necesario entrenar todas sus partes solo la que necesites mejorar.
  • Es fácil incluir “humanos” en el proceso

Problemas:

  • Un fallo en un agente puede propagarse a los demás.
  • Puedes usar agentes que verifican las respuestas. ¿Pero quién verifica al verificador?
  • Comunicar a los agentes entre si. Usar lenguaje natural puede no ser la mejor opción.
  • Requiere mucho trabajo y tiempo ir creando los diversos flujos de trabajo

LLM + entrenamiento:

Como fan de la ciencia ficción es mi solución favorita. Es la que más se aproxima a la idea que tenemos de IA inteligente.

Un modelo único capaz de generar respuestas inteligentes.

Ventajas:

  • La idea es simple

Problemas:

  • Requiere grandes modelos difíciles y caros de entrenar
  • Grandes cantidades de datos de calidad. Es difícil encontrar buenos ejemplos de razonamiento.
  • Ahora mismo su “razonamiento” no es muy entendible. A veces incluso llega a la respuesta correcta y la ignora.
  • Caros de usar

Ejemplos:

O1, O3, DeepSeek V3, QwQ 32B

LLM + algoritmos clásicos:

Como desarrollador de software es mi solución favorita. Combina el razonamiento de los modelos de lenguaje con pasos intermedios que ayudan a guiar este razonamiento hacia las mejores ideas.

Ventajas:

  • Se puede aplicar a modelos de lenguaje no entrenados para razonar.
  • Reduce los costes de razonamiento

Problemas:

  • ¿Cómo saber lo buena qué es una idea?. Generalmente se usan LLM entrenados para ello, pero no son buenos cuantificando las ideas.

Ejemplos:

Marco-O1

Problemas del transformer:

Los actuales LLM usan diferentes modificaciones de un transformer, una arquitectura de red neuronal que pese a sus buenos resultados impone serias limitaciones.

Para nuestro caso nos afectan principalmente dos:

  • El contexto tiene un tamaño limitado. Pasado de cierto punto el modelo “pierde el hilo” del texto que está generando. Lo cual limita el tamaño del “razonamiento” que puede generar.
  • El modelo de lenguaje no predice una palabra, predice una distribución de probabilidad de que cada una de las palabras (realmente, tokens) que conoce sea el siguiente. Pero de ese resultado elegimos solo una y esa información se pierde. Por lo que el modelo de lenguaje pierde toda la información entre cada palabra.

Deepthougt 8B. Controla el razonamiento de un LLM

Últimamente se ha puesto de moda un nuevo paradigma de modelo de lenguaje. Aquellos entrenados para razonar.

Básicamente son modelos que se plantean la resolución de un problema paso a paso. Y luego recorren esos pasos aprovechando que los LLM son recursivos.

Derpthougt 8B funciona así, eso no es una novedad. El cambio viene en la idea de como plantea el razonamiento. Lo hace de forma estructurada usando JSON. Eso nos permite manipular su razonamiento fácilmente, interfiriendo en sus «pensamientos».

A diferencia de lo habitual en los LLM. Para funcionar necesita como mínimo dos llamadas al modelo.

Vamos a empezar a ver cómo funciona. Un aviso importante, el modelo es muy estricto con los prompts. Hay que respetarlos lo más estrictamente posible.

Para la prueba vamos a usar llamacpp con la versión cuantizada Q8.

./llama-server -m ./deepthought-8b-llama-v0.01-alpha-Q8_0.gguf

El prompt inicial es el siguiente:

<|im_start|>system
You are a superintelligent AI system, capable of comprehensive reasoning. When provided with <reasoning>, you must provide your logical reasoning chain to solve the user query. Be verbose with your outputs.<|im_end|>
<|im_start|>user
{{User Query}}<|im_end|>
<|im_start|>reasoning
<reasoning>
[
{
"step": 1,

Podéis ver qué se usa el truco de comenzar la respuesta del modelo de lenguaje para obligar al modelo de lenguaje a seguirla.

En este primer paso genera el razonamiento, siguiendo cada paso la siguiente estructura JSON:

  {
    "step": 1,
    "type": "problem_understanding",
    "thought": "I need to count the number of times the letter 'r' appears.
  }

Una vez tenemos el razonamiento en formato JSON lo volvemos a pasar con este prompt.

<|im_start|>reasoning
<reasoning>
{{Steps JSON}}
</reasoning>|im_end|>
<|im_start|>assistant

Y obtenemos la respuesta.

Veamos un ejemplo con la tipica pregunta de cuantas letras «r» tiene «Straberrry» (tiene una R de más a proposito)

El primer prompt

<|im_start|>system
You are a superintelligent AI system, capable of comprehensive reasoning. When provided with <reasoning>, you must provide your logical reasoning chain to solve the user query. Be verbose with your outputs.<|im_end|>
<|im_start|>user
How many letters "r" does the word strawberrry have?<|im_end|>
<|im_start|>reasoning
<reasoning>
[
{
"step": 1,

Y luego el segundo prompt con todos los pasos del razonamiento:

<|im_start|>reasoning
<reasoning>
[
{
"step": 1,
"type": "problem_understanding",
"thought": "I need to count the number of times the letter 'r' appears in the word 'straberrry'."
},
{
"step": 2,
"type": "data_gathering",
"thought": "The word to analyze is 'straberrry'. I'll need to examine each character in this word."
},
{
"step": 3,
"type": "hypothesis_formation",
"thought": "Based on a quick glance, I hypothesize that there are 3 'r's in the word 'straberrry'."
},
{
"step": 4,
"type": "analysis",
"thought": "I'll go through the word character by character: s (not r), t (not r), r (count: 1), a (not r), b (not r), e (not r), r (count: 2), r (count: 3), r (count: 4), y (not r)."
},
{
"step": 5,
"type": "calculation",
"thought": "After analyzing each character, I've counted 4 occurrences of the letter 'r'."
},
{
"step": 6,
"type": "verification",
"thought": "To verify, I'll recount: s-t-r-a-b-e-r-r-r-y. This confirms 4 'r's."
},
{
"step": 7,
"type": "error_checking",
"thought": "I'll double-check for any missed 'r's or counting errors. No errors found."
},
{
"step": 8,
"type": "conclusion_drawing",
"thought": "The letter 'r' appears 4 times in the word 'straberrry'."
},
{
"step": 9,
"type": "reflection",
"thought": "My initial hypothesis was close but not exact. This reminds me to be careful about quick estimates and to always verify."
},
{
"step": 10,
"type": "implementation",
"thought": "The final response should be the number 4, as this is the correct count of 'r's in 'straberrry'."
}
]</reasoning>|im_end|>
<|im_start|>assistant

El código Python para ejecutar esto contra el servidor de llama.cpp:

import requests
import json

llamaURL = "http://127.0.0.1:8080" 

def instruct(prompt, n_predict, temperature):
    #print("Asking llama.cpp")
    #print(prompt)
    
    response = requests.post(llamaURL+"/completion", json={
        'prompt': prompt,
        'n_predict': n_predict,
        'temperature': temperature,
        'cache_prompt': True
    })
    
    if response.status_code == 200:
        #print("Response llama.cpp")
        #print(response.json().get('content'))
        return response.json().get('content')
    else:
        raise Exception(f"Request failed with status code {response.status_code}")

def promptResolve(steps):
    return '''<|im_start|>reasoning
<reasoning>
[
  {
    "step": 1,
'''+steps+'''<|im_end|>
<|im_start|>assistant'''

def promptSteps(query):
    return '''<|im_start|>system
You are a superintelligent AI system, capable of comprehensive reasoning. When provided with <reasoning>, you must provide your logical reasoning chain to solve the user query. Be verbose with your outputs.<|im_end|>
<|im_start|>user
'''+query+'''<|im_end|>
<|im_start|>reasoning
<reasoning>
[
  {
    "step": 1,'''


try:
    query = '''How many letters "r" does the word strawberrry have?'''    

    steps = instruct(promptSteps(query), 8000, 0.5)    
    result = instruct(promptResolve(steps), 8000, 0.5)
    print(promptResolve(steps))
    print(result)
except Exception as e:
    print(e)

Controlando el razonamiento:

Para controlar el razonamiento hemos de interferir en la creación de pasos. Eso lo haremos usando el token «}» como «stop token». De esta forma después de cada paso de razonamiento (en JSON, os recuerdo) el modelo de lenguaje retornará el control a nuestro código, pudiendo nosotros modificar el paso recién añadido o el siguiente paso que le pasaremos al modelo

En este caso añado un ejemplo para controlar el número de pasos que va generar el modelo.

import requests
import json

llamaURL = "http://127.0.0.1:8080" 

def instruct(prompt, n_predict, temperature):
    #print("Asking llama.cpp")
    #print(prompt)
    
    response = requests.post(llamaURL+"/completion", json={
        'prompt': prompt,
        'n_predict': n_predict,
        'temperature': temperature,
        'cache_prompt': True
    })
    
    if response.status_code == 200:
        #print("Response llama.cpp")
        #print(response.json().get('content'))
        return response.json().get('content')
    else:
        raise Exception(f"Request failed with status code {response.status_code}")


def generateStep(prompt, n_predict, temperature):
    #print("Asking llama.cpp")
    #print(prompt)
    
    response = requests.post(llamaURL+"/completion", json={
        'prompt': prompt,
        'n_predict': n_predict,
        'temperature': temperature,
        'cache_prompt': True,
        'stop': ['}']
    })
    
    if response.status_code == 200:
        #print("Response llama.cpp")
        #print(response.json().get('content'))
        return response.json().get('content')
    else:
        raise Exception(f"Request failed with status code {response.status_code}")


def promptStep(query, steps):
    return '''<|im_start|>system
You are a superintelligent AI system, capable of comprehensive reasoning. When provided with <reasoning>, you must provide your logical reasoning chain to solve the user query. Be verbose with your outputs.<|im_end|>
<|im_start|>user
'''+query+'''<|im_end|>
<|im_start|>reasoning
<reasoning>
'''+steps

def promptResolve(steps):
    return '''<|im_start|>reasoning
<reasoning>
'''+steps+'''
<reasoning><|im_end|>
<|im_start|>assistant'''

def openStep(i):
    return '''    {
    "step": '''+str(i)+''',
'''

def closeStep():
    return "},"


try:
    query = '''How many letters "r" does the word strawberry have?'''
    
    stepByStep = '''[
'''
    for i in range(1,11):
        stepByStep += openStep(i)
        stepByStep += generateStep(promptStep(query, stepByStep), 8000, 0.5)
        stepByStep += closeStep()

    stepByStep += ''']'''    
    result = instruct(promptResolve(stepByStep), 8000, 0.5)
    print(promptResolve(stepByStep))
    print(result)
except Exception as e:
    print(e)

Algunas ideas que se pueden hacer con esto:

  • Controlar el número de pasos
  • Controlar el tiempo de ejecución
  • Eliminar pasos
  • Añadir pasos
  • Crear un árbol de razonamiento

Puede lo que aquí se explica en el siguiente vídeo:

Haz click para ver el vídeo en mi canal de YouTube

¿Cómo de abierto es un modelo de lenguaje?

La OSI presento hace poco una definición de modelo de IA abierta, el equivalente del «Open Source» para los modelos de lenguajes. Antes de entrar en detalles con lo que ha definido la OSI vamos a hablar de los diferentes aspectos que se pueden «liberar» Grosso modo:

  • API: dar acceso al modelo a través de una API pública.
  • Pesos: el modelo propiamente dicho. Junto con el modelo se libera información de aspectos técnicos cómo información sobre cómo ejecutarlo o cuál es el formato de los prompts
  • Pesos destilados: es una versión reducida del modelo de lenguaje obtenidos a partir de «refinar» el modelo original. Es más cerrado puesto que complica el generar modelos derivados. Por ejemplo el finetuning del modelo.
  • Documentación de cómo usarlo: no basta con los pesos, hay que saber cómo usarlos. La arquitectura del modelo, el formato del prompt, …
  • Cómo replicar el modelo: generalmente tiene la forma de «el paper» del modelo. Dónde se explica cómo se ha creado el modelo y permite duplicarlo. No siempre es tan exhausto, últimamente hay muchos casos que parecen más un documento de marketing que de investigación.
  • El código de entrenamiento: el código necesario para entrenar tu propio modelo «igual» que el proporcionado
  • Descripción del dataset: un resumen indicando el tipo de datos y su origen. Por lo general se mezclan dataset públicos, privados y datos sintéticos.
  • Dataset: los datos usados para el entrenamiento. Es la parte más difícil que sea liberada ya que es lo más valioso y complicado de conseguir.

Por lo general las licencias suelen restringir algunas de las siguientes libertades:

  • Usar el modelo de forma comercial. Muchos modelos solo permiten su uso no comercial.
  • Usar el modelo de forma libre sin limitaciones. Es habitual que las empresas limiten los usos del modelo. La más habitual es que prohíban usarlo para entrenar otros modelos.
  • Modificar/reentrenar el modelo. Algunas empresas prohíben modificar sus modelos.

Para cumplir con la OSI es necesario que la licencia del modelo no tenga restricciones.

Para más información puedes ver el siguiente vídeo de mi canal:

Haz click para ver el vídeo en mi canal de YouTube

Ejemplo de Speculative Decoding con Qwen-2.5-coder-7B y 0.5B.

Speculative Decoding es un técnica (realmente un conjunto de ellas) para acelerar un modelo de lenguaje usando un «oraculo» que genera un borrador tratando de adivinar lo que el modelo va a generar. En este caso usaremos Qwen-2.5-coder-0.5B como oraculo para generar el borrador.

Para esta prueba usaremos un ejemplo que viene con Llama.cpp. Pero antes de poder usarlo hay que cambiar en el fichero examples/speculative/speculative.cpp el valor de la constante SPEC_VOCAB_MAX_SIZE_DIFFERENCE de 100 a 200.

#define SPEC_VOCAB_MAX_SIZE_DIFFERENCE  200

Una vez hecho esto hay que volver a compilarlo y ya se puede probar con el comando:

./llama-speculative
-m models/Qwen2.5.1-Coder-7B-Instruct-Q8_0.gguf
-md models/Qwen2.5-coder-0.5b-instruct-q4_k_m.gguf
-c 4000 --draft 8 --color
--sampling-seq k --top-k 10 --temp 0.7
-p "Generate a tetris game using JS and HTML in one HTML file"
-ngl 99 -ngld 99

Puedes verlo en funcionamientos en el siguiente vídeo (así como la explicación de cada parámetro):

Haz click para ver el vídeo en mi canal de YouTube

Qwen 2.5 Coder: Contexto extendido, templates y CoT.

Qwen 2.5 coder es una familia de modelos que ha dado muy buenos resultados generando código. Tanto que pueden competir con modelos privados mucho mayores como ChatGPT4o o Claude 3 Opus. 

Podéis ver más sobre estos modelos en el siguiente vídeo:

Haz click para ver el vídeo en mi canal de YouTube

Este post se centra en los prompts necesarios para usar sus diversas funcionalidades.

Completar texto:

La funcionalidad habitual de los modelos de lenguaje. Le pasas un texto y va prediciendo las siguientes palabras (bueno, tokens).

No necesita ningún prompt especial.

Rellenar texto intermedio (infill):

Una funcionalidad imprescindible para completar código. El código no se escribe como la prosa. Es habitual insertar código en mitad de ficheros ya escritos. Además hay que tener en cuanta todo el contenido del fichero.

El prompt divide el texto en un prefijo (el código que va antes del texto a generar) y un sufijo (el código que va después del texto a generar)

<|fim_prefix|>{code_pre}<|fim_suffix|>{code_suf}<|fim_middle|>

Completar proyecto:

Otra función útil es que para completar código se tenga en cuenta múltiples ficheros del proyecto y la estructura del mismo.

El prompt consta del nombre del repositorio (puede ser cualquiera) y los distintos ficheros que se quiere que se tengan en cuenta. Cada fichero incluye la ruta con su nombre y tras un salto de línea el código.

<|repo_name|>{repo_name}
<|file_sep|>{file_path1}
{file_content1}
<|file_sep|>{file_path2}
{file_content2}

Seguir instrucciones o chatear:

Está funcionalidad se puede usar tanto para dar instrucciones al modelo como para mantener una conversación con él.

En todos estos casos es importante respetar los saltos de línea.

<|im_start|>system
{system_prompt}<|im_end|>
<|im_start|>user
{prompt}<|im_end|>
<|im_start|>assistant

Contexto extendido a 128k:

El contexto por defecto es de 32k tokens, pero usando YARN con un escalado de x4 puede llegar a 128k (cada motor de inferencia tendrá su forma de configurar esto, por ejemplo en llama.ccp es usando los parámetros:  )

Esto solo funciona en los modelos de 7B o más parámetros: -rope-scaling yarn –rope-scale 4.0

Generar texto con CoT (cadena de pensamientos):

De regalo este truco, no es oficial, yo lo he sacado de un comentario en Reddit del usuario Eposnix. Este usuario compartió un prompt que permite realizar CoT aplicado a la generación de código. Hace que el modelo de lenguaje entre en bucle tratando de corregir el código que genera hasta que esté perfecto. Cuidado que puede hacer que el mdoelo entre en bucle, por lo que es recomendable usar este prompt limitando el numero total de tokens que puede generar.

1. Generate your initial code solution
2. Rate your solution on a scale of 1-5 based on these criteria:
- 5: Exceptional - Optimal performance, well-documented, follows best practices, handles edge cases
- 4: Very Good - Efficient solution, good documentation, follows conventions, handles most cases
- 3: Acceptable - Working solution but could be optimized, basic documentation
- 2: Below Standard - Works partially, poor documentation, potential bugs
- 1: Poor - Non-functional or severely flawed approach

3. If your rating is below 3, iterate on your solution
4. Continue this process until you achieve a rating of 3 or higher
5. Present your final solution with:
- The complete code as a solid block
- Comments explaining key parts
- Rating and justification
- Any important usage notes or limitations

Tras ese prompt puedes especificar que deseas que programe Qwen

Crear un podcast de cualquier blog o noticia usando IA en local (llama.cpp + Piper)

Hace no mucho Google sacó una herramienta que permite crear podcasts donde dos IAs discuten sobre el texto que les pasas. Meta no hace mucho sacó su propia versión usando Llama que se puede usar en local. Aquí presento mi idea, con código para que podáis jugar vosotros.

Podéis ver el vídeo con más detalles en mi canal de YouTube:

Haz click para ver el vídeo en mi canal de YouTube

El proceso tiene varias partes:

Extraer el texto: 

El documento de origen puede tener una gran cantidad de formatos, para que funcione con la IA es necesario pasarlo a texto plano (txt). En este caso esa parte del trabajo os lo dejo a vosotros.

Limpiar el texto: 

Es posible que el texto extraído tenga «ruido», caracteres no válidos o que no forman parte del texto principal (cabeceras, notas de pie, número de página). Los resultados son mejores si le pedimos a una IA que limpie el texto.

Resumir el texto:

Su utilidad no es solo tener un podcast más corto y «concentrado». También sirve para lograr que el texto «quepa» dentro del contexto del modelos del lenguaje.

Generar el guión del podcast: 

En este caso se generará como si hablaran dos personas. Alice y Bob. Para ello pediremos al modelo de lenguaje que genere un podcast 

Generar el audio:

Aquí surge el problema de cómo generar audio con dos voces. En principio con Piper podemos fácilmente usar el parámetro –json-input y un fichero en formato json, indicando la voz usada en cada línea (es necesario un fichero de voz con múltiples voces). Por desgracia es necesario crear tu propia compilación de Piper. Así que haremos algo más simple: dividiremos el texto en líneas aprovechando que cada una va precedida de la voz que lo dice (el uso de [Alice] y [Bob] no es accidental). Y generamos un fichero wav independiente para cada línea. Luego tendremos que unirlos. En mi caso uso la herramienta sox.

const fetch = require('sync-fetch')
const fs = require("fs");
const { execSync } = require('child_process');

const llamaURL = "http://127.0.0.1:8080/completion";
const tokenizerURL = "http://127.0.0.1:8080/tokenize";
const inputFilename = "./text.txt";

//Llama a llama.cpp
function CallIA(prompt, n_predict, temperature) {
	console.log("Asking llama.cpp");
	
	let response = fetch(llamaURL, {
		method: 'POST',
		body: JSON.stringify({
			prompt,
			n_predict: n_predict,
			temperature: temperature,
			cache_prompt: true
		})
	}).json().content;

	return response;
}

//Consulta el tamaño en tokens del texto
function callTokenizer(text) {
	console.log("Asking llama.cpp");    

	let response = fetch(tokenizerURL, {
		method: 'POST',
		body: JSON.stringify({
            text,
            add_special: true
        })    
    }).json();

    console.log(response.tokens);
	return response.tokens.length;
}

//Limpiar texto
function generatePromptClean(text){
    return "<|im_start|>system\nYou are Qwen, created by Alibaba Cloud. You are a helpful assistant.<|im_end|>\n<|im_start|>user\nRepite el texto que te voy a pasar, limpia los caracteres extraños y corrige los posibles errores\n"+text+"\n<|im_end|>\n<|im_start|>assistant\n";
}  
//Resumir texto
function generatePromptSumarize(text){
    return "<|im_start|>system\nYou are Qwen, created by Alibaba Cloud. You are a helpful assistant.<|im_end|>\n<|im_start|>user\nResume el texto que te voy a pasar, extrae las partes más interesantes y curiosas de él\n"+text+"\n<|im_end|>\n<|im_start|>assistant\n";    
}   
//Generar guion
function generatePromptDialog(text){
    return "<|im_start|>system\nYou are Qwen, created by Alibaba Cloud. You are a helpful assistant.<|im_end|>\n<|im_start|>user\nConvierte el siguiente texto en una conversacion, en español, animada y divertida entre dos personas: Alice y Bob. Indica cada usuario poniendo delante [Alice] o [Bob].Comienza Alice\n"+text+"\n<|im_end|>\n<|im_start|>assistant\n[Alice]";    
}   

function generateAudio(text){
    //Almacena listado de ficheros para concatenar con sox
    var concatSox = ""; 

    //Se separa cada linea que empieza por [
    var podcastWithVoices = podcast.split("[");
    for(var i = 0; i < podcastWithVoices.length; i++){
        var line = podcastWithVoices[i].trim();
        //Elegimos la voz Alice/Bob
        var speaker;
        if(line.startsWith("Alice")){
            speaker = 1;
        } else {
            speaker = 0;
        }

        //Eliminamos el nombre para que no lo lea
        line = line.replace("Alice]", "").replace("Bob]", "");
        
        //Llamamos a Piper para generar el audio en un fichero .wav
        execSync(`echo '${line}' | piper --model ./models/es_ES-sharvard-medium.onnx --speaker ${speaker} --output_file podcast${i}.wav`, { encoding: 'utf-8' });

        //Añadimos el fichero a la lista para concatenar
        concatSox += "podcast"+i+".wav ";
    }

    //Unimos todos los ficheros .wav
    console.log(`sox ${concatSox} podcast.wav`);
    execSync(`sox ${concatSox} podcast.wav`);
}

//Leer fichero de texto
var text = fs.readFileSync(inputFilename, 'utf8');

//Tokenizador calcula cuantos tokens ocupa el texto (no he logrado que funcione)
//callTokenizer(text);

//Limpiamos el texto
//text = callIA(generatePromptClean(text), 8000, 0.2)

//Resumimos el texto
//text = callIA(generatePromptSumarize(text), 8000, 0.2)

//Generamos el dialogo
//Es necesario añadir [Alice] 
var podcast = "[Alice]"+CallIA(generatePromptDialog(text), 8000, 0.2);
console.log(podcast);

//Limpiamos el texto generado por la IA
podcast = podcast.replace(/(\r\n|\n|\r)/gm, "");

//Llama a piper para generar el audio linea a linea
generateAudio(podcast);

Si queréis ver (bueno, oir) el resultado, tenéis un ejemplo al final del vídeo.