domingo, 14 de junio de 2026

DATOS. Tratamiento de datos

Datos no estructurados (VII)

Reconocimiento de entidades (NER) (VI)

Finalizaba la entrada anterior planteando la existencia de alternativas al modelo heurístico por pipeline híbrido, las cuales se concretan en varias opciones teóricas según vimos anteriormente). En realidad, esas opciones son eso, más teóricas que reales, ya que ni la basada en ML clásico ni la basada en DL discriminativo son realmente viables en función de las restricción reales de datos (confidencialidad, dificultad para conseguir los datos suficientes y coste del etiquetado) ni de hardware (limitaciones de procesamiento y de memoria) que puede afrontar un organismo con escasos recursos como es un SEO. La consecuencia es que sólo es viable la opción basada en IA generativa, pero únicamente la que se puede correr en local, lo que conlleva, además, una limitación en cuanto a los modelos de lenguaje a emplear, que no son otros que los modelos pequeños o SLM. Pero lo que esto no garantizada a priori es la viabilidad real y funcional del modelo IA local.

En consecuencia, la única alternativa viable es la IA generativa ejecutada en local. Esto conlleva, además, una restricción en los modelos de lenguaje a emplear, reduciéndolos a modelos pequeños o SLM. No obstante, esta viabilidad técnica no garantiza, a priori, la eficacia funcional del modelo de IA local para resolver un determinado problema. En el contexto de esta entrada y de las que la preceden, el problema a resolver es (sigue siendo) la extracción de las NER de un texto sintético que ya nos es conocido.

Como tendremos ocasión de comprobar en esta entrada, en la práctica pretender replicar la competencia de un LLM comercial online mediante el simple prompting de un SLM local es una vía infructuosa; las limitaciones en la capacidad de atención y la baja densidad de parámetros de estos modelos pequeños afectan radicalmente a su precisión en el desempeño de tareas como la extracción de datos a partir de un texto no estructurado. Por tanto, alcanzar una equivalencia funcional exige un cambio estructural en el procedimiento. Dado que el modelo en la nube queda descartado por motivos estrictos de confidencialidad, la solución real no radica en el aislamiento del modelo de lenguaje, sino en el diseño de una arquitectura híbrida: un pipeline robusto donde un modelo heurístico asuma la segmentación previa y la estructuración del texto, delegando en el SLM únicamente la extracción fina allí donde las reglas rígidas no alcanzan. El éxito, en consecuencia, pasa de depender de la potencia del modelo a depender de la inteligencia del proceso.

Dado que el tema requiere mucho más espacio del que podemos darle en esta entrada atendiendo a su propia finalidad, no me voy a detener en explicar qué es Ollama y cómo hemos llegado hasta el punto en que somos capaces de utilizar un modelo pequeño de lenguaje SLM como herramienta de trabajo; simplemente lo damos por ahora como un hecho , aunque nos tengamos que detener en algún detalle a la hora de explicar el funcionamiento del script.



# 0. Implementamos las bibliotecas necesarias: json, ollama, pydantic y typing

import json
from ollama import chat
from pydantic import BaseModel, Field
from typing import List

# 1. Definimos el esquema de salida esperado usando pydantic

class EntidadExtraida(BaseModel):
    texto: str = Field(description="El fragmento de texto exacto tal como aparece en el documento original.")
    etiqueta: str = Field(
        description=(
            "La categoría de la entidad. Debe ser una de las siguientes: "
            "'ALUMNO', 'ROL_PROFESIONAL', 'CENTRO_EDUCATIVO', 'UBICACION', "
            "'FAMILIAR', 'FECHA', 'ORGANISMO', 'APLICATIVO'."
        )
    )

class ResultadoNER(BaseModel):
    entidades: List[EntidadExtraida]

# 2. Entregamos el documento a procesar (obtener NER)

