feat(datascience): GLiREL relation extractor (zero-shot triplets) drop-in con LLM

- glirel_load_model: cache por (model_name, device); device='auto' resuelve via torch
- extract_relations_glirel: tokeniza por whitespace, mapea spans char->token,
  llama predict_relations y devuelve RelationCandidate; fallback text.find si la
  entidad llega sin offsets; max_pairs=N -> top-N por score
- pyproject.toml: glirel en extra nlp

Closes #0039

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-30 16:41:09 +02:00
parent fa9b1d449d
commit fa5bcca155
5 changed files with 494 additions and 0 deletions
@@ -0,0 +1,72 @@
---
name: glirel_load_model
kind: function
lang: py
domain: datascience
version: "1.0.0"
purity: impure
signature: "def glirel_load_model(model_name: str = 'jackboyla/glirel-large-v0', device: str = 'auto') -> Any"
description: "Carga (y cachea por (model_name, device)) un modelo GLiREL zero-shot relation extraction. La primera llamada descarga ~500 MB desde HuggingFace; sucesivas devuelven la instancia cacheada. device='auto' usa CUDA si esta disponible, o CPU."
tags: [glirel, relation, nlp, model, huggingface, zero-shot, datascience, python]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: []
params:
- name: model_name
desc: "ID del modelo en HuggingFace Hub (defecto: jackboyla/glirel-large-v0)"
- name: device
desc: "'auto' (CUDA si disponible, sino CPU), 'cpu', 'cuda', 'cuda:N'"
output: "instancia GLiREL lista para predict_relations, cacheada por (model_name, device)"
tested: true
tests:
- "ImportError si glirel no esta instalado"
- "Cache devuelve la misma instancia con los mismos parametros"
- "device='auto' resuelve a cpu o cuda segun torch.cuda.is_available"
test_file_path: "python/functions/datascience/tests/test_extract_relations_glirel.py"
file_path: "python/functions/datascience/glirel_load_model.py"
---
## Ejemplo
```python
from python.functions.datascience import glirel_load_model
# Primera llamada descarga el modelo (~500 MB, una vez)
model = glirel_load_model(device="auto")
# Llamadas sucesivas con mismos params devuelven el cache
model_again = glirel_load_model(device="auto")
assert model is model_again
```
## Instalacion
GLiREL no esta en las dependencias principales del registry. Para usarlo:
```bash
cd python && uv pip install glirel # solo glirel
cd python && uv pip install -e '.[nlp]' # extra completo (gliner + glirel)
```
## Tamaño y latencia
- `jackboyla/glirel-large-v0`: ~500 MB en disco (modelo + tokenizer).
- Primera carga: 8-20 s en CPU, depende del disco y red.
- Inferencia CPU: depende del numero de pares entidad x relation_types. 5-20 pares/s
con esquema pequeño (5 relation types).
- Inferencia GPU (CUDA T4): 50-200x mas rapido que CPU.
## Notas
- El cache es por (model_name, device): cargar el mismo modelo en CPU y CUDA crea dos
instancias. Es intencional para permitir A/B.
- Si `torch` no esta instalado y `device='auto'`, cae a `'cpu'` sin error.
- Para limpiar el cache (memoria GPU): borrar entradas de `_MODEL_CACHE` directamente
o reiniciar el proceso.
- impure: lee disco/red la primera vez y mantiene estado en `_MODEL_CACHE`.
- GLiREL es bueno para relaciones explicitas en el texto (`X trabaja en Y`, `A llamo a B`),
malo para razonamiento implicito ("CEO de la empresa"). Para razonamiento implicito
seguir usando `extract_relations_llm`.