Saltar al contenido

lección 7

Etiquetar texto con un modelo de lenguaje

Seiscientos avisos de vecinos sin etiquetar: cómo se le pide a un modelo de lenguaje que los clasifique, qué no se le puede mandar y por qué no te fías hasta medir cuánto coincide con una persona.

⏱ 30 min

En marzo de 2023, tres politólogos de la Universidad de Zúrich, Fabrizio Gilardi, Meysam Alizadeh y Maël Kubli, hicieron una prueba que cualquiera habría querido hacer. Tenían miles de tuits y de noticias que un equipo de personas formadas ya había etiquetado a mano —de qué tema hablaba cada uno, si estaba a favor o en contra— y le pidieron lo mismo a ChatGPT. De media, el modelo acertó unos 25 puntos más que los trabajadores que se contratan por internet para etiquetar, y cada etiqueta costó menos de 0,003 dólares: unas treinta veces menos. El artículo salió publicado en PNAS y se convirtió en la cita que todo el mundo usa para justificar que ya no hace falta etiquetar a mano.

Lo que casi nadie cita es la otra mitad de sus tablas. En la tarea más sencilla, decidir si un texto hablaba del tema o no, el acierto fue del 83 % en un conjunto de datos y del 59 % en otro: la misma herramienta, la misma pregunta, veinticuatro puntos de diferencia. Y los propios autores dejan como pregunta abierta cómo funciona en otros idiomas. Es decir: funciona, pero no sabes cuánto funciona en tu caso hasta que lo mides en tu caso. Esa frase es la lección entera.

Hasta aquí todas las columnas que has arreglado tenían un tipo que se podía comprobar: un importe es un número o no lo es, una fecha existe o no existe. Pero en casi cualquier tabla que venga de personas hay una columna que no tiene tipo que arreglar: el texto libre. El aviso que escribe un vecino, el comentario de una encuesta, la descripción de una incidencia. Ahí está casi siempre la información buena, y es justo la que no se puede agrupar ni contar hasta que alguien le pone una etiqueta.

## Qué es un modelo de lenguaje, en llano

Un modelo de lenguaje es un programa que lee un texto y devuelve otro texto. Se llama así porque se ha construido leyendo cantidades enormes de texto escrito por personas hasta aprender a continuar cualquier frase de forma verosímil. Los que se usan hoy son tan grandes que en inglés se les llama LLM, de large language model, «modelo de lenguaje grande». Tú le escribes «¿de qué trata este aviso: la farola de la plaza lleva una semana apagada?» y te contesta «alumbrado», porque es la continuación más verosímil de esa pregunta.

Para lo que vas a hacer con él, quédate con tres consecuencias de esa definición. La primera: devuelve texto, no una categoría. Si le pides que elija entre nueve categorías, lo normal es que conteste una de ellas, pero nada le impide contestar «Alumbrado.» con mayúscula y punto, «farolas», o una frase entera explicando su razonamiento. La segunda: no dice «no lo sé» a menos que le dejes; si le obligas a elegir, elige, y lo hace con el mismo aplomo cuando acierta que cuando se lo inventa. La tercera: la misma pregunta dos veces puede dar dos respuestas distintas, porque al escribir elige entre varias continuaciones posibles con algo de azar. Ese azar se regula con un mando que se llama temperatura: con la temperatura baja repite casi siempre lo mismo. En el estudio de Zúrich, el modelo coincidía consigo mismo el 91 % de las veces con temperatura 1 y el 97 % con temperatura 0,2.

Y una aclaración sobre esta lección, para que no haya malentendidos: aquí no vas a hablar con ningún modelo. Usar uno de verdad exige una cuenta de pago con una empresa y una clave que no se puede poner en una página web. Lo que sí vas a hacer es lo que hace la persona que trabaja con él: escribir la instrucción, preparar lo que se manda, y medir lo que vuelve. Las respuestas del modelo vienen ya escritas en los datos de cada ejercicio, igual que te llegarían en una columna después de una llamada real.

## Cómo se le pide que etiquete

A lo que le escribes al modelo se le llama instrucción; en inglés, prompt. Para etiquetar, una buena instrucción es corta y tiene cuatro piezas, y cada una existe para evitar un problema concreto de los tres de arriba:

  1. 01.La lista cerrada de categorías, escritas exactamente como las quieres de vuelta. Mejor como códigos sin tildes ni espacios (limpieza_viaria, alumbrado) que como frases. Así la respuesta se puede comparar con la lista con una línea de código, y si llega «farolas» sabes al momento que se ha salido.
  2. 02.Una sola categoría por aviso. Si dejas que elija dos, tendrás avisos que cuentan dos veces y porcentajes que suman más de cien.
  3. 03.Qué contestar si no sabe: «dudoso». Es la pieza que más se olvida y la que más importa. Sin ella, el modelo clasifica también el aviso que dice «ver foto» o el que mezcla una farola y un bache, y esas respuestas inventadas se cuelan en tus cifras con el mismo aspecto que las buenas.
  4. 04.Que responda solo con la categoría, sin explicar. Lo que vuelve lo va a leer un programa, no una persona.
