Dans ce guide pratique, vous apprendrez à créer une solution de déploiement de modèles hautement évolutive avec des LLM intégrés pour vos applications.
Dans vos exemples, nous utiliserons le modèle ChatGPT2 de Hugging Face, mais vous pouvez facilement brancher n'importe quel autre modèle dont ChatGPT4, Claude, etc.
Que vous conceviez une nouvelle application dotée de capacités d'IA ou que vous amélioriez les systèmes d'IA existants, ce guide vous aidera étape par étape à créer une solide intégration LLM.
Avant de commencer à écrire du code, voyons ce qu'il faut pour créer une intégration LLM de production. Les appels d'API ne sont pas la seule chose que vous devez prendre en compte lors de la création d'une intégration LLM prête pour la production, vous devez également prendre en compte des éléments tels que la fiabilité, le coût et la stabilité. Vos applications de production doivent résoudre des problèmes tels que les interruptions de service, les limites de débit et la variabilité des temps de réponse, tout en maîtrisant les coûts.
Voici ce que nous allons construire ensemble :
Avant de commencer à coder, assurez-vous d'avoir :
Vous voulez suivre ? Le code complet est disponible dans votre référentiel GitHub.
Commençons par préparer votre environnement de développement. Nous créerons une structure de projet propre et installerons tous les packages nécessaires.
Tout d'abord, créons votre répertoire de projet et configurons un environnement virtuel Python. Ouvrez votre terminal et exécutez :
mkdir llm_integration && cd llm_integration python3 -m venv env syource env/bin/activate
Maintenant, configurons les dépendances de votre projet. Créez un nouveau fichier exigences.txt avec ces packages essentiels :
transformers==4.36.0 huggingface-hub==0.19.4 redis==4.6.0 pydantic==2.5.0 pydantic-settings==2.1.0 tenacity==8.2.3 python-dotenv==1.0.0 fastapi==0.104.1 uvicorn==0.24.0 torch==2.1.0 numpy==1.24.3
Décomposons pourquoi nous avons besoin de chacun de ces packages :
Installez tous les packages avec la commande :
mkdir llm_integration && cd llm_integration python3 -m venv env syource env/bin/activate
Organisons votre projet avec une structure épurée. Créez ces répertoires et fichiers dans le répertoire de votre projet :
transformers==4.36.0 huggingface-hub==0.19.4 redis==4.6.0 pydantic==2.5.0 pydantic-settings==2.1.0 tenacity==8.2.3 python-dotenv==1.0.0 fastapi==0.104.1 uvicorn==0.24.0 torch==2.1.0 numpy==1.24.3
Commençons par votre client LLM qui est l'élément le plus important de votre candidature. C'est ici que nous interagirons avec le modèle ChatGPT (ou tout autre LLM que vous préférez). Ajoutez les extraits de code suivants à votre fichier core/llm_client.py :
pip install -r requirements.txt
Dans cette première partie de votre cours LLMClient, nous mettons en place les bases :
Ajoutons maintenant la méthode qui parle à votre modèle :
llm_integration/ ├── core/ │ ├── llm_client.py # your main LLM interaction code │ ├── prompt_manager.py # Handles prompt templates │ └── response_handler.py # Processes LLM responses ├── cache/ │ └── redis_manager.py # Manages your caching system ├── config/ │ └── settings.py # Configuration management ├── api/ │ └── routes.py # API endpoints ├── utils/ │ ├── monitoring.py # Usage tracking │ └── rate_limiter.py # Rate limiting logic ├── requirements.txt └── main.py └── usage_logs.json
Décomposons ce qui se passe dans cette méthode de complétion :
Ensuite, nous devons ajouter le gestionnaire de réponses pour analyser et structurer la sortie brute du LLM. Faites-le dans votre fichier core/response_handler.py avec les extraits de code suivants :
import torch from transformers import AutoModelForCausalLM, AutoTokenizer from tenacity import retry, stop_after_attempt, wait_exponential from typing import Dict, Optional import logging class LLMClient: def __init__(self, model_name: str = "gpt2", timeout: int = 30): try: self.tokenizer = AutoTokenizer.from_pretrained(model_name) self.model = AutoModelForCausalLM.from_pretrained( model_name, device_map="auto", torch_dtype=torch.float16 ) except Exception as e: logging.error(f"Error loading model: {str(e)}") # Fallback to a simpler model if the specified one fails self.tokenizer = AutoTokenizer.from_pretrained("gpt2") self.model = AutoModelForCausalLM.from_pretrained("gpt2") self.timeout = timeout self.logger = logging.getLogger(__name__)
Créons maintenant votre système de mise en cache pour améliorer les performances des applications et réduire les coûts. Ajoutez les extraits de code suivants à votre fichier cache/redis_manager.py :
@retry( stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10), reraise=True ) async def complete(self, prompt: str, temperature: float = 0.7, max_tokens: Optional[int] = None) -> Dict: """Get completion from the model with automatic retries""" try: inputs = self.tokenizer(prompt, return_tensors="pt").to( self.model.device ) with torch.no_grad(): outputs = self.model.generate( **inputs, max_new_tokens=max_tokens or 100, temperature=temperature, do_sample=True ) response_text = self.tokenizer.decode( outputs[0], skip_special_tokens=True ) # Calculate token usage for monitoring input_tokens = len(inputs.input_ids[0]) output_tokens = len(outputs[0]) - input_tokens return { 'content': response_text, 'usage': { 'prompt_tokens': input_tokens, 'completion_tokens': output_tokens, 'total_tokens': input_tokens + output_tokens }, 'model': "gpt2" } except Exception as e: self.logger.error(f"Error in LLM completion: {str(e)}") raise
Dans les extraits de code ci-dessus, nous avons créé une classe CacheManager qui gère toutes les opérations de mise en cache avec les éléments suivants :
Créons votre gestionnaire d'invites qui gérera les invites de votre modèle LLM. Ajoutez le code suivant à votre core/prompt_manager.py :
mkdir llm_integration && cd llm_integration python3 -m venv env syource env/bin/activate
Créez ensuite un exemple de modèle d'invite pour la modération du contenu dans votre fichier prompts/content_moderation.json avec des extraits de code :
transformers==4.36.0 huggingface-hub==0.19.4 redis==4.6.0 pydantic==2.5.0 pydantic-settings==2.1.0 tenacity==8.2.3 python-dotenv==1.0.0 fastapi==0.104.1 uvicorn==0.24.0 torch==2.1.0 numpy==1.24.3
Votre gestionnaire d'invites pourra désormais charger des modèles d'invites à partir de votre fichier JSON et obtenir également un modèle d'invite formaté.
Pour conserver toutes vos configurations LLM au même endroit et les réutiliser facilement dans votre application, créons des paramètres de configuration. Ajoutez le code ci-dessous à votre fichier config/settings.py :
pip install -r requirements.txt
Ensuite, implémentons une limitation de débit pour contrôler la manière dont les utilisateurs accèdent aux ressources de votre application. Pour ce faire, ajoutez le code suivant à votre fichier utils/rate_limiter.py :
llm_integration/ ├── core/ │ ├── llm_client.py # your main LLM interaction code │ ├── prompt_manager.py # Handles prompt templates │ └── response_handler.py # Processes LLM responses ├── cache/ │ └── redis_manager.py # Manages your caching system ├── config/ │ └── settings.py # Configuration management ├── api/ │ └── routes.py # API endpoints ├── utils/ │ ├── monitoring.py # Usage tracking │ └── rate_limiter.py # Rate limiting logic ├── requirements.txt └── main.py └── usage_logs.json
Dans RateLimiter, nous avons implémenté une méthode check_rate_limit réutilisable qui peut être utilisée dans n'importe quel itinéraire pour gérer la limitation de débit en transmettant simplement la période et le nombre de requêtes autorisées pour chaque utilisateur pendant une période donnée.
Créons maintenant vos points de terminaison API dans le fichier api/routes.py pour intégrer votre LLM dans votre application :
import torch from transformers import AutoModelForCausalLM, AutoTokenizer from tenacity import retry, stop_after_attempt, wait_exponential from typing import Dict, Optional import logging class LLMClient: def __init__(self, model_name: str = "gpt2", timeout: int = 30): try: self.tokenizer = AutoTokenizer.from_pretrained(model_name) self.model = AutoModelForCausalLM.from_pretrained( model_name, device_map="auto", torch_dtype=torch.float16 ) except Exception as e: logging.error(f"Error loading model: {str(e)}") # Fallback to a simpler model if the specified one fails self.tokenizer = AutoTokenizer.from_pretrained("gpt2") self.model = AutoModelForCausalLM.from_pretrained("gpt2") self.timeout = timeout self.logger = logging.getLogger(__name__)
Ici, nous avons défini un point de terminaison /moderate dans la classe APIRouter, qui est responsable de l'organisation des routes API. Le décorateur @lru_cache est appliqué aux fonctions d'injection de dépendances (get_llm_client, get_response_handler, get_cache_manager et get_prompt_manager) pour garantir que les instances de LLMClient, CacheManager et PromptManager sont mises en cache pour de meilleures performances. La fonction moderate_content, décorée avec @router.post, définit une route POST pour la modération du contenu et utilise le mécanisme Depends de FastAPI pour injecter ces dépendances. À l'intérieur de la fonction, la classe RateLimiter, configurée avec les paramètres de limite de débit à partir des paramètres, applique les limites de requêtes.
Enfin, mettons à jour votre main.py pour tout rassembler :
@retry( stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10), reraise=True ) async def complete(self, prompt: str, temperature: float = 0.7, max_tokens: Optional[int] = None) -> Dict: """Get completion from the model with automatic retries""" try: inputs = self.tokenizer(prompt, return_tensors="pt").to( self.model.device ) with torch.no_grad(): outputs = self.model.generate( **inputs, max_new_tokens=max_tokens or 100, temperature=temperature, do_sample=True ) response_text = self.tokenizer.decode( outputs[0], skip_special_tokens=True ) # Calculate token usage for monitoring input_tokens = len(inputs.input_ids[0]) output_tokens = len(outputs[0]) - input_tokens return { 'content': response_text, 'usage': { 'prompt_tokens': input_tokens, 'completion_tokens': output_tokens, 'total_tokens': input_tokens + output_tokens }, 'model': "gpt2" } except Exception as e: self.logger.error(f"Error in LLM completion: {str(e)}") raise
Dans le code ci-dessus, nous avons créé une application FastAPI et le routeur en utilisant api.routes sous le préfixe /api/v1. Activation de la journalisation pour afficher des messages d'information avec des horodatages. L'application exécutera localhost:8000 en utilisant Uvicorn, avec le rechargement à chaud activé.
Nous avons maintenant tous les composants en place, commençons à rendre votre application opérationnelle. Tout d'abord, créez un fichier .env dans le répertoire racine de votre projet et ajoutez votre HUGGINGFACE_API_KEY et REDIS_URL :
mkdir llm_integration && cd llm_integration python3 -m venv env syource env/bin/activate
Assurez-vous ensuite que Redis est exécuté sur votre machine. Sur la plupart des systèmes basés sur Unix, vous pouvez le démarrer avec la commande :
transformers==4.36.0 huggingface-hub==0.19.4 redis==4.6.0 pydantic==2.5.0 pydantic-settings==2.1.0 tenacity==8.2.3 python-dotenv==1.0.0 fastapi==0.104.1 uvicorn==0.24.0 torch==2.1.0 numpy==1.24.3
Vous pouvez maintenant démarrer votre candidature :
pip install -r requirements.txt
votre serveur FastAPI commencera à fonctionner sur http://localhost:8000. La documentation automatique de l'API sera disponible sur http://localhost:8000/docs - c'est très utile pour tester vos points de terminaison !
Testons votre API nouvellement créée avec une vraie requête. Ouvrez un nouveau terminal et exécutez cette commande curl :
llm_integration/ ├── core/ │ ├── llm_client.py # your main LLM interaction code │ ├── prompt_manager.py # Handles prompt templates │ └── response_handler.py # Processes LLM responses ├── cache/ │ └── redis_manager.py # Manages your caching system ├── config/ │ └── settings.py # Configuration management ├── api/ │ └── routes.py # API endpoints ├── utils/ │ ├── monitoring.py # Usage tracking │ └── rate_limiter.py # Rate limiting logic ├── requirements.txt └── main.py └── usage_logs.json
Vous devriez voir une réponse comme celle-ci sur votre terminal :
Ajoutons maintenant quelques fonctionnalités de surveillance pour suivre les performances de votre application et la quantité de ressources utilisées. Ajoutez le code suivant à votre fichier utils/monitoring.py :
import torch from transformers import AutoModelForCausalLM, AutoTokenizer from tenacity import retry, stop_after_attempt, wait_exponential from typing import Dict, Optional import logging class LLMClient: def __init__(self, model_name: str = "gpt2", timeout: int = 30): try: self.tokenizer = AutoTokenizer.from_pretrained(model_name) self.model = AutoModelForCausalLM.from_pretrained( model_name, device_map="auto", torch_dtype=torch.float16 ) except Exception as e: logging.error(f"Error loading model: {str(e)}") # Fallback to a simpler model if the specified one fails self.tokenizer = AutoTokenizer.from_pretrained("gpt2") self.model = AutoModelForCausalLM.from_pretrained("gpt2") self.timeout = timeout self.logger = logging.getLogger(__name__)
La classe UsageMonitor effectuera les opérations suivantes :
Ensuite, ajoutez une nouvelle méthode pour calculer les statistiques d'utilisation :
@retry( stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10), reraise=True ) async def complete(self, prompt: str, temperature: float = 0.7, max_tokens: Optional[int] = None) -> Dict: """Get completion from the model with automatic retries""" try: inputs = self.tokenizer(prompt, return_tensors="pt").to( self.model.device ) with torch.no_grad(): outputs = self.model.generate( **inputs, max_new_tokens=max_tokens or 100, temperature=temperature, do_sample=True ) response_text = self.tokenizer.decode( outputs[0], skip_special_tokens=True ) # Calculate token usage for monitoring input_tokens = len(inputs.input_ids[0]) output_tokens = len(outputs[0]) - input_tokens return { 'content': response_text, 'usage': { 'prompt_tokens': input_tokens, 'completion_tokens': output_tokens, 'total_tokens': input_tokens + output_tokens }, 'model': "gpt2" } except Exception as e: self.logger.error(f"Error in LLM completion: {str(e)}") raise
Mettez à jour votre API pour ajouter les fonctionnalités de surveillance de la classe UsageMonitor :
from typing import Dict import logging class ResponseHandler: def __init__(self): self.logger = logging.getLogger(__name__) def parse_moderation_response(self, raw_response: str) -> Dict: """Parse and structure the raw LLM response for moderation""" try: # Default response structure structured_response = { "is_appropriate": True, "confidence_score": 0.0, "reason": None } # Simple keyword-based analysis lower_response = raw_response.lower() # Check for inappropriate content signals if any(word in lower_response for word in ['inappropriate', 'unsafe', 'offensive', 'harmful']): structured_response["is_appropriate"] = False structured_response["confidence_score"] = 0.9 # Extract reason if present if "because" in lower_response: reason_start = lower_response.find("because") structured_response["reason"] = raw_response[reason_start:].split('.')[0].strip() else: structured_response["confidence_score"] = 0.95 return structured_response except Exception as e: self.logger.error(f"Error parsing response: {str(e)}") return { "is_appropriate": True, "confidence_score": 0.5, "reason": "Failed to parse response" } def format_response(self, raw_response: Dict) -> Dict: """Format the final response with parsed content and usage stats""" try: return { "content": self.parse_moderation_response(raw_response["content"]), "usage": raw_response["usage"], "model": raw_response["model"] } except Exception as e: self.logger.error(f"Error formatting response: {str(e)}") raise
Maintenant, testez votre point de terminaison /stats en exécutant cette commande curl :
import redis from typing import Optional, Any import json import hashlib class CacheManager: def __init__(self, redis_url: str, ttl: int = 3600): self.redis = redis.from_url(redis_url) self.ttl = ttl def _generate_key(self, prompt: str, params: dict) -> str: """Generate a unique cache key""" cache_data = { 'prompt': prompt, 'params': params } serialized = json.dumps(cache_data, sort_keys=True) return hashlib.sha256(serialized.encode()).hexdigest() async def get_cached_response(self, prompt: str, params: dict) -> Optional[dict]: """Retrieve cached LLM response""" key = self._generate_key(prompt, params) cached = self.redis.get(key) return json.loads(cached) if cached else None async def cache_response(self, prompt: str, params: dict, response: dict) -> None: """Cache LLM response""" key = self._generate_key(prompt, params) self.redis.setex( key, self.ttl, json.dumps(response) )
La commande ci-dessus vous montrera les statistiques de vos requêtes sur le point de terminaison /modéré, comme indiqué dans la capture d'écran ci-dessous :
Tout au long de ce tutoriel, vous avez appris à utiliser un grand modèle de langage dans les applications de production. Vous avez implémenté des fonctionnalités telles que les clients API, la mise en cache, la gestion des invites et la gestion des erreurs. À titre d'exemple de ces concepts, vous avez développé un système de modération de contenu.
Maintenant que vous disposez d'une base solide, vous pouvez améliorer votre système avec :
Veuillez rappeler que dans les exemples, vous avez utilisé le modèle ChatGPT2, mais vous pouvez adapter ce système pour fonctionner avec n'importe quel fournisseur LLM. Choisissez donc le modèle qui répond à vos exigences et qui respecte votre budget.
N'hésitez pas à me contacter si vous avez des questions ou si vous souhaitez me dire ce que vous construisez avec ce système.
Bon codage ! ?
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!