SystemTce/dify-skills

Guide complet pour l'optimisation des performances des workflows et plugins Dify.

Qu'est-ce que dify-skills ?

Cette compétence fournit un guide complet pour l'optimisation des performances des workflows et plugins Dify, couvrant l'optimisation de la structure des graphes, le contrôle des coûts LLM, le réglage du pool de workers, l'optimisation du pool de variables, le traitement parallèle et la surveillance des performances. Elle est conçue pour les développeurs et les administrateurs système utilisant Dify qui rencontrent des temps d'exécution longs, des coûts d'API LLM élevés, une capacité de traitement parallèle insuffisante, ou une faible utilisation des ressources système. La compétence est basée sur les fonctionnalités de Dify (v0.8.0+ incluant les branches parallèles) et s'applique aux déploiements en cloud ou sur site. Elle inclut des listes de contrôle de diagnostic rapide, une matrice de sélection de modèles, des stratégies de mise en cache et des cas concrets comme l'optimisation de requêtes N+1 (réduction de 80% du temps d'exécution), le rendu de grands graphes (réduction de 75% du temps de chargement), la suppression de logs par lots (sans blocage métier), l'intégration TiDB (réduction de 86% du temps de requête) et le déploiement haute disponibilité Higress (99,9% de disponibilité). La compétence explique comment configurer le pool de workers, gérer les variables et utiliser l'itération parallèle pour améliorer le débit.

Compatible avec✓Claude Code~Codex CLI~Cursor✓Gemini CLI
npx skills add https://github.com/SystemTce/dify-skills/tree/main/03-performance

Installed? Explore more Développement et programmation skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Compétence d'Optimisation des Performances Dify

Aperçu

Cette compétence fournit un guide complet pour l'optimisation des performances des workflows et plugins Dify, couvrant l'optimisation de la structure des graphes, le contrôle des coûts LLM, le réglage du pool de workers, l'optimisation du pool de variables, le traitement parallèle et la surveillance des performances.

Scénarios d'application

Utilisez cette compétence lorsque vous rencontrez les situations suivantes :

  • ⏱️ Le temps d'exécution du workflow est trop long, nécessitant une optimisation
  • 💰 Les coûts d'API LLM sont trop élevés, nécessitant une réduction de la consommation de tokens
  • 🚀 La capacité de traitement parallèle est insuffisante, nécessitant une augmentation du débit
  • 📊 L'utilisation des ressources système est faible, nécessitant une optimisation de la configuration
  • 📈 Goulots d'étranglement de performance pour le traitement de données à grande échelle
  • 🔍 Besoin de diagnostic et de surveillance des performances

Valeur fondamentale

  • Effets d'optimisation quantifiables : Réduction de 40 à 60 % du temps d'exécution des branches parallèles, réduction de 30 à 50 % des appels LLM grâce au cache
  • Basé sur des cas concrets : 5 cas d'optimisation réels avec comparaison avant/après
  • Stratégies d'optimisation complètes : Couvre tous les niveaux (workflow, LLM, plugins, surveillance)
  • Outils de diagnostic rapide : Liste de contrôle de diagnostic sur 5 dimensions

Liste de contrôle de diagnostic rapide

Avant de commencer l'optimisation, utilisez la liste suivante pour localiser rapidement les problèmes de performance :

📊 Diagnostic de la structure du graphe

  • Existe-t-il trop de dépendances séquentielles ?
  • Est-il possible d'utiliser des branches parallèles ? (v0.8.0+)
  • Y a-t-il des nœuds et connexions inutiles ?
  • Le nombre de nœuds dépasse-t-il 50 ?
  • Utilisez-vous un modèle de conception approprié ?

🤖 Diagnostic d'utilisation LLM

  • Le choix du modèle est-il adapté ? (tâches légères avec modèles légers)
  • Le prompt est-il trop long ? (peut-il être simplifié ?)
  • Le cache de réponse LLM est-il activé ?
  • Utilisez-vous une sortie structurée ? (JSON Schema)
  • La consommation de tokens est-elle dans le budget ?

