Con el modelo y el contexto creado, vamos a una parte muy interesante que es la Tokenización, un resumen muy simple es pasar el texto a números, para poder realizar la inferencia.
Convertiremos la pregunta a IDs y el modelo LLM nos dará IDs que deberemos destokenizar para convertirlo a texto.
const vocab_t *vocab = llama_model_get_vocab(modelo); // Cargamos el vocabulario del modelo.
// Debemos crear un
Cada modelo tendrá su propio vocabulario por eso lo primero que hacemos es descargar el vocabulario del modelo.
El texto que le pasamos a tokenizar debe ser un PROMPT que tendrá palabras claves, que nos permite definir el rol del sistema que indica como debe comportarse, el del usuario que es nuestra pregunta y en la respuesta tendremos el rol assistant.
<|begin_of_text|>: Indica el inicio del documento.
<|start_header_id|>system<|end_header_id|>: Aquí empieza el ROL.
<|start_header_id|>user<|end_header_id|>: Aquí empieza la pregunta.
<|eot_id|>: Fin de turno (lo que hablábamos antes).
Para pasar nuestro mensaje a este formato usaremos la función «llama_chat_apply_template»
// Preparamos prompt con su rol de system y user
const char *rolSystem = "La forma de comunicarme es en Español";
mensajeChat_t mensajes[] = {
{"system", rolSystem },
{"user", prompt}
};
llama_chat_apply_template(llama_model_chat_template(modelo, NULL), mensajes,2, true, prompt_formateado, bytes_prompt_final);
prompt_formateado[bytes_prompt_final] = '\0'; // Asegurar cierre de cadena de C
llama_tokenize(vocab,prompt_formateado,strlen(prompt_formateado),prompt_tokens,n_tokens,false,true)
En el código se puede ver con más detalle ya que deberemos crear con malloc el espacio de memoria suficiente para contener el prompt. Hasta este momento solo hemos pasado nuestra pregunta con el rol que utilizaremos a IDs, ahora deberemos realizr la inferencia pero antes debemos crear el «sampler» que nos permitirá definir como seleccionar las posibles opciones.
paramSampler_t sparams = llama_sampler_chain_default_params();
sampler_t *miSampler = llama_sampler_chain_init(sparams);
// Definimos la forma de elegir
llama_sampler_chain_add(miSampler, llama_sampler_init_greedy()); // Elige la mas exata
llama_sampler_chain_add(miSampler, llama_sampler_init_min_p(0.05f, 1)); // Min-P
llama_sampler_chain_add(miSampler, llama_sampler_init_temp(0.8f)); //Temperatura
llama_sampler_chain_add(miSampler, llama_sampler_init_dist(LLAMA_DEFAULT_SEED)); // Distribución
Tenemos varias funciones de selección que pueden ser:
| Función de Inicialización | Parámetros Clave | ¿Qué hace exactamente? | ¿Cuándo usarlo? (Caso de uso) |
|---|---|---|---|
| llama_sampler_init_greedy() | Ninguno | Búsqueda codiciosa: Elige siempre la palabra con el porcentaje más alto, ignorando la creatividad o el azar. | Para tareas que requieren respuestas exactas e idénticas siempre (programación, matemáticas, JSON). |
| llama_sampler_init_temp(float temp) | temp: Nivel de caos (ej. 0.7f). | Temperatura: Escala las probabilidades. Una temperatura alta nivela el terreno (da oportunidad a palabras raras); una baja las distancia más. | Es el ecualizador global. 0.2 para máxima lógica, 0.8 o 1.0 para chats creativos o escritura. |
| llama_sampler_init_top_k(int32_t k) | k: Número de palabras (ej. 40). | Top-K: Ordena las palabras de mayor a menor probabilidad y elimina todas las que queden por debajo del puesto k. | Para evitar que el modelo elija palabras completamente absurdas o rotas fuera del top inicial. |
| llama_sampler_init_top_p(float p, size_t min_keep) | p: Porcentaje (ej. 0.95f), min_keep: Mínimo a mantener. | Top-P (Nucleus): Suma los porcentajes de las palabras más probables hasta llegar al p por ciento (ej. 95%) y descarta el resto. | Es dinámico. Si el modelo está seguro, el Top-P se encoge automáticamente; si duda, se expande. |
| llama_sampler_init_min_p(float p, size_t min_keep) | p: Escala respecto al líder (ej. 0.05f), min_keep: Mínimo. | Min-P: Elimina cualquier palabra cuya probabilidad sea menor que un porcentaje del token ganador (ej. menos del 5% del líder). | El sampler moderno más recomendado. Limpia el «ruido» de forma mucho más limpia que Top-P y Top-K. |
| llama_sampler_init_repetition(int32_t penalty_last_n, float penalty_repeat, float penalty_freq, float penalty_present) | penalty_last_n: Ventana de memoria (ej. 64), penalty_repeat: Fuerza (ej. 1.1f). | Penalización de repetición: Revisa los últimos n tokens escritos y les baja la probabilidad si el modelo intenta usarlos otra vez. | ¡Esencial! Evita que el modelo se quede atrapado en bucles infinitos repitiendo la misma frase una y otra vez. |
| llama_sampler_init_dist(uint32_t seed) | seed: Semilla aleatoria (ej. 1234 o un número basado en el tiempo). | Distribución: Es el encargado de tirar el dado final sobre las opciones supervivientes para elegir el token definitivo. | Va siempre al final de la cadena (a menos que uses Greedy). Permite que la misma pregunta tenga respuestas variadas. |
Ahora ya podremos generar nuestro batch y realizar la inferencia, mediante lo que llamamos bucle de inferencia que enviara al modelo la pregunta y recibira la respuesta que tendremos que decodificar para que la veamos como texto.
llama_batch miBatch = llama_batch_get_one(prompt_tokens, n_tokens); // Crea batch
Bucle
llama_decode(contexto, miBatch) // LLama a la inferencia.
new_token_id = llama_sampler_sample(miSampler, contexto, -1);
if (llama_vocab_is_eog(vocab, new_token_id)) { break; } // Esto es el fin de la generación
llama_token_to_piece(vocab, new_token_id, buf, sizeof(buf), 0, true);
buf[n] = 0;
printf("%s", buf); // Imprime segun vamos recibiendo
// Prepara el siguiente lote con TOKEN sample
miBatch = llama_batch_get_one(&new_token_id, 1);
No debemos olvidarnos antes de terminar nuestro programa de limpiar la memoria creada.
printf("\n--- 9. Limpia memoria ---\n");
llama_sampler_free(miSampler);
free(prompt_tokens);
free(prompt_formateado);
llama_free(contexto);
llama_model_free(modelo);
llama_backend_free();
Ya tenemos la programación básica, en el próximo hablaremos de como mantener contexto, que se podra ver en el otro ejemplo que explicaremos que es «Agente«
