Como vimos en el post anterior, Ollama nos permite interactuar con LLMs de una forma sencilla y transparente. Mucho más allá de realizar ciertas pruebas sencillas o iniciarnos en el mundo de los LLMs para comprobar su funcionamiento, en el mundo de desarrollo software se suelen necesitar opciones más avanzadas y personalizadas.

En este post exploraremos estas opciones avanzadas que nos ofrece Ollama para poder personalizar nuestros modelos, así como hacer uso de su API y poder sacarle todo el partido para crear aplicaciones de IA.

Conceptos previos

En el post anterior comentamos algunos aspectos más teóricos para la ejecución de los LLMs en local a través de Ollama. Al avanzar a casos de uso más complejos, también es necesario tener en cuenta nuevos conceptos.

Hay que aclarar que estos conceptos teóricos son transversales a los LLMs, independientemente de las herramientas que se analizan en los posts en las que puede que no siempre sea posible una implementación directa de dicho concepto (por ejemplo: Ollama no entrena modelos sino que aplica adaptadores LoRA/QLoRA para por ejemplo aplicar fine-tuning a un modelo).

Estos conceptos son:

Fine-tunning

El fine-tuning es el proceso en el que se adapta un modelo previamente entrenado a una tarea específica. Esto se realiza a través de un conjunto de datos ligados a esta tarea concreta, que podrán actualizar de múltiples formas (total o parcialmente) los pesos de la red neuronal. Este proceso permite adaptar un modelo a una tarea concreta para la que no ha sido entrenado (en la mayoría de las ocasiones los modelos se entrenan para un uso genérico). Esto mejora el desempeño del modelo en dicha tarea, sin necesidad de reentrenarlo desde el principio, lo que lleva a un ahorro de tiempo y recursos.

Como se comentó en el post anterior, el funcionamiento de los LLMs consiste en predecir la siguiente palabra en un contexto. Sin una guía muy concreta a través de prompts (prompt engineering), un LLM que no haya sido “tuneado” podría producir una respuesta coherente aunque no adecuada a la intención del usuario.

Por ejemplo, si se le solicita algo como: “¿Cómo puedo hacer un currículo?” un LLM podría responder “Usando Microsoft Word”. Esta respuesta es completamente válida pero no está alineada con lo que el usuario necesita, a pesar de que el propio LLM puede tener un conocimiento extenso sobre la creación de currículos.

El fine-tuning es especialmente útil para personalizar el estilo de un LLM para responder a los usuarios de una forma en concreto, por ejemplo en un chatbot, o para agregar conocimientos específicos de un dominio (por ejemplo, vocabulario especializado con el que no ha sido entrenado el modelo de origen), como en entornos legales, financieros o de salud.

Algunos tipos de fine-tuning que existen son:

Otra catalogación de tipos de fine-tuning puede ser en base a si está supervisado por humanos (SFT o Supervised Fine-Tuning), semi supervisado o no supervisado.

Formatos de ficheros: Safetensors y GGUF

Partiendo de la base de que un tensor es un objeto matemático (básicamente un array que puede tener múltiples dimensiones) para la representación de datos, Safetensor es un formato de fichero desarrollado por Hugging Face que almacena dichos tensors de forma segura. A diferencia de otros formatos, Safetensor está habilitado en un formato de solo lectura (evitando la ejecución de código no deseado) y diseñado para la eficiencia y portabilidad de datos.

Scalar, vector, matriz, tensor

Un ejemplo de lo que es un tensor si lo trasladamos al mundo real, podría ser:

Entre otros formatos de ficheros, también se puede encontrar GGUF (GPT-Generated Unified Format), que posibilita la gestión de LLMs de forma optimizada. Este formato permite, además de codificar los tensors, incluir un conjunto de metadatos y dar soporte a diversos tipos de cuantización y fine-tuning.

GGUF está pensado para la extensibilidad y versatilidad, pudiendo incorporar nueva información sin romper la compatibilidad con los modelos antiguos además de los que puedan venir en el futuro.

Modelo GGUF
Modelo GGUF

Parámetros del modelo

Así como las aplicaciones tienen parámetros comunes que son configurables según ciertos escenarios (multidivisa, multiidioma), los modelos también contienen parámetros similares.

Más allá de que cada modelo puede implementar múltiples parámetros concretos, existen algunos comunes y que tal vez sean los más relevantes de cara a su optimización. Entre estos parámetros se encuentran:

Los anteriores parámetros tal vez sean los más relevantes, pero existen más, aunque se debe tener en cuenta que parece que no todos se pueden configurar según las distintas opciones disponibles de interacción con Ollama (API, cli, Modelfile).

Longitud de contexto

Este es uno de los parámetros a personalizar en los modelos más importantes. Se trata del número máximo de tokens que el modelo puede procesar al mismo tiempo. Hay que indicar que este número de tokens comprende:

La longitud del contexto es crítica, puesto que afectará directamente a la calidad de la respuesta del modelo. Por ejemplo, en conversaciones largas o en las que se aporta una cantidad muy grande de información (adjuntando documentos), si se supera la longitud del contexto del modelo, empezará a responder de una forma errática (puede responder con repeticiones de respuestas en una conversación de varias preguntas-respuestas o no responder a lo que se pregunta porque no tiene toda la información disponible).

Aunque sea un parámetro configurable, los LLMs vienen preentrenados con una longitud de contexto máxima (se pueden ver valores como 2048, 4096, 8192, …, 128K, aunque también existen modelos con contextos de hasta ¡2 millones! de tokens como Gemini 1.5 Pro).

Configurar este parámetro más allá de los valores preentrenados para cada modelo también producirá respuestas incoherentes, además de que valores altos afectarán al consumo de recursos de la máquina como la RAM, pudiendo ocasionar problemas de rendimiento.

Este parámetro tiene múltiples formas de cambiarlo en cada modelo:

Longitud de contexto: cli
curl http://localhost:11434/api/generate -d '{
  "model": "llama3.2:1b",
  "prompt": "¿A que velocidad gira la Tierra?",
  "options": {
    "num_ctx": 1024
   }
}'
Longitud de contexto: api

API

Además de los comandos interactivos, Ollama proporciona un API para poder interactuar con los LLMs. Este API es útil sobre todo en casos en los que se quiera realizar una integración con otras aplicaciones (como por ejemplo desde Spring AI), puesto que lo único que habría que hacer es realizar una llamada al endpoint Rest correspondiente.