1Eres un asistente que clasifica avisos de vecinos para un consorcio de servicios municipales.
2Lee el aviso y responde con una sola categoría de esta lista, escrita exactamente igual:
3limpieza_viaria
4recogida_residuos
5alumbrado
6baches_y_aceras
7parques_y_jardines
8agua_y_alcantarillado
9ruido
10trafico_y_aparcamiento
11animales
12Si el aviso no encaja claramente en ninguna, o habla de dos cosas a la vez, responde dudoso.
13Responde solo con la categoría, sin explicaciones.

Una instrucción para etiquetar: corta, cerrada y con salida para lo que no está claro.

Aun con la mejor instrucción, la respuesta hay que comprobarla, porque sigue siendo texto. La comprobación es la misma idea que el mapa de los booleanos de «Tipos que mienten»: enumerar lo que aceptas y mirar lo que se queda fuera, en vez de convertir a ciegas.

1import pandas as pd
2
3CATEGORIAS = ["limpieza_viaria", "recogida_residuos", "alumbrado",
4 "baches_y_aceras", "parques_y_jardines", "agua_y_alcantarillado",
5 "ruido", "trafico_y_aparcamiento", "animales"]
6VALIDAS = CATEGORIAS + ["dudoso"]
7
8respuestas = pd.Series(["alumbrado", "baches_y_aceras", "Alumbrado.",
9 "dudoso", "farolas", "limpieza_viaria"])
10
11fuera = respuestas[~respuestas.isin(VALIDAS)]
12print("Respuestas fuera de la lista:", len(fuera), "->", fuera.tolist())

Lo que vuelve del modelo se valida contra la lista antes de contar nada.

## Por lotes, y lo que cuesta

Nadie pega seiscientos avisos uno a uno en una ventana de chat. Se hace por lotes: un programa recorre la tabla, manda cada aviso junto a la instrucción, recibe la respuesta y la guarda en una columna nueva al lado del identificador del aviso. Ese identificador es lo que permite, al volver, saber de qué fila era cada respuesta.

Y cada llamada se paga. Estas empresas cobran por cantidad de texto, contando lo que mandas y lo que te devuelven. La unidad se llama token, que es un trozo de palabra: en castellano, una palabra corta es un token y una larga, dos o tres. Lo importante es la consecuencia: el coste crece en línea recta con el número de avisos, y la instrucción se paga entera con cada uno de ellos. Con la cifra del estudio de Zúrich, menos de 0,003 dólares por etiqueta en 2023, seiscientos avisos cuestan menos de dos dólares. Seiscientos mil, cerca de dos mil, y eso ya es una partida que alguien tiene que aprobar, sobre todo si la clasificación se repite cada mes.

Consejo de senior: antes de mandar el lote grande, manda veinte avisos y míralos con tus ojos. Cuesta céntimos y caza los errores de la instrucción (una categoría mal escrita, una respuesta que llega con punto final) antes de pagarlos seiscientos mil veces. Y apunta en algún sitio la fecha, el modelo y la instrucción exacta que usaste: los precios y los propios modelos cambian cada pocos meses, y dentro de un año nadie sabrá con qué se etiquetó esa columna si no lo dejaste escrito.

## Qué se puede mandar fuera y qué no

Ahora mira la tabla de avisos tal como sale del sistema del consorcio: identificador del aviso, nombre del vecino, su teléfono, su dirección, el municipio y el texto. Cuando mandas un aviso a un modelo de lenguaje, se lo estás mandando a otra empresa, a sus servidores, fuera de tu organización. Y el nombre, el teléfono y la dirección de un vecino son datos personales.

El Reglamento General de Protección de Datos (RGPD), la ley europea que regula esto, dice dos cosas que aquí se aplican directamente. La primera es que solo se tratan los datos necesarios para lo que se quiere hacer: es el principio de minimización. Para decidir si un aviso habla de una farola no hace falta saber quién lo escribió ni dónde vive. La segunda es que, cuando otra empresa trata datos personales por cuenta de tu organización, tiene que haber un contrato de encargado del tratamiento: un contrato en el que esa empresa se compromete por escrito a usar los datos solo para el encargo, a protegerlos y a borrarlos al terminar. Un consorcio público no manda los datos de sus vecinos a una empresa de fuera sin ese contrato, y si la empresa está fuera de la Unión Europea, hay reglas añadidas.

