Intelligenza Artificiale
Modelli di progettazione in Python per ingegneri AI e LLM: una guida pratica

Per gli ingegneri dell'intelligenza artificiale è fondamentale creare un codice pulito, efficiente e manutenibile, soprattutto quando si costruiscono sistemi complessi.
Modelli di progettazione sono soluzioni riutilizzabili a problemi comuni nella progettazione del software. Per Ingegneri di intelligenza artificiale e modelli linguistici di grandi dimensioni (LLM), i design pattern aiutano a costruire sistemi robusti, scalabili e manutenibili che gestiscono flussi di lavoro complessi in modo efficiente. Questo articolo si addentra nei design pattern in Python, concentrandosi sulla loro rilevanza nell'IA e LLMbasati su . Spiegherò ogni modello con casi d'uso pratici di intelligenza artificiale ed esempi di codice Python.
Esploriamo alcuni modelli di progettazione chiave particolarmente utili nei contesti di intelligenza artificiale e apprendimento automatico, insieme ad esempi in Python.
Perché i modelli di progettazione sono importanti per gli ingegneri dell'intelligenza artificiale
I sistemi di intelligenza artificiale spesso implicano:
- Creazione di oggetti complessi (ad esempio, caricamento di modelli, pipeline di preelaborazione dei dati).
- Gestione delle interazioni tra componenti (ad esempio, inferenza del modello, aggiornamenti in tempo reale).
- Gestire scalabilità, manutenibilità e flessibilità per soddisfare requisiti mutevoli.
I design pattern affrontano queste sfide, fornendo una struttura chiara e riducendo le correzioni ad hoc. Si dividono in tre categorie principali:
- Modelli Creativi: Concentrati sulla creazione di oggetti. (Singleton, Factory, Builder)
- Modelli strutturali: Organizza le relazioni tra gli oggetti. (Adattatore, Decoratore)
- Modelli comportamentali: Gestire la comunicazione tra oggetti. (Strategia, Osservatore)
1. Modello Singleton
Migliori Modello singolo assicura che una classe abbia una sola istanza e fornisce un punto di accesso globale a tale istanza. Ciò è particolarmente prezioso nei flussi di lavoro AI in cui le risorse condivise, come impostazioni di configurazione, sistemi di registrazione o istanze di modello, devono essere gestite in modo coerente senza ridondanza.
Quando usare
- Gestione delle configurazioni globali (ad esempio, iperparametri del modello).
- Condivisione di risorse tra più thread o processi (ad esempio, Memoria della GPU).
- Garantire un accesso coerente a un singolo motore di inferenza o connessione al database.
Implementazione/Attuazione
Ecco come implementare un pattern Singleton in Python per gestire le configurazioni per un modello di intelligenza artificiale:
class ModelConfig:
"""
A Singleton class for managing global model configurations.
"""
_instance = None # Class variable to store the singleton instance
def __new__(cls, *args, **kwargs):
if not cls._instance:
# Create a new instance if none exists
cls._instance = super().__new__(cls)
cls._instance.settings = {} # Initialize configuration dictionary
return cls._instance
def set(self, key, value):
"""
Set a configuration key-value pair.
"""
self.settings[key] = value
def get(self, key):
"""
Get a configuration value by key.
"""
return self.settings.get(key)
# Usage Example
config1 = ModelConfig()
config1.set("model_name", "GPT-4")
config1.set("batch_size", 32)
# Accessing the same instance
config2 = ModelConfig()
print(config2.get("model_name")) # Output: GPT-4
print(config2.get("batch_size")) # Output: 32
print(config1 is config2) # Output: True (both are the same instance)
Spiegazione
- Migliori
__new__Metodo: Questo assicura che venga creata solo un'istanza della classe. Se esiste già un'istanza, restituisce quella esistente. - Stato condiviso: Entrambi
config1econfig2puntano alla stessa istanza, rendendo tutte le configurazioni globalmente accessibili e coerenti. - Caso d'uso dell'intelligenza artificiale: Utilizzare questo modello per gestire impostazioni globali come percorsi verso set di dati, configurazioni di registrazione o variabili di ambiente.
2. Modello di fabbrica
Migliori Modello di fabbrica fornisce un modo per delegare la creazione di oggetti a sottoclassi o metodi di fabbrica dedicati. Nei sistemi AI, questo modello è ideale per creare diversi tipi di modelli, caricatori di dati o pipeline in modo dinamico in base al contesto.
Quando usare
- Creazione dinamica di modelli basati sull'input dell'utente o sui requisiti delle attività.
- Gestione di logiche complesse per la creazione di oggetti (ad esempio pipeline di pre-elaborazione multi-step).
- Separare l'istanziazione degli oggetti dal resto del sistema per migliorare la flessibilità.
Implementazione/Attuazione
Costruiamo una Factory per creare modelli per diverse attività di intelligenza artificiale, come la classificazione del testo, la sintesi e la traduzione:
class BaseModel:
"""
Abstract base class for AI models.
"""
def predict(self, data):
raise NotImplementedError("Subclasses must implement the `predict` method")
class TextClassificationModel(BaseModel):
def predict(self, data):
return f"Classifying text: {data}"
class SummarizationModel(BaseModel):
def predict(self, data):
return f"Summarizing text: {data}"
class TranslationModel(BaseModel):
def predict(self, data):
return f"Translating text: {data}"
class ModelFactory:
"""
Factory class to create AI models dynamically.
"""
@staticmethod
def create_model(task_type):
"""
Factory method to create models based on the task type.
"""
task_mapping = {
"classification": TextClassificationModel,
"summarization": SummarizationModel,
"translation": TranslationModel,
}
model_class = task_mapping.get(task_type)
if not model_class:
raise ValueError(f"Unknown task type: {task_type}")
return model_class()
# Usage Example
task = "classification"
model = ModelFactory.create_model(task)
print(model.predict("AI will transform the world!"))
# Output: Classifying text: AI will transform the world!
Spiegazione
- Classe base astratta: Il
BaseModella classe definisce l'interfaccia (predict) che tutte le sottoclassi devono implementare, garantendo la coerenza. - Logica di fabbrica: Il
ModelFactoryseleziona dinamicamente la classe appropriata in base al tipo di attività e crea un'istanza. - Estensibilità: Aggiungere un nuovo tipo di modello è semplice: basta implementare una nuova sottoclasse e aggiornare la fabbrica
task_mapping.
Caso d'uso dell'intelligenza artificiale
Immagina di progettare un sistema che seleziona un LLM diverso (ad esempio, BERT, GPT o T5) in base al task. Il pattern Factory semplifica l'estensione del sistema man mano che nuovi modelli diventano disponibili senza modificare il codice esistente.
3. Modello del costruttore
Migliori Modello costruttore Builder separa la costruzione di un oggetto complesso dalla sua rappresentazione. È utile quando un oggetto comporta più passaggi per inizializzarlo o configurarlo.
Quando usare
- Creazione di pipeline multi-step (ad esempio, pre-elaborazione dei dati).
- Gestione delle configurazioni per esperimenti o addestramento del modello.
- Creazione di oggetti che richiedono molti parametri, garantendo leggibilità e manutenibilità.
Implementazione/Attuazione
Ecco come utilizzare il modello Builder per creare una pipeline di pre-elaborazione dei dati:
class DataPipeline:
"""
Builder class for constructing a data preprocessing pipeline.
"""
def __init__(self):
self.steps = []
def add_step(self, step_function):
"""
Add a preprocessing step to the pipeline.
"""
self.steps.append(step_function)
return self # Return self to enable method chaining
def run(self, data):
"""
Execute all steps in the pipeline.
"""
for step in self.steps:
data = step(data)
return data
# Usage Example
pipeline = DataPipeline()
pipeline.add_step(lambda x: x.strip()) # Step 1: Strip whitespace
pipeline.add_step(lambda x: x.lower()) # Step 2: Convert to lowercase
pipeline.add_step(lambda x: x.replace(".", "")) # Step 3: Remove periods
processed_data = pipeline.run(" Hello World. ")
print(processed_data) # Output: hello world
Spiegazione
- Metodi concatenati: Il
add_stepIl metodo consente il concatenamento per una sintassi intuitiva e compatta durante la definizione delle pipeline. - Esecuzione passo dopo passo: La pipeline elabora i dati eseguendo ogni passaggio in sequenza.
- Caso d'uso dell'intelligenza artificiale: Utilizzare il modello Builder per creare pipeline di pre-elaborazione dati complesse e riutilizzabili o configurazioni di addestramento modelli.
4. Modello strategico
Migliori Modello di strategia definisce una famiglia di algoritmi intercambiabili, incapsulando ciascuno di essi e consentendo al comportamento di cambiare dinamicamente in fase di esecuzione. Ciò è particolarmente utile nei sistemi di intelligenza artificiale in cui lo stesso processo (ad esempio, inferenza o elaborazione dei dati) potrebbe richiedere approcci diversi a seconda del contesto.
Quando usare
- Passare da uno diverso all'altro inferenza strategie (ad esempio, elaborazione batch vs. streaming).
- Applicare dinamicamente diverse tecniche di elaborazione dei dati.
- Scelta di strategie di gestione delle risorse in base all'infrastruttura disponibile.
Implementazione/Attuazione
Utilizziamo lo Strategy Pattern per implementare due diverse strategie di inferenza per un modello di intelligenza artificiale: inferenza batch e inferenza streaming.
class InferenceStrategy:
"""
Abstract base class for inference strategies.
"""
def infer(self, model, data):
raise NotImplementedError("Subclasses must implement the `infer` method")
class BatchInference(InferenceStrategy):
"""
Strategy for batch inference.
"""
def infer(self, model, data):
print("Performing batch inference...")
return [model.predict(item) for item in data]
class StreamInference(InferenceStrategy):
"""
Strategy for streaming inference.
"""
def infer(self, model, data):
print("Performing streaming inference...")
results = []
for item in data:
results.append(model.predict(item))
return results
class InferenceContext:
"""
Context class to switch between inference strategies dynamically.
"""
def __init__(self, strategy: InferenceStrategy):
self.strategy = strategy
def set_strategy(self, strategy: InferenceStrategy):
"""
Change the inference strategy dynamically.
"""
self.strategy = strategy
def infer(self, model, data):
"""
Delegate inference to the selected strategy.
"""
return self.strategy.infer(model, data)
# Mock Model Class
class MockModel:
def predict(self, input_data):
return f"Predicted: {input_data}"
# Usage Example
model = MockModel()
data = ["sample1", "sample2", "sample3"]
context = InferenceContext(BatchInference())
print(context.infer(model, data))
# Output:
# Performing batch inference...
# ['Predicted: sample1', 'Predicted: sample2', 'Predicted: sample3']
# Switch to streaming inference
context.set_strategy(StreamInference())
print(context.infer(model, data))
# Output:
# Performing streaming inference...
# ['Predicted: sample1', 'Predicted: sample2', 'Predicted: sample3']
Spiegazione
- Classe di strategia astratta: Il
InferenceStrategydefinisce l'interfaccia che tutte le strategie devono seguire. - Strategie concrete: Ogni strategia (ad esempio,
BatchInference,StreamInference) implementa la logica specifica di quell'approccio. - Commutazione dinamica: Il
InferenceContextconsente di cambiare strategia in fase di esecuzione, offrendo flessibilità per diversi casi d'uso.
Quando usare
- Passa da inferenza batch per l'elaborazione offline e inferenza streaming per applicazioni in tempo reale.
- Adattare dinamicamente le tecniche di pre-elaborazione o di aumento dei dati in base all'attività o al formato di input.
5. Modello dell'osservatore
Migliori Modello osservatore stabilisce una relazione uno-a-molti tra oggetti. Quando un oggetto (il soggetto) cambia stato, tutti i suoi dipendenti (osservatori) vengono automaticamente avvisati. Ciò è particolarmente utile nei sistemi di intelligenza artificiale per il monitoraggio in tempo reale, la gestione degli eventi o la sincronizzazione dei dati.
Quando usare
- Monitoraggio di parametri quali accuratezza o perdita durante l'addestramento del modello.
- Aggiornamenti in tempo reale per dashboard o registri.
- Gestione delle dipendenze tra componenti in flussi di lavoro complessi.
Implementazione/Attuazione
Utilizziamo l'Observer Pattern per monitorare le prestazioni di un modello di intelligenza artificiale in tempo reale.
class Subject:
"""
Base class for subjects being observed.
"""
def __init__(self):
self._observers = []
def attach(self, observer):
"""
Attach an observer to the subject.
"""
self._observers.append(observer)
def detach(self, observer):
"""
Detach an observer from the subject.
"""
self._observers.remove(observer)
def notify(self, data):
"""
Notify all observers of a change in state.
"""
for observer in self._observers:
observer.update(data)
class ModelMonitor(Subject):
"""
Subject that monitors model performance metrics.
"""
def update_metrics(self, metric_name, value):
"""
Simulate updating a performance metric and notifying observers.
"""
print(f"Updated {metric_name}: {value}")
self.notify({metric_name: value})
class Observer:
"""
Base class for observers.
"""
def update(self, data):
raise NotImplementedError("Subclasses must implement the `update` method")
class LoggerObserver(Observer):
"""
Observer to log metrics.
"""
def update(self, data):
print(f"Logging metric: {data}")
class AlertObserver(Observer):
"""
Observer to raise alerts if thresholds are breached.
"""
def __init__(self, threshold):
self.threshold = threshold
def update(self, data):
for metric, value in data.items():
if value > self.threshold:
print(f"ALERT: {metric} exceeded threshold with value {value}")
# Usage Example
monitor = ModelMonitor()
logger = LoggerObserver()
alert = AlertObserver(threshold=90)
monitor.attach(logger)
monitor.attach(alert)
# Simulate metric updates
monitor.update_metrics("accuracy", 85) # Logs the metric
monitor.update_metrics("accuracy", 95) # Logs and triggers alert
- Oggetto: Gestisce un elenco di osservatori e li avvisa quando cambia il suo stato. In questo esempio, il
ModelMonitorla classe tiene traccia delle metriche. - Gli osservatori: Esegui azioni specifiche quando notificato. Ad esempio, il
LoggerObserverregistra le metriche, mentre ilAlertObservergenera avvisi se viene superata una soglia. - Progettazione disaccoppiata: Osservatori e soggetti sono scarsamente accoppiati, rendendo il sistema modulare ed estensibile.
Come i modelli di progettazione differiscono per gli ingegneri AI rispetto agli ingegneri tradizionali
I design pattern, pur essendo universalmente applicabili, assumono caratteristiche uniche quando implementati nell'ingegneria AI rispetto all'ingegneria software tradizionale. La differenza sta nelle sfide, negli obiettivi e nei flussi di lavoro intrinseci ai sistemi AI, che spesso richiedono che i pattern siano adattati o estesi oltre i loro usi convenzionali.
1. Creazione di oggetti: esigenze statiche vs. dinamiche
- Ingegneria tradizionale: I pattern di creazione di oggetti come Factory o Singleton sono spesso utilizzati per gestire configurazioni, connessioni al database o stati di sessione utente. Questi sono generalmente statici e ben definiti durante la progettazione del sistema.
- Ingegneria dell'IA: La creazione di oggetti spesso comporta flussi di lavoro dinamici, Quali:
- Creazione di modelli al volo basati sull'input dell'utente o sui requisiti di sistema.
- Caricamento di diverse configurazioni di modelli per attività quali traduzione, riepilogo o classificazione.
- Creazione di più pipeline di elaborazione dati che variano in base alle caratteristiche del set di dati (ad esempio, testo tabellare o non strutturato).
Esempio:Nell'intelligenza artificiale, un modello Factory potrebbe generare dinamicamente un modello di apprendimento profondo basato sul tipo di attività e sui vincoli hardware, mentre nei sistemi tradizionali potrebbe semplicemente generare un componente dell'interfaccia utente.
2. Limitazioni delle prestazioni
- Ingegneria tradizionale: I modelli di progettazione sono in genere ottimizzati per la latenza e la produttività in applicazioni quali server Web, query di database o rendering dell'interfaccia utente.
- Ingegneria dell'IA: I requisiti di prestazione nell'IA si estendono a latenza di inferenza del modello, Scheda grafica/TPU utilizzo e ottimizzazione della memoriaI modelli devono adattarsi:
- Memorizzazione nella cache dei risultati intermedi per ridurre i calcoli ridondanti (modelli Decorator o Proxy).
- Algoritmi di commutazione dinamica (modello strategico) per bilanciare latenza e precisione in base al carico del sistema o a vincoli in tempo reale.
3. Natura centrata sui dati
- Ingegneria tradizionale: I modelli spesso operano su strutture di input-output fisse (ad esempio, moduli, risposte API REST).
- Ingegneria dell'IA: I modelli devono gestire variabilità dei dati sia nella struttura che nella scala, tra cui:
- Streaming di dati per sistemi in tempo reale.
- Dati multimodali (ad esempio testo, immagini, video) che richiedono pipeline con fasi di elaborazione flessibili.
- Set di dati di grandi dimensioni che necessitano di pipeline di pre-elaborazione e ampliamento efficienti, spesso utilizzando modelli come Builder o Pipeline.
4. Sperimentazione vs. Stabilità
- Ingegneria tradizionale: L'enfasi è posta sulla creazione di sistemi stabili e prevedibili in cui i modelli garantiscano prestazioni e affidabilità costanti.
- Ingegneria dell'IA: I flussi di lavoro dell'intelligenza artificiale sono spesso sperimentale e coinvolgere:
- Iterare su diverse architetture di modelli o tecniche di pre-elaborazione dei dati.
- Aggiornamento dinamico dei componenti del sistema (ad esempio, riaddestramento dei modelli, scambio di algoritmi).
- Estensione dei flussi di lavoro esistenti senza interrompere le pipeline di produzione, spesso utilizzando modelli estensibili come Decorator o Factory.
Esempio:Una Factory in AI potrebbe non solo istanziare un modello, ma anche allegare pesi precaricati, configurare ottimizzatori e collegare callback di addestramento, il tutto in modo dinamico.




