Files
fn_registry/python/functions/datascience/extract_relations_glirel.md
T
egutierrez fa5bcca155 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>
2026-04-30 16:41:09 +02:00

6.1 KiB

name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, params, output, tested, tests, test_file_path, file_path
name kind lang domain version purity signature description tags uses_functions uses_types returns returns_optional error_type imports params output tested tests test_file_path file_path
extract_relations_glirel function py datascience 1.0.0 impure def extract_relations_glirel(text: str, entities: list[EntityCandidate], relation_types: list[str], model: Any, threshold: float = 0.5, max_pairs: int = 0) -> list[RelationCandidate] Extrae relaciones zero-shot con GLiREL. Drop-in del contrato de extract_relations_llm pero sin coste por token y mas rapido para corpus grandes. Tokeniza por whitespace, mapea spans de entidades (de attributes['start'/'end'] o fallback text.find) a indices de tokens, y devuelve RelationCandidate cuyos from_name/to_name siempre coinciden con entidades del input.
glirel
relation
nlp
extract
zero-shot
knowledge-graph
fuzzygraph
graph
datascience
python
glirel_load_model_py_datascience
entity_candidate_py_datascience
relation_candidate_py_datascience
relation_candidate_py_datascience
false error_go_core
warnings
re
name desc
text mismo chunk de texto que se uso para extraer las entidades (parrafo, doc corto)
name desc
entities lista de EntityCandidate ya extraidas (de extract_entities_gliner, extract_entities_llm o regex). Si tienen attributes['start'/'end'] se usan; si no, fallback a text.find(name) con warning.
name desc
relation_types tipos de relacion permitidos, ej: ['works_for','owns','communicated_with']. Vacio lanza ValueError.
name desc
model instancia GLiREL cargada con glirel_load_model. Inyectar para evitar penalty de carga en batch.
name desc
threshold score minimo para aceptar una relacion (0.0-1.0). Defecto 0.5.
name desc
max_pairs 0 = todas las relaciones encontradas. >0 = top N por score (descarta el resto).
lista de RelationCandidate(from_name, to_name, relation_type, description='', confidence). from_name/to_name siempre coinciden con entidades del input. true
Schema basico y modelo stub retorna RelationCandidate triplets validos
Threshold se propaga al modelo
relation_types vacio lanza ValueError
Menos de 2 entidades retorna vacio
Entidad sin offsets usa fallback text.find con warning
Entidad cuyo nombre no aparece en el texto se descarta
Excepcion del modelo se captura y retorna vacio
Relation_type fuera del set permitido se descarta
max_pairs=N limita el output a top N por score
head_pos/tail_pos resuelven entidades por posicion de token
Fallback por head_text/tail_text si head_pos no esta presente
python/functions/datascience/tests/test_extract_relations_glirel.py python/functions/datascience/extract_relations_glirel.py

Ejemplo

from python.functions.datascience import (
    glirel_load_model,
    extract_relations_glirel,
)
from python.types.datascience.entity_candidate import EntityCandidate

model = glirel_load_model(device="auto")

text = "Alice Johnson works at OpenAI in San Francisco."
entities = [
    EntityCandidate(name="Alice Johnson", type_label="Person",
                    attributes={"start": 0, "end": 13}, confidence=0.92),
    EntityCandidate(name="OpenAI", type_label="Organization",
                    attributes={"start": 23, "end": 29}, confidence=0.87),
    EntityCandidate(name="San Francisco", type_label="Location",
                    attributes={"start": 33, "end": 46}, confidence=0.81),
]

relations = extract_relations_glirel(
    text=text,
    entities=entities,
    relation_types=["works_for", "located_in", "owns"],
    model=model,
    threshold=0.5,
)
# [RelationCandidate(from_name='Alice Johnson', to_name='OpenAI',
#                    relation_type='works_for', confidence=0.91), ...]

Drop-in con extract_relations_llm

El retorno es identico (list[RelationCandidate]) y from_name/to_name siempre coinciden con entidades del input — deduplicate_relations_py_datascience lo acepta sin cambios. Diferencias:

  • Coste: GLiREL = 0 USD/token. LLM = depende del modelo.
  • Latencia: GLiREL es mucho mas rapido en GPU; en CPU depende del numero de pares (entidades x relation_types).
  • Razonamiento implicito: el LLM lo deduce ("CEO de la empresa" -> persona works_for empresa); GLiREL solo extrae lo explicito en el texto.
  • Esquemas grandes: GLiREL escala bien con muchos relation_types; el LLM pierde foco con esquemas muy largos.
  • Idiomas: GLiREL-large-v0 esta entrenado principalmente en ingles. Para ES evaluar precision/recall caso a caso o caer al LLM.

Spans de entidades

GLiREL necesita los spans (token indices) de cada entidad en el texto. Esta funcion:

  1. Lee attributes["start"] y attributes["end"] (offsets de caracteres) si existen — el output natural de extract_entities_gliner y extract_iocs.
  2. Si faltan, usa text.find(entity.name) como fallback (con warning).
  3. Tokeniza por whitespace y mapea cada char span a un span de tokens ([start_token, end_token]).
  4. Pasa todo a model.predict_relations(tokens, labels=..., ner=...).

Si la entidad no se puede localizar en el texto, se descarta (no se le pueden buscar relaciones sin saber donde esta).

Notas

  • impure: el modelo es estado externo. error_type: error_go_core segun la regla de pureza del registry.
  • Si dos entidades tienen el mismo nombre, GLiREL podria mezclarlas; el matcheo por head_pos/tail_pos (token start) las distingue mejor que head_text.
  • Una relation_type que no aparece en el output NO es un error — solo significa que GLiREL no encontro evidencia.
  • Combinar con LLM para razonamiento implicito: ver issue 0040 (pipeline hibrido).
  • Para precision maxima, ajustar threshold por dominio: 0.3-0.4 = recall alto; 0.6-0.8 = precision alta.

Limitacion

GLiREL es bueno para relaciones explicitas en el texto (X trabaja en Y, A llamo a B), malo para razonamiento implicito (la nueva CEO, su empresa). Para razonamiento implicito seguir usando extract_relations_llm. El pipeline hibrido (issue 0040) compone GLiREL para extraccion masiva + LLM para los casos implicitos que GLiREL no cubre.