texto_analizar = (
    "El alumno Alejandro Martínez Soler, escolarizado en 4º de Primaria del CEIP San Juan Bautista "
    "de Oviedo, presenta dificultades de adaptación significativas. La tutora, Doña Carmen Villalobos, "
    "informa de que tras la reunión mantenida el pasado martes 12 de mayo con la madre del menor, "
    "La Sra. Elena Soler, no se ha observado mejoría en el aula. El Equipo de Orientación Educativa "
    "(EOEP) ha sido notificado por el Director del centro, Don Roberto Pando, clasificando el expediente "
    "como intervención prioritaria. Se ha solicitado formalmente la colaboración del Servicio de Salud "
    "del Principado de Asturias (SESPA) para coordinar la valoración psiquiátrica del menor antes "
    "del viernes 19 de junio. Nota: Toda la documentación clínica de Alejandro ha sido archivada en "
    "el aplicativo institucional SAECE según el protocolo de la Consejería de Educación."
)

print("Enviando petición a llama3.2:3b...")

# 3. Llamada a Ollama utilizando salida estructurada (en el paso 1). Incluye la llamada al SLM y el prompt

response = chat(
    model='llama3.2:3b',
    messages=[
        {
            'role': 'system',
            'content': (
                "Eres un asistente experto en procesamiento del lenguaje natural especializado en el ámbito educativo. "
                "Tu tarea es realizar Reconocimiento de Entidades Nombradas (NER) sobre el texto proporcionado. "
                "Extrae únicamente las entidades literales que correspondan a estas categorías estrictas:\n"
                "- ALUMNO: Nombre del estudiante.\n"
                "- ROL_PROFESIONAL: Cargos, puestos o figuras docentes/técnicas (ej. tutora, Director, Equipo de Orientación Educativa, EOEP).\n"
                "- CENTRO_EDUCATIVO: Nombres de colegios o institutos.\n"
                "- UBICACION: Ciudades, municipios o provincias.\n"
                "- FAMILIAR: Nombres de padres, madres o tutores legales.\n"
                "- FECHA: Referencias temporales explícitas.\n"
                "- ORGANISMO: Entidades públicas, servicios de salud o consejerías.\n"
                "- APLICATIVO: Software, plataformas web o bases de datos institucionales.\n"
                "Sé riguroso y extrae solo texto literal, sin omitir ni inventar nada."
            )
        },
        {
            'role': 'user',
            'content': f"Analiza el siguiente texto:\n\n{texto_analizar}"
        }
    ],
    format=ResultadoNER.model_json_schema(), # Forzamos la estructura JSON mediante el esquema de Pydantic
    options={'temperature': 0.0}  			 # Forzamos a literalidad tratsando de evitar alucinaciones
)

# 4. Procesar y mostrar el resultado

try:
    datos_extraidos = json.loads(response.message.content)
    print("\n--- Entidades Detectadas por llama3.2:3b ---")
    print(json.dumps(datos_extraidos, indent=4, ensure_ascii=False))
except Exception as e:
    print(f"Error al parsear la respuesta: {e}")
    print("Respuesta cruda del modelo:", response.message.content)


Dentro de este script podemos identificar varias partes, empezando por las bibliotecas necesarias para su funcionamiento: json, ollama, pydantic y typing. Cada una de ellas aporta componentes fundamentales para el logro del objetivo propuesto: ollama proporciona el canal de comunicación con el modelo SLM, que es el encargado de leer y "comprender" el documento, pero las demás contribuyen determinando el correcto funcionamiento de éste para que el análisis y la salidad se ajuste estrictamente al objetivo.

El esquema de funcionamiento del script queda descrito por el orden de acciones que se recogen en los comentarios:

  • Primero definimos qué queremos obtener y cómo mediante pydantic y typing
  • Despues porporcionamos el material (texto o conjunto de datos no estructurados) sobre el que trabajar
  • En tercer lugar implementamos el SLM y el instrumento que permite la comunicación entre con él (Ollama), precisamente en orden inverso. En este punto se acoplan las directrices de rol del system prompt con el esquema JSON derivado de Pydantic, fijando la temperatura en 0.0 para garantizar el determinismo absoluto de la prueba.
  • finalmente procesamos los resultados y los mostramos en la consola, controlando cualquier posible error mediante una estructura try...except.