La salida práctica casi siempre es la misma, y es la más sencilla: mandar solo lo que la tarea necesita. El texto, para clasificarlo, y el identificador del aviso, que es un número interno que fuera no significa nada y que te permite casar la respuesta con su fila al volver. El nombre, el teléfono, la dirección y hasta el municipio se quedan en casa.

Tres de las cinco columnas no cruzan la línea. Y lo que vuelve trae el mismo aviso_id que salió: por eso se manda, y por eso no hace falta mandar nada más.

Hay una trampa que el dibujo no enseña y que hay que tener presente: quitar columnas no limpia el texto. Un vecino escribe «contenedor desbordado, llamadme al 964201030» o «soy la vecina del tercero B de la calle Mayor, 12», y el dato personal viaja dentro del aviso aunque hayas borrado la columna del teléfono. Los teléfonos, que tienen una forma fija, se pueden tapar con una expresión regular, que es un patrón de texto: el de abajo busca nueve cifras seguidas que empiecen por 6, 7, 8 o 9.

1import pandas as pd
2
3avisos = pd.DataFrame({
4 "aviso_id": [101, 102, 103],
5 "nombre": ["Marta Gil", "Josep Ribes", "Ana Soler"],
6 "telefono": ["612345678", "964201030", "699887766"],
7 "direccion": ["C/ Mayor 12", "Av. del Mar 3", "Pl. Nova 1"],
8 "texto": ["La farola de la plaza lleva una semana apagada",
9 "Contenedor desbordado, llamadme al 964201030",
10 "Bache enorme delante del colegio"],
11})
12
13# 1. Se manda solo lo que la tarea necesita: el id (para casar la respuesta) y el texto
14envio = avisos[["aviso_id", "texto"]].copy()
15
16# 2. El texto también puede llevar un dato personal dentro: se tapa
17envio["texto"] = envio["texto"].str.replace(r"\b[6-9]\d{8}\b", "[telefono]", regex=True)
18
19print(envio.to_string(index=False))

Primero se eligen las columnas; después se mira dentro del texto.

Que el modelo «no guarde nada» no te lo dice el modelo: te lo dice un contrato. Las condiciones de uso de estos servicios cambian, y lo que se manda por la versión gratuita de una aplicación de chat no tiene las mismas garantías que lo que se manda por un servicio contratado. Si en la tabla hay datos de personas, la pregunta no es técnica y no la decides tú solo: se hace antes de mandar el primer aviso, no después.

## Antes de fiarte: mide cuánto coincide con una persona

Ya tienes una columna con seiscientas etiquetas. Tienen muy buena pinta, y precisamente por eso no te las puedes creer todavía: un resultado bueno es una hipótesis, no una conclusión. La forma de ponerlo a prueba es la que usaron en Zúrich: una persona etiqueta a mano una parte de los mismos avisos y se compara su etiqueta con la del modelo, aviso por aviso.

Tres detalles deciden si esa comparación vale algo. Los avisos de la muestra se eligen al azar, no los primeros de la tabla ni los que parecen fáciles. La persona etiqueta sin ver lo que dijo el modelo: si lo ve, tiende a darle la razón, y el acuerdo sale inflado justo en los casos difíciles, que son los que importan. Y a lo que sale se le llama acuerdo, no acierto, porque la persona también se equivoca; lo que mides es cuánto se parecen dos formas de etiquetar, una de las cuales es la que ya usabais.

El número que sale se lee como cualquier cifra de acierto: contra una línea base. Si en tu muestra el 27 % de los avisos son de baches, etiquetarlos todos como baches daría un 27 % de acuerdo sin leer ni uno. Un 82 % no se compara con el cero ni con el cien: se compara con ese 27 %, y con lo que dé la forma barata que haya a mano, como una regla de palabras clave («si dice farola, es alumbrado»). Existe una medida que descuenta el acuerdo que saldría por puro azar, la kappa de Cohen, pero la idea es la misma y comparar con la línea base te la da sin fórmulas.

1import pandas as pd
2
3muestra = pd.DataFrame({
4 "persona": ["ruido", "ruido", "animales", "animales", "ruido", "animales"],
5 "modelo": ["ruido", "animales", "animales", "animales", "ruido", "dudoso"],
6})
7
8acuerdo = (muestra["persona"] == muestra["modelo"]).mean()
9print(f"Acuerdo: {acuerdo:.0%}")
10print(pd.crosstab(muestra["persona"], muestra["modelo"]).to_string())