⚙️ Diagnostic du pool de workers

  • La configuration du nombre de workers est-elle raisonnable ? (2-8 threads)
  • La profondeur de la file d'attente est-elle trop grande ?
  • Y a-t-il du gaspillage de workers inactifs ?
  • La stratégie de mise à l'échelle est-elle raisonnable ?

💾 Diagnostic du pool de variables

  • Stockez-vous de grands objets dans le pool de variables ?
  • Les variables sont-elles nettoyées rapidement ?
  • Utilisez-vous des références plutôt que des copies ?
  • La portée des variables est-elle raisonnable ?

🔄 Diagnostic du traitement parallèle

  • L'itérateur est-il configuré avec parallel_nums ?
  • Utilisez-vous la réponse en streaming ?
  • Les tâches asynchrones sont-elles correctement configurées ?
  • Existe-t-il des opérations bloquantes ?

Première partie : Optimisation de la structure du graphe

1.1 Réduire les dépendances séquentielles

Problème : Trop de dépendances séquentielles entraînent une croissance linéaire du temps d'exécution du workflow.

Stratégie d'optimisation :

  1. Identifier les nœuds parallélisables : Analyser les dépendances entre nœuds pour trouver ceux qui peuvent être exécutés en parallèle
  2. Utiliser des branches parallèles : Dify v0.8.0+ supporte les branches parallèles
  3. Reconstruire le workflow : Transformer les flux séquentiels en mode parallèle + agrégation

Exemple :

# Avant optimisation : Exécution séquentielle (temps total = 3 + 2 + 4 = 9 secondes)
Début → Appel API 1 (3s) → Appel API 2 (2s) → Appel API 3 (4s) → Fin

# Après optimisation : Exécution parallèle (temps total = max(3,2,4) = 4 secondes)
Début → [Appel API 1 (3s), Appel API 2 (2s), Appel API 3 (4s)] → Agrégation de variables → Fin

Effet d'optimisation : Réduction du temps d'exécution de 40 à 60 %

1.2 Fonctionnalité de branches parallèles (v0.8.0+)

Dify v0.8.0 introduit la fonctionnalité de branches parallèles, permettant à plusieurs branches de s'exécuter simultanément.

Utilisation :

  1. Créer plusieurs branches dans l'éditeur de workflow
  2. S'assurer qu'il n'y a pas de dépendances de données entre les branches
  3. Utiliser un agrégateur de variables pour collecter les résultats

Scénarios d'application :

  • Appels parallèles de plusieurs nœuds HTTP Request
  • Exécution parallèle de plusieurs nœuds Tool
  • Traitement parallèle de la récupération de base de connaissances + appel API
  • Inférence parallèle multi-modèles (scénario de comparaison de modèles)

Exemple de configuration :

# Configuration des branches parallèles
parallel_branches:
  - branch_1:
      nodes: [http_request_1, code_1]
  - branch_2:
      nodes: [http_request_2, code_2]
  - branch_3:
      nodes: [tool_1, llm_1]

1.3 Éviter les nœuds inutiles

Problèmes courants :

  • Nœuds de transformation de données redondants
  • Nœuds de variables intermédiaires inutiles
  • Nœuds de conditions excessifs

Recommandations d'optimisation :

  • Fusionner les logiques de traitement similaires
  • Utiliser des nœuds de code pour remplacer plusieurs nœuds simples
  • Simplifier la logique des conditions

1.4 Modèles de conception de la structure du graphe

Choisir le modèle de conception approprié en fonction du type de tâche :

  1. Pipeline séquentiel : Début → LLM → Fin (tâches simples)
  2. Branche conditionnelle : Début → LLM → Si-Sinon → Chemins multiples (tâches de décision)
  3. Traitement itératif : Début → Code → Itération → LLM (tâches par lots)
  4. Récupération de connaissances : Début → Récupération de connaissances → LLM (applications RAG)
  5. Agrégation multi-sources : Plusieurs Tool/HTTP → Agrégateur de variables → LLM (agrégation de données)

