IA
Intermédiaire

Introduction aux LLMs pour DevOps : Comprendre et Utiliser l'IA Générative

Florian Courouge
15 min de lecture
2,492 mots
0 vues
LLM
IA
DevOps
Machine Learning
GPT
Claude
Automatisation

Introduction aux LLMs pour DevOps : Comprendre et Utiliser l'IA Générative

Les Large Language Models (LLMs) ont révolutionné notre façon d'interagir avec les machines. Pour les professionnels DevOps, comprendre ces technologies est devenu essentiel pour automatiser des tâches complexes, améliorer la productivité et rester compétitif.

Qu'est-ce qu'un LLM ?

Un Large Language Model est un modèle d'intelligence artificielle entraîné sur d'immenses corpus de texte pour comprendre et générer du langage naturel. Ces modèles utilisent une architecture appelée Transformer, introduite par Google en 2017.

Architecture Transformer simplifiée

┌─────────────────────────────────────────────────────────────┐
│                    ARCHITECTURE TRANSFORMER                  │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│   Input: "Comment déployer sur Kubernetes ?"                │
│              │                                               │
│              ▼                                               │
│   ┌─────────────────────┐                                   │
│   │   Tokenization      │  → Découpage en tokens            │
│   │   ["Comment",       │                                   │
│   │    "déployer",...]  │                                   │
│   └─────────────────────┘                                   │
│              │                                               │
│              ▼                                               │
│   ┌─────────────────────┐                                   │
│   │   Embeddings        │  → Vecteurs numériques            │
│   │   [0.23, -0.45,...] │                                   │
│   └─────────────────────┘                                   │
│              │                                               │
│              ▼                                               │
│   ┌─────────────────────┐                                   │
│   │   Self-Attention    │  → Contexte et relations          │
│   │   (Multi-Head)      │                                   │
│   └─────────────────────┘                                   │
│              │                                               │
│              ▼                                               │
│   ┌─────────────────────┐                                   │
│   │   Feed Forward      │  → Transformation                 │
│   │   Neural Network    │                                   │
│   └─────────────────────┘                                   │
│              │                                               │
│              ▼                                               │
│   Output: Réponse générée token par token                   │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Concepts clés

Concept Description Exemple DevOps
Token Unité de base du texte "kubectl" = 1-2 tokens
Context Window Mémoire de travail 128K tokens pour Claude 3
Temperature Créativité vs déterminisme 0 pour du code, 0.7 pour du texte
Prompt Instruction donnée au modèle "Génère un Dockerfile optimisé"
Fine-tuning Spécialisation du modèle Adapter pour votre documentation

Les principaux LLMs en 2025

Comparatif des modèles leaders

modeles:
  claude-3-opus:
    editeur: "Anthropic"
    context_window: "200K tokens"
    forces:
      - "Raisonnement complexe"
      - "Analyse de code"
      - "Sécurité intégrée"
    usage_devops: "Revue de code, documentation"

  gpt-4-turbo:
    editeur: "OpenAI"
    context_window: "128K tokens"
    forces:
      - "Polyvalence"
      - "Écosystème plugins"
      - "Vision (images)"
    usage_devops: "Scripts, automation"

  gemini-pro:
    editeur: "Google"
    context_window: "1M tokens"
    forces:
      - "Context massif"
      - "Multimodal natif"
      - "Intégration GCP"
    usage_devops: "Analyse logs volumineuse"

  llama-3:
    editeur: "Meta"
    context_window: "8K-128K tokens"
    forces:
      - "Open source"
      - "Self-hosting"
      - "Personnalisation"
    usage_devops: "On-premise, données sensibles"

  mistral-large:
    editeur: "Mistral AI"
    context_window: "32K tokens"
    forces:
      - "Européen (RGPD)"
      - "Performances/coût"
      - "Multi-langues"
    usage_devops: "Conformité EU"

Cas d'usage DevOps concrets

1. Génération de configuration

# Prompt structuré pour génération de Helm values
cat << 'EOF' | llm-cli generate
Génère un fichier values.yaml pour Helm avec :
- Application: api-backend
- Replicas: 3 (prod), 1 (dev)
- Resources: 512Mi RAM, 250m CPU
- Ingress avec TLS
- Health checks configurés
- Secrets depuis Vault
Format: YAML valide, commenté
EOF

Résultat typique :

# Configuration Helm - API Backend
replicaCount:
  production: 3
  development: 1

image:
  repository: registry.company.com/api-backend
  tag: "latest"
  pullPolicy: IfNotPresent

# Ressources containers
resources:
  requests:
    memory: "512Mi"
    cpu: "250m"
  limits:
    memory: "1Gi"
    cpu: "500m"

# Configuration Ingress
ingress:
  enabled: true
  className: "nginx"
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
  hosts:
    - host: api.company.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: api-tls
      hosts:
        - api.company.com

# Health checks
livenessProbe:
  httpGet:
    path: /health/live
    port: http
  initialDelaySeconds: 30
  periodSeconds: 10

readinessProbe:
  httpGet:
    path: /health/ready
    port: http
  initialDelaySeconds: 5
  periodSeconds: 5

# Secrets Vault
vault:
  enabled: true
  role: "api-backend"
  secrets:
    - name: DATABASE_URL
      path: "secret/data/api/database"
      key: "url"

2. Analyse et debugging

#!/usr/bin/env python3
"""
Analyseur de logs Kubernetes avec LLM
"""
import anthropic
from datetime import datetime

def analyze_k8s_logs(logs: str, context: str = "") -> dict:
    """
    Analyse des logs K8s avec Claude pour identifier les problèmes.
    """
    client = anthropic.Anthropic()

    prompt = f"""Analyse ces logs Kubernetes et identifie :
1. Les erreurs critiques
2. Les warnings importants
3. Les patterns problématiques
4. Les recommandations de fix

Contexte: {context}

Logs:

{logs}


Réponds en JSON structuré avec severity, description, et remediation."""

    response = client.messages.create(
        model="claude-3-opus-20240229",
        max_tokens=4096,
        messages=[{"role": "user", "content": prompt}]
    )

    return response.content[0].text

# Exemple d'utilisation
if __name__ == "__main__":
    # Récupérer les logs d'un pod problématique
    import subprocess
    logs = subprocess.run(
        ["kubectl", "logs", "--tail=100", "pod/api-backend-xxx"],
        capture_output=True, text=True
    ).stdout

    analysis = analyze_k8s_logs(
        logs,
        context="Pod qui redémarre en boucle depuis 2h"
    )
    print(analysis)

3. Documentation automatique

# .gitlab-ci.yml - Stage de documentation automatique
generate-docs:
  stage: docs
  image: python:3.11
  script:
    - pip install anthropic pyyaml
    - |
      python << 'SCRIPT'
      import anthropic
      import os
      import yaml

      client = anthropic.Anthropic()

      # Lire les fichiers de config
      with open('kubernetes/deployment.yaml') as f:
          deployment = f.read()

      prompt = f"""Génère une documentation Markdown pour ce déploiement Kubernetes.
      Inclus:
      - Description de l'architecture
      - Prérequis
      - Étapes de déploiement
      - Variables d'environnement
      - Troubleshooting courant

      Fichier:
      ```yaml
      {deployment}
      ```
      """

      response = client.messages.create(
          model="claude-3-sonnet-20240229",
          max_tokens=4096,
          messages=[{"role": "user", "content": prompt}]
      )

      with open('docs/DEPLOYMENT.md', 'w') as f:
          f.write(response.content[0].text)
      SCRIPT
    - git add docs/
    - git commit -m "docs: Auto-generated deployment documentation" || true
  only:
    - main

4. Revue de code automatisée

name: AI Code Review

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  ai-review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Get changed files
        id: changed
        run: |
          echo "files=$(git diff --name-only origin/main...HEAD | tr '\n' ' ')" >> $GITHUB_OUTPUT

      - name: AI Review
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          pip install anthropic
          python << 'EOF'
          import anthropic
          import os
          import subprocess

          client = anthropic.Anthropic()

          # Récupérer le diff
          diff = subprocess.run(
              ["git", "diff", "origin/main...HEAD"],
              capture_output=True, text=True
          ).stdout

          prompt = f"""Tu es un expert DevOps/SRE senior. Revois ce diff et fournis:

1. **Sécurité**: Vulnérabilités potentielles
2. **Performance**: Optimisations possibles
3. **Best Practices**: Conformité aux standards
4. **Suggestions**: Améliorations concrètes

Sois constructif et précis. Format Markdown.

```diff
{diff}

"""

      response = client.messages.create(
          model="claude-3-sonnet-20240229",
          max_tokens=4096,
          messages=[{"role": "user", "content": prompt}]
      )

      # Poster le commentaire sur la PR
      print(response.content[0].text)
      EOF

## Intégration dans vos pipelines

### Architecture recommandée

┌─────────────────────────────────────────────────────────────────┐ │ PIPELINE CI/CD + LLM │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ Code │───▶│ Build │───▶│ Test │───▶│ Deploy │ │ │ │ Commit │ │ │ │ │ │ │ │ │ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │ │ │ │ │ │ │ │ ▼ ▼ ▼ ▼ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ LLM Gateway │ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ │ │ Review │ │ Docs │ │ Analyze │ │ Monitor │ │ │ │ │ │ Code │ │ Gen │ │ Logs │ │ Alerts │ │ │ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────┐ │ │ │ LLM APIs │ │ │ │ Claude/GPT/ │ │ │ │ Mistral │ │ │ └─────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────┘


### Gateway LLM maison

```python filename="llm_gateway.py"
"""
Gateway LLM pour uniformiser les appels aux différents providers.
Gère le rate limiting, caching, et fallback.
"""
from abc import ABC, abstractmethod
from functools import lru_cache
import hashlib
import redis
import anthropic
import openai

class LLMProvider(ABC):
    @abstractmethod
    def generate(self, prompt: str, **kwargs) -> str:
        pass

class ClaudeProvider(LLMProvider):
    def __init__(self):
        self.client = anthropic.Anthropic()

    def generate(self, prompt: str, **kwargs) -> str:
        response = self.client.messages.create(
            model=kwargs.get("model", "claude-3-sonnet-20240229"),
            max_tokens=kwargs.get("max_tokens", 4096),
            messages=[{"role": "user", "content": prompt}]
        )
        return response.content[0].text

class GPTProvider(LLMProvider):
    def __init__(self):
        self.client = openai.OpenAI()

    def generate(self, prompt: str, **kwargs) -> str:
        response = self.client.chat.completions.create(
            model=kwargs.get("model", "gpt-4-turbo"),
            max_tokens=kwargs.get("max_tokens", 4096),
            messages=[{"role": "user", "content": prompt}]
        )
        return response.choices[0].message.content

class LLMGateway:
    """Gateway avec caching Redis et fallback automatique."""

    def __init__(self, redis_url: str = "redis://localhost:6379"):
        self.cache = redis.from_url(redis_url)
        self.providers = {
            "claude": ClaudeProvider(),
            "gpt": GPTProvider(),
        }
        self.fallback_order = ["claude", "gpt"]

    def _cache_key(self, prompt: str, provider: str) -> str:
        return f"llm:{provider}:{hashlib.md5(prompt.encode()).hexdigest()}"

    def generate(
        self,
        prompt: str,
        provider: str = "claude",
        use_cache: bool = True,
        cache_ttl: int = 3600,
        **kwargs
    ) -> str:
        """
        Génère une réponse avec caching et fallback.
        """
        # Vérifier le cache
        if use_cache:
            cache_key = self._cache_key(prompt, provider)
            cached = self.cache.get(cache_key)
            if cached:
                return cached.decode()

        # Essayer les providers dans l'ordre
        last_error = None
        for p in [provider] + [x for x in self.fallback_order if x != provider]:
            try:
                result = self.providers[p].generate(prompt, **kwargs)

                # Mettre en cache
                if use_cache:
                    self.cache.setex(cache_key, cache_ttl, result)

                return result
            except Exception as e:
                last_error = e
                continue

        raise last_error

# Utilisation
gateway = LLMGateway()
response = gateway.generate(
    "Explique les pods Kubernetes en 3 phrases",
    provider="claude",
    use_cache=True
)

Bonnes pratiques

1. Prompts engineering pour DevOps

# __META__:title=Template de prompt efficace
## Contexte
Tu es un expert [DevOps/SRE/Cloud Architect] avec 10+ ans d'expérience.
Environnement: [Kubernetes 1.28 / AWS / Terraform]

## Tâche
[Description précise de ce que tu veux accomplir]

## Contraintes
- [Contrainte 1: ex. compatibilité avec Helm 3]
- [Contrainte 2: ex. pas de secrets en clair]
- [Contrainte 3: ex. doit fonctionner offline]

## Format attendu
[YAML/JSON/Markdown/Code avec langage]

## Exemple
[Optionnel: exemple du résultat attendu]

2. Sécurité et confidentialité

:::warning Ne jamais envoyer aux LLMs publics :

  • Secrets, tokens, clés API
  • Données clients/PII
  • Code propriétaire sensible
  • Configurations de sécurité détaillées :::
# Politique d'utilisation LLM
politique:
  donnees_autorisees:
    - "Documentation publique"
    - "Code open source"
    - "Configurations génériques"
    - "Logs anonymisés"

  donnees_interdites:
    - "Secrets et credentials"
    - "Données personnelles (RGPD)"
    - "Code propriétaire core"
    - "Configurations sécurité prod"

  providers_approuves:
    - name: "Anthropic Claude"
      usage: "Général, code review"
      data_retention: "30 jours"

    - name: "Azure OpenAI"
      usage: "Données sensibles"
      data_retention: "Aucune"
      compliance: ["SOC2", "HIPAA"]

    - name: "Mistral (self-hosted)"
      usage: "Données confidentielles"
      data_retention: "Local uniquement"

3. Coûts et optimisation

def estimate_llm_cost(
    input_tokens: int,
    output_tokens: int,
    model: str = "claude-3-sonnet"
) -> dict:
    """
    Estime le coût d'une requête LLM.
    Prix en USD pour 1M tokens (janvier 2025).
    """
    pricing = {
        "claude-3-opus": {"input": 15.0, "output": 75.0},
        "claude-3-sonnet": {"input": 3.0, "output": 15.0},
        "claude-3-haiku": {"input": 0.25, "output": 1.25},
        "gpt-4-turbo": {"input": 10.0, "output": 30.0},
        "gpt-4o": {"input": 5.0, "output": 15.0},
        "gpt-4o-mini": {"input": 0.15, "output": 0.60},
    }

    if model not in pricing:
        raise ValueError(f"Modèle inconnu: {model}")

    input_cost = (input_tokens / 1_000_000) * pricing[model]["input"]
    output_cost = (output_tokens / 1_000_000) * pricing[model]["output"]

    return {
        "model": model,
        "input_tokens": input_tokens,
        "output_tokens": output_tokens,
        "input_cost_usd": round(input_cost, 4),
        "output_cost_usd": round(output_cost, 4),
        "total_cost_usd": round(input_cost + output_cost, 4),
        "monthly_estimate_1000_requests": round((input_cost + output_cost) * 1000, 2)
    }

# Exemple
print(estimate_llm_cost(
    input_tokens=2000,   # ~1500 mots de contexte
    output_tokens=1000,  # ~750 mots de réponse
    model="claude-3-sonnet"
))
# {'model': 'claude-3-sonnet', 'total_cost_usd': 0.021, 'monthly_estimate_1000_requests': 21.0}

Self-hosting : LLMs on-premise

Pour les données sensibles, le self-hosting est souvent nécessaire.

Stack recommandée

version: '3.8'
services:
  ollama:
    image: ollama/ollama:latest
    ports:
      - "11434:11434"
    volumes:
      - ollama_data:/root/.ollama
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]
    environment:
      - OLLAMA_NUM_PARALLEL=4
      - OLLAMA_MAX_LOADED_MODELS=2

  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    ports:
      - "3000:8080"
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
      - WEBUI_AUTH=true
    volumes:
      - webui_data:/app/backend/data
    depends_on:
      - ollama

  litellm:
    image: ghcr.io/berriai/litellm:main-latest
    ports:
      - "4000:4000"
    environment:
      - OLLAMA_API_BASE=http://ollama:11434
    volumes:
      - ./litellm_config.yaml:/app/config.yaml
    command: ["--config", "/app/config.yaml"]

volumes:
  ollama_data:
  webui_data:
# Installer Ollama
curl -fsSL https://ollama.ai/install.sh | sh

# Télécharger un modèle
ollama pull mistral:7b-instruct-v0.2-q4_K_M

# Ou un modèle plus puissant (nécessite plus de VRAM)
ollama pull mixtral:8x7b-instruct-v0.1-q4_K_M

# Tester
curl http://localhost:11434/api/generate -d '{
  "model": "mistral:7b-instruct-v0.2-q4_K_M",
  "prompt": "Explique Docker en une phrase",
  "stream": false
}'

Conclusion

Les LLMs sont devenus des outils incontournables pour les professionnels DevOps. Ils permettent d'accélérer considérablement :

  • La génération de code : Configurations, scripts, IaC
  • La documentation : Auto-génération et mise à jour
  • Le debugging : Analyse de logs et identification de patterns
  • La revue de code : Détection automatique de problèmes

Les clés du succès :

  1. Choisir le bon modèle selon vos besoins (coût, performance, confidentialité)
  2. Structurer vos prompts pour des résultats cohérents
  3. Intégrer dans vos pipelines de manière progressive
  4. Respecter la sécurité des données sensibles
  5. Monitorer les coûts et optimiser l'usage

Ressources complémentaires

F

Florian Courouge

Expert DevOps & Kafka | Consultant freelance specialise dans les architectures distribuees et le streaming de donnees.

Articles similaires