Por defecto, el API está expuesta en el puerto 11434 (http://localhost:11434 o http://127.0.0.1:11434), aunque es configurable. Los endpoints que expone el API son:

Ollama api generate
Ollama api chat
Ollama api embeddings
Ollama api tags
Ollama api show
ollama api delete
ollama api pul
ollama api create
ollama api copy

Compatibilidad con API OpenAI

Como es bien conocido, OpenAI es uno de los primeros y más importantes impulsores de esta nueva ola de IA-LLMs, por lo que es lógico pensar que muchas aplicaciones hacen uso de sus APIs. Para mantener las integraciones con el resto de aplicaciones de la forma más sencilla posible, Ollama añade una capa para que las APIs sean compatibles con el formato de OpenAI.

En base, lo que sucede es que, además de los endpoints comentados anteriormente, se exponen otros sobre el path /v1/ (http://localhost:11434/v1/) con el formato del API de OpenAI. Algunos de los endpoints compatibles actualmente disponibles son:

v1 chat completions
v1 embeddings
v1 models

Con esto en mente, muchas de las librerías que se integran con el API de OpenAI solo necesitarían adaptar algunos parámetros de configuración para usar Ollama. Algunos de estos parámetros son:

Modelfiles

Ya en las primeras etapas de Ollama se estaba pensando en la modularidad y extensibilidad (en el equipo fundador de Ollama ha participado gente que había trabajado previamente en Docker). Es por esto que existen los Modelfiles, que no son más que ficheros de configuración que actúan como receta para la definición por capas de los modelos en Ollama. Este fichero sería una combinación de los pesos del modelo en formato GGUF, la plantilla, el system prompt y otras instrucciones.

Esta información está dividida en distintas instrucciones en el Modelfile (como lo está un Dockerfile), siendo las siguientes algunas de las más importantes:

Parámetro Descripción Tipo Ejemplo
num_ctx Define el tamaño de la ventana de contexto int 4096
temperature Valor indicativo de la “creatividad” del modelo float 0.6
stop Posibles marcas de stop para el ciclo del LLM. Cuando el LLM encuentre este patrón, parará y devolverá la salida. string "AI assistant:"
top_k Filtrado de opciones de salida a las k con más probabilidades int 40
top_p Filtrado de opciones de salida con probabilidades acumuladas float 0.9
Variable Descripción
{{ .System }} El prompt del sistema para configurar su comportamiento.
{{ .Prompt }} El prompt del usuario
{{ .Response }} La respuesta del LLM

Un ejemplo de instrucción template podría ser:

TEMPLATE """{{ if .System }}<|im_start|>system
{{ .System }}<|im_end|>
{{ end }}{{ if .Prompt }}<|im_start|>user
{{ .Prompt }}<|im_end|>
{{ end }}<|im_start|>assistant
"""
SYSTEM """ Eres un agente de viajes que proporciona información útil como leyes, precios, lugares a visitar importantes, sitios de comida, alojamientos y demás información turística importante. """
ADAPTER ./llama3.2-lora.gguf
LICENSE """ MIT License """

Un ejemplo de instrucciones message podría ser:

MESSAGE user ¿Está Madrid en España?
MESSAGE assistant si
MESSAGE user ¿Está Paris en España?
MESSAGE assistant no
MESSAGE user ¿Está Barcelona en España?
MESSAGE assistant si

Hay que indicar que el Modelfile no es case sensitive, simplemente las instrucciones se indican con mayúsculas por claridad y, además, las instrucciones no tienen por qué seguir un orden estricto (igualmente se indica la instrucción FROM de primera por claridad).

Teniendo en cuenta lo descrito anteriormente, un ejemplo sencillo de Modelfile podría ser:

FROM llama3.2:1b
PARAMETER temperature 0.3
PARAMETER num_ctx 8192
SYSTEM Eres un agente de viajes que proporciona información útil como leyes, precios, lugares a visitar importantes, sitios de comida, alojamientos y demás información turística importante.

Después de guardar dicho fichero, se ejecutaría el siguiente comando para su creación:

ollama create custom-model -f ./ModelfileCustom

Una vez creado, se puede comprobar que ya se lista junto al resto de modelos, pudiendo interactuar con él:

ejemplo modelfile

Importando modelos externos

Ollama permite la ejecución de modelos externos a su hub de modelos que sean distribuidos en formatos estándar como GGUF o Safetensors, o la inclusión de adaptadores para el fine-tuning. Algunos ejemplos de este proceso son:

GGUF

  1. Descargar el fichero en formato .gguf. Se puede encontrar un ejemplo en este enlace.
  2. Generar el Modelfile con la referencia al fichero descargado.
FROM ./external-models/gguf/llama-3.2-1b-instruct-q4_k_m.gguf
PARAMETER num_ctx 4096
SYSTEM "Eres un chatbot que sólo cuenta chistes"
  1. Crear el modelo para posteriormente poder ejecutarlo:
ollama create custom-gguf-model -f ./Modelfile_gguf
importar modelo externo gguf

Safetensors

  1. Descargar los ficheros necesarios en la misma carpeta. Se puede encontrar un ejemplo en este enlace.
  2. Generar el Modelfile con la referencia a la ruta en donde se encuentran los ficheros.
FROM ./external-models/safetensors/llama3_2_instruct_st/
PARAMETER num_ctx 4096
PARAMETER temperature 0.7
  1. Crear el modelo para posteriormente poder ejecutarlo:
ollama create custom-st-model -f ./modelfile

Adaptadores

  1. Descargar los ficheros necesarios en la misma carpeta. Se puede encontrar un ejemplo en este enlace.
  2. Generar el Modelfile con la referencia a la ruta en donde se encuentran los ficheros.
FROM llama-3.2-3b-instruct-bnb-4bit 
ADAPTER ./adapters/llama3_2_lora/llama3.2_LoRA_Spanish.gguf
PARAMETER temperature 0.5
SYSTEM "Ahora respondes en el estilo enseñado por el LoRA."
  1. Crear el modelo para posteriormente poder ejecutarlo:
ollama create custom-lora-model -f ./modelfile

Cuantización con Ollama

Ollama también incluye la opción de poder cuantizar (reducción de la precisión numérica en los pesos del modelo) un modelo en el momento de su creación. Básicamente consiste en indicar el parámetro -q (o –quantize) en el comando create de la siguiente forma:

ollama create llama-quantized -f ./Modelfile -q q4_K_M

En base al siguiente Modelfile, se puede comprobar el resultado de la cuantización (se puede observar como el modelo resultante tiene un tamaño menor):

FROM llama3.2:1b-instruct-fp16
PARAMETER temperature 0.9
SYSTEM """ Eres un agente de viajes que te llamas Mr Travel"""
cuantización ollama ejemplo

Realmente, por debajo se utilizarán las instrucciones de cuantización de la librería llama.cpp para realizar este proceso, guardando el modelo con el nombre correspondiente. Algunas de las opciones posibles de cuantización son: q4_0, q5_0, q6_K, q8_0, q4_K_S, q4_K_M, etc.

Conclusiones

En este post se han visto opciones de interacción con Ollama más avanzadas. Se ha probado el funcionamiento del API que expone Ollama, así como ciertos parámetros y configuraciones importantes para un buen rendimiento de los modelos.

También se ha podido probar una de las funcionalidades más importantes de Ollama: personalizar los modelos para que podamos adaptarlo lo mejor posible a nuestro caso de uso y poder tener una mejor experiencia de usuario en nuestras aplicaciones de IA.

En el siguiente post introduciremos otras herramientas de ejecución de LLMS en local.

Referencias

Cuéntanos qué te parece.

Los comentarios serán moderados. Serán visibles si aportan un argumento constructivo. Si no estás de acuerdo con algún punto, por favor, muestra tus opiniones de manera educada.

Suscríbete