El porcentaje dice cuánto coinciden; la tabla cruzada dice dónde no.

De las dos salidas, la que hace trabajar es la tabla. El porcentaje te dice si el modelo sirve en general; la tabla te dice en qué no sirve, y casi nunca falla por igual en todo. Lo normal es que acierte de sobra en las categorías que tienen palabras propias (una farola es alumbrado se diga como se diga) y se confunda en las que comparten vocabulario: un contenedor desbordado con bolsas por el suelo, ¿es limpieza de la calle o recogida de residuos? Esas fronteras son las que hay que mirar.

Los desacuerdos no están repartidos: se amontonan en un rincón. Alumbrado y baches casi no fallan; limpieza y residuos se confunden en las dos direcciones, y ahí van también casi todos los dudosos.

Ese rincón es una decisión, no una curiosidad. Puedes afinar la instrucción con una línea sobre la frontera entre las dos categorías y volver a medir; puedes juntarlas si a efectos prácticos las atiende el mismo servicio; o puedes aceptar que en esas dos el modelo no basta y que una persona las revise. Lo que no puedes hacer es publicar el 83 % general como si valiera para todas, porque para limpieza y residuos no vale.

Lo que la muestra no tiene, la muestra no lo mide. Si en tus avisos hay un 27 % escritos en valenciano y la persona solo etiquetó avisos en castellano, el 83 % no dice nada de los otros: el estudio de Zúrich deja precisamente el rendimiento en otros idiomas como pregunta abierta. El acuerdo se mide en cada trozo de la población donde lo vayas a usar, y para el que no esté en la muestra no hay cifra.

## Lo dudoso va a una persona

La última pieza es la que convierte el experimento en algo que se puede usar un lunes. No se trata de elegir entre «lo hace el modelo» y «lo hace una persona»: se trata de repartir. El Ayuntamiento de Girona lo hace así desde octubre de 2024 con las instancias genéricas que le llegan por la sede electrónica. Su sistema, un modelo de aprendizaje automático, lee el texto de cada solicitud y devuelve la unidad que debería atenderla junto con una probabilidad de acertar. Si la probabilidad pasa del 60 %, la solicitud se asigna sola; si no, va a la oficina de registro y la clasifica una persona. Con eso se reparte automáticamente el 86 % de las instancias. Y antes de dejarlo funcionar solo, lo tuvieron un tiempo trabajando en paralelo con la clasificación a mano, para comparar los dos resultados: exactamente la medida de acuerdo de esta lección.

Un modelo de lenguaje no da una probabilidad tan cómoda como la de Girona, pero tú ya le has dado las herramientas para decir que no está seguro. Lo que va a una persona sale de cuatro sitios: lo que el modelo contestó «dudoso», lo que contestó fuera de la lista, lo que cae en las categorías donde la muestra dio un acuerdo bajo y lo que la muestra no cubrió. Todo lo demás se reparte solo.

Fíjate en qué ocupa la parte de la persona: no es el «dudoso», es la frontera entre dos categorías. Afinar la instrucción en ese punto ahorra más trabajo que cualquier otra cosa.

Y el reparto no se fija una vez para siempre. Lo que revisa la persona es, gratis, una muestra nueva para medir el acuerdo otra vez; si un mes cambia el formulario, o empiezan a llegar avisos de un tipo nuevo, es ahí donde se nota primero. Un sistema así no se entrega y se olvida: se deja con su forma de vigilarse puesta.

  • Una instrucción corta, con la lista cerrada, una sola etiqueta y la salida «dudoso». Y la respuesta se valida contra la lista antes de contar nada.
  • Solo sale lo que la tarea necesita. El identificador y el texto; los datos personales se quedan, y lo que viaja dentro del texto también se mira.
  • No te fías hasta medir el acuerdo con una persona, en una muestra al azar, a ciegas y contra una línea base. La tabla cruzada te dice dónde no sirve.
  • Lo dudoso, lo raro y lo no medido va a una persona. El modelo reparte lo fácil y una persona se queda con lo difícil, que es donde está el trabajo de verdad.

Con esto, hasta la columna de texto libre tiene ya una etiqueta que se puede contar, y sabes cuánto fiarte de ella. Has visto los problemas de una tabla de uno en uno, cada uno en su lección y con datos pequeños: lo que falta, lo repetido, lo que se sale, el tipo que miente y el texto que nadie había leído. Una tabla de verdad los trae todos mezclados, y la pregunta que queda es en qué orden se tocan y qué hay que dejar escrito en cada paso.

Regístrate para guardar tu progreso.