Procedimientos basados en IA
Pretendo finalizar con esta entrada el tratamiento de los archivos como datos, paso previso al acceso al contenidos o conjunto de datos que contiene el archivo. Llamaré documento a ese contenido. Dar este paso requiere resolver previamente dos cuestiones: de la primera nos ocupamos a continuación y de la segunda nos ocuparemos en las entradas que siguen y que tratan del acceso a diferentes tipos de archivos, emplezando por la diferenciación entre datos ordenados y datos no ordenados, y siguiendo por las tecnologías específicas para acceder a diferentes tipos de documentos. Sólo cuando hayamos realizado este recorrido podremos ocuparnos en detalle de los procedimientos de identificación y captación del contenido documental. Un largo camino por recorrer.
Volviendo a lo que nos interesa ahora, lo que aporta la IA no puede pasar desapercibido, pero tengo que decir que no porque sea especialmente relevante para la problemática que ahora nos ocupa. De hecho puede considerarse una solución más costosa y menos fucional que algunas de las ya expuestas; pero esto no quita para que debamos hablar de ella.
Y debemos hacerlo por dos motivos: el primero para aclarar una cuestión de gran interés que será motivo de reflexión en detalle en otras entradas (de otra sección), y que tiene que ver más bien con las limitaciones: hoy por hoy no es posible utilizar los modelos IA on-line con documentos confidenciales o que aporten información confidencial, por lo que sólo podremos usar soluciones off-line, que son mucho más limitadas en sus funcionalidades y rendimientos. Y esta es la segunda cuestión, que las opciones IA realmente disponibles no son nesariamente mejores soluciones que las que ya hemos planteado, aunque interese conocerlas. De eso se trata aquí y ahora.
Realmente para que este contenido sea de provecho es necesario que desarrolle varias entradas en las que explique los recursos de los que voy a hacer uso ahora, pero por una vez vamos a saltarnos el orden lógico de las cosas y ofrecer soluciones que ya deberían haber sido explicadas con cierto detalle. Pido disculpas por todo ello y espero que lo que expongo por adelantado sirva para despertar el interés de los profesionales de los SEO.
Parto de tener instalada una IA en local (yo concretamente Ollama), así como determinados modelos (en mi caso los siguientes: mxbai-embed-large:latest (embeding), deepseek-r1:1.5b, qwen2.5-coder:3b, llama3.2:3b y gemma3:1b como slm)
En esta entrada no voy a hacer mucho más que mostarte los dos script que he trabajo con IA-Gemini. Primero el modelo embeding...
#Bibliotecas necesarias --------------------------------------------
import ollama
import numpy as np
import psutil # Para gestionar el cierre del proceso
import os
import signal
# --- CONFIGURACIÓN de ollama ---------------------------------------
MODELO_EMBEDDING = 'mxbai-embed-large'
archivos = [
"2023_SISE_Final.pdf",
"PTSC_Informe_v1.docx",
"Seguimiento_PSC.xlsx",
"Vacaciones.jpg"
]
busqueda = "Informe Seguimiento PTSC"
# --- FUNCIONES -------------------------------------------------------
def obtener_embedding(texto):
try:
resultado = ollama.embed(model=MODELO_EMBEDDING, input=texto)
return resultado['embeddings'][0]
except Exception as e:
print(f"Error al conectar con Ollama: {e}")
return None
def calcular_similitud_coseno(v1, v2):
if v1 is None or v2 is None: return 0
return np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))
def cerrar_ollama():
"""Busca el proceso de Ollama y lo finaliza."""
print("\nCerrando Ollama para liberar recursos...")
encontrado = False
for proc in psutil.process_iter(['pid', 'name']):
# Buscamos 'ollama' en el nombre del proceso
if 'ollama' in proc.info['name'].lower():
try:
# Enviamos señal de terminación
os.kill(proc.info['pid'], signal.SIGTERM)
encontrado = True
except Exception as e:
print(f"No se pudo cerrar el proceso {proc.info['pid']}: {e}")
if encontrado:
print("Servidor Ollama detenido correctamente.")
else:
print("No se encontró ningún proceso de Ollama activo.")
# --- PROCEDIMIENTO PRINCIPAL --------------------------------------------------------
try:
print(f"--- Iniciando búsqueda inteligente para: '{busqueda}' ---")
vector_busqueda = obtener_embedding(busqueda)
resultados = []
for archivo in archivos:
vector_archivo = obtener_embedding(archivo)
similitud = calcular_similitud_coseno(vector_busqueda, vector_archivo)
score_porcentaje = max(0, similitud * 100)
resultados.append((archivo, score_porcentaje))
resultados.sort(key=lambda x: x[1], reverse=True)
print("\nMejores coincidencias:")
for nombre, score in resultados[:3]:
if score > 50:
print(f"Archivo: {nombre:<25} (Confianza: {score:.1f}%)")
finally:
cerrar_ollama()
... y después el modelo slm
import ollama
import psutil
import os
import signal
import re
# --- CONFIGURACIÓN ---
# Usamos un modelo de lenguaje ligero para comparar
MODELO_LLM = 'gemma3:1b'
archivos = [
"2023_SISE_Final.pdf",
"PTSC_Informe_v1.docx",
"Seguimiento_PSC.xlsx",
"Vacaciones.jpg"
]
busqueda = "Informe Seguimiento PTSC"
def evaluar_relevancia_llm(nombre_archivo, consulta):
"""
Le pide al LLM que puntúe la relación entre el archivo y la búsqueda.
"""
prompt = f"""
Analiza si el nombre del archivo coincide semánticamente con la búsqueda.
Responde ÚNICAMENTE con un número del 0 al 100, donde 100 es coincidencia exacta.
Búsqueda: {consulta}
Archivo: {nombre_archivo}
Puntuación:"""
try:
respuesta = ollama.generate(model=MODELO_LLM, prompt=prompt, options={"num_predict": 5, "temperature": 0})
# Extraemos solo los números de la respuesta
score = re.findall(r'\d+', respuesta['response'])
return int(score[0]) if score else 0
except Exception as e:
print(f"Error con el modelo: {e}")
return 0
def cerrar_ollama():
print("\nFinalizando procesos de Ollama...")
for proc in psutil.process_iter(['pid', 'name']):
if 'ollama' in proc.info['name'].lower():
try:
os.kill(proc.info['pid'], signal.SIGTERM)
except:
pass
# --- PROCEDIMIENTO ---
print(f"--- Evaluando con LLM: {MODELO_LLM} ---")
resultados = []
for archivo in archivos:
print(f"Analizando: {archivo}...", end="\r")
score = evaluar_relevancia_llm(archivo, busqueda)
resultados.append((archivo, score))
# Ordenar por puntuación
resultados.sort(key=lambda x: x[1], reverse=True)
print("\n\nResultados del modelo de lenguaje:")
print("-" * 45)
for nombre, score in resultados:
# Mostramos todos para ver cómo "piensa" el modelo pequeño
print(f"Archivo: {nombre:<25} | Score LLM: {score}/100")
cerrar_ollama()
Sobre la base de los nombres de documentos pasados como datos y el criterio de búsqueda
archivos = [
"2023_SISE_Final.pdf",
"PTSC_Informe_v1.docx",
"Seguimiento_PSC.xlsx",
"Vacaciones.jpg"
]
busqueda = "Informe Seguimiento PTSC"
... estos son los resultados obtenidos:
--- Iniciando búsqueda inteligente para: 'Informe Seguimiento PTSC' ---
Mejores coincidencias:
Archivo: PTSC_Informe_v1.docx (Confianza: 79.1%)
Archivo: Seguimiento_PSC.xlsx (Confianza: 75.3%)
Archivo: Vacaciones.jpg (Confianza: 59.9%)
Modelo slm
--- Evaluando con LLM: gemma3:1b ---Analizando: 2023_SISE_Final.pdf...
Analizando: PTSC_Informe_v1.docx...
Analizando: Seguimiento_PSC.xlsx...
Analizando: Vacaciones.jpg...
Resultados del modelo de lenguaje:
---------------------------------------------Archivo: 2023_SISE_Final.pdf | Score LLM: 95/100
Archivo: PTSC_Informe_v1.docx | Score LLM: 95/100
Archivo: Seguimiento_PSC.xlsx | Score LLM: 95/100
Archivo: Vacaciones.jpg | Score LLM: 30/100
Como ves, los resultados son muy interesantes, aunque falta probarlos con tareas reales y de mayor carga de contenidos y de dificultad. Además puedes comprobar la funcionalidad del uso de la IA local, incluyendos sus limitaciones: lo que hemos obtenido con ella en esta ocasión no mejora sustancialmente lo conseguido, por ejemplo, usando la biblioteca rapidfuzz. Pero tiempo habrá para realizar comparaciones de mayor precisión y exigencia. Por ahora estamos probando viabilidad de medios y estrategias de uso.
No hay comentarios:
Publicar un comentario
Comenta esta entrada