{"id":1204,"date":"2026-06-11T08:48:00","date_gmt":"2026-06-11T06:48:00","guid":{"rendered":"https:\/\/www.pinguytaz.net\/?p=1204"},"modified":"2026-06-03T20:25:39","modified_gmt":"2026-06-03T18:25:39","slug":"construyendo-un-agente-de-ia-nativo-con-c-y-llama-cpp-iii","status":"publish","type":"post","link":"https:\/\/www.pinguytaz.net\/index.php\/2026\/06\/11\/construyendo-un-agente-de-ia-nativo-con-c-y-llama-cpp-iii\/","title":{"rendered":"Construyendo un Agente de IA Nativo con C y Llama.cpp (III)"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Con el modelo y el contexto creado, vamos a una parte muy interesante que es la Tokenizaci\u00f3n, un resumen muy simple es pasar el texto a n\u00fameros, para poder realizar la inferencia.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Convertiremos la pregunta a IDs y el modelo LLM nos dar\u00e1 IDs que deberemos destokenizar para convertirlo a texto.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const vocab_t *vocab = llama_model_get_vocab(modelo);  \/\/ Cargamos el vocabulario del modelo.\n\n\/\/ Debemos crear un <\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Cada modelo tendr\u00e1 su propio vocabulario por eso lo primero que hacemos es descargar el vocabulario del modelo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">El texto que le pasamos a tokenizar debe ser un PROMPT que tendr\u00e1 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.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;|begin_of_text|&gt;: Indica el inicio del documento.\n\n&lt;|start_header_id|&gt;system&lt;|end_header_id|&gt;: Aqu\u00ed empieza el ROL.\n\n&lt;|start_header_id|&gt;user&lt;|end_header_id|&gt;: Aqu\u00ed empieza la pregunta.\n\n&lt;|eot_id|&gt;: Fin de turno (lo que habl\u00e1bamos antes).\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Para pasar nuestro mensaje a este formato usaremos la funci\u00f3n \u00abllama_chat_apply_template\u00bb<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Preparamos prompt con su rol de system y user\nconst char *rolSystem = \"La forma de comunicarme es en Espa\u00f1ol\";\nmensajeChat_t mensajes&#91;] = {\n      {\"system\", rolSystem },\n      {\"user\",   prompt}\n};\n\nllama_chat_apply_template(llama_model_chat_template(modelo, NULL), mensajes,2, true, prompt_formateado, bytes_prompt_final);\nprompt_formateado&#91;bytes_prompt_final] = '\\0'; \/\/ Asegurar cierre de cadena de C\n\t\t\nllama_tokenize(vocab,prompt_formateado,strlen(prompt_formateado),prompt_tokens,n_tokens,false,true)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">En el c\u00f3digo se puede ver con m\u00e1s 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 \u00absampler\u00bb que nos permitir\u00e1 definir como seleccionar las posibles opciones.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>paramSampler_t sparams = llama_sampler_chain_default_params(); \nsampler_t *miSampler = llama_sampler_chain_init(sparams);\n\/\/ Definimos la forma de elegir  \nllama_sampler_chain_add(miSampler, llama_sampler_init_greedy()); \/\/ Elige la mas exata\nllama_sampler_chain_add(miSampler, llama_sampler_init_min_p(0.05f, 1)); \/\/ Min-P\nllama_sampler_chain_add(miSampler, llama_sampler_init_temp(0.8f));   \/\/Temperatura\nllama_sampler_chain_add(miSampler, llama_sampler_init_dist(LLAMA_DEFAULT_SEED)); \/\/ Distribuci\u00f3n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Tenemos varias funciones de selecci\u00f3n que pueden ser:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Funci\u00f3n de Inicializaci\u00f3n<\/th><th>Par\u00e1metros Clave<\/th><th>\u00bfQu\u00e9 hace exactamente?<\/th><th>\u00bfCu\u00e1ndo usarlo? (Caso de uso)<\/th><\/tr><tr><td>llama_sampler_init_greedy()<\/td><td>Ninguno<\/td><td>B\u00fasqueda codiciosa: Elige siempre la palabra con el porcentaje m\u00e1s alto, ignorando la creatividad o el azar.<\/td><td>Para tareas que requieren respuestas exactas e id\u00e9nticas siempre (programaci\u00f3n, matem\u00e1ticas, JSON).<\/td><\/tr><tr><td>llama_sampler_init_temp(float temp)<\/td><td>temp: Nivel de caos (ej. 0.7f).<\/td><td>Temperatura: Escala las probabilidades. Una temperatura alta nivela el terreno (da oportunidad a palabras raras); una baja las distancia m\u00e1s.<\/td><td>Es el ecualizador global. 0.2 para m\u00e1xima l\u00f3gica, 0.8 o 1.0 para chats creativos o escritura.<\/td><\/tr><tr><td>llama_sampler_init_top_k(int32_t k)<\/td><td>k: N\u00famero de palabras (ej. 40).<\/td><td>Top-K: Ordena las palabras de mayor a menor probabilidad y elimina todas las que queden por debajo del puesto k.<\/td><td>Para evitar que el modelo elija palabras completamente absurdas o rotas fuera del top inicial.<\/td><\/tr><tr><td>llama_sampler_init_top_p(float p, size_t min_keep)<\/td><td>p: Porcentaje (ej. 0.95f), min_keep: M\u00ednimo a mantener.<\/td><td>Top-P (Nucleus): Suma los porcentajes de las palabras m\u00e1s probables hasta llegar al p por ciento (ej. 95%) y descarta el resto.<\/td><td>Es din\u00e1mico. Si el modelo est\u00e1 seguro, el Top-P se encoge autom\u00e1ticamente; si duda, se expande.<\/td><\/tr><tr><td>llama_sampler_init_min_p(float p, size_t min_keep)<\/td><td>p: Escala respecto al l\u00edder (ej. 0.05f), min_keep: M\u00ednimo.<\/td><td>Min-P: Elimina cualquier palabra cuya probabilidad sea menor que un porcentaje del token ganador (ej. menos del 5% del l\u00edder).<\/td><td>El sampler moderno m\u00e1s recomendado. Limpia el \u00abruido\u00bb de forma mucho m\u00e1s limpia que Top-P y Top-K.<\/td><\/tr><tr><td>llama_sampler_init_repetition(int32_t penalty_last_n, float penalty_repeat, float penalty_freq, float penalty_present)<\/td><td>penalty_last_n: Ventana de memoria (ej. 64), penalty_repeat: Fuerza (ej. 1.1f).<\/td><td>Penalizaci\u00f3n de repetici\u00f3n: Revisa los \u00faltimos n tokens escritos y les baja la probabilidad si el modelo intenta usarlos otra vez.<\/td><td>\u00a1Esencial! Evita que el modelo se quede atrapado en bucles infinitos repitiendo la misma frase una y otra vez.<\/td><\/tr><tr><td>llama_sampler_init_dist(uint32_t seed)<\/td><td>seed: Semilla aleatoria (ej. 1234 o un n\u00famero basado en el tiempo).<\/td><td>Distribuci\u00f3n: Es el encargado de tirar el dado final sobre las opciones supervivientes para elegir el token definitivo.<\/td><td>Va siempre al final de la cadena (a menos que uses Greedy). Permite que la misma pregunta tenga respuestas variadas.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>llama_batch miBatch = llama_batch_get_one(prompt_tokens, n_tokens);  \/\/ Crea batch\n\nBucle\n   llama_decode(contexto, miBatch) \/\/ LLama a la inferencia.\n   new_token_id = llama_sampler_sample(miSampler, contexto, -1);  \n   if (llama_vocab_is_eog(vocab, new_token_id)) { break; }      \/\/ Esto es el fin de la generaci\u00f3n\n\n   llama_token_to_piece(vocab, new_token_id, buf, sizeof(buf), 0, true);\n   buf&#91;n] = 0;\n   printf(\"%s\", buf);    \/\/ Imprime segun vamos recibiendo\n   \/\/ Prepara el siguiente lote con TOKEN sample\n   miBatch = llama_batch_get_one(&amp;new_token_id, 1);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">No debemos olvidarnos antes de terminar nuestro programa de limpiar la memoria creada.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code> printf(\"\\n--- 9. Limpia memoria ---\\n\");\n llama_sampler_free(miSampler);\n free(prompt_tokens);\n free(prompt_formateado); \n llama_free(contexto);\n llama_model_free(modelo);\n llama_backend_free();<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Ya tenemos la programaci\u00f3n b\u00e1sica, en el pr\u00f3ximo hablaremos de como mantener contexto, que se podra ver en el otro ejemplo que explicaremos que es \u00ab<strong>Agente<\/strong>\u00ab<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Con el modelo y el contexto creado, vamos a una parte muy interesante que es la Tokenizaci\u00f3n, un resumen muy simple es pasar el texto a n\u00fameros, para poder realizar la inferencia. Convertiremos la pregunta a IDs y el modelo LLM nos dar\u00e1 IDs que deberemos destokenizar para convertirlo a texto. Cada modelo tendr\u00e1 su [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1197,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"site-container-style":"default","site-container-layout":"default","site-sidebar-layout":"default","disable-article-header":"default","disable-site-header":"default","disable-site-footer":"default","disable-content-area-spacing":"default","footnotes":""},"categories":[212],"tags":[219,220],"class_list":["post-1204","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-llama-cpp-ia","tag-modelo","tag-token"],"_links":{"self":[{"href":"https:\/\/www.pinguytaz.net\/index.php\/wp-json\/wp\/v2\/posts\/1204","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.pinguytaz.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.pinguytaz.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.pinguytaz.net\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.pinguytaz.net\/index.php\/wp-json\/wp\/v2\/comments?post=1204"}],"version-history":[{"count":4,"href":"https:\/\/www.pinguytaz.net\/index.php\/wp-json\/wp\/v2\/posts\/1204\/revisions"}],"predecessor-version":[{"id":1212,"href":"https:\/\/www.pinguytaz.net\/index.php\/wp-json\/wp\/v2\/posts\/1204\/revisions\/1212"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.pinguytaz.net\/index.php\/wp-json\/wp\/v2\/media\/1197"}],"wp:attachment":[{"href":"https:\/\/www.pinguytaz.net\/index.php\/wp-json\/wp\/v2\/media?parent=1204"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.pinguytaz.net\/index.php\/wp-json\/wp\/v2\/categories?post=1204"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.pinguytaz.net\/index.php\/wp-json\/wp\/v2\/tags?post=1204"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}