feat: funciones Python datascience, finance, cybersecurity y pipelines

Datascience: aggregate_by_group, deduplicate_entities/relations, detect_drift,
diff_entities/relations, extract_entities/relations_llm, hotness_score, melt,
merge_graphs, pivot, build_entity/relation_schema_prompt.
Finance: avellaneda_stoikov_quotes, generate_gbm_prices, generate_taker_order,
hawkes_intensity + módulo finance.py.
Cybersecurity: envelope_encrypt/decrypt + módulo cybersecurity.py.
Pipelines: extraction_pipeline, monte_carlo_market, run_market_sim.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-05 17:11:32 +02:00
parent 25a392df48
commit 63a9cb5273
62 changed files with 5376 additions and 0 deletions
@@ -0,0 +1,75 @@
---
name: extract_relations_llm
kind: function
lang: py
domain: datascience
version: "1.0.0"
purity: impure
signature: "def extract_relations_llm(text: str, entities: list, relation_types: list[str], llm_chat_json: Callable[[list[dict]], dict], language_instruction: str = 'Respond in English.') -> list"
description: "Extrae relaciones entre entidades de un chunk de texto usando un LLM inyectado. Valida que from_name y to_name correspondan a entidades existentes, y usa 'related_to' como fallback para tipos de relacion no permitidos."
tags: [extraction, relation, llm, knowledge-graph, nlp, datascience, fuzzygraph, graph]
uses_functions: []
uses_types:
- entity_candidate_py_datascience
- relation_candidate_py_datascience
returns:
- relation_candidate_py_datascience
returns_optional: false
error_type: "error_go_core"
imports: [logging, sys, os, typing]
tested: true
tests:
- "texto con dos entidades relacionadas"
- "texto con entidades pero sin relacion"
- "menos de dos entidades retorna lista vacia"
- "llm inventa entidad que no existe se descarta"
test_file_path: "python/functions/datascience/extract_relations_llm_test.py"
file_path: "python/functions/datascience/extract_relations_llm.py"
---
## Ejemplo
```python
from extract_relations_llm import extract_relations_llm
from python.types.datascience.entity_candidate import EntityCandidate
# Stub de llm_chat_json (en produccion usar llm_completion_retry o similar)
def my_llm(messages: list[dict]) -> dict:
# Llamar al LLM real aqui
return {"relations": [...]}
entities = [
EntityCandidate(name="Acme Corp", type_label="Organization", confidence=0.95),
EntityCandidate(name="John Smith", type_label="Person", confidence=0.9),
]
relation_types = ["employs", "funds", "owns", "communicates_with", "related_to"]
relations = extract_relations_llm(
text="Acme Corp employs John Smith as CEO and funds his research.",
entities=entities,
relation_types=relation_types,
llm_chat_json=my_llm,
)
for rel in relations:
print(f"{rel.from_name} --[{rel.relation_type}]--> {rel.to_name} ({rel.confidence:.2f})")
# Acme Corp --[employs]--> John Smith (0.90)
# Acme Corp --[funds]--> John Smith (0.85)
```
## Notas
**Inyeccion de dependencia del LLM:** `llm_chat_json` recibe una lista de mensajes en formato OpenAI (`[{"role": "system", "content": ...}, {"role": "user", "content": ...}]`) y retorna un dict con la clave `"relations"`. Esto desacopla la funcion de cualquier proveedor de LLM concreto.
**Validacion de entidades:** Solo se aceptan relaciones donde `from_name` y `to_name` aparecen exactamente en los nombres de las entidades proporcionadas. Relaciones con nombres inventados por el LLM se descartan silenciosamente (con debug log).
**Fallback de tipo:** Si el LLM propone un `relation_type` que no esta en la lista permitida, se reemplaza por `"related_to"`. Si `"related_to"` tampoco esta en la lista, se incluye igualmente como catch-all seguro.
**Menos de 2 entidades:** La funcion retorna `[]` inmediatamente sin llamar al LLM, ya que no puede haber relaciones con menos de 2 participantes.
**Error handling:** Si `llm_chat_json` lanza una excepcion, se captura con warning y retorna `[]`. Si la respuesta no contiene la clave `"relations"` o no es una lista, idem.
**Confianza:** Los valores de confianza del LLM se clampean al rango `[0.0, 1.0]`. Valores no numericos se convierten a `0.0`.
Disenado para fuzzygraph — se compone con `extract_entities_llm` (paso anterior) y `deduplicate_relations` (paso siguiente en el pipeline de extraccion).