Una breve nota aclaratoria sobre el uso de una herramienta de IA como es Ollama dentro de este script, sin más pretensiones. El uso de un servicio Chat de IA generativa, como Gemini o Chat-GPT, puede dar a entender que esa es, si no la única, sí la principal forma de utilizar la IA, pero lo cierto es que existen otras formas que pasan por integrarla dentro de un script de Python (por ejemplo). Y esto es precisamente lo que hemos hecho en el script anterior; algo que, como podemos observar, resulta muy fácil de realizar en Python al contar con bibliotecas específicas, en nuestro caso from ollama import chat .

En sentido estricto y sumamente restringido, import ollama y...



response = chat(
    model='llama3.2:3b'
    

... son las instrucciones que hacen posible que usemos Ollama response = chat( y el SLM seleccionado model='llama3.2:3b', al que sigue el prompt, que es fundamental para su implementación. Este prompt debe ajustarse a una redacción concreta, ya que de ella depende el funcionamiento efectivo del SLM. Esto es válido también para los LLM, pero aun más para un SLM, dadas sus características y limitaciones respecto a sus hermanos mayores. El prompt que implementamos en este script se puede considerar ajustado a esos condicionantes.



response = chat(
    model='llama3.2:3b',
    messages=[
        {
            'role': 'system',
            'content': (
                "Eres un asistente experto en procesamiento del lenguaje natural especializado en el ámbito educativo. "
                "Tu tarea es realizar Reconocimiento de Entidades Nombradas (NER) sobre el texto proporcionado. "
                "Extrae únicamente las entidades literales que correspondan a estas categorías estrictas:\n"
                "- ALUMNO: Nombre del estudiante.\n"
                "- ROL_PROFESIONAL: Cargos, puestos o figuras docentes/técnicas (ej. tutora, Director, Equipo de Orientación Educativa, EOEP).\n"
                "- CENTRO_EDUCATIVO: Nombres de colegios o institutos.\n"
                "- UBICACION: Ciudades, municipios o provincias.\n"
                "- FAMILIAR: Nombres de padres, madres o tutores legales.\n"
                "- FECHA: Referencias temporales explícitas.\n"
                "- ORGANISMO: Entidades públicas, servicios de salud o consejerías.\n"
                "- APLICATIVO: Software, plataformas web o bases de datos institucionales.\n"
                "Sé riguroso y extrae solo texto literal, sin omitir ni inventar nada."
            )
        },
        {
            'role': 'user',
            'content': f"Analiza el siguiente texto:\n\n{texto_analizar}"
        }
    ],
    

A priori, este diseño satisface los niveles de exigencia del prompting para trabajar con modelos de lenguaje:

  • Asignación de rol que ayuda al modelo a, probabilísticamente, "acotar" el vocabulario y entender el contexto institucional.
  • Instrucciones de restricción rigurosas mediante el uso de palabras ("únicamente", "categorías estrictas" y "solo texto literal, sin omitir ni inventar nada") que actuan como barreras efectivas contra las alucinaciones.
  • Taxonomía con ejemplos In-line, como en ROL_PROFESIONAL, donde se incluyen ejemplos del dominio (tutora, Director, EOEP), lo que permite acotar entidades (v.g. identificar si "Equipo de Orientación" es un rol o un organismo).

Hagamos ahora un sencillo ejercicio de comparación entre lo que nos revuelve el uso de este prompt con Gemini y su LLM...

ALUMNO: Alejandro Martínez Soler
ROL_PROFESIONAL: tutora, Carmen Villalobos, Equipo de Orientación Educativa, EOEP, Director, Roberto Pando
CENTRO_EDUCATIVO: CEIP San Juan Bautista
UBICACION: Oviedo
FAMILIAR: Elena Soler
FECHA: martes 12 de mayo, viernes 19 de junio
ORGANISMO: Servicio de Salud del Principado de Asturias, SESPA, Consejería de Educación
APLICATIVO: SAECE

... y el resultado de su empleo con Ollama + llama3.2:3b

- ALUMNO: Alejandro Martínez Soler
- ROL_PROFESIONAL:
* Tutora: Doña Carmen Villalobos
* Director: Don Roberto Pando
* Equipo de Orientación Educativa (EOEP)
- CENTRO_EDUCATIVO: CEIP San Juan Bautista de Oviedo
- UBICACION: Oviedo
- FAMILIAR:
* Elena Soler (madre del alumno)
* FECHA:
* pasado martes 12 de mayo
* viernes 19 de junio
- ORGANISMO: Servicio de Salud del Principado de Asturias (SESPA)
- APLICATIVO: SAECE

Resulta muy interesante comprobar que el modelo LLM no consigue mejores resultados que el SLM en la tarea propuesta (NER) y sobre un texto plano; esto refuerza la idea de que hoy en día es posible obtener buenos resultados en según que tareas trabajando con modelos pequeños en local, lo que hace posible desarrollar proyectos con estas tecnologías con confianza en los resultados que podemos obtener, facilitando así dar respuesta a condicionantes como son los derivados de la privacidad. no obstante estos modelos no son superiores, ni siquiera iguales, a los LLM en cuanto la tarea se complica o entramos en contextos más extensos o interconectados. Pero cada cosa a su tiempo. De momento nos podemos quedar con lo que hasta ahora nos resulta útil: para un NER, un SLM corriendo en local puede que no tenga mucho que envidiar a un LLM... incluso es posible que se inviertan los papeles...

Pero veamos qué obtenemos al aplicar nuestro script:

{
"entidades": [
{
"texto": "Alejandro Martínez Soler",
"etiqueta": "ALUMNO"
},
{
"texto": "Doña Carmen Villalobos",
"etiqueta": "ROL_PROFESIONAL"
},
{
"texto": "La Sra. Elena Soler",
"etiqueta": "FAMILIAR"
},
{
"texto": "Don Roberto Pando",
"etiqueta": "ROL_PROFESIONAL"
},
{
"texto": "CEIP San Juan Bautista de Oviedo",
"etiqueta": "CENTRO_EDUCATIVO"
},
{
"texto": "Oviedo",
"etiqueta": "UBICACION"
},
{
"texto": "SEPA",
"etiqueta": "ORGANISMO"
},
{
"texto": "SAECE",
"etiqueta": "APLICATIVO"
}
]
}

Es de destacar el cambio formal que se ha producido, ya que pasamos de un listado estructurado de elementos a la expresión formal de una estructura JSON. Pero además también podemos comprobar cómo el mismo SLM que antes extraía los datos solicitados, ahora comete muchos más errores y omisiones. La explicación hay que buscarla en la naturaleza del modelo (y sus limitaciones) enfrentada a las exigencias de la tarea: al ser texto y prompt los mismos, la diferencia estriba en la exigencia de devolver una estructura que obliga a prestar atención a muchos detalles de forma como es un JSON. Ante todo ello, un modelo pequeño de lenguaje es incapaz de ofrecer una respuesta de calidad, la misma que sí puede ofrecer si no se le exige más allá de sus posibilidades. Esto abre una segunda vía de trabajo o, si se prefiere, un diseño en el que el código Python se complemente eficientemente con la IA.

Hasta aquí esta entrada, que evidentemente queda inconclusa. Lo que resta, que no es poco, para la próxima.

NOTAS
1 Puede que sea necesario dedicar una entrada al tema, pero diré que, más por cacharrear que por otra cosa, lo cierto es que tengo instalado Ollama en mi ordenador y con este servicio una serie de modelos. La instalación de Ollama no supone ninguna dificultad y la instalación de los modelos tampoco, así que me voy a ahorrar en estos momentos.
2 Según Gemini, en sentido estricto, Ollama es un entorno de ejecución (runtime) y un gestor de modelos ligero y de código abierto, diseñado para empaquetar, desplegar y ejecutar Modelos de Lenguaje (LLMs y SLMs) de forma local. No es un modelo de inteligencia artificial en sí mismo, sino la infraestructura que permite interactuar con ellos sin dependencia de servicios en la nube.

No hay comentarios:

Publicar un comentario

Comenta esta entrada