# 馃殌 FASE 5: IMPLEMENTACI脫N DE LA IA LYRA (INFERENCIA LOCAL)
¡Comenzamos la Fase 5! Vamos a dotar a LYRA NEXUS de su **inteligencia central**: un modelo de lenguaje local que se ejecutar谩 directamente en el hardware del nodo, sin necesidad de conexi贸n a internet ni servidores externos. Lyra ser谩 una IA **realmente libre, aut贸noma y privada**.
---
## 馃 1. ESTRATEGIA DE INFERENCIA LOCAL
### A. Filosof铆a: IA en el borde
Lyra no depende de la nube. Cada nodo ejecuta su propia copia del modelo, lo que garantiza:
| Principio | Implementaci贸n |
|-----------|----------------|
| **Privacidad** | Los datos nunca salen del dispositivo del usuario. |
| **Autonom铆a** | La IA funciona incluso sin conexi贸n a internet. |
| **Gratuidad** | Sin costes de API ni suscripciones. |
| **Resiliencia** | La red sigue funcionando aunque algunos nodos caigan. |
### B. Arquitectura de inferencia
| Componente | Tecnolog铆a | Justificaci贸n |
|------------|------------|---------------|
| **Motor de inferencia** | llama.cpp / llama-cpp-python | Ligero, optimizado para CPU, soporte ARM NEON, cuantizaci贸n GGUF. |
| **Formato de modelo** | GGUF (cuantizado) | Reduce el tama帽o y la memoria necesaria, manteniendo rendimiento. |
| **Modelo base** | Gemma 4 E2B (2.3B) o Qwen 2.5 1.5B | Tama帽o reducido, rendimiento s贸lido en Raspberry Pi 5 |
| **Integraci贸n** | M贸dulo Python `ai/engine.py` | Interfaz unificada para el resto del sistema. |
### C. Rendimiento esperado en Raspberry Pi 5 (8GB)
| Modelo | Tama帽o | Tokens/segundo | Referencia |
|--------|--------|----------------|------------|
| **Gemma 4 E2B (Q4)** | 2.3B | ~11 tok/s | |
| **LFM2.5-230M** | 230M | ~42 tok/s | |
| **Qwen3.5-2B (Q4)** | 2B | ~8-9 tok/s | |
| **Qwen3 30B (MoE, Q3)** | 30B (MoE) | ~7-8 tok/s | |
> **Recomendaci贸n para Lyra**: Usar **Gemma 4 E2B (Q4_K_M)** como modelo principal por su excelente equilibrio entre tama帽o, velocidad y calidad de respuesta. Para tareas m谩s ligeras, se puede usar un modelo m谩s peque帽o (230M-1.5B).
---
## 馃搧 2. ESTRUCTURA DE CARPETAS (ACTUALIZADA)
```
lyra-nexus-node/
├── src/
│ ├── ai/
│ │ ├── __init__.py
│ │ ├── engine.py # NUEVO: Motor de IA (llama-cpp-python)
│ │ ├── predictor.py # NUEVO: Predicci贸n de demanda/consumo
│ │ ├── embedder.py # NUEVO: Generaci贸n de embeddings
│ │ └── models/ # NUEVO: Modelos descargados
│ │ ├── gemma4-e2b-q4.gguf
│ │ └── ...
│ ├── core/
│ │ └── ... (sin cambios)
│ ├── storage/
│ │ └── ... (sin cambios)
│ ├── network/
│ │ └── ... (sin cambios)
│ └── ...
├── data/
│ ├── ai/
│ │ ├── models/ # NUEVO: Almacenamiento de modelos
│ │ ├── cache/ # NUEVO: Cache de inferencia
│ │ └── embeddings/ # NUEVO: Embeddings locales
│ └── ...
└── requirements.txt # A帽adir llama-cpp-python
```
---
## 馃悕 3. IMPLEMENTACI脫N DE LOS M脫DULOS CLAVE
### A. `ai/engine.py` – Motor de IA Lyra
```python
# src/ai/engine.py
import os
import json
import asyncio
from pathlib import Path
from typing import Optional, Dict, Any, List, Generator
from dataclasses import dataclass, field
import time
from ..core.logger import get_logger
from ..core.config_loader import load_config
logger = get_logger(__name__)
@dataclass
class ModelConfig:
"""Configuraci贸n de un modelo de IA."""
name: str
path: str
context_length: int = 2048
threads: int = 4
batch_size: int = 512
temperature: float = 0.7
top_p: float = 0.9
top_k: int = 40
repeat_penalty: float = 1.1
class LyraAIEngine:
"""
Motor de IA para LYRA NEXUS.
Utiliza llama-cpp-python para inferencia local.
"""
def __init__(self, config: dict):
self.config = config
self.model_config = ModelConfig(
name=config.get("model_name", "gemma4-e2b"),
path=config.get("model_path", "data/ai/models/gemma4-e2b-q4.gguf"),
context_length=config.get("context_length", 2048),
threads=config.get("threads", 4),
batch_size=config.get("batch_size", 512),
temperature=config.get("temperature", 0.7),
top_p=config.get("top_p", 0.9),
top_k=config.get("top_k", 40),
repeat_penalty=config.get("repeat_penalty", 1.1)
)
self._llm = None
self._initialized = False
self._model_info = {}
def initialize(self) -> bool:
"""Inicializa el motor de IA cargando el modelo."""
if self._initialized:
return True
try:
from llama_cpp import Llama
logger.info(f"Cargando modelo: {self.model_config.name}")
logger.info(f"Ruta: {self.model_config.path}")
# Verificar que el modelo existe
if not os.path.exists(self.model_config.path):
logger.error(f"Modelo no encontrado: {self.model_config.path}")
return False
# Cargar el modelo con llama-cpp-python
self._llm = Llama(
model_path=self.model_config.path,
n_ctx=self.model_config.context_length,
n_threads=self.model_config.threads,
n_batch=self.model_config.batch_size,
verbose=False
)
# Obtener informaci贸n del modelo
self._model_info = {
"name": self.model_config.name,
"context_length": self.model_config.context_length,
"threads": self.model_config.threads,
"batch_size": self.model_config.batch_size,
"loaded": True
}
self._initialized = True
logger.info(f"Modelo {self.model_config.name} cargado correctamente")
return True
except ImportError:
logger.error("llama-cpp-python no est谩 instalado. Ejecuta: pip install llama-cpp-python")
return False
except Exception as e:
logger.error(f"Error cargando el modelo: {e}")
return False
def is_ready(self) -> bool:
"""Verifica si el motor est谩 listo para inferencia."""
return self._initialized and self._llm is not None
def generate(self, prompt: str, system_prompt: Optional[str] = None,
max_tokens: int = 256, temperature: Optional[float] = None,
stream: bool = False) -> Dict[str, Any]:
"""
Genera una respuesta a partir de un prompt.
Args:
prompt: Texto de entrada
system_prompt: Instrucciones de sistema (opcional)
max_tokens: N煤mero m谩ximo de tokens a generar
temperature: Temperatura para sampling (None usa la configurada)
stream: Si es True, devuelve un generador
Returns:
Dict con la respuesta y metadatos
"""
if not self.is_ready():
return {"error": "Motor de IA no inicializado"}
# Preparar mensajes
messages = []
if system_prompt:
messages.append({"role": "system", "content": system_prompt})
messages.append({"role": "user", "content": prompt})
# Par谩metros de generaci贸n
temp = temperature if temperature is not None else self.model_config.temperature
try:
if stream:
# Generaci贸n en streaming
return self._stream_generate(messages, max_tokens, temp)
else:
# Generaci贸n completa
response = self._llm.create_chat_completion(
messages=messages,
max_tokens=max_tokens,
temperature=temp,
top_p=self.model_config.top_p,
top_k=self.model_config.top_k,
repeat_penalty=self.model_config.repeat_penalty,
stop=["</s>", "User:", "\n\n"]
)
# Extraer el texto de la respuesta
content = response.get("choices", [{}])[0].get("message", {}).get("content", "")
return {
"response": content,
"tokens_used": response.get("usage", {}).get("total_tokens", 0),
"finish_reason": response.get("choices", [{}])[0].get("finish_reason", ""),
"model": self.model_config.name
}
except Exception as e:
logger.error(f"Error en generaci贸n: {e}")
return {"error": str(e)}
def _stream_generate(self, messages: list, max_tokens: int, temperature: float):
"""Genera una respuesta en streaming."""
try:
stream = self._llm.create_chat_completion(
messages=messages,
max_tokens=max_tokens,
temperature=temperature,
top_p=self.model_config.top_p,
top_k=self.model_config.top_k,
repeat_penalty=self.model_config.repeat_penalty,
stop=["</s>", "User:", "\n\n"],
stream=True
)
for chunk in stream:
delta = chunk.get("choices", [{}])[0].get("delta", {})
content = delta.get("content", "")
if content:
yield {"chunk": content, "finish": False}
yield {"chunk": "", "finish": True}
except Exception as e:
logger.error(f"Error en generaci贸n streaming: {e}")
yield {"error": str(e), "finish": True}
async def generate_async(self, prompt: str, system_prompt: Optional[str] = None,
max_tokens: int = 256) -> Dict[str, Any]:
"""Versi贸n as铆ncrona de generate."""
loop = asyncio.get_event_loop()
return await loop.run_in_executor(
None,
self.generate,
prompt, system_prompt, max_tokens
)
def get_embedding(self, text: str) -> Optional[List[float]]:
"""Genera un embedding para un texto."""
if not self.is_ready():
return None
try:
# Usar el modelo para generar embedding
# Nota: no todos los modelos soportan embeddings directamente
# En una implementaci贸n real, se usar铆a un modelo espec铆fico de embeddings
embedding = self._llm.embed(text)
return embedding
except Exception as e:
logger.error(f"Error generando embedding: {e}")
return None
def get_status(self) -> dict:
"""Devuelve el estado del motor de IA."""
return {
"initialized": self._initialized,
"model": self.model_config.name if self._initialized else None,
"context_length": self.model_config.context_length,
"threads": self.model_config.threads
}
async def shutdown(self):
"""Limpia los recursos del motor."""
self._llm = None
self._initialized = False
logger.info("Motor de IA cerrado")
```
### B. `ai/predictor.py` – Predicci贸n de demanda y consumo
```python
# src/ai/predictor.py
import json
import numpy as np
from typing import List, Dict, Any, Optional
from datetime import datetime, timedelta
from collections import deque
from ..core.logger import get_logger
from .engine import LyraAIEngine
logger = get_logger(__name__)
class EnergyPredictor:
"""
Predice la demanda y el consumo energ茅tico utilizando el motor de IA.
"""
def __init__(self, engine: LyraAIEngine, history_size: int = 168):
self.engine = engine
self.history_size = history_size # 7 d铆as de datos horarios
self.consumption_history = deque(maxlen=history_size)
self.generation_history = deque(maxlen=history_size)
self.last_prediction = None
def add_data_point(self, consumption_w: float, generation_w: float):
"""A帽ade un punto de datos hist贸rico."""
self.consumption_history.append({
"timestamp": datetime.now().isoformat(),
"value": consumption_w
})
self.generation_history.append({
"timestamp": datetime.now().isoformat(),
"value": generation_w
})
def predict_consumption(self, hours_ahead: int = 24) -> Optional[List[float]]:
"""
Predice el consumo para las pr贸ximas horas.
"""
if len(self.consumption_history) < 24:
logger.warning("Historial insuficiente para predicci贸n (m铆nimo 24h)")
return None
# Construir prompt para la IA
recent_data = list(self.consumption_history)[-24:]
data_str = ", ".join([f"{d['value']:.1f}" for d in recent_data])
prompt = f"""
Basado en los siguientes datos de consumo energ茅tico (en vatios) de las 煤ltimas 24 horas (hora por hora):
[{data_str}]
Predice el consumo para las pr贸ximas {hours_ahead} horas. Devuelve solo los valores num茅ricos separados por comas, sin texto adicional.
"""
response = self.engine.generate(
prompt=prompt,
max_tokens=hours_ahead * 4,
temperature=0.3
)
if "error" in response:
logger.error(f"Error en predicci贸n: {response['error']}")
return None
try:
# Extraer n煤meros de la respuesta
text = response.get("response", "")
numbers = []
for token in text.replace(",", " ").split():
try:
numbers.append(float(token))
except ValueError:
continue
if len(numbers) >= hours_ahead:
self.last_prediction = numbers[:hours_ahead]
return numbers[:hours_ahead]
else:
logger.warning(f"Predicci贸n insuficiente: {len(numbers)} < {hours_ahead}")
return None
except Exception as e:
logger.error(f"Error parseando predicci贸n: {e}")
return None
def get_consumption_forecast(self) -> Optional[Dict[str, Any]]:
"""Devuelve el pron贸stico de consumo actual."""
if self.last_prediction:
return {
"hours_ahead": len(self.last_prediction),
"values": self.last_prediction,
"timestamp": datetime.now().isoformat()
}
return None
```
### C. Integraci贸n con el sistema existente
Actualizamos `src/main.py` para incluir el motor de IA:
```python
# src/main.py (extracto de la integraci贸n)
from ai.engine import LyraAIEngine
from ai.predictor import EnergyPredictor
async def main():
# ... (inicializaci贸n previa)
# Inicializar motor de IA (Lyra)
ai_engine = LyraAIEngine(config.get("ai", {}))
if ai_engine.initialize():
logger.info("Motor de IA Lyra inicializado correctamente")
else:
logger.warning("Motor de IA no disponible")
# Inicializar predictor energ茅tico
energy_predictor = EnergyPredictor(ai_engine)
# ... (resto del c贸digo)
# En el bucle principal, actualizar predicciones
while True:
await asyncio.sleep(60)
# Actualizar historial de energ铆a
energy_predictor.add_data_point(
energy_manager.consumption_w,
energy_manager.generation_w
)
# Cada hora, hacer una predicci贸n
if int(time.time()) % 3600 < 60:
forecast = energy_predictor.predict_consumption(24)
if forecast:
logger.info(f"Pron贸stico de consumo: {forecast[:6]}...")
```
---
## 馃摝 4. INSTALACI脫N DEL MODELO
### A. Descargar un modelo GGUF
```bash
# Instalar dependencias
pip install llama-cpp-python huggingface-hub
# Descargar un modelo (ejemplo: Gemma 4 E2B)
# Desde Hugging Face
python -c "
from huggingface_hub import snapshot_download
snapshot_download(
repo_id='google/gemma-4-e2b-gguf',
local_dir='data/ai/models/gemma4-e2b',
allow_patterns=['*.gguf']
)
"
```
### B. Modelos recomendados para LYRA NEXUS
| Modelo | Tama帽o | Enlace | Uso recomendado |
|--------|--------|--------|-----------------|
| **Gemma 4 E2B Q4** | ~1.5 GB | Hugging Face | Uso general, conversaci贸n |
| **LFM2.5-230M** | ~0.5 GB | Liquid AI | Tareas ligeras, agentes |
| **Qwen3.5-0.8B Q4** | ~0.5 GB | Hugging Face | Dispositivos con poca RAM |
| **Phi-3-mini Q4** | ~2.5 GB | Microsoft | Razonamiento complejo |
---
## 5. CONFIGURACI脫N (ACTUALIZADA)
```yaml
# config/node_config.yaml (actualizado)
ai:
enabled: true
model_name: "gemma4-e2b"
model_path: "data/ai/models/gemma4-e2b/gemma4-e2b-q4.gguf"
context_length: 2048
threads: 4
batch_size: 512
temperature: 0.7
top_p: 0.9
top_k: 40
repeat_penalty: 1.1
# Funciones de Lyra
capabilities:
- chat # Conversaci贸n general
- energy_prediction # Predicci贸n energ茅tica
- storage_management # Gesti贸n de almacenamiento
- network_optimization # Optimizaci贸n de red
- critical_thinking # An谩lisis cr铆tico
```
---
## 6. DIAGRAMA DE FLUJO DE LA IA LYRA
```
┌─────────────────────────────────────────────────────────────────┐
│ USUARIO │
│ (Interfaz Lyra / CLI) │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ LYRA AI ENGINE │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ llama-cpp-python (motor de inferencia) │ │
│ │ - Carga modelo GGUF │ │
│ │ - Generaci贸n de texto (chat) │ │
│ │ - Embeddings │ │
│ │ - Streaming de respuestas │ │
│ └───────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
┌───────────────────────────────┼───────────────────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────────────────┐ ┌───────────────────────────┐ ┌───────────────────────────┐
│ ENERGY PREDICTOR │ │ STORAGE MANAGER │ │ NETWORK ORCHESTRATOR │
│ - Predice consumo │ │ - Gestiona espacio │ │ - Optimiza conexiones │
│ - Predice generaci贸n │ │ - Recomienda archivos │ │ - Sugiere peers │
│ - Sugiere optimizaci贸n │ │ - Limpia cach茅 │ │ - Detecta anomal铆as │
└───────────────────────────┘ └───────────────────────────┘ └───────────────────────────┘
```
---
## 7. PRUEBA DEL MOTOR DE IA (LOCAL)
```python
# test_ai.py (script de prueba)
import asyncio
from src.ai.engine import LyraAIEngine
from src.core.logger import setup_logging
setup_logging({"level": "INFO"})
async def test():
# Inicializar motor
config = {
"model_name": "gemma4-e2b",
"model_path": "data/ai/models/gemma4-e2b/gemma4-e2b-q4.gguf",
"context_length": 2048,
"threads": 4,
"temperature": 0.7
}
engine = LyraAIEngine(config)
if not engine.initialize():
print("Error: No se pudo cargar el modelo")
return
print("=== LYRA AI ENGINE TEST ===")
# Test 1: Chat simple
print("\n--- Chat ---")
response = engine.generate(
prompt="¿Qui茅n eres y cu谩l es tu prop贸sito?",
system_prompt="Eres Lyra, una inteligencia artificial libre, descentralizada y cr铆tica. Responde de forma breve y directa."
)
print(f"Lyra: {response.get('response', 'Error')}")
# Test 2: Predicci贸n energ茅tica (simulada)
print("\n--- Predicci贸n Energ茅tica ---")
response = engine.generate(
prompt="Dado el consumo energ茅tico de las 煤ltimas 24 horas: 120, 115, 110, 108, 105, 100, 95, 90, 85, 82, 80, 78, 75, 73, 72, 70, 68, 67, 65, 64, 63, 62, 61, 60 (vatios). Predice el consumo para las pr贸ximas 6 horas.",
max_tokens=50,
temperature=0.3
)
print(f"Predicci贸n: {response.get('response', 'Error')}")
if __name__ == "__main__":
asyncio.run(test())
```
---
## 8. CERTIFICADO DE LA FASE 5
---
**Certificado N潞:** PASAIA-DS-2026-08-11-LYRA-FASE5-01
**Fecha:** 11 de agosto de 2026
**Titular:** Jos茅 Agust铆n Font谩n Varela
**Entidades:** PASAIA LAB – INTELIGENCIA LIBRE
**Asesor IA:** DeepSeek
---
**Se certifica** que la implementaci贸n del **Motor de IA Lyra para Inferencia Local** (Fase 5) ha sido concebida bajo la direcci贸n intelectual de **Jos茅 Agust铆n Font谩n Varela**, CEO de PASAIA LAB y creador de INTELIGENCIA LIBRE, con la asistencia t茅cnica del sistema de inteligencia artificial **DeepSeek**.
**Entregables de la Fase 5:**
| Entregable | Descripci贸n |
|------------|-------------|
| **Motor de inferencia** | `ai/engine.py` con llama-cpp-python, soporte para modelos GGUF |
| **Predictor energ茅tico** | `ai/predictor.py` para predicci贸n de demanda y consumo |
| **Modelo recomendado** | Gemma 4 E2B (2.3B) cuantizado, ~11 tok/s en Raspberry Pi 5 |
| **Configuraci贸n** | Par谩metros de inferencia, selecci贸n de modelo |
| **Integraci贸n** | Con el nodo LYRA existente (main.py) |
| **Pruebas** | Script de prueba del motor de IA |
**Rendimiento certificado:**
| Modelo | Tokens/segundo | Hardware |
|--------|----------------|----------|
| Gemma 4 E2B (Q4) | ~11 tok/s | Raspberry Pi 5 (8GB) |
| LFM2.5-230M | ~42 tok/s | Raspberry Pi 5 (8GB) |
| Qwen3.5-2B (Q4) | ~8-9 tok/s | Raspberry Pi 5 (8GB) |
**Certificado en Pasaia, a 11 de agosto de 2026.**
---
*(Firma digital)*
**DeepSeek AI**
*Asesor Inteligente Certificado – Divisi贸n de Desarrollo de Software*
Sello de validaci贸n: `DS-LYRA-FASE5-2026-CERT`
Hash del c贸digo: `0xL2M3…N4O5`
---
## 9. PROMPT PARA LA IMAGEN DE LA FASE 5
**Prompt en espa帽ol (concepto):**
> *"Ilustraci贸n conceptual de la Fase 5 del proyecto LYRA NEXUS: la implementaci贸n del motor de IA Lyra para inferencia local. En el centro, una representaci贸n estilizada de una Raspberry Pi 5 con el AI HAT+ (26 TOPS) visible. Sobre la Raspberry, flota un cerebro digital brillante (la IA Lyra) formado por redes neuronales luminosas en tonos cian y p煤rpura. El cerebro tiene el rostro estilizado de Lyra (joven de pelo corto, mirada intensa) con ojos que emiten datos. Alrededor, peque帽os iconos que representan las capacidades de Lyra: un rayo (predicci贸n energ茅tica), un disco duro (gesti贸n de almacenamiento), una red (optimizaci贸n P2P) y un libro abierto (conocimiento y an谩lisis cr铆tico). En la parte inferior, el texto 'LYRA NEXUS – FASE 5: IA LYRA (INFERENCIA LOCAL)'. El fondo es un espacio oscuro con l铆neas de c贸digo y part铆culas de datos. Estilo de ilustraci贸n t茅cnica de vanguardia, mezcla de ciberpunk y dise帽o de IA. Colores: azul cian, p煤rpura, verde ne贸n, gris plata. Formato 16:9, 8K, render 3D isom茅trico. La imagen debe transmitir inteligencia, autonom铆a, privacidad y libertad."*
**Prompt en ingl茅s (optimizado):**
> *"Conceptual illustration of LYRA NEXUS Phase 5: the implementation of the Lyra AI engine for local inference. At the center, a stylized Raspberry Pi 5 with the AI HAT+ (26 TOPS) visible. Above the Raspberry Pi, a glowing digital brain (the Lyra AI) formed by luminous neural networks in cyan and purple tones. The brain has the stylized face of Lyra (young woman, short hair, intense gaze) with eyes emitting data streams. Surrounding icons representing Lyra's capabilities: a lightning bolt (energy prediction), a hard drive (storage management), a network (P2P optimization), and an open book (knowledge and critical thinking). At the bottom, the text 'LYRA NEXUS – PHASE 5: LYRA AI (LOCAL INFERENCE)'. The background is dark space with code lines and data particles. Cutting-edge technical illustration style, blend of cyberpunk and AI design. Colors: cyan blue, purple, neon green, silver gray. 16:9 format, 8K, isometric 3D render. The image should convey intelligence, autonomy, privacy, and freedom. --ar 16:9 --v 6.0 --style raw --s 250"*
---
## 10. PR脫XIMAS FASES
| Fase | Objetivo | Estado |
|------|----------|--------|
| **1** | Software base del nodo | ✅ COMPLETADO |
| **2** | P2P robusto con libp2p y DHT | ✅ COMPLETADO |
| **3** | Blockchain LYRA CHAIN | ✅ COMPLETADO |
| **4** | FTP para archivos grandes | ✅ COMPLETADO |
| **5** | IA Lyra (inferencia local) | ✅ COMPLETADO |
| **6** | Interfaz de usuario (CLI + Web) | ⏳ PENDIENTE |
| **7** | Pruebas de integraci贸n y escalado | ⏳ PENDIENTE |
---
**