Documentation détaillée : Voir workflow-optimization/graph-structure.md


Deuxième partie : Stratégies d'optimisation LLM

2.1 Stratégie de sélection de modèle

Le choix du modèle est crucial pour l'optimisation des coûts.

Matrice de sélection de modèle :

Type de tâcheModèle recommandéCoût en tokensScénario d'application
Classification simpleQwen-Turbo, Gemini FlashFaibleClassification de texte, analyse de sentiments
Génération de texteGPT-3.5-turbo, Qwen-PlusMoyenGénération de contenu, résumé
Raisonnement complexeGPT-4, Claude OpusÉlevéAnalyse complexe, décision
Déploiement localOllama (Llama 3, Qwen)Coût API nulScénarios sensibles à la vie privée

Comparaison des coûts :

  • GPT-4 : 0,03 $/1K tokens (entrée) + 0,06 $/1K tokens (sortie)
  • GPT-3.5-turbo : 0,0015 $/1K tokens (entrée) + 0,002 $/1K tokens (sortie)
  • Qwen-Turbo : 0,0008 ¥/1K tokens (environ 20 fois la différence de coût)

Recommandations d'optimisation :

  • Utiliser des modèles légers pour les tâches légères (Qwen/Gemini)
  • Utiliser des modèles puissants pour les tâches complexes (GPT-4/Claude)
  • Envisager d'utiliser des modèles locaux (Ollama) pour réduire les coûts

2.2 Techniques d'optimisation des prompts

Simplifier le prompt :

# Avant optimisation (150 tokens)
"""
Vous êtes un assistant de service client professionnel. Veuillez lire attentivement la question client ci-dessous et, en fonction de notre base de connaissances produits, fournir une réponse détaillée, précise et amicale. Dans votre réponse, veuillez noter les points suivants :
1. Gardez un ton professionnel et poli
2. Fournissez des solutions spécifiques
3. Si vous n'êtes pas sûr, indiquez-le
4. Citez la documentation produit pertinente

Question client : {query}
"""

# Après optimisation (50 tokens)
"""
En tant qu'assistant de service client, répondez à la question client en fonction de la base de connaissances, en restant professionnel et poli.

Question : {query}
"""

Économie de tokens : 66 % (150 → 50 tokens)

Autres techniques d'optimisation :

  • Supprimer les explications et exemples redondants
  • Utiliser des instructions concises
  • Éviter les contextes répétés
  • Utiliser une sortie structurée pour réduire les coûts d'analyse

2.3 Stratégie de cache

Cache de réponse LLM :

Utiliser Redis pour mettre en cache les réponses LLM, évitant les appels répétés.

Implémentation :

import hashlib
import redis

# Connexion à Redis
r = redis.Redis(host='localhost', port=6379, db=0)

def get_llm_response_with_cache(prompt, model="gpt-3.5-turbo"):
    # Générer la clé de cache
    cache_key = f"llm:{model}:{hashlib.md5(prompt.encode()).hexdigest()}"

    # Vérifier le cache
    cached = r.get(cache_key)
    if cached:
        return cached.decode('utf-8')

    # Appeler le LLM
    response = call_llm_api(prompt, model)

    # Stocker le cache (TTL : 1 heure)
    r.setex(cache_key, 3600, response)

    return response

Stratégies de cache :

  • Cache de réponse LLM : Même prompt retourne le résultat en cache
  • Cache de récupération de base de connaissances : Même requête retourne les vecteurs en cache
  • Cache de résultat de nœud : Évite l'exécution répétée du même nœud

Effet d'optimisation : Réduction de 30 à 50 % des appels API

2.4 Sortie structurée

Utiliser JSON Schema pour garantir la stabilité de la sortie LLM, réduisant les erreurs d'analyse et les tentatives.

Exemple de configuration :

