Dify Optimización de Rendimiento SKILL
Resumen
Este SKILL proporciona una guía completa de optimización de rendimiento para flujos de trabajo y plugins de Dify, cubriendo temas clave como la optimización de la estructura del grafo, el control de costos de LLM, el ajuste del pool de workers, la optimización del pool de variables, el procesamiento paralelo y la monitorización del rendimiento.
Escenarios de Aplicación
Debe usar este SKILL cuando se encuentre con las siguientes situaciones:
- ⏱️ El tiempo de ejecución del flujo de trabajo es demasiado largo y necesita optimización de rendimiento
- 💰 El costo de la API de LLM es demasiado alto y necesita reducir el consumo de tokens
- 🚀 La capacidad de procesamiento concurrente es insuficiente y necesita aumentar el rendimiento
- 📊 La utilización de recursos del sistema es baja y necesita optimizar la configuración
- 📈 Cuellos de botella de rendimiento en el procesamiento de datos a gran escala
- 🔍 Necesita realizar diagnóstico y monitorización de rendimiento
Valor Central
- Efectos de optimización cuantificables: La ejecución de ramas paralelas reduce el tiempo en un 40-60%, el caché de LLM reduce las llamadas en un 30-50%
- Impulsado por casos prácticos: 5 casos de optimización reales, con comparaciones antes y después
- Estrategias de optimización integrales: Cubre todos los niveles: flujo de trabajo, LLM, plugins, monitorización, etc.
- Herramienta de diagnóstico rápido: Lista de verificación de diagnóstico de 5 dimensiones
Lista de Verificación de Diagnóstico Rápido
Antes de comenzar la optimización, use la siguiente lista para localizar rápidamente los problemas de rendimiento:
📊 Diagnóstico de Estructura del Grafo
- ¿Existen demasiadas dependencias en serie?
- ¿Se pueden usar ramas paralelas? (v0.8.0+)
- ¿Hay nodos y conexiones innecesarios?
- ¿El número de nodos supera los 50?
- ¿Se está utilizando el patrón de diseño adecuado?
🤖 Diagnóstico de Uso de LLM
- ¿La selección del modelo es adecuada? (tareas ligeras con modelos ligeros)
- ¿El prompt es demasiado largo? (¿se puede simplificar?)
- ¿Está habilitado el caché de respuestas de LLM?
- ¿Se está utilizando salida estructurada? (JSON Schema)
- ¿El consumo de tokens está dentro del presupuesto?
⚙️ Diagnóstico del Pool de Workers
- ¿La configuración de la cantidad de workers es razonable? (2-8 hilos)
- ¿La profundidad de la cola es demasiado grande?
- ¿Hay workers inactivos que se desperdician?
- ¿La estrategia de escalado es razonable?
💾 Diagnóstico del Pool de Variables
- ¿Se almacenan objetos grandes en el pool de variables?
- ¿Las variables se limpian de manera oportuna?
- ¿Se utiliza referencia en lugar de copia?
- ¿El ámbito de las variables es razonable?
🔄 Diagnóstico de Procesamiento Concurrente
- ¿El iterador tiene configurado
parallel_nums? - ¿Se utilizan respuestas en streaming?
- ¿Las tareas asíncronas están configuradas correctamente?
- ¿Hay operaciones bloqueantes?
Primera Parte: Optimización de la Estructura del Grafo
1.1 Reducir Dependencias en Serie
Problema: Demasiadas dependencias en serie hacen que el tiempo de ejecución del flujo de trabajo aumente linealmente.
Estrategias de Optimización:
- Identificar nodos paralelizables: Analice las dependencias entre nodos para encontrar aquellos que se pueden ejecutar en paralelo
- Usar ramas paralelas: Dify v0.8.0+ admite la función de ramas paralelas
- Reestructurar el flujo de trabajo: Transforme el flujo en serie en un patrón paralelo + agregación
Ejemplo:
# Antes de optimizar: Ejecución en serie (tiempo total = 3 + 2 + 4 = 9 segundos)
Inicio → LlamadaAPI1(3s) → LlamadaAPI2(2s) → LlamadaAPI3(4s) → Fin
# Después de optimizar: Ejecución en paralelo (tiempo total = max(3,2,4) = 4 segundos)
Inicio → [LlamadaAPI1(3s), LlamadaAPI2(2s), LlamadaAPI3(4s)] → AgregadorVariables → Fin
Efecto de la optimización: Reducción del tiempo de ejecución en un 40-60%
1.2 Función de Ramas Paralelas (v0.8.0+)
Dify v0.8.0 introdujo la función de ramas paralelas, permitiendo que múltiples ramas se ejecuten simultáneamente.
Método de uso:
- Cree múltiples ramas en el editor de flujo de trabajo
- Asegúrese de que no haya dependencias de datos entre las ramas
- Use un agregador de variables para recopilar los resultados
Escenarios de aplicación:
- Múltiples nodos HTTP Request en llamadas paralelas
- Múltiples nodos Tool en ejecución paralela
- Recuperación de Knowledge + Llamada API en paralelo
- Inferencia paralela de múltiples modelos (escenario de comparación de modelos)
Ejemplo de configuración:
# Configuración de ramas paralelas
ramas_paralelas:
- rama_1:
nodos: [peticion_http_1, codigo_1]
- rama_2:
nodos: [peticion_http_2, codigo_2]
- rama_3:
nodos: [herramienta_1, llm_1]
1.3 Evitar Nodos Innecesarios
Problemas comunes:
- Nodos redundantes de transformación de datos
- Nodos de variables intermedias innecesarios
- Nodos de condición excesivos
Recomendaciones de optimización:
- Combine lógicas de procesamiento similares
- Use nodos de código en lugar de múltiples nodos simples
- Simplifique la lógica de las condiciones
1.4 Patrones de Diseño de Estructura del Grafo
Seleccione el patrón de diseño adecuado según el tipo de tarea:
- Pipeline secuencial: Inicio → LLM → Fin (tareas simples)
- Ramas condicionales: Inicio → LLM → Si-No → Múltiples rutas (tareas de decisión)
- Procesamiento iterativo: Inicio → Código → Iteración → LLM (tareas por lotes)
- Recuperación de conocimiento: Inicio → Recuperación-Knowledge → LLM (aplicaciones RAG)
- Agregación de múltiples fuentes: Múltiples Tool/HTTP → Agregador-Variables → LLM (agregación de datos)
Documentación detallada: Consulte workflow-optimization/graph-structure.md
Segunda Parte: Estrategias de Optimización de LLM
2.1 Estrategia de Selección de Modelos
Elegir el modelo adecuado es clave para la optimización de costos.
Matriz de selección de modelos:
| Tipo de Tarea | Modelo Recomendado | Costo de Token | Escenario de Aplicación |
|---|---|---|---|
| Clasificación simple | Qwen-Turbo, Gemini Flash | Bajo | Clasificación de texto, análisis de sentimientos |
| Generación de texto | GPT-3.5-turbo, Qwen-Plus | Medio | Generación de contenido, resúmenes |
| Razonamiento complejo | GPT-4, Claude Opus | Alto | Análisis complejo, decisiones |
| Despliegue local | Ollama (Llama 3, Qwen) | Costo de API cero | Escenarios con datos sensibles |
Comparación de costos:
- GPT-4: $0.03/1K tokens (entrada) + $0.06/1K tokens (salida)
- GPT-3.5-turbo: $0.0015/1K tokens (entrada) + $0.002/1K tokens (salida)
- Qwen-Turbo: ¥0.0008/1K tokens (aproximadamente 20 veces de diferencia de costo)
Recomendaciones de optimización:
- Tareas ligeras use modelos ligeros (Qwen/Gemini)
- Tareas complejas use modelos potentes (GPT-4/Claude)
- Considere usar modelos locales (Ollama) para reducir costos
2.2 Técnicas de Optimización de Prompt
Simplificar el Prompt:
# Antes de optimizar (150 tokens)
"""
Eres un asistente de atención al cliente profesional. Lee cuidadosamente la siguiente pregunta del cliente y, basándote en nuestra base de conocimientos de productos,
proporciona una respuesta detallada, precisa y amigable. Ten en cuenta los siguientes puntos al responder:
1. Mantén un tono profesional y cortés
2. Proporciona soluciones específicas
3. Si no estás seguro, indícalo
4. Cita la documentación de productos relevante
Pregunta del cliente: {query}
"""
# Después de optimizar (50 tokens)
"""
Como asistente de atención al cliente, responde la pregunta del cliente basándote en la base de conocimientos, manteniendo un tono profesional y cortés.
Pregunta: {query}
"""
Ahorro de tokens: 66% (150 → 50 tokens)
Otras técnicas de optimización:
- Eliminar explicaciones y ejemplos redundantes
- Usar instrucciones concisas
- Evitar contexto repetitivo
- Usar salida estructurada para reducir costos de parseo
2.3 Estrategias de Caché
Caché de respuestas de LLM:
Use Redis para cachear las respuestas de LLM, evitando llamadas repetitivas.
Implementación:
import hashlib
import redis
# Conectar a Redis
r = redis.Redis(host='localhost', port=6379, db=0)
def obtener_respuesta_llm_con_cache(prompt, modelo="gpt-3.5-turbo"):
# Generar clave de caché
clave_cache = f"llm:{modelo}:{hashlib.md5(prompt.encode()).hexdigest()}"
# Verificar caché
cacheado = r.get(clave_cache)
if cacheado:
return cacheado.decode('utf-8')
# Llamar a LLM
respuesta = llamar_api_llm(prompt, modelo)
# Almacenar en caché (TTL: 1 hora)
r.setex(clave_cache, 3600, respuesta)
return respuesta
Estrategias de caché:
- Caché de respuestas de LLM: Mismo Prompt devuelve resultado cacheado
- Caché de recuperación de Knowledge: Misma consulta devuelve vector cacheado
- Caché de resultados de nodos: Evita ejecutar el mismo nodo repetidamente
Efecto de la optimización: Reducción de llamadas a API en un 30-50%
2.4 Salida Estructurada
Use JSON Schema para garantizar la estabilidad de la salida de LLM, reduciendo errores de parseo y reintentos.
Ejemplo de configuración:
{
"type": "object",
"properties": {
"categoria": {
"type": "string",
"enum": ["Técnica", "Ventas", "Postventa"]
},
"prioridad": {
"type": "integer",
"minimum": 1,
"maximum": 5
},
"resumen": {
"type": "string",
"maxLength": 100
}
},
"required": ["categoria", "prioridad", "resumen"]
}
Efecto de la optimización:
- Reduce la cantidad de tokens de salida
- Evita errores de parseo y reintentos
- Mejora la eficiencia del procesamiento en nodos downstream
Documentación detallada: Consulte llm-optimization/
Tercera Parte: Ajuste del Pool de Workers
3.1 Pool de Workers Dinámico
Dify usa un pool de workers dinámico para ejecutar nodos en paralelo, con una configuración predeterminada de 2 a 8 hilos de trabajo.
Arquitectura del Pool de Workers:
GraphEngine
├── ReadyQueue (Cola de nodos listos)
├── EventQueue (Cola de eventos)
├── Dispatcher (Distribuidor de eventos)
└── WorkerPool (2-8 hilos de trabajo)
├── Worker 1
├── Worker 2
├── ...
└── Worker N
3.2 Parámetros de Configuración
Configuración clave:
| Parámetro | Valor por defecto | Descripción | Recomendación de optimización |
|---|---|---|---|
| min_workers | 2 | Número mínimo de Workers | Establecer según la concurrencia mínima requerida |
| max_workers | 8 | Número máximo de Workers | Establecer según el número de núcleos de CPU |
| umbral_profundidad_cola | 10 | Umbral de activación de escalado | Ajustar según la profundidad promedio de la cola |
| tiempo_espera_inactivo | 60s | Tiempo de espera de inactividad del Worker | Ajustar según la frecuencia de las tareas |
Estrategia de escalado:
# Condición de escalado hacia arriba
if profundidad_cola > umbral_profundidad_cola and workers < max_workers:
agregar_worker()
# Condición de escalado hacia abajo
if tiempo_inactivo_worker > tiempo_espera_inactivo and workers > min_workers:
eliminar_worker()
3.3 Benchmark de Rendimiento
Escenario de prueba: Flujo de trabajo con 100 nodos
| Número de Workers | Tiempo de ejecución | Rendimiento | Uso de CPU |
|---|---|---|---|
| 2 | 45s | 2.2 nodos/s | 40% |
| 4 | 25s | 4.0 nodos/s | 70% |
| 8 | 15s | 6.7 nodos/s | 95% |
Efecto de la optimización: Al aumentar los Workers de 2 a 8, el rendimiento aumenta 3x
3.4 Recomendaciones de Optimización
- Configure max_workers según el número de núcleos de CPU: Generalmente, se establece en 1-2 veces el número de núcleos de CPU
- Monitoree la profundidad de la cola: Si la profundidad de la cola es consistentemente alta, aumente max_workers
- Evite el escalado excesivo: Demasiados Workers pueden generar sobrecarga por cambios de contexto
- Use I/O asíncrono: Para tareas intensivas en I/O, use procesamiento asíncrono para mejorar la eficiencia
Documentación detallada: Consulte workflow-optimization/parallel-execution.md
Cuarta Parte: Optimización del Pool de Variables
4.1 Evitar Almacenar Objetos Grandes
Problema: Almacenar objetos grandes (como archivos grandes, texto largo) en el pool de variables consume mucha memoria.
Estrategias de optimización:
# ❌ No recomendado: Almacenar objetos grandes
variables = {
"archivo_grande": open("archivo_grande.pdf", "rb").read(), # 10MB
"texto_largo": "..." * 100000 # 1MB
}
# ✅ Recomendado: Almacenar referencia
variables = {
"ruta_archivo": "/ruta/al/archivo_grande.pdf",
"resumen_texto": resumir(texto_largo) # Almacenar solo el resumen
}
4.2 Usar Referencias en Lugar de Copias
Problema: Copiar variables aumenta el uso de memoria y el tiempo de procesamiento.
Estrategias de optimización:
# ❌ No recomendado: Copiar variables
resultado = procesar_datos(datos.copy())
# ✅ Recomendado: Usar referencias
resultado = procesar_datos(datos) # Operaciones de solo lectura usan referencia
4.3 Limpiar Variables de Manera Oportuna
Problema: Las variables que ya no se usan ocupan memoria.
Estrategias de optimización:
# En un nodo de código, limpiar variables que ya no se usan
def main(args):
# Procesar datos
datos_grandes = procesar_datos_grandes(args["input"])
resultado = extraer_resultado(datos_grandes)
# Limpiar objetos grandes
del datos_grandes
return {"resultado": resultado}
4.4 Gestión del Ámbito de Variables
Tipos de variables:
- Variables del sistema:
sys.query,sys.files,sys.conversation_id - Variables de nodo:
{{#node_id.output#}} - Variables de entorno: Configuración y gestión de claves
- Variables de iteración: Elemento actual e índice en el bucle
Recomendaciones de optimización:
- Use el ámbito más pequeño posible
- Evite la contaminación de variables globales
- Libere variables temporales a tiempo
Documentación detallada: Consulte workflow-optimization/variable-pool.md
Quinta Parte: Procesamiento Paralelo y Respuestas en Streaming
5.1 Procesamiento Paralelo con Iteradores
Use el parámetro parallel_nums del iterador para procesar datos en arrays de manera paralela.
Ejemplo de configuración:
nodo_iteracion:
type: iteration
inputs:
items: "{{#codigo_nodo.output.items#}}"
config:
parallel_nums: 5 # Procesar 5 elementos en paralelo
Comparación de rendimiento:
| Cantidad de datos | Procesamiento en serie | Procesamiento paralelo (5) | Mejora |
|---|---|---|---|
| 10 elementos | 20s | 5s | 4x |
| 50 elementos | 100s | 25s | 4x |
| 100 elementos | 200s | 50s | 4x |
5.2 Respuestas en Streaming
Use respuestas en streaming para mejorar la experiencia del usuario, reduciendo el tiempo hasta el primer byte (TTFB).
Implementación:
# Llamada a API con respuestas en streaming
respuesta = requests.post(
"https://api.dify.ai/v1/workflows/run",
headers={"Authorization": f"Bearer {api_key}"},
json={"inputs": {...}, "response_mode": "streaming"},
stream=True
)
for linea in respuesta.iter_lines():
if linea:
evento = json.loads(linea)
print(evento["data"])
Efecto de la optimización:
- TTFB reducido en un 80%
- Tiempo de respuesta percibido por el usuario reducido en un 50%
5.3 Procesamiento de Tareas Asíncronas
Use Celery para procesar tareas de larga duración de manera asíncrona.
Arquitectura:
Servidor API → Cola Celery → Pool de Workers → Ejecución de Tareas
Escenarios de aplicación:
- Procesamiento de archivos grandes
- Importación de datos por lotes
- Llamadas a API de larga duración
- Tareas programadas
5.4 Optimización de Arquitectura Basada en Eventos
Dify adopta una arquitectura basada en eventos, donde la ejecución de nodos genera un flujo de eventos.
Estrategias de optimización:
- Use manejo de eventos no bloqueante
- Procese las colas de eventos por lotes
- Optimice la lógica de distribución de eventos
Documentación detallada: Consulte workflow-optimization/parallel-execution.md
Sexta Parte: Casos de Optimización de Rendimiento
Caso 1: Optimización de Consultas de Base de Datos (Problema N+1)
Escenario de aplicación:
- El flujo de trabajo necesita consultar múltiples datos relacionados
- Existen consultas cíclicas a la base de datos
- El tiempo de ejecución aumenta linealmente con la cantidad de datos
Características del problema:
- Número de consultas = 1 + N (N es el número de registros)
- Las conexiones a la base de datos se establecen y cierran con frecuencia
- Tiempo de ejecución excesivo
Estado antes de la optimización:
# Consultar lista de usuarios
usuarios = consultar("SELECT * FROM users LIMIT 100")
# Consultar pedidos para cada usuario (problema N+1)
for usuario in usuarios:
pedidos = consultar(f"SELECT * FROM orders WHERE user_id = {usuario.id}")
usuario.orders = pedidos
- Número de consultas: 101 (1 + 100)
- Tiempo de ejecución: 10.5s
- Carga de la base de datos: Alta
Plan de optimización:
# Consultar todos los datos de una sola vez
usuarios = consultar("SELECT * FROM users LIMIT 100")
ids_usuarios = [usuario.id for usuario in usuarios]
# Consultar pedidos por lote
pedidos = consultar(f"SELECT * FROM orders WHERE user_id IN ({','.join(map(str, ids_usuarios))})")
# Asociar datos en memoria
pedidos_por_usuario = {}
for pedido in pedidos:
if pedido.user_id not in pedidos_por_usuario:
pedidos_por_usuario[pedido.user_id] = []
pedidos_por_usuario[pedido.user_id].append(pedido)
for usuario in usuarios:
usuario.orders = pedidos_por_usuario.get(usuario.id, [])
Efecto después de la optimización:
- Número de consultas: 2 (reducción del 98%)
- Tiempo de ejecución: 2.1s (reducción del 80%)
- Carga de la base de datos: Baja
Beneficios esperados:
- Corto plazo: Reducción del 80% en el tiempo de ejecución, menor carga en la base de datos
- Largo plazo: Admite escalas de datos más grandes, mejora la escalabilidad del sistema
- ROI: Costo de desarrollo 2 horas, ahorro mensual del 30% en costos de servidor
Caso 2: Optimización de Renderizado de Nodos a Gran Escala (100+ nodos)
Escenario de aplicación:
- El flujo de trabajo contiene 100+ nodos
- La renderización del frontend es lenta
- El editor responde lentamente
Características del problema:
- Tiempo de carga de la página > 5s
- Retraso notable al arrastrar nodos
- Alto uso de memoria del navegador
Estado antes de la optimización:
- Número de nodos: 150
- Tiempo de carga de la página: 8.5s
- Uso de memoria: 500MB
- Experiencia de usuario: Muy lenta
Plan de optimización:
- Desplazamiento virtual: Renderizar solo los nodos en el área visible
- Carga diferida de nodos: Cargar detalles de nodos según demanda
- Optimización con Canvas: Usar Canvas en lugar de renderizado DOM
- Optimización de gestión de estado: Reducir re-renderizados innecesarios
Efecto después de la optimización:
- Tiempo de carga de la página: 2.1s (reducción del 75%)
- Uso de memoria: 150MB (reducción del 70%)
- Experiencia de usuario: Fluida
Beneficios esperados:
- Corto plazo: Mejora significativa de la experiencia de usuario
- Largo plazo: Admite el diseño de flujos de trabajo más complejos
- ROI: Costo de desarrollo 1 semana, aumento del 40% en la satisfacción del usuario
Caso 3: Optimización de Rendimiento en la Eliminación de Logs de Flujo de Trabajo
Escenario de aplicación:
- Necesidad de limpiar logs históricos periódicamente
- Gran volumen de datos de logs (millones)
- La operación de eliminación es lenta
Características del problema:
- La eliminación bloquea la base de datos
- Afecta las operaciones normales
- Tiempo de ejecución impredecible
Estado antes de la optimización:
- Cantidad de logs: 5 millones
- Tiempo de eliminación: 45 minutos
- Bloqueo de base de datos: Bloqueo prolongado de tablas
- Impacto en el negocio: Grave
Plan de optimización:
# Antes de optimizar: Eliminación única
DELETE FROM workflow_logs WHERE created_at < '2024-01-01';
# Después de optimizar: Eliminación por lotes
tamano_lote = 10000
while True:
eliminados = DELETE FROM workflow_logs
WHERE created_at < '2024-01-01'
LIMIT tamano_lote;
if eliminados < tamano_lote:
break
# Breve pausa para liberar el bloqueo de la base de datos
sleep(0.1)
Efecto después de la optimización:
- Tiempo de eliminación: 50 minutos (ligeramente mayor, pero no bloquea el negocio)
- Bloqueo de base de datos: Bloqueo breve (0.1s)
- Impacto en el negocio: Ninguno
Beneficios esperados:
- Corto plazo: El negocio no se ve afectado
- Largo plazo: Mejora de la estabilidad de la base de datos
- ROI: Costo de desarrollo 4 horas, se evitan pérdidas por interrupción del negocio
Caso 4: Integración de TiDB como Base de Datos Distribuida
Escenario de aplicación:
- Gran volumen de datos de Knowledge (a nivel de TB)
- Cuello de botella de rendimiento con PostgreSQL en una sola máquina
- Necesidad de capacidad de escalado horizontal
Características del problema:
- Tiempo de respuesta de consultas > 5s
- Uso de CPU de la base de datos > 90%
- No se puede seguir escalando
Estado antes de la optimización:
- Base de datos: PostgreSQL en una sola máquina
- Volumen de datos: 2TB
- Tiempo de respuesta de consultas: 8.5s
- Capacidad de escalado: Limitada
Plan de optimización:
- Migrar a TiDB: Base de datos SQL distribuida
- Optimización de índices vectoriales: Usar TiDB Vector para acelerar la recuperación
- Separación de lecturas y escrituras: Distribuir las solicitudes de lectura a múltiples réplicas
- Tablas particionadas: Particionar por tiempo para mejorar la eficiencia de las consultas
Efecto después de la optimización:
- Tiempo de respuesta de consultas: 1.2s (reducción del 86%)
- CPU de base de datos: 40% (reducción del 50%)
- Capacidad de escalado: Admite 10x el volumen de datos
Beneficios esperados:
- Corto plazo: Mejora significativa del rendimiento de consultas
- Largo plazo: Admite el rápido crecimiento del negocio
- ROI: Costo de migración 2 semanas, admite 10x de crecimiento del negocio
Caso 5: Despliegue de Alta Disponibilidad con Higress AI Gateway
Escenario de aplicación:
- El entorno de producción necesita alta disponibilidad
- Balanceo de carga de múltiples modelos LLM
- Necesidad de capacidad de conmutación por error
Características del problema:
- Riesgo de punto único de fallo
- Llamadas a API de LLM inestables
- Incapacidad para manejar picos de tráfico
Estado antes de la optimización:
- Arquitectura: Instancia única de Dify
- Disponibilidad: 95%
- Tiempo de recuperación de fallos: 10 minutos
- Picos de tráfico: No se pueden manejar
Plan de optimización:
# Configuración de Higress AI Gateway
apiVersion: networking.higress.io/v1
kind: McpBridge
metadata:
name: dify-gateway
spec:
replicas: 3 # 3 instancias
loadBalancer:
algorithm: round-robin
healthCheck:
enabled: true
interval: 10s
failover:
enabled: true
maxRetries: 3
Arquitectura:
Usuario → Higress Gateway → [Instancia Dify 1, Instancia Dify 2, Instancia Dify 3]
↓
Balanceo de carga + Conmutación por error
Efecto después de la optimización:
- Disponibilidad: 99.9%
- Tiempo de recuperación de fallos: < 1 segundo (conmutación automática)
- Picos de tráfico: Admite 10x el tráfico
Beneficios esperados:
- Corto plazo: Mejora significativa de la estabilidad del sistema
- Largo plazo: Admite aplicaciones críticas para el negocio
- ROI: Costo de despliegue 3 días, se evitan pérdidas por interrupción del negocio
Séptima Parte: Pruebas y Monitorización de Rendimiento
7.1 Sistema de Indicadores de Rendimiento
Indicadores de ejecución de flujo de trabajo:
| Indicador | Valor objetivo | Descripción |
|---|---|---|
| Tiempo de ejecución promedio | < 2s | Tiempo completo de ejecución del flujo de trabajo |
| Tiempo de ejecución P95 | < 5s | Tiempo de ejecución del 95% de las solicitudes |
| Tiempo de ejecución P99 | < 10s | Tiempo de ejecución del 99% de las solicitudes |
| Tasa de éxito de nodos | > 99% | Proporción de nodos ejecutados con éxito |
| Tasa de éxito de llamadas a API | > 99.5% | Tasa de éxito de llamadas a API externas |
| Capacidad de procesamiento concurrente | > 100 QPS | Número de solicitudes procesadas por segundo |
Indicadores de uso de recursos:
| Indicador | Valor objetivo | Descripción |
|---|---|---|
| Uso de CPU | < 70% | Uso promedio de CPU |
| Uso de memoria | < 80% | Uso promedio de memoria |
| Conexiones de base de datos | < 80% | Uso del pool de conexiones |
| Memoria de Redis | < 70% | Uso de memoria de Redis |
Indicadores de costos:
| Indicador | Valor objetivo | Descripción |
|---|---|---|
| Costo de uso de tokens | < Presupuesto | Costo de API de LLM |
| Costo de infraestructura | < Presupuesto | Costo de servidores, base de datos |
| Costo por usuario | En disminución continua | Costo por usuario |
7.2 Herramientas de Monitorización
Monitorización LLMOps:
# Monitorización integrada de Dify
from dify import Monitor
monitor = Monitor()
# Registrar ejecución de flujo de trabajo
monitor.log_execucion_flujo_trabajo(
workflow_id="xxx",
tiempo_ejecucion=2.5,
numero_nodos=10,
uso_tokens=1500,
costo=0.003
)
# Consultar estadísticas
stats = monitor.obtener_estadisticas_flujo_trabajo(
workflow_id="xxx",
rango_tiempo="7d"
)
Seguimiento de ejecución:
- Historial de ejecución de flujos de trabajo
- Estadísticas de pasos de ejecución de nodos
- Estadísticas de uso de LLM
- Registros de errores y reintentos
Monitorización de recursos:
# Prometheus + Grafana
# Monitorizar CPU, memoria, red, disco
# Ejemplo de consulta
rate(dify_workflow_execution_total[5m]) # Tasa de ejecución de flujos de trabajo
histogram_quantile(0.95, dify_workflow_duration_seconds) # Tiempo de ejecución P95
7.3 Métodos de Prueba de Rendimiento
Pruebas de carga:
# Usar Locust para pruebas de carga
from locust import HttpUser, task, between
class UsuarioDify(HttpUser):
wait_time = between(1, 3)
@task
def ejecutar_flujo_trabajo(self):
self.client.post(
"/v1/workflows/run",
headers={"Authorization": f"Bearer {self.api_key}"},
json={"inputs": {"query": "Pregunta de prueba"}}
)
# Ejecutar prueba
# locust -f load_test.py --users 100 --spawn-rate 10
Pruebas de estrés:
# Usar Apache Bench
ab -n 1000 -c 50 -H "Authorization: Bearer xxx" \
-p request.json \
https://api.dify.ai/v1/workflows/run
Benchmark:
# Prueba de benchmark de rendimiento
import time
def benchmark_flujo_trabajo(workflow_id, iteraciones=100):
tiempos = []
for i in range(iteraciones):
inicio = time.time()
ejecutar_flujo_trabajo(workflow_id)
fin = time.time()
tiempos.append(fin - inicio)
return {
"avg": sum(tiempos) / len(tiempos),
"p50": sorted(tiempos)[len(tiempos) // 2],
"p95": sorted(tiempos)[int(len(tiempos) * 0.95)],
"p99": sorted(tiempos)[int(len(tiempos) * 0.99)]
}
7.4 Herramientas de Análisis de Rendimiento
Python Profiler:
import cProfile
import pstats
# Perfilado de código
def perfil_funcion():
profiler = cProfile.Profile()
profiler.enable()
# Código a perfilar
resultado = funcion_lenta()
profiler.disable()
# Análisis de resultados
stats = pstats.Stats(profiler)
stats.sort_stats('cumtime').print_stats(10)
Documentación detallada: Consulte performance-monitoring.md
Referencias Rápidas
| Categoría | Documentación | Enlace |
|---|---|---|
| Guía completa | Guía de optimización de flujo de trabajo | workflow-optimization/README.md |
| Estructura del grafo | Diseño de estructura del grafo | workflow-optimization/graph-structure.md |
| Ejecución en paralelo | Estrategias de ejecución en paralelo | workflow-optimization/parallel-execution.md |
| Pool de variables | Gestión del pool de variables | workflow-optimization/variable-pool.md |
| Optimización de LLM | Estrategias de optimización de LLM | llm-optimization/ |
| Monitorización | Herramientas de monitorización de rendimiento | performance-monitoring.md |
| Mantenimiento | Guía de mantenimiento de Dify | maintenance-guide.md |
Este SKILL se actualiza continuamente. Si tiene sugerencias de optimización, no dude en contribuir.