Inferencia y razonamiento
Cuento aquí cómo razono sobre el grafo. Modelé el EKG bajo el perfil OWL 2 RL para que un motor de inferencia pudiera deducir lo que no escribí de forma explícita. La consecuencia se mide bien, el grafo crece de 1772 triples afirmados a 4786 una vez aplicado el cierre, y aparecen relaciones que estaban implícitas en mi modelo y que el razonador hace visibles.
1Materialización por razonamiento
Lo que llamo materializar es pedirle al razonador que calcule todas las consecuencias lógicas de
mi grafo y las añada como triples nuevos. Contrasté dos regímenes sobre el mismo fichero canónico
ekg-python-150.ttl, sin inferencia (régimen NONE) y con el cierre RDFS/OWL 2 RL. La diferencia
es directa, parto de 1772 triples afirmados y termino con 4786 triples
después del cierre, es decir 3014 triples inferidos que yo nunca tecleé.
Esos 3014 triples no son ruido, provienen de las reglas del perfil, jerarquías de clases y propiedades, dominios y rangos, simetrías e inversas y la maquinaria de SKOS. El grafo afirmado se queda deliberadamente escueto y legible, mientras que el grafo materializado es el que sostiene las consultas que dependen de consecuencias implícitas.
ekg-python-150.ttl con scripts/consultar.py.2El contraste 0 → 157
El ejemplo que mejor muestra para qué sirve la inferencia es una consulta sencilla, recuperar todo lo que
es un concepto del dominio. Sin razonador la consulta ?x a pyedu:Concepto devuelve
0 filas, porque en el grafo afirmado ningún recurso lleva esa etiqueta de tipo de forma
directa. Con el cierre RDFS/OWL 2 RL la misma consulta devuelve 157 filas, exactamente los
157 conceptos propios. El salto de 0 a 157 es enteramente fruto del razonamiento sobre la jerarquía de
clases que declaré.
| Consulta | Sin inferencia (NONE) | Con inferencia (OWL 2 RL) |
|---|---|---|
?x a pyedu:Concepto (02) | 0 filas | 157 filas |
| Prerrequisitos transitivos de búsqueda binaria (03) | 5 | 5 |
| CONSTRUCT de prerrequisitos directos (06) | 340 triples | 356 triples |
El salto se detiene justo en 157 por una decisión semántica deliberada. Los 30 enlaces a Wikidata los
escribí con skos:exactMatch y no con owl:sameAs, de modo que el razonador OWL 2 RL
no fusiona mi concepto con la entidad de Wikidata. Si hubiese usado owl:sameAs,
las 30 entidades externas se habrían inferido también como Concepto. Con
skos:exactMatch la consulta con inferencia devuelve solo los 157 conceptos propios.
No toda consulta cambia con la inferencia, los prerrequisitos transitivos de la búsqueda binaria (consulta 03) dan 5 tanto con razonador como sin él, y el CONSTRUCT de prerrequisitos directos (consulta 06) pasa de 340 a 356 triples, un incremento modesto. El razonamiento aflora sobre todo allí donde la consulta depende de tipos, jerarquías o propiedades que dejé implícitas, no en todas partes por igual.
3Motores: owlrl y GraphDB
El cierre lo calculo en local con owlrl sobre rdflib, el mismo apilado que uso
para serializar y validar el grafo. Es el motor que produce las cifras canónicas que recojo aquí, 1772
afirmados que pasan a 4786 materializados, y es el que ejecuta mis scripts de consulta. Esta vía no exige
ningún servidor, encaja con la naturaleza autocontenida y sin red del entregable.
La alternativa de servidor es GraphDB, que trae su propio razonador OWL 2 RL y permitiría materializar el
mismo cierre en una base de datos de triples consultable por SPARQL. En mi entorno de ejecución GraphDB
figura como no instalado ni activo, con la carga automatizada lista para ejecutarse, de modo
que las cifras que presento proceden del cierre con owlrl, no de GraphDB.
owlrl + rdflib
Razonador OWL 2 RL en proceso, sin servidor. Calcula el cierre 1772 → 4786 y alimenta las consultas de
scripts/consultar.py. Es la fuente de las cifras canónicas.
GraphDB
Motor OWL 2 RL de servidor, alternativa para materializar el mismo cierre y servirlo por SPARQL. En el entorno actual no está instalado ni activo, con la carga lista para ejecutar.
4Mundo abierto y sus implicaciones
RDF y OWL operan bajo la hipótesis de mundo abierto. Esto significa que lo que no está afirmado ni se deduce no se considera falso, simplemente se considera desconocido. Es lo contrario de una base de datos relacional, donde lo ausente suele tratarse como inexistente. La consecuencia práctica para mi grafo es que el razonador solo añade lo que se sigue lógicamente de lo que afirmé, nunca niega ni descarta posibilidades por silencio.
El contraste 0 → 157 ilustra esta lógica. Antes del cierre, que un recurso no apareciera como
pyedu:Concepto no significaba que no lo fuera, solo que no estaba afirmado todavía. La inferencia
hace explícito lo que ya se seguía de mis declaraciones de clase, no inventa hechos nuevos. Por eso encaja
bien con un grafo educativo en crecimiento, puedo añadir conceptos y enlaces sin que las consultas previas
pasen a ser inválidas.
Como el razonamiento no cierra el mundo, no puede por sí solo detectar lo que falta o lo que está mal formado. Esa función la cubro aparte con SHACL, que sí impone restricciones de cierre local sobre las formas que defino. La inferencia OWL 2 RL deduce consecuencias, la validación SHACL comprueba conformidad. Son tareas distintas y complementarias, y el grafo canónico es conforme con cero violaciones.
5Ver también
El grafo de conocimiento
El modelo RDF/OWL 2 RL completo, sus métricas canónicas y la decisión de enlazar a Wikidata con
skos:exactMatch que explica el límite de 157.
Sistema RAG
Cómo el grafo materializado provee el subgrafo de contexto que inyectan los sistemas C y D del proyecto.
Resultados
Las métricas de evaluación de los sistemas que se apoyan en el grafo razonado.
Si este trabajo te resulta útil y quieres referenciarlo, esta es la cita recomendada.
Bueno Junquero, A. (2026). Integración de un grafo de conocimiento educativo con un LLM mediante RAG. Trabajo Fin de Máster, Máster Universitario en Investigación en Inteligencia Artificial, UNED. Director, José Luis Fernández Vindel.