Construyendo un Agente de IA Nativo con C y Llama.cpp (IV)

El contexto nos permite tener un historico de lo preguntado, y así adaptar nuestra respuesta pero este es limitado, según lo definamos como hemos podido ver al crearlo.

context_t *iniciaContexto(modelo_t *modelo)
{
   paramContext_t parametrosContexto = llama_context_default_params();
   // Optimización para OpenBLAS en CPU
   //parametrosContexto.n_ctx = 2048;  // Tamaño contexto
   //parametrosContexto.n_batch = 2048; // Tokes a procesar para llama_decodee.
   parametrosContexto.n_ctx = 512;  // Tamaño contexto
   parametrosContexto.n_batch = 512; // Tokes a procesar para llama_decodee.

   // Crear el contexto ligado al modelo
   return  llama_init_from_model(modelo, parametrosContexto);
}

Vemos en el código que serán 2048 bytes, pero según vamos realizando iteracciones se va llenando, así que llegado ese momento

// Analizamos el espacio del contexto
int n_ctx = llama_n_ctx(contexto);
int n_ctx_usada = llama_memory_seq_pos_max(llama_get_memory(contexto), 0) + 1;
if (n_ctx_usada + miBatch.n_tokens > n_ctx)   // Sobrepasamos el contexto, por lo que debemos limpiar o restructurar.

Una vez que vemos que no disponemos de más contexto podemos realizar tres cosas:

  • Salir del programa porque no tenemos más espacio, no es lo más normal a utilizar.
  • Limpiar el contexto por completo, acordandonos de poner el rol del sistema para que se vuelva a comportar con el ROL definicdo.
  • Rotar perdiendo solo lo más antiguo «Ventana Deslizante»

La primera opción es muy sencilla, pues valdrá con realizar un exit(x) el segundo también es sencillo y sera limpiar el área del contexto por completo y reiniciar la inferencia desde el principio.

llama_memory_seq_rm(llama_get_memory(contexto), 0, -1, -1); // Borra todo el área del contexto.
free(prompt_formateado);  // Limpia volvemos a inferir
inferencia(rolSystem, prompt, modelo, contexto, miSampler,vocab);  // Volvemos a realizar la inferencia.

La tercera opción y la que consideramos más apropiada pues no es compleja y nos da mucho juego es la técnica de la Ventana Deslizante (Sliding Window) que en lugar de borrar todo cuando el contexto llega a su límite, aplicamos una poda selectiva:

  • Preservamos el ROL: Los primeros tokens (instrucciones del sistema) nunca se borran.
  • Rotación: Borramos un bloque intermedio y desplazamos los mensajes recientes hacia atrás usando «llama_memory_seq_add»

Lo primero es conocer los Tokens que utiliza la definición del Rol-System ya que muchas veces es pequeña o nula, pero por ejemplo en la creación de un agente como veremos más adelante es bastante amplia.

// Antes de nada debemos saber cuanto ocupa el Rol del sistema.
mensajeChat_t rol_System[] = {{"system", rolSystem }};

// Calculamos los tokens del ROL, 
int32_t bytes_ROL = llama_chat_apply_template(llama_model_chat_template(modelo, NULL), rol_System, 1, false, NULL, 0); 
// Buffer temporal para el ROL formateado
char * prompt_ROL = malloc(bytes_ROL + 1);
llama_chat_apply_template(llama_model_chat_template(modelo, NULL), rol_System, 1, false, prompt_ROL, bytes_ROL); 
prompt_ROL[bytes_ROL] = '\0';
Contamos TOKENS usamos NULL en el buffer de tokens y 0 solo cuenta
int32_t tokens_ROL = llama_tokenize( vocab, prompt_ROL, bytes_ROL, NULL, 0, true, true ); // add_especial es true porque el ROL abre la secuencia.
free(prompt_ROL); // Limpiamos memoria temporal del ROL que no sera necesaria

Con el dato de los tokens del Rol-System ya podemos realizar una rotación, antes definiremos también cuantos se echan hacia atrás, podemos ver un ejemplo grafico de 2 tokens para el ROL y 10 en total.

ESTADO 1: Contexto Lleno
[ S1 | S2 | T1 | T2 | T3 | T4 | T5 | T6 | T7 | T8 ]  <-- ¡Lleno!
  ^----^    ^--------------------------------^
  SYSTEM          HISTORIAL DE CHAT

ESTADO 2: Aplicando Sliding Window (Borramos el 20% antiguo)
[ S1 | S2 | -- | -- | T3 | T4 | T5 | T6 | T7 | T8 ]
            ^-- Hueco creado (borramos T1 y T2)

ESTADO 3: Compactación y Desplazamiento (Shift)
[ S1 | S2 | T3 | T4 | T5 | T6 | T7 | T8 | N1 | N2 ]
                                          ^----^
                                      NUEVOS TOKENS

En código quedaría de la siguiente forma

// Técnica avanzada de "Sliding Window" (Ventana Deslizable).
int32_t n_tokens_a_borrar = 256;                 // Definimos bloque a borrar
// Límites de la "poda" p0(Despues del ROL) p1 + borrado
int32_t p0 = tokens_ROL;   //Los TOKENs necesarios para el ROL, desde donde borraremos
int32_t p1 = tokens_ROL + n_tokens_a_borrar;   // Hasta donde borramos
llama_memory_seq_rm(llama_get_memory(contexto), 0, p0, p1);
// Movemos lo que quedó al final hacia atrás para cerrar el hueco
llama_memory_seq_add(llama_get_memory(contexto), 0, p1, -1, -n_tokens_a_borrar);

// Continuamos con la inferencia llamando a llama_decode.

Y ya nos queda que lo dejamos para el próximo la generación del agente, que veremos que lo único que añadiremos es una definición correcta del Rol-System, y las funciones agenticas.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Información básica sobre protección de datos Ver más

  • Responsable: Javier.
  • Finalidad:  Moderar los comentarios.
  • Legitimación:  Por consentimiento del interesado.
  • Destinatarios y encargados de tratamiento:  No se ceden o comunican datos a terceros para prestar este servicio. El Titular ha contratado los servicios de alojamiento web a Hostinger.es que actúa como encargado de tratamiento.
  • Derechos: Acceder, rectificar y suprimir los datos.
  • Información Adicional: Puede consultar la información detallada en la Política de Privacidad.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos. Contiene enlaces a sitios web de terceros con políticas de privacidad ajenas que podrás aceptar o no cuando accedas a ellos. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Ver
Privacidad