--- id: "0040" title: "Pipeline hibrido extraccion entidades+relaciones (regex + GLiNER/GLiREL + LLM fallback)" status: completado type: feature domain: [] scope: multi-app priority: media depends: [] blocks: [] related: [] created: 2026-05-17 updated: 2026-05-17 tags: [] --- # 0040 — Pipeline hibrido extraccion entidades+relaciones (regex + GLiNER/GLiREL + LLM fallback) ## Metadata | Campo | Valor | |-------|-------| | **ID** | 0040 | | **Estado** | pendiente | | **Prioridad** | media | | **Tipo** | feature — Python pipeline (`python/functions/pipelines/`) | ## Dependencias Bloquea-por: **0037** (IoC regex), **0038** (GLiNER), **0039** (GLiREL). **Desbloquea:** flujo OSINT/grafo de produccion con coste predecible. Reusable desde apps en `apps/*/` y desde notebooks en `analysis/*/`. --- ## Objetivo Pipeline que combina los tres extractores en cascada para obtener triplets `(entidad, relacion, entidad)` masivamente con buen coste/calidad: 1. **Capa regex** (0037) — extrae IoCs tecnicos con precision 100%. Coste 0. 2. **Capa GLiNER** (0038) — extrae entidades semanticas (person, organization, location, event...) zero-shot. Coste bajo. 3. **Capa GLiREL** (0039) — relaciones zero-shot entre las entidades de capa 1+2. 4. **Capa LLM fallback** (existente: `extract_entities_llm` + `extract_relations_llm`) — solo se invoca cuando `confidence < threshold` o sobre los chunks marcados como "complejos". Output: `(list[EntityCandidate], list[RelationCandidate])` listos para `deduplicate_entities` → `deduplicate_relations` → `ops_to_sigma_json` / `ops_to_rdf_triples`. ## Funcion a crear | Function ID | Rol | |---|---| | `extract_graph_hybrid_py_pipelines` | Pipeline orquestador. `kind: pipeline`, `purity: impure`, `uses_functions: [...]` con todos los anteriores | ## Contrato ```python def extract_graph_hybrid( chunks: list[str], entity_schema: list[dict], relation_types: list[str], gliner_model, # inyectado glirel_model, # inyectado llm_chat_json: Callable | None = None, # opcional; si None, sin fallback LLM ioc_types: list[str] | None = None, # None = todos confidence_threshold: float = 0.6, # bajo este umbral se llama LLM languages: str = "Respond in Spanish.", ) -> tuple[list[EntityCandidate], list[RelationCandidate]] ``` Logica interna por chunk: 1. `extract_iocs(chunk, ioc_types)` → `EntityCandidate` con `type_ref` tecnico (ip/email/hash/...). 2. `extract_entities_gliner(chunk, entity_schema, gliner_model)` → entidades semanticas. 3. Si hay chunks con < N entidades o confidence baja **y** hay `llm_chat_json` → `extract_entities_llm` sobre esos chunks; mergear. 4. `extract_relations_glirel(chunk, entities_del_chunk, relation_types, glirel_model)`. 5. Si baja cobertura de relaciones y hay LLM → `extract_relations_llm` sobre el chunk. 6. Devolver listas concatenadas (sin deduplicar — eso lo hace el caller con `deduplicate_*`). ## Pureza `kind: pipeline` → `purity: impure` (regla del registry). `uses_functions`: lista los 5+ extractores invocados. `error_type: error_go_core`. ## Deliverables - `python/functions/pipelines/extract_graph_hybrid.py` + `.md` - Test de integracion en `python/functions/pipelines/tests/test_extract_graph_hybrid.py` con un corpus pequeño (2-3 textos OSINT realistas, mock del LLM). - `.md` documenta: cuando usar fallback LLM, latencia esperada por chunk, recomendacion de batch size. ## Validacion ```bash ./fn run extract_graph_hybrid_py_pipelines ``` Bench end-to-end sobre 100 KB de texto: - Solo LLM (linea base actual): registrar tiempo y coste estimado. - Pipeline hibrido: registrar tiempo, coste (solo chunks con fallback) y delta de calidad vs solo-LLM. Registrar resultados en el `.md` para tener referencia historica. ## Notas - La deduplicacion fuzzy (Levenshtein + Union-Find) ya esta hecha en `deduplicate_entities` — NO replicar aqui. - IoCs y entidades semanticas pueden solapar (ej: GLiNER detecta `apple.com` como organization, regex como domain). Resolver dejando ambas con `type_ref` distinto y que `deduplicate_entities` con `same_type_only=True` no las mezcle. Documentar esta decision. - Pensar en un app `apps/osint_extractor/` que use este pipeline + sigma viz como demo. Fuera de scope de este issue — proponer en proposals despues.