{
  "type": "object",
  "properties": {
    "category": {
      "type": "string",
      "enum": ["Technique", "Commercial", "Après-vente"]
    },
    "priority": {
      "type": "integer",
      "minimum": 1,
      "maximum": 5
    },
    "summary": {
      "type": "string",
      "maxLength": 100
    }
  },
  "required": ["category", "priority", "summary"]
}

Effet d'optimisation :

  • Réduction du nombre de tokens de sortie
  • Évite les erreurs d'analyse et les tentatives
  • Améliore l'efficacité du traitement des nœuds en aval

Documentation détaillée : Voir llm-optimization/


Troisième partie : Réglage du pool de workers

3.1 Pool de workers dynamique

Dify utilise un pool de workers dynamique pour exécuter les nœuds en parallèle, avec une configuration par défaut de 2 à 8 threads de travail.

Architecture du pool de workers :

GraphEngine
├── ReadyQueue (File d'attente des nœuds prêts)
├── EventQueue (File d'attente des événements)
├── Dispatcher (Distributeur d'événements)
└── WorkerPool (2-8 threads de travail)
    ├── Worker 1
    ├── Worker 2
    ├── ...
    └── Worker N

3.2 Paramètres de configuration

Configuration clé :

ParamètreValeur par défautDescriptionRecommandation d'optimisation
min_workers2Nombre minimal de workersDéfinir en fonction des besoins de concurrence minimale
max_workers8Nombre maximal de workersDéfinir en fonction du nombre de cœurs CPU
queue_depth_threshold10Seuil de déclenchement de l'expansionAjuster en fonction de la profondeur moyenne de la file d'attente
idle_timeout60sTemps d'inactivité avant suppression d'un workerAjuster en fonction de la fréquence des tâches

Stratégie de mise à l'échelle :

# Condition d'expansion
if queue_depth > queue_depth_threshold and workers < max_workers:
    add_worker()

# Condition de réduction
if worker_idle_time > idle_timeout and workers > min_workers:
    remove_worker()

3.3 Référence de performance

Scénario de test : Workflow de 100 nœuds

Nombre de workersTemps d'exécutionDébitUtilisation CPU
245s2,2 nœuds/s40 %
425s4,0 nœuds/s70 %
815s6,7 nœuds/s95 %

Effet d'optimisation : Passage de 2 à 8 workers, amélioration du débit de 3x

3.4 Recommandations d'optimisation

  1. Définir max_workers en fonction du nombre de cœurs CPU : Généralement 1 à 2 fois le nombre de cœurs CPU
  2. Surveiller la profondeur de la file d'attente : Si la profondeur reste élevée, augmenter max_workers
  3. Éviter une expansion excessive : Trop de workers entraîne des frais généraux de changement de contexte
  4. Utiliser des E/S asynchrones : Pour les tâches intensives en E/S, utiliser le traitement asynchrone pour améliorer l'efficacité

Documentation détaillée : Voir workflow-optimization/parallel-execution.md


Quatrième partie : Optimisation du pool de variables

4.1 Éviter de stocker de grands objets

Problème : Stocker de grands objets (comme des fichiers volumineux, de longs textes) dans le pool de variables consomme beaucoup de mémoire.

Stratégie d'optimisation :

# ❌ Non recommandé : Stocker de grands objets
variables = {
    "large_file": open("large_file.pdf", "rb").read(),  # 10 Mo
    "long_text": "..." * 100000  # 1 Mo
}

# ✅ Recommandé : Stocker une référence
variables = {
    "file_path": "/chemin/vers/large_file.pdf",
    "text_summary": resume(long_text)  # Stocker uniquement le résumé
}

4.2 Utiliser des références plutôt que des copies

Problème : La copie de variables augmente l'utilisation de la mémoire et le temps de traitement.

Stratégie d'optimisation :

# ❌ Non recommandé : Copier la variable
resultat = traiter_donnees(data.copy())

# ✅ Recommandé : Utiliser une référence
resultat = traiter_donnees(data)  # Utiliser une référence pour les opérations en lecture seule

4.3 Nettoyer les variables rapidement

Problème : Les variables non utilisées consomment de la mémoire.

Stratégie d'optimisation :

# Dans un nœud de code, nettoyer les variables non utilisées
def main(args):
    # Traiter les données
    large_data = traiter_grandes_donnees(args["input"])
    resultat = extraire_resultat(large_data)

    # Nettoyer les grands objets
    del large_data

    return {"resultat": resultat}

4.4 Gestion de la portée des variables

Types de variables :

  • Variables système : sys.query, sys.files, sys.conversation_id
  • Variables de nœud : {{#node_id.output#}}
  • Variables d'environnement : Gestion de la configuration et des clés
  • Variables d'itération : Élément et index actuels dans une boucle

Recommandations d'optimisation :

  • Utiliser la portée minimale
  • Éviter la pollution des variables globales
  • Libérer les variables temporaires rapidement

Documentation détaillée : Voir workflow-optimization/variable-pool.md


Cinquième partie : Traitement parallèle et réponse en streaming

5.1 Traitement parallèle de l'itérateur

Utiliser le paramètre parallel_nums de l'itérateur pour traiter les données de tableau en parallèle.

Exemple de configuration :

iteration_node:
  type: iteration
  inputs:
    items: "{{#code_node.output.items#}}"
  config:
    parallel_nums: 5  # Traiter 5 éléments en parallèle

Comparaison des performances :

| Volume de données | Traitement séquentiel | Traitement parallèle (5) | Amélioration | |------------------|----------------------|-------------------------| | 10 éléments | 20s | 5s | 4x | | 50 éléments | 100s | 25s | 4x | | 100 éléments | 200s | 50s | 4x |

5.2 Réponse en streaming

Utiliser la réponse en streaming pour améliorer l'expérience utilisateur et réduire le temps jusqu'au premier octet (TTFB).

Implémentation :

# Activer la réponse en streaming pour l'appel API
reponse = requests.post(
    "https://api.dify.ai/v1/workflows/run",
    headers={"Authorization": f"Bearer {api_key}"},
    json={"inputs": {...}, "response_mode": "streaming"},
    stream=True
)

for ligne in reponse.iter_lines():
    if ligne:
        evenement = json.loads(ligne)
        print(evenement["data"])

Effet d'optimisation :

  • Réduction du TTFB de 80 %
  • Réduction du temps de réponse perçu par l'utilisateur de 50 %

5.3 Traitement des tâches asynchrones

Utiliser Celery pour traiter de manière asynchrone les tâches de longue durée.

Architecture :

Serveur API → File d'attente Celery → Pool de workers → Exécution des tâches

Scénarios d'application :

  • Traitement de fichiers volumineux
  • Importation de données par lots
  • Appels API de longue durée
  • Tâches planifiées

5.4 Optimisation de l'architecture pilotée par les événements

Dify adopte une architecture pilotée par les événements, où l'exécution des nœuds produit un flux d'événements.

Stratégies d'optimisation :

  • Utiliser un traitement d'événements non bloquant
  • Traiter la file d'attente d'événements par lots
  • Optimiser la logique de distribution des événements

Documentation détaillée : Voir workflow-optimization/parallel-execution.md


Sixième partie : Cas d'optimisation des performances

Cas 1 : Optimisation des requêtes de base de données (problème N+1)

Scénario d'application :

  • Le workflow nécessite l'interrogation de plusieurs données connexes
  • Présence de requêtes en boucle vers la base de données
  • Le temps d'exécution augmente linéairement avec le volume de données

Caractéristiques du problème :

  • Nombre de requêtes = 1 + N (N est le nombre d'enregistrements)
  • Connexions fréquentes à la base de données
  • Temps d'exécution trop long

État avant optimisation :

# Récupérer la liste des utilisateurs
utilisateurs = query("SELECT * FROM users LIMIT 100")

# Pour chaque utilisateur, interroger les commandes (problème N+1)
for utilisateur in utilisateurs:
    commandes = query(f"SELECT * FROM orders WHERE user_id = {utilisateur.id}")
    utilisateur.commandes = commandes
  • Nombre de requêtes : 101 (1 + 100)
  • Temps d'exécution : 10,5 s
  • Charge de la base de données : Élevée

Solution d'optimisation :

# Interroger toutes les données en une seule fois
utilisateurs = query("SELECT * FROM users LIMIT 100")
ids_utilisateurs = [utilisateur.id for utilisateur in utilisateurs]

# Interroger les commandes par lots
commandes = query(f"SELECT * FROM orders WHERE user_id IN ({','.join(map(str, ids_utilisateurs))})")

# Associer les données en mémoire
commandes_par_utilisateur = {}
for commande in commandes:
    if commande.user_id not in commandes_par_utilisateur:
        commandes_par_utilisateur[commande.user_id] = []
    commandes_par_utilisateur[commande.user_id].append(commande)

for utilisateur in utilisateurs:
    utilisateur.commandes = commandes_par_utilisateur.get(utilisateur.id, [])

Résultat après optimisation :

  • Nombre de requêtes : 2 (réduction de 98 %)
  • Temps d'exécution : 2,1 s (réduction de 80 %)
  • Charge de la base de données : Faible

Bénéfices attendus :

  • Court terme : Réduction de 80 % du temps d'exécution, réduction de la charge de la base de données
  • Long terme : Prise en charge de volumes de données plus importants, amélioration de l'évolutivité du système
  • ROI : Coût de développement de 2 heures, économie mensuelle de 30 % sur les coûts de serveur

Cas 2 : Optimisation du rendu de graphes à grande échelle (100+ nœuds)

Scénario d'application :

  • Le workflow contient 100+ nœuds
  • Rendu frontal saccadé
  • Réponse lente de l'éditeur

Caractéristiques du problème :

  • Temps de chargement de la page > 5 s
  • Latence notable lors du glisser-déposer de nœuds
  • Utilisation mémoire élevée du navigateur

État avant optimisation :

  • Nombre de nœuds : 150
  • Temps de chargement de la page : 8,5 s
  • Utilisation mémoire : 500 Mo
  • Expérience utilisateur : Saccades graves

Solution d'optimisation :

  1. Défilement virtuel : Ne rendre que les nœuds dans la zone visible
  2. Chargement paresseux des nœuds : Charger les détails des nœuds à la demande
  3. Optimisation Canvas : Utiliser Canvas au lieu du rendu DOM
  4. Optimisation de la gestion d'état : Réduire les re-rendus inutiles

Résultat après optimisation :

  • Temps de chargement de la page : 2,1 s (réduction de 75 %)
  • Utilisation mémoire : 150 Mo (réduction de 70 %)
  • Expérience utilisateur : Fluide

Bénéfices attendus :

  • Court terme : Amélioration significative de l'expérience utilisateur
  • Long terme : Prise en charge de conceptions de workflow plus complexes
  • ROI : Coût de développement d'une semaine, augmentation de 40 % de la satisfaction utilisateur

Cas 3 : Optimisation de la suppression des logs de workflow

Scénario d'application :

  • Nécessité de nettoyer périodiquement les logs historiques
  • Volume important de logs (millions)
  • Opération de suppression longue

Caractéristiques du problème :

  • L'opération de suppression bloque la base de données
  • Impact sur les opérations normales
  • Temps d'exécution imprévisible

État avant optimisation :

  • Nombre de logs : 5 millions
  • Temps de suppression : 45 minutes
  • Verrou de base de données : Verrouillage de table prolongé
  • Impact sur les opérations : Grave

Solution d'optimisation :

# Avant optimisation : Suppression en une seule fois
DELETE FROM workflow_logs WHERE created_at < '2024-01-01';

# Après optimisation : Suppression par lots
taille_lot = 10000
while True:
    supprime = DELETE FROM workflow_logs
                WHERE created_at < '2024-01-01'
                LIMIT taille_lot;

    if supprime < taille_lot:
        break

    # Petite pause pour libérer le verrou de la base de données
    sleep(0.1)

Résultat après optimisation :

  • Temps de suppression : 50 minutes (légèrement augmenté, mais ne bloque pas les opérations)
  • Verrou de base de données : Verrouillage court (0,1 s)
  • Impact sur les opérations : Aucun

Bénéfices attendus :

  • Court terme : Les opérations ne sont pas affectées
  • Long terme : Stabilité accrue de la base de données
  • ROI : Coût de développement de 4 heures, évite les pertes dues aux interruptions d'activité

Cas 4 : Intégration du stockage distribué TiDB

Scénario d'application :

  • Volume important de données de base de connaissances (niveau To)
  • Goulot d'étranglement de performance avec PostgreSQL monolithique
  • Besoin de capacité de mise à l'échelle horizontale

Caractéristiques du problème :

  • Temps de réponse des requêtes > 5 s
  • Utilisation CPU de la base de données > 90 %
  • Impossible d'étendre davantage

État avant optimisation :

  • Base de données : PostgreSQL monolithique
  • Volume de données : 2 To
  • Temps de réponse des requêtes : 8,5 s
  • Capacité d'extension : Limitée

Solution d'optimisation :

  1. Migration vers TiDB : Base de données SQL distribuée
  2. Optimisation des index vectoriels : Utiliser TiDB Vector pour accélérer la récupération
  3. Séparation lecture/écriture : Distribuer les requêtes de lecture vers plusieurs réplicas
  4. Partitionnement de tables : Partitionner par temps pour améliorer l'efficacité des requêtes

Résultat après optimisation :

  • Temps de réponse des requêtes : 1,2 s (réduction de 86 %)
  • CPU de la base de données : 40 % (réduction de 50 %)
  • Capacité d'extension : Prise en charge de 10x le volume de données

Bénéfices attendus :

  • Court terme : Amélioration significative des performances des requêtes
  • Long terme : Prise en charge de la croissance rapide de l'activité
  • ROI : Coût de migration de 2 semaines, prise en charge de 10x la croissance de l'activité

Cas 5 : Déploiement haute disponibilité avec Higress AI Gateway

Scénario d'application :

  • L'environnement de production nécessite une haute disponibilité
  • Équilibrage de charge pour plusieurs modèles LLM
  • Besoin de capacité de basculement

Caractéristiques du problème :

  • Risque de point de défaillance unique
  • Appels API LLM instables
  • Incapacité à faire face aux pics de trafic

État avant optimisation :

  • Architecture : Instance unique Dify
  • Disponibilité : 95 %
  • Temps de récupération après panne : 10 minutes
  • Pic de trafic : Incapable de gérer

Solution d'optimisation :

# Configuration de Higress AI Gateway
apiVersion: networking.higress.io/v1
kind: McpBridge
metadata:
  name: dify-gateway
spec:
  replicas: 3  # 3 instances
  loadBalancer:
    algorithm: round-robin
  healthCheck:
    enabled: true
    interval: 10s
  failover:
    enabled: true
    maxRetries: 3

Architecture :

Requêtes utilisateur → Higress Gateway → [Instance Dify 1, Instance Dify 2, Instance Dify 3]
                ↓
          Équilibrage de charge + Basculement

Résultat après optimisation :

  • Disponibilité : 99,9 %
  • Temps de récupération après panne : < 1 seconde (basculement automatique)
  • Pic de trafic : Prise en charge de 10x le trafic

Bénéfices attendus :

  • Court terme : Amélioration significative de la stabilité du système
  • Long terme : Prise en charge des applications critiques pour l'activité
  • ROI : Coût de déploiement de 3 jours, évite les pertes dues aux interruptions d'activité

Septième partie : Tests de performance et surveillance

7.1 Système d'indicateurs de performance

Indicateurs d'exécution du workflow :

IndicateurValeur cibleDescription
Temps d'exécution moyen< 2sTemps d'exécution complet du workflow
Temps d'exécution P95< 5sTemps d'exécution pour 95% des requêtes
Temps d'exécution P99< 10sTemps d'exécution pour 99% des requêtes
Taux de succès des nœuds> 99%Proportion de nœuds exécutés avec succès
Taux de succès des appels API> 99,5%Proportion de succès des appels API externes
Capacité de traitement parallèle> 100 QPSNombre de requêtes traitées par seconde

Indicateurs d'utilisation des ressources :

IndicateurValeur cibleDescription
Utilisation CPU< 70%Utilisation moyenne du CPU
Utilisation mémoire< 80%Utilisation moyenne de la mémoire
Connexions base de données< 80%Utilisation du pool de connexions
Mémoire Redis< 70%Utilisation de la mémoire Redis

Indicateurs de coût :

IndicateurValeur cibleDescription
Coût d'utilisation des tokens< BudgetCoût de l'API LLM
Coût d'infrastructure< BudgetCoût des serveurs, base de données
Coût par utilisateurEn baisse continueCoût par utilisateur

7.2 Outils de surveillance

Surveillance LLMOps :

# Surveillance intégrée Dify
from dify import Monitor

moniteur = Monitor()

# Enregistrer l'exécution du workflow
moniteur.log_workflow_execution(
    workflow_id="xxx",
    execution_time=2.5,
    node_count=10,
    token_usage=1500,
    cost=0.003
)

# Interroger les statistiques
stats = moniteur.get_workflow_stats(
    workflow_id="xxx",
    time_range="7d"
)

Traçage d'exécution :

  • Historique d'exécution du workflow
  • Statistiques des étapes d'exécution des nœuds
  • Statistiques d'utilisation LLM
  • Logs d'erreur et enregistrements de tentatives

Surveillance des ressources :

# Prometheus + Grafana
# Surveiller le CPU, la mémoire, le réseau, le disque

# Exemple de requête
rate(dify_workflow_execution_total[5m])  # Taux d'exécution du workflow
histogram_quantile(0.95, dify_workflow_duration_seconds)  # Temps d'exécution P95

7.3 Méthodes de test de performance

Test de charge :

# Utiliser Locust pour les tests de charge
from locust import HttpUser, task, between

class UtilisateurDify(HttpUser):
    wait_time = between(1, 3)

    @task
    def executer_workflow(self):
        self.client.post(
            "/v1/workflows/run",
            headers={"Authorization": f"Bearer {self.api_key}"},
            json={"inputs": {"query": "Question de test"}}
        )

# Exécuter le test
# locust -f load_test.py --users 100 --spawn-rate 10

Test de stress :

# Utiliser Apache Bench
ab -n 1000 -c 50 -H "Authorization: Bearer xxx" \
   -p request.json \
   https://api.dify.ai/v1/workflows/run

Test de référence :

# Test de performance de référence
import time

def benchmark_workflow(workflow_id, iterations=100):
    times = []
    for i in range(iterations):
        start = time.time()
        run_workflow(workflow_id)
        end = time.time()
        times.append(end - start)

    return {
        "avg": sum(times) / len(times),
        "p50": sorted(times)[len(times) // 2],
        "p95": sorted(times)[int(len(times) * 0.95)],
        "p99": sorted(times)[int(len(times) * 0.99)]
    }

7.4 Outils d'analyse de performance

Profileur Python :

import cProfile
import pstats

def profiler_workflow():
    # ...

# Exemple de profileur
cProfile.run('profiler_workflow()', 'profile_stats')
p = pstats.Stats('profile_stats')
p.sort_stats('cumulative').print_stats(10)

Analyse des performances de Dify :

# Utiliser les endpoints de diagnostique intégrés de Dify
curl -X GET http://localhost:5001/health
curl -X GET http://localhost:5001/metrics

Documentation détaillée : Voir monitoring/

Individual skills in this repo

This repo contains 5 individual skills — each has its own dedicated page.

Skills associés