BPE (Byte Pair Encoding) es un algoritmo que construye un vocabulario de subpalabras fusionando repetidamente el par de símbolos adyacentes más frecuente en un corpus. Empieza tratando cada carácter (o byte) como una unidad y termina con unidades más grandes que pueden ser morfemas, palabras completas o fragmentos frecuentes. Por eso un token no equivale a una palabra: el texto se divide en trozos estadísticamente rentables, y esa diferencia cambia el conteo y el coste.
Qué es BPE y por qué existe: del carácter al subword
Tokenizar es convertir texto en una secuencia de unidades discretas (tokens) que el modelo pueda procesar como números. Existen tres estrategias básicas: tokenizar por caracteres (vocabulario diminuto, pero secuencias larguísimas y poca densidad de información por token), tokenizar por palabras (vocabulario enorme, pero cualquier palabra no vista se vuelve un problema y las variantes morfológicas —"correr", "corriendo", "corredor"— se tratan como entradas independientes) y tokenizar por subpalabras, que busca el punto medio: unidades frecuentes que cubren también lo infrecuente componiéndolo por partes.
BPE nació en compresión de datos y se adoptó en procesamiento de lenguaje natural precisamente por eso: garantiza que cualquier texto pueda codificarse (nada queda "fuera de vocabulario") mientras mantiene un vocabulario de tamaño manejable. La idea central es que las palabras frecuentes acaban siendo un solo token, las raras se descomponen en fragmentos conocidos, y el modelo nunca ve un símbolo desconocido.
Un detalle importante: en la práctica muchos tokenizadores modernos operan sobre bytes (BPE a nivel de byte), no sobre caracteres Unicode. Eso permite representar cualquier texto, incluidos emojis o alfabetos no latinos, sin símbolo especial de "desconocido". Para el ejemplo que sigue usaremos caracteres por claridad, pero el mecanismo es idéntico.
Ejemplo numérico paso a paso: conteo de pares y reglas de fusión
Tomemos un corpus diminuto con las palabras y sus frecuencias:
"bajo" × 3
"baja" × 2
"bajada" × 1
Paso 0 — Inicialización. Cada carácter es un símbolo. Escribimos el corpus como secuencias separadas por un marcador de fin de palabra (lo omitimos aquí para no complicar el conteo, pero en un BPE real existe). Vocabulario inicial: {b, a, j, o}.
Paso 1 — Contar pares adyacentes. Recorremos cada ocurrencia y contamos:
bajo → (b,a), (a,j), (j,o) ×3 ⇒ 3, 3, 3
baja → (b,a), (a,j), (j,a) ×2 ⇒ 2, 2, 2
bajada → (b,a), (a,j), (j,a), (a,d), (d,a) ×1 ⇒ 1,1,1,1,1
Totales: (b,a)=6, (a,j)=6, (j,o)=3, (j,a)=3, (a,d)=1, (d,a)=1. Hay empate en la cima entre (b,a) y (a,j); cualquier criterio de desempate determinista (por ejemplo, orden lexicográfico) sirve. Supongamos que gana (b,a).
Paso 2 — Fusionar. Creamos el símbolo ba y reescribimos el corpus:
bajo → ba j o ×3
baja → ba j a ×2
bajada → ba j a d a ×1
Vocabulario: {b, a, j, o, ba}.
Paso 3 — Repetir. Nuevos pares: (ba,j)=6, (j,o)=3, (j,a)=3, (a,d)=1, (d,a)=1. Gana (ba,j) → símbolo baj. Corpus: baj o ×3, baj a ×2, baj a d a ×1.
Paso 4. Pares: (baj,o)=3, (baj,a)=3, (a,d)=1, (d,a)=1. Desempate → (baj,o) → símbolo bajo. Ahora "bajo" es un único token; el corpus queda bajo ×3, baj a ×2, baj a d a ×1.
Paso 5. Pares: (baj,a)=3, (a,d)=1, (d,a)=1. Gana (baj,a) → baja. Corpus: bajo ×3, baja ×2, baja d a ×1.
Y así sucesivamente. Cada iteración añade exactamente una entrada al vocabulario y reduce la longitud total del corpus en tantos símbolos como apariciones tenía el par fusionado. Si te detienes tras k fusiones, tu vocabulario mide |símbolos base| + k. En un tokenizador real se hacen decenas de miles de fusiones sobre corpus de miles de millones de caracteres; el procedimiento es el mismo, solo cambia la escala.
Construcción del vocabulario y codificación de texto nuevo
Terminado el entrenamiento, el vocabulario es la lista ordenada de todas las unidades que BPE ha producido: los 256 bytes iniciales más cada fusión aplicada, en el orden en que se aplicó. Ese orden importa: al codificar texto nuevo, el tokenizador reaplica las fusiones en la misma secuencia con la que se aprendieron, no elige "la mejor fusión posible" para cada palabra.
Procedimiento de codificación de una palabra nueva:
- Separa la palabra en caracteres (bytes) y añade el marcador de fin de palabra si el tokenizador lo usa (por ejemplo,
</w>o un espacio inicial tipoĠ). - Recorre la lista de fusiones en orden. Si el par fusionado aparece en la secuencia actual, fusiónalo (todas las apariciones).
- Repite hasta agotar las fusiones. Lo que quede son los tokens finales.
Ejemplo con un vocabulario de juguete entrenado sobre bajo, baja, bajito:
- Fusiones aprendidas en orden: (b,a)→
ba, (ba,j)→baj, (baj,o)→bajo, (baj,i)→baji, (baji,t)→bajit. - Codificamos
bajita(no vista en entrenamiento):b a j i t a→ba j i t a→baj i t a→baji t a→bajit a. Resultado: 2 tokens (bajit+a), frente a 6 caracteres.
Nótese que bajita nunca se convirtió en un token único: BPE generaliza por piezas, no memoriza palabras. Ese es exactamente el comportamiento deseado (subword).
Por qué "token" no equivale a "palabra": conteo, ventanas de contexto y coste
Un token es la unidad que el modelo ve; una palabra es una unidad lingüística. La relación entre ambas es variable y depende del idioma, del dominio y del tokenizador concreto.
Ejemplo con supuestos explícitos (ilustrativo, no es un benchmark): supongamos que un tokenizador produce de media ~1,3 tokens por palabra en inglés y ~1,8 en español (el español usa palabras más largas, más acentos y menos palabras funcionales de una sola pieza en el vocabulario; el rango razonable suele estar entre 1,5 y 2,2). Para un texto de 1.000 palabras:
inglés: 1000 × 1,3 ≈ 1300 tokens
español: 1000 × 1,8 ≈ 1800 tokens
diferencia ≈ 500 tokens ≈ +38 %
Consecuencias prácticas:
- Conteo y ventana de contexto: si el límite es, digamos, 8.000 tokens, en inglés caben ~6.150 palabras y en español ~4.440. El "mismo" texto ocupa más ventana en español.
- Coste: las APIs suelen facturar por token (entrada y salida). Con los supuestos anteriores, el mismo contenido en español costaría ~38 % más que en inglés, asumiendo una tarifa por token idéntica. Verifica siempre la tarifa real; no la des por supuesta.
- Rendimiento: palabras raras, código, identificadores largos, URLs y emojis se fragmentan en muchos tokens y consumen contexto y presupuesto de forma desproporcionada.
Checklist rápido antes de enviar un prompt largo:
- Estima tokens con el tokenizador real del modelo, no con
len(texto.split()). - Si el texto está en español y el presupuesto es ajustado, considera resumir o dividir.
- Revisa si emojis, números largos o código inflan el conteo.
- Calcula coste = (tokens_entrada × tarifa_entrada) + (tokens_salida_estimados × tarifa_salida).
Preguntas frecuentes
¿Qué diferencia hay entre un token y una palabra en un LLM?
Un token es la unidad mínima que el modelo recibe y procesa: puede ser un carácter, varios caracteres, una sílaba, una palabra completa o incluso un fragmento de palabra con un espacio delante. Una palabra es una unidad lingüística delimitada por espacios o puntuación, no una unidad computacional. Como BPE construye el vocabulario a partir de fragmentos frecuentes, una palabra rara o larga puede dividirse en varios tokens, mientras que una palabra muy común puede ser un solo token. Por eso el conteo de tokens casi nunca coincide con el conteo de palabras.
¿Cómo decide BPE qué par de caracteres fusionar primero?
El algoritmo parte de un corpus de entrenamiento, cuenta la frecuencia de cada par de símbolos adyacentes y fusiona siempre el par más frecuente, sustituyéndolo por un símbolo nuevo que entra al vocabulario. Luego repite el proceso sobre el texto ya actualizado, recalculando los pares en cada iteración. El número de fusiones es un hiperparámetro: se detiene cuando se alcanza el tamaño de vocabulario deseado. Es un criterio puramente estadístico, no lingüístico: gana la frecuencia, no la "utilidad" gramatical.
¿Por qué un texto en español puede gastar más tokens que en inglés?
El vocabulario de la mayoría de los tokenizadores se entrena con corpus donde el inglés domina, así que las palabras inglesas frecuentes suelen quedar como tokens únicos. El español tiene palabras más largas, morfología flexiva rica (género, número, conjugaciones) y una ortografía con tildes y eñes que fragmenta más los términos. El resultado típico: una misma idea expresada en español tiende a ocupar más tokens que en inglés, aunque la proporción exacta varía según el tokenizador y el texto. Como estimación razonable, en textos comparables el español puede consumir del orden de un 15 % a un 30 % más de tokens; verifícalo siempre con el tokenizador concreto que vayas a usar.
¿Qué pasa con los emojis y los números al tokenizar con BPE?
Los emojis suelen descomponerse en varios tokens porque están codificados en UTF-8 como secuencias de bytes, y muchos tokenizadores operan sobre bytes o sobre fragmentos poco frecuentes en el corpus de entrenamiento. Los números son un caso especialmente irregular: "2024" puede ser un token, y "20245" puede partirse en "202" + "45" o en dígitos sueltos, lo que afecta a tareas aritméticas y a la consistencia del formato. En general, cuanto menos frecuente sea el patrón en el corpus, más fragmentos generará.
¿Cómo afecta el número de tokens al coste de la API?
El coste se factura por tokens, no por palabras ni por caracteres, así que un texto que se fragmenta en más tokens cuesta más aunque ocupe lo mismo en pantalla. Esto afecta a la entrada (el prompt que envías) y a la salida (lo que genera el modelo), y en modelos con ventana de contexto limitada también reduce cuánto texto cabe. La palanca práctica: medir los tokens con el tokenizador del modelo que uses antes de enviar lotes grandes, y evitar redundancias en los prompts. Las tarifas concretas cambian con el tiempo y el proveedor, así que consúltalas en su documentación vigente en lugar de asumir una cifra fija.