Cierra el ciclo del analysis gliner_glirel_tuning: documenta en app.md el pipeline NER+RE disponible en el registry y abre los dos issues que faltan para cablearlo en extract_graph_hybrid + panel paste_extract. Archiva el 0042 original (mREBEL) tras la decision a favor de GLiNER2 (Apache 2.0, joint NER+RE, 20-30x mas rapido en CPU). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4.5 KiB
id, title, status, priority, created, parent
| id | title | status | priority | created | parent |
|---|---|---|---|---|---|
| 0041 | Split confidence_threshold en entity_threshold + relation_threshold | pending | medium | 2026-05-04 | 0013 |
Objetivo
extract_graph_hybrid y el panel paste_extract actualmente comparten un solo confidence_threshold. El analisis empirico (projects/osint_graph/analysis/gliner_glirel_tuning/) demuestra que las dos capas tienen distribuciones de score radicalmente distintas:
- GLiNER emite scores 0.92-0.99 en narrativa, 0.5-0.95 en OSINT. Threshold sano: 0.50-0.70.
- GLiREL emite scores 0.05-0.34. Threshold sano: 0.10-0.20.
- mREBEL (issue 0042) emite confianzas implicitas via
num_beams— distinto modelo, distinto rango.
Un solo threshold global o filtra todas las relaciones (t=0.6 mata GLiREL) o satura el grafo de entidades dudosas (t=0.15 deja pasar entidades borderline).
Cambios
En python/functions/pipelines/extract_graph_hybrid.py
Aceptar dos thresholds opcionales con back-compat:
def extract_graph_hybrid(
chunks, entity_schema, relation_types,
gliner_model, glirel_model,
llm_chat_json=None,
confidence_threshold=0.6, # legacy, valor por defecto si los dos siguientes no se pasan
entity_threshold=None, # nuevo — gobierna GLiNER + LLM-fallback de entidades
relation_threshold=None, # nuevo — gobierna GLiREL + LLM-fallback de relaciones
):
if entity_threshold is None:
entity_threshold = confidence_threshold
if relation_threshold is None:
relation_threshold = confidence_threshold
...
Pasar cada threshold a su capa respectiva (GLiNER predict_entities(threshold=entity_threshold), GLiREL predict_relations(threshold=relation_threshold)).
En enrichers/paste_extract/run.py
Aceptar entity_threshold y relation_threshold en params. Mantener confidence_threshold por compatibilidad. Defaults sugeridos en el manifest:
params:
text: { type: string, required: true }
use_hybrid: { type: bool, default: true }
entity_threshold: { type: float, default: 0.50 }
relation_threshold: { type: float, default: 0.15 }
En extract_panel.cpp / extract_panel.h
Reemplazar el slider unico por dos sliders verticales (mas el toggle use_hybrid):
┌─ Extract config ─────────────────────────────┐
│ ☑ Use hybrid (GLiNER + GLiREL) │
│ │
│ Entity threshold 0.50 [==== ] │
│ Relation threshold 0.15 [== ] │
└──────────────────────────────────────────────┘
Defaults: entity_threshold=0.50, relation_threshold=0.15.
Tests
tests/test_paste_extract.py:
- Test que pasar solo
confidence_thresholdmantiene comportamiento legacy. - Test que pasar
entity_threshold=0.5, relation_threshold=0.1aplica thresholds distintos a cada capa. - Test que la UI envia los dos parametros correctamente al subprocess.
Definicion de hecho
- Pego un texto y veo entidades con confianza 0.5+ Y relaciones con confianza 0.15+ por defecto.
- Mover el slider de relaciones a 0.05 me muestra mas relaciones (potencialmente espurias) sin afectar las entidades.
- Mover el slider de entidades a 0.9 reduce las entidades sin tocar las relaciones.
- El test legacy (
confidence_thresholdsolo) sigue pasando.
Datos que respaldan los defaults
Notebook 01_gliner_glirel_tuning.ipynb, tabla "GLiNER thresholds" (corpus es_corporate, en_corporate, es_journalism). Notebook 02_e2e_spanish_graph.ipynb, comparacion recall (t=0.15) vs precision (t=0.30) — ambos modos producen grafos validos por separado, no hay un punto medio compartido bueno.
Out of scope
- Optimizacion automatica de thresholds (issue futuro).
- Threshold por tipo de entidad (
personmas estricto quelocation) — issue futuro. - Calibracion automatica con feedback del usuario (al hacer Apply, ajustar thresholds aprendiendo).
Reversibilidad
Si los nuevos defaults producen mas ruido del esperado, basta con cambiarlos en el manifest. El esquema de dos thresholds es estrictamente mas expresivo que el legacy.
Relacionado
- Issue 0042 — sustituir GLiREL por mREBEL. Si 0042 va primero, este issue cambia:
relation_thresholdse vuelve menos relevante (mREBEL no usa threshold continuo del mismo modo) peroentity_thresholdsigue siendo necesario.