Todos los productos
Search
Centro de documentos

Platform For AI:Despliegue de un servicio de ComfyUI para generación de video con IA

Última actualización: Sep 04, 2026

ComfyUI es una herramienta AIGC basada en nodos y construida sobre Stable Diffusion, diseñada para la generación de videos cortos y la producción de animaciones. PAI-EAS admite el despliegue de servicios de ComfyUI basado en escenarios.

Antes de empezar

Limitaciones y consideraciones clave

Lea esta sección antes de realizar el despliegue para evitar desperdicio de recursos y errores comunes.

  • Recursos de despliegue: Se recomiendan los tipos de instancia GPU GU30, NVIDIA A10 o NVIDIA T4. El tipo de instancia ml.gu7i.c16m60.1-gu30 ofrece la mejor relación precio-rendimiento.

    Importante

    Cada instancia de PAI-EAS ejecuta un único proceso de ComfyUI y admite solo una GPU (instancia única con GPU única o múltiples instancias con GPU única). No se admite la inference paralela con múltiples GPU. No seleccione tipos de instancia con múltiples GPU (como 2×A10). Estos tipos de instancia desperdician recursos y no mejoran el rendimiento de tareas individuales.

  • Escalado horizontal: Para aumentar la concurrencia, utilice la API Edition e incremente el número de réplicas en lugar de seleccionar un tipo de instancia con múltiples GPU.

Elección de la edición de despliegue

Seleccione la edición que mejor se adapte a su caso de uso:

Edición

Caso de uso

Método de acceso

Funciones principales

Método de facturación

Standard Edition

Desarrollo y pruebas para un solo usuario

  • WebUI

  • Llamadas a API (síncronas, con depuración en línea)

  • Concurrencia limitada

  • Despliegue de una instancia única

Al desplegarse en recursos públicos, la facturación comienza tan pronto como la instancia está en ejecución, incluso sin llamadas a la API.

API Edition

Cargas de trabajo de producción con alta concurrencia

Llamadas a API (asíncronas)

  • Basado en el servicio de cola de PAI-EAS

  • Requiere recursos adicionales de CPU

  • Admite balanceo de carga

Cluster Edition WebUI

Equipos multiusuario y entrenamiento

WebUI

  • Entornos de usuario aislados

  • Recursos de GPU compartidos

  • Mayor consumo de recursos

Para más información sobre su funcionamiento, consulte How Cluster Edition works

Para más información sobre facturación, consulte Elastic Algorithm Service (EAS) billing.

Nota

Las llamadas síncronas y asíncronas a la API difieren según si se utiliza el servicio de cola de PAI-EAS:

  • Llamada síncrona: Envía una solicitud directamente a la instancia de inference sin utilizar el servicio de cola de PAI-EAS.

  • Llamada asíncrona: Utiliza el servicio de cola de PAI-EAS. Las solicitudes se envían a una cola de entrada y los resultados se entregan mediante un modelo de suscripción.

Dado que ComfyUI cuenta con su propio sistema de colas asíncronas integrado, incluso las llamadas síncronas se procesan de forma asíncrona internamente. Después de enviar una solicitud, el sistema devuelve un Prompt ID que se utiliza para sondear el resultado de la inference.

Despliegue del servicio

Standard Edition, Cluster Edition y API Edition: Puede utilizar el despliegue de modelos basado en escenarios para una experiencia simplificada, o el despliegue de modelos personalizado para opciones de configuración avanzadas.

Método 1: Despliegue de modelos basado en escenarios (recomendado)

  1. Inicie sesión en la PAI console. Seleccione una región en la parte superior de la página. A continuación, seleccione el espacio de trabajo deseado y haga clic en Elastic Algorithm Service (EAS).

  2. En la página Elastic Algorithm Service (EAS), haga clic en Deploy Service. En la sección Scenario-based Model Deployment, haga clic en AI Video Generation: ComfyUI-based Deployment.

  3. Configure los siguientes parámetros clave y establezca otros parámetros según sea necesario:

    • Version: Consulte Choose a deployment edition.

    • Model Settings: Por ejemplo, al usar Object Storage Service (OSS), seleccione un bucket y un directorio. Una vez completado el despliegue correctamente, el sistema crea automáticamente los directorios necesarios de ComfyUI en esta ubicación.

      Importante

      PAI-EAS no admite la instalación de nodos personalizados (plugins) directamente desde la red a través de ComfyUI Manager o Git Clone. Para utilizar sus propios modelos, instalar nodos personalizados o realizar llamadas a la API, debe configurar este montaje de almacenamiento.

    • Resource Configuration: Debe seleccionar un tipo de instancia GPU. Se recomiendan GU30, NVIDIA A10 o NVIDIA T4. ml.gu7i.c16m60.1-gu30 ofrece la mejor relación precio-rendimiento. Si este tipo de instancia no está disponible, seleccione ecs.gn6i-c16g1.4xlarge en su lugar.

  4. Haga clic en Deploy. Espere aproximadamente 5 minutos. Cuando Service Status cambie a Running, el despliegue habrá finalizado.

Método 2: Despliegue de modelos personalizado

  1. Inicie sesión en la PAI console. Seleccione una región en la parte superior de la página. A continuación, seleccione el espacio de trabajo deseado y haga clic en Elastic Algorithm Service (EAS).

  2. Haga clic en Deploy Service. En la sección Custom Model Deployment, haga clic en Custom Deployment.

  3. Configure los siguientes parámetros clave:

    • Deployment Method: Seleccione Image-based Deployment y active la casilla Enable Web App.

    • Image Configuration: En la lista Alibaba Cloud Image, seleccione comfyui:2.3. Convención de nombres de versiones de imagen: x.x para Standard Edition, x.x-api para API Edition y x.x-cluster para Cluster Edition.

      Nota
      • Debido a que las versiones se actualizan con frecuencia, seleccione la versión de imagen más reciente disponible al realizar el despliegue.

      • Para conocer los casos de uso de cada edición, consulte Choose a deployment edition.

    • Mount storage: Tomando Object Storage Service (OSS) como ejemplo, seleccione un bucket y un directorio. Una vez completado el despliegue correctamente, el sistema crea automáticamente los directorios necesarios de ComfyUI en esta ubicación. Asegúrese de que el bucket se encuentre en la misma región que el servicio PAI-EAS.

      Importante

      PAI-EAS no admite la instalación de nodos personalizados (plugins) directamente desde la red a través de ComfyUI Manager o Git Clone. Para utilizar sus propios modelos, instalar nodos personalizados o realizar llamadas a la API, debe configurar este montaje de almacenamiento.

      • URI: Haga clic en image para seleccionar un directorio OSS existente. Por ejemplo, oss://bucket-test/data-oss/.

      • Mount Path: Establezca este valor en /mnt/data para montar el directorio OSS en la ruta del contenedor /mnt/data.

    • Command to Run:

      • Después de seleccionar una versión de imagen, el sistema configura automáticamente el comando de ejecución.

      • Si configuró un montaje de almacenamiento, debe agregar el parámetro --data-dir al Command, y su valor debe coincidir exactamente con Mount Path. Por ejemplo, python main.py --listen --port 8000 --data-dir /mnt/data --cache-root /stable-diffusion-cache.

    • Resource Type: Seleccione Public Resources.

    • Deployment: Debe seleccionar un tipo de instancia GPU. Se recomiendan GU30, NVIDIA A10 o NVIDIA T4. ml.gu7i.c16m60.1-gu30 ofrece la mejor relación precio-rendimiento. Si este tipo de instancia no está disponible, seleccione ecs.gn6i-c16g1.4xlarge en su lugar.

  4. Haga clic en Deploy. El despliegue tarda aproximadamente 5 minutos. Cuando Service Status cambie a Running, el servicio estará desplegado.

Uso del servicio a través de WebUI

Importante

Standard Edition y Cluster Edition admiten el acceso a través de WebUI.

Apertura de la interfaz web

Haga clic en el nombre del servicio objetivo para abrir la página Overview y, a continuación, haga clic en Web Application en la esquina superior derecha.

Si la página tarda mucho en cargar, consulte Page freezes or takes too long to load .

Uso de un flujo de trabajo de plantilla

ComfyUI proporciona plantillas predefinidas para tareas comunes.

  1. Seleccione una plantilla (por ejemplo, Wan VACE Text to Video).

    Nota

    Las plantillas varían según las versiones de imagen de ComfyUI. Si la plantilla de ejemplo no está disponible, seleccione una plantilla diferente o cargue un archivo de flujo de trabajo desde el sistema de archivos local.

  2. Después de que se cargue el flujo de trabajo, es posible que vea errores sobre modelos faltantes. Puede descartar estos errores (se recomienda seleccionar la opción para no volver a mostrar este mensaje).

  3. Dado que las rutas de los modelos pueden haber cambiado, ejecutar el flujo de trabajo directamente puede producir el siguiente error:

    Prompt outputs failed validation:
    UNETLoader:
    - Value not in list: unet_name: 'wan2.1_vace_14B_fp16.safetensors' not in (list of length 200)
    LoraLoader:
    - Value not in list: lora_name: 'Wan21_CausVid_14B_T2V_lora_rank32.safetensors' not in (list of length 364)

    En la sección Load models here, vuelva a seleccionar wan2.1_vace_14B_fp16.safetensors en el cargador UNET y Wan21_CausVid_14B_T2V_lora_rank32.safetensors en el cargador LoRA.

  4. Una vez que el flujo de trabajo se ejecute correctamente, el video generado aparecerá en la sección Save Video. image

Uso de modelos y nodos personalizados

  1. Asegúrese de que el servicio tenga configurado un montaje de almacenamiento. Una vez desplegado el servicio, el sistema crea automáticamente la siguiente estructura de directorios en el almacenamiento OSS o NAS montado.

    data-oss/
    ├── custom_nodes/     # Custom node files (ComfyUI plugins)
    ├── models/           # Model files
    ├── input/
    ├── output/
    ├── unet/
    └── temp/
  2. Cargue archivos de modelos o nodos. Por ejemplo, puede utilizar OSS y upload files to OSS through the console. Para archivos grandes, consulte How do I upload large objects to OSS?.

    • Carga de archivos de modelos: Revise la documentación del repositorio fuente del nodo que utiliza el modelo y cargue el modelo en el subdirectorio correspondiente dentro de models. Por ejemplo:

      • Cargador de checkpoints: Cargue los modelos en models/checkpoints.

      • Cargador de modelos de estilo: Cargue los modelos en models/styles.

    • Carga de archivos de nodos: Cargue los nodos personalizados en el directorio custom_nodes del almacenamiento montado.

  3. Carga de contenido nuevo.

    • Modelos: En la parte superior de la página, haga clic en PaiCustom > Load New Models. Si el modelo sigue sin aparecer, haga clic en PaiCustom > Restart Process. Después de que se reinicie el proceso, actualice la página del navegador.

    • Nodos: Haga clic en Restart Process. Después de que se reinicie el proceso, actualice la página del navegador.

Llamada al servicio a través de API

Puede llamar al servicio ComfyUI a través de su API para integrarlo en sus aplicaciones y automatizar la generación de contenido. El flujo de trabajo principal consiste en: enviar un JSON de flujo de trabajo > obtener un ID de tarea > usar el ID de tarea para recuperar el resultado de la generación.

Importante
  • Compatibilidad de ediciones: Standard Edition solo admite llamadas síncronas y proporciona depuración en línea. API Edition solo admite llamadas asíncronas y únicamente el endpoint /prompt.

  • Recuperación de resultados generados: Las imágenes y videos generados se almacenan en el directorio output montado. Las respuestas de la API devuelven nombres de archivos y subdirectorios en lugar de los archivos mismos. Para OSS, construya la ruta completa del archivo para descargarlos. Para más información, consulte Download OSS files by using the Alibaba Cloud SDK.

Preparación del cuerpo de la solicitud API

El formato del cuerpo de la solicitud depende del método de llamada:

  • Llamada síncrona: Envuelva el contenido JSON del flujo de trabajo dentro de un par clave-valor prompt.

  • Llamada asíncrona: El cuerpo de la solicitud es directamente el contenido JSON del flujo de trabajo.

Nota

Cómo descargar un flujo de trabajo: En la esquina superior izquierda de la página de ComfyUI, haga clic en image > File > Export (API).

Dado que el flujo de trabajo Wan VACE Text to Video mencionado anteriormente consume mucho tiempo, se proporciona el siguiente flujo de trabajo de prueba para facilitar las pruebas (cada ejecución tarda aproximadamente 3 minutos).

Haga clic para ver el ejemplo de cuerpo de solicitud para el flujo de trabajo de prueba

Llamada síncrona

{
    "prompt": {
        "3": {
            "inputs": {
                "seed": 423988542100860,
                "steps": 40,
                "cfg": 7,
                "sampler_name": "dpmpp_sde_gpu",
                "scheduler": "karras",
                "denoise": 1,
                "model": [
                    "4",
                    0
                ],
                "positive": [
                    "6",
                    0
                ],
                "negative": [
                    "7",
                    0
                ],
                "latent_image": [
                    "5",
                    0
                ]
            },
            "class_type": "KSampler",
            "_meta": {
                "title": "KSampler"
            }
        },
        "4": {
            "inputs": {
                "ckpt_name": "LandscapeBING_v10.safetensors"
            },
            "class_type": "CheckpointLoaderSimple",
            "_meta": {
                "title": "Checkpoint Loader (Simple)"
            }
        },
        "5": {
            "inputs": {
                "width": 720,
                "height": 1280,
                "batch_size": 1
            },
            "class_type": "EmptyLatentImage",
            "_meta": {
                "title": "Empty Latent"
            }
        },
        "6": {
            "inputs": {
                "text": "Rocket takes off from the ground, fire,sky, airplane",
                "speak_and_recognation": {
                    "__value__": [
                        false,
                        true
                    ]
                },
                "clip": [
                    "4",
                    1
                ]
            },
            "class_type": "CLIPTextEncode",
            "_meta": {
                "title": "CLIP Text Encoder"
            }
        },
        "7": {
            "inputs": {
                "text": "",
                "speak_and_recognation": {
                    "__value__": [
                        false,
                        true
                    ]
                },
                "clip": [
                    "4",
                    1
                ]
            },
            "class_type": "CLIPTextEncode",
            "_meta": {
                "title": "CLIP Text Encoder"
            }
        },
        "8": {
            "inputs": {
                "samples": [
                    "3",
                    0
                ],
                "vae": [
                    "4",
                    2
                ]
            },
            "class_type": "VAEDecode",
            "_meta": {
                "title": "VAE Decode"
            }
        },
        "9": {
            "inputs": {
                "filename_prefix": "ComfyUI",
                "images": [
                    "8",
                    0
                ]
            },
            "class_type": "SaveImage",
            "_meta": {
                "title": "Save Image"
            }
        },
        "13": {
            "inputs": {
                "seed": 788620942678235,
                "steps": 40,
                "cfg": 2.5,
                "sampler_name": "euler_ancestral",
                "scheduler": "karras",
                "denoise": 1,
                "model": [
                    "17",
                    0
                ],
                "positive": [
                    "16",
                    0
                ],
                "negative": [
                    "16",
                    1
                ],
                "latent_image": [
                    "16",
                    2
                ]
            },
            "class_type": "KSampler",
            "_meta": {
                "title": "KSampler"
            }
        },
        "14": {
            "inputs": {
                "samples": [
                    "13",
                    0
                ],
                "vae": [
                    "18",
                    2
                ]
            },
            "class_type": "VAEDecode",
            "_meta": {
                "title": "VAE Decode"
            }
        },
        "15": {
            "inputs": {
                "filename_prefix": "ComfyUI",
                "fps": 10.000000000000002,
                "lossless": false,
                "quality": 85,
                "method": "default",
                "images": [
                    "14",
                    0
                ]
            },
            "class_type": "SaveAnimatedWEBP",
            "_meta": {
                "title": "Save WEBP"
            }
        },
        "16": {
            "inputs": {
                "width": 512,
                "height": 768,
                "video_frames": 35,
                "motion_bucket_id": 140,
                "fps": 15,
                "augmentation_level": 0.15000000000000002,
                "clip_vision": [
                    "18",
                    1
                ],
                "init_image": [
                    "8",
                    0
                ],
                "vae": [
                    "18",
                    2
                ]
            },
            "class_type": "SVD_img2vid_Conditioning",
            "_meta": {
                "title": "SVD_Image to Video_Conditioning"
            }
        },
        "17": {
            "inputs": {
                "min_cfg": 1,
                "model": [
                    "18",
                    0
                ]
            },
            "class_type": "VideoLinearCFGGuidance",
            "_meta": {
                "title": "Linear CFG Guidance"
            }
        },
        "18": {
            "inputs": {
                "ckpt_name": "svd_xt.safetensors"
            },
            "class_type": "ImageOnlyCheckpointLoader",
            "_meta": {
                "title": "Checkpoint Loader (Image Only)"
            }
        },
        "19": {
            "inputs": {
                "frame_rate": 10,
                "loop_count": 0,
                "filename_prefix": "comfyUI",
                "format": "video/h264-mp4",
                "pix_fmt": "yuv420p",
                "crf": 20,
                "save_metadata": true,
                "trim_to_audio": false,
                "pingpong": false,
                "save_output": true,
                "images": [
                    "14",
                    0
                ]
            },
            "class_type": "VHS_VideoCombine",
            "_meta": {
                "title": "Combine to Video"
            }
        }
    }
}

Llamada asíncrona

{
    "3": {
        "inputs": {
            "seed": 423988542100860,
            "steps": 40,
            "cfg": 7,
            "sampler_name": "dpmpp_sde_gpu",
            "scheduler": "karras",
            "denoise": 1,
            "model": [
                "4",
                0
            ],
            "positive": [
                "6",
                0
            ],
            "negative": [
                "7",
                0
            ],
            "latent_image": [
                "5",
                0
            ]
        },
        "class_type": "KSampler",
        "_meta": {
            "title": "KSampler"
        }
    },
    "4": {
        "inputs": {
            "ckpt_name": "LandscapeBING_v10.safetensors"
        },
        "class_type": "CheckpointLoaderSimple",
        "_meta": {
            "title": "Checkpoint Loader (Simple)"
        }
    },
    "5": {
        "inputs": {
            "width": 720,
            "height": 1280,
            "batch_size": 1
        },
        "class_type": "EmptyLatentImage",
        "_meta": {
            "title": "Empty Latent"
        }
    },
    "6": {
        "inputs": {
            "text": "Rocket takes off from the ground, fire,sky, airplane",
            "speak_and_recognation": {
                "__value__": [
                    false,
                    true
                ]
            },
            "clip": [
                "4",
                1
            ]
        },
        "class_type": "CLIPTextEncode",
        "_meta": {
            "title": "CLIP Text Encoder"
        }
    },
    "7": {
        "inputs": {
            "text": "",
            "speak_and_recognation": {
                "__value__": [
                    false,
                    true
                ]
            },
            "clip": [
                "4",
                1
            ]
        },
        "class_type": "CLIPTextEncode",
        "_meta": {
            "title": "CLIP Text Encoder"
        }
    },
    "8": {
        "inputs": {
            "samples": [
                "3",
                0
            ],
            "vae": [
                "4",
                2
            ]
        },
        "class_type": "VAEDecode",
        "_meta": {
            "title": "VAE Decode"
        }
    },
    "9": {
        "inputs": {
            "filename_prefix": "ComfyUI",
            "images": [
                "8",
                0
            ]
        },
        "class_type": "SaveImage",
        "_meta": {
            "title": "Save Image"
        }
    },
    "13": {
        "inputs": {
            "seed": 788620942678235,
            "steps": 40,
            "cfg": 2.5,
            "sampler_name": "euler_ancestral",
            "scheduler": "karras",
            "denoise": 1,
            "model": [
                "17",
                0
            ],
            "positive": [
                "16",
                0
            ],
            "negative": [
                "16",
                1
            ],
            "latent_image": [
                "16",
                2
            ]
        },
        "class_type": "KSampler",
        "_meta": {
            "title": "KSampler"
        }
    },
    "14": {
        "inputs": {
            "samples": [
                "13",
                0
            ],
            "vae": [
                "18",
                2
            ]
        },
        "class_type": "VAEDecode",
        "_meta": {
            "title": "VAE Decode"
        }
    },
    "15": {
        "inputs": {
            "filename_prefix": "ComfyUI",
            "fps": 10.000000000000002,
            "lossless": false,
            "quality": 85,
            "method": "default",
            "images": [
                "14",
                0
            ]
        },
        "class_type": "SaveAnimatedWEBP",
        "_meta": {
            "title": "Save WEBP"
        }
    },
    "16": {
        "inputs": {
            "width": 512,
            "height": 768,
            "video_frames": 35,
            "motion_bucket_id": 140,
            "fps": 15,
            "augmentation_level": 0.15000000000000002,
            "clip_vision": [
                "18",
                1
            ],
            "init_image": [
                "8",
                0
            ],
            "vae": [
                "18",
                2
            ]
        },
        "class_type": "SVD_img2vid_Conditioning",
        "_meta": {
            "title": "SVD_Image to Video_Conditioning"
        }
    },
    "17": {
        "inputs": {
            "min_cfg": 1,
            "model": [
                "18",
                0
            ]
        },
        "class_type": "VideoLinearCFGGuidance",
        "_meta": {
            "title": "Linear CFG Guidance"
        }
    },
    "18": {
        "inputs": {
            "ckpt_name": "svd_xt.safetensors"
        },
        "class_type": "ImageOnlyCheckpointLoader",
        "_meta": {
            "title": "Checkpoint Loader (Image Only)"
        }
    },
    "19": {
        "inputs": {
            "frame_rate": 10,
            "loop_count": 0,
            "filename_prefix": "comfyUI",
            "format": "video/h264-mp4",
            "pix_fmt": "yuv420p",
            "crf": 20,
            "save_metadata": true,
            "trim_to_audio": false,
            "pingpong": false,
            "save_output": true,
            "images": [
                "14",
                0
            ]
        },
        "class_type": "VHS_VideoCombine",
        "_meta": {
            "title": "Combine to Video"
        }
    }
}

Llamadas síncronas

Las llamadas síncronas envían solicitudes directamente a la instancia del servicio PAI-EAS. Este método es adecuado para desarrollo, pruebas y escenarios de baja concurrencia.

Depuración en línea

La depuración en línea le permite probar llamadas a la API directamente en la consola sin escribir código. Esto resulta útil para validar rápidamente configuraciones de flujos de trabajo.

En la página Elastic Algorithm Service (EAS), haga clic en Online Debugging en la columna Actions del servicio objetivo para abrir la página de depuración en línea.

  1. Envíe una solicitud POST para obtener el Prompt ID.

    1. En la sección Request Parameter Online Tuning de la página de depuración, introduzca el cuerpo de solicitud preparado en el campo Body y agregue /prompt a la URL de la solicitud.

    2. Haga clic en Send Request para ver la respuesta en la sección Debugging Information.

      Después de enviar la solicitud, el panel Debug Info a la derecha muestra la respuesta: Status Code es 200, y Response Body contiene los campos prompt_id (por ejemplo, 130bc***c8c-3a1359a04e5d), number y node_errors. Registre el valor de prompt_id para usarlo en el siguiente paso.

  2. Envíe una solicitud GET para recuperar el resultado de la inference mediante el Prompt ID.

    1. En la sección Request Parameter Online Tuning, cambie el método de solicitud a GET e introduzca /history/<prompt id> en el campo URL.

      Reemplace <prompt id> con el Prompt ID obtenido en el Paso 1.

    2. Haga clic en Send Request para recuperar el resultado de la inference.

      Puede encontrar la salida generada en el directorio output del almacenamiento montado.

Llamadas basadas en código

Puede llamar a la API mediante código para integrar ComfyUI en sus aplicaciones. El flujo de trabajo es el mismo que en la depuración en línea: primero obtenga el Prompt ID y luego consulte el resultado de la inference.

  1. Vea la información de llamada.

    1. En la pestaña Inference Services, haga clic en el nombre del servicio objetivo para abrir la página Overview.

    2. En la sección Basic Information, haga clic en View Call Information.

    3. En el panel Call Information, copie el endpoint de acceso y el token:

      El panel Call Information tiene dos pestañas: Shared Gateway y VPC Direct Connection. El endpoint público, el endpoint VPC y el token se encuentran en la pestaña Shared Gateway.

      • Seleccione Public Endpoint o VPC Endpoint según sea necesario.

      • Los ejemplos a continuación utilizan para el endpoint de acceso y para el token.

  2. Envíe una solicitud para obtener el Prompt ID.

    • Método HTTP: POST.

    • URL de solicitud: <EAS_ENDPOINT>/prompt. Si <EAS_ENDPOINT> termina con /, elimine la barra diagonal final. La URL final tendrá un aspecto similar a http://comfyui****.175805416243****.cn-beijing.pai-eas.aliyuncs.com/prompt.

    • Encabezados de solicitud:

      Encabezado

      Valor

      Descripción

      Authorization

      <EAS_TOKEN>

      El token de autorización.

      Content-Type

      application/json

      Especifica el formato del cuerpo de la solicitud.

    Ejemplos de código:

    cURL

    curl --location --request POST '<EAS_ENDPOINT>/prompt' \
    --header 'Authorization: <EAS_TOKEN>' \
    --header 'Content-Type: application/json' \
    --data-raw '{
        "prompt":
        ...omitted
    }'

    El parámetro --data-raw contiene el cuerpo de la solicitud.

    Python

    Ejemplo de código:

    import requests
    import json
    
    # Replace <EAS_ENDPOINT> and <EAS_TOKEN> with the endpoint and token from Step 1.
    service_url = "<EAS_ENDPOINT>"
    token = "<EAS_TOKEN>"
    
    if service_url[-1] == "/":
        service_url = service_url[:-1]
    
    # Request body: set the "prompt" value to the workflow JSON content.
    payload = """{
        "prompt":
        ...omitted
    }"""
    payload = json.loads(payload)
    
    session = requests.session()
    session.headers.update({"Authorization": token})
      
    response = session.post(url=f'{service_url}/prompt', json=payload)
    if response.status_code != 200:
        raise Exception(response.content)
    
    data = response.json()
    print(data)

    Respuesta de ejemplo:

    {
        "prompt_id": "021ebc5b-e245-4e37-8bd3-00f7b949****",
        "number": 5,
        "node_errors": {}
    }

    Extraiga el Prompt ID de la respuesta.

  3. Recupere el resultado de la inference.

    • Método HTTP: GET

    • URL de solicitud: <EAS_ENDPOINT>/history/<prompt_id>. Reemplace <prompt_id> con el prompt_id obtenido en el Paso 1.

    • Encabezados de solicitud:

      Encabezado

      Valor

      Descripción

      Authorization

      <EAS_TOKEN>

      El token de autorización obtenido en el Paso 1.

    Ejemplos de código:

    cURL

    curl --location --request GET '<EAS_ENDPOINT>/history/<prompt_id>' \
         --header 'Authorization: <EAS_TOKEN>'

    Python

    import requests
    
    # Replace <EAS_ENDPOINT> and <EAS_TOKEN> with the endpoint and token from Step 1.
    # Replace <prompt_id> with the prompt_id obtained in Step 2.
    service_url = "<EAS_ENDPOINT>"
    token = "<EAS_TOKEN>"
    prompt_id = "<prompt_id>"
    
    if service_url[-1] == "/":
        service_url = service_url[:-1]
    
    session = requests.session()
    session.headers.update({"Authorization": token})
    
    response = session.get(url=f'{service_url}/history/{prompt_id}')
    
    if response.status_code != 200:
        raise Exception(response.content)
    
    data = response.json()
    print(data)

    Respuesta de ejemplo:

    Haga clic para ver el ejemplo de respuesta

    {
        "130bcd6b-5bb5-496c-9c8c-3a1359a0****": {
            "prompt": "...(omitted)",
            "outputs": {
                "9": {
                    "images": [
                        {
                            "filename": "ComfyUI_1712645398_18dba34d-df87-4735-a577-c63d5506a6a1_.png",
                            "subfolder": "",
                            "type": "output"
                        }
                    ]
                },
                "15": {
                    "images": [
                        {
                            "filename": "ComfyUI_1712645867_.webp",
                            "subfolder": "",
                            "type": "output"
                        }
                    ],
                    "animated": [
                        true
                    ]
                },
                "19": {
                    "gifs": [
                        {
                            "filename": "comfyUI_00002.mp4",
                            "subfolder": "",
                            "type": "output",
                            "format": "video/h264-mp4"
                        }
                    ]
                }
            },
            "status": {
                "status_str": "success",
                "completed": true,
                "messages": "...(omitted)"
            }
        }
    }

    El campo outputs en la respuesta contiene las imágenes generadas (PNG/WebP) y los videos (MP4). Puede ubicar estos archivos en el directorio output del almacenamiento montado buscando por los nombres de archivo.

Llamadas asíncronas

Las llamadas asíncronas están diseñadas para cargas de trabajo de producción con alta concurrencia. Este método utiliza el servicio de cola de PAI-EAS para el balanceo de carga. Las solicitudes devuelven una respuesta inmediata y los resultados se obtienen mediante la suscripción a la cola de resultados.

Importante

Las llamadas asíncronas solo admiten el endpoint api_prompt. El parámetro task_id es un identificador crítico para vincular las solicitudes con sus resultados. Asigne un valor único a cada solicitud para poder correlacionarla con el resultado correspondiente en la cola. La ruta de la solicitud es:

{service_url}/api_prompt?task_id={assign a unique value}

  1. Consulte la información de llamada.

    En la pestaña Inference Services, haga clic en el nombre del servicio objetivo para abrir la página Overview. En la sección Basic Information, haga clic en View Call Information. En la pestaña Asynchronous Call del cuadro de diálogo Call Information, consulte el endpoint de acceso al servicio y el token.

    image

    En las siguientes secciones se utiliza <EAS_ENDPOINT> para referirse al Internet Input Endpoint (si quien realiza la llamada se encuentra en la misma VPC que PAI-EAS, puede usar el VPC Input Endpoint) y <EAS_TOKEN> para referirse al Token.

  2. Envíe una solicitud.

    Ejemplo de código:

    import requests
    import json
    
    service_url = "<EAS_ENDPOINT>"
    token = "<EAS_TOKEN>"
    
    if service_url[-1] == "/":
        service_url = service_url[:-1]
    
    session = requests.session()
    session.headers.update({"Authorization":token})
    
    # Request body - workflow JSON, no need to wrap with "prompt".
    # Use triple quotes to define it as a multi-line string, otherwise you need to capitalize the boolean values (true and false) in the workflow JSON.
    payload = """{
        '3':
        ...omitted
      }
      """
    payload = json.loads(payload)
    
    for i in range(5):
      # task_id is the key identifier for matching requests and results. Assign a unique value to each request to correlate with the queue results later.
      response = session.post(url=f'{service_url}/api_prompt?task_id=txt2img_{i}', json=payload)
      if response.status_code != 200:
        exit(f"send request error:{response.content}")
      else:
        print(f"send {i} success, index is {response.content}")
  3. Suscríbase a los resultados.

    1. Instale el SDK eas_prediction.

      pip install eas_prediction  --user
    2. Ejecute el siguiente código para obtener el resultado.

      from eas_prediction import QueueClient
      from urllib.parse import urlparse, urlunparse
      
      service_url     = "<EAS_ENDPOINT>"
      token           = "<EAS_TOKEN>"
      
      # Parse service URL
      def parse_service_url(service_url):
          parsed = urlparse(service_url)
          service_domain = f"{parsed.scheme}://{parsed.netloc}"
          path_parts = [p for p in parsed.path.strip('/').split('/') if p]
          service_name = path_parts[-1]
          return service_domain, service_name
      
      service_domain, service_name = parse_service_url(service_url)
      print(f"service_domain: {service_domain}, service_name: {service_name}.")
      
      # Create result queue client
      sink_queue = QueueClient(service_domain, f'{service_name}/sink')
      sink_queue.set_token(token)
      sink_queue.init()
      
      # Listen for results
      watcher = sink_queue.watch(0, 5, auto_commit=False)
      for x in watcher.run():
          if 'task_id' in x.tags:
              print('index {} task_id is {}'.format(x.index, x.tags['task_id']))
          print(f'index {x.index} data is {x.data}')
          # Commit acknowledgment
          sink_queue.commit(x.index)

      Respuesta de ejemplo:

      index 42 task_id is txt2img_0
      index 42 data is b'[{"type": "executed", "data": {"node": "9", "output": {"images": [{"filename": "ComfyUI_1712647318_8e7f3c93-d2a8-4377-92d5-8eb552adc172_.png", "subfolder": "", "type": "output"}]}, "prompt_id": "c3c983b6-f92b-4dd5-b4dc-442db4d1736f"}}, {"type": "executed", "data": {"node": "15", "output": {"images": [{"filename": "ComfyUI_1712647895_.webp", "subfolder": "", "type": "output"}], "animated": [true]}, "prompt_id": "c3c983b6-f92b-4dd5-b4dc-442db4d1736f"}}, {"type": "executed", "data": {"node": "19", "output": {"gifs": [{"filename": "comfyUI_00001.mp4", "subfolder": "", "type": "output", "format": "video/h264-mp4"}]}, "prompt_id": "c3c983b6-f92b-4dd5-b4dc-442db4d1736f"}}, {"9": {"images": [{"filename": "ComfyUI_1712647318_8e7f3c93-d2a8-4377-92d5-8eb552adc172_.png", "subfolder": "", "type": "output"}]}, "15": {"images": [{"filename": "ComfyUI_1712647895_.webp", "subfolder": "", "type": "output"}], "animated": [true]}, "19": {"gifs": [{"filename": "comfyUI_00001.mp4", "subfolder": "", "type": "output", "format": "video/h264-mp4"}]}}]'
      index 43 task_id is txt2img_1
      index 43 data is b'[{"9": {"images": [{"filename": "ComfyUI_1712647318_8e7f3c93-d2a8-4377-92d5-8eb552adc172_.png", "subfolder": "", "type": "output"}]}, "15": {"images": [{"filename": "ComfyUI_1712647895_.webp", "subfolder": "", "type": "output"}], "animated": [true]}, "19": {"gifs": [{"filename": "comfyUI_00001.mp4", "subfolder": "", "type": "output", "format": "video/h264-mp4"}]}}]'
      index 44 task_id is txt2img_2
      index 44 data is b'[{"9": {"images": [{"filename": "ComfyUI_1712647318_8e7f3c93-d2a8-4377-92d5-8eb552adc172_.png", "subfolder": "", "type": "output"}]}, "15": {"images": [{"filename": "ComfyUI_1712647895_.webp", "subfolder": "", "type": "output"}], "animated": [true]}, "19": {"gifs": [{"filename": "comfyUI_00001.mp4", "subfolder": "", "type": "output", "format": "video/h264-mp4"}]}}]'
      index 45 task_id is txt2img_3
      index 45 data is b'[{"9": {"images": [{"filename": "ComfyUI_1712647318_8e7f3c93-d2a8-4377-92d5-8eb552adc172_.png", "subfolder": "", "type": "output"}]}, "15": {"images": [{"filename": "ComfyUI_1712647895_.webp", "subfolder": "", "type": "output"}], "animated": [true]}, "19": {"gifs": [{"filename": "comfyUI_00001.mp4", "subfolder": "", "type": "output", "format": "video/h264-mp4"}]}}]'
      index 46 task_id is txt2img_4
      index 46 data is b'[{"9": {"images": [{"filename": "ComfyUI_1712647318_8e7f3c93-d2a8-4377-92d5-8eb552adc172_.png", "subfolder": "", "type": "output"}]}, "15": {"images": [{"filename": "ComfyUI_1712647895_.webp", "subfolder": "", "type": "output"}], "animated": [true]}, "19": {"gifs": [{"filename": "comfyUI_00001.mp4", "subfolder": "", "type": "output", "format": "video/h264-mp4"}]}}]'

      Los archivos de resultados de inference se encuentran en el directorio output del almacenamiento montado.

Preguntas frecuentes

A continuación se presentan los problemas comunes y sus soluciones para el despliegue y uso de ComfyUI.

Problemas de despliegue

P: El servicio permanece en estado de espera o ComfyUI no genera resultados

Esto suele deberse a recursos insuficientes. Compruebe que la imagen del servicio y el tipo de instancia estén configurados correctamente. Se recomiendan los tipos de instancia GPU GU30, NVIDIA A10 o NVIDIA T4. El tipo de instancia ml.gu7i.c16m60.1-gu30 ofrece la mejor relación precio-rendimiento.

Problemas con modelos y nodos

P: WebUI muestra un error "Missing Model"

Problema: Un cuadro de diálogo titulado Missing Model indica que falta el modelo en checkpoints/v1-5-pruned-emaonly-fp16.safetensors, y una advertencia roja a la izquierda muestra Invalid directory specified (does this require custom nodes?).

Solución: Puede ignorar este error sin riesgo. Esta validación no aplica para ComfyUI desplegado en PAI. Consulte los errores reales de tiempo de ejecución.

Se recomienda seleccionar la opción para no volver a mostrar este mensaje o deshabilitar la validación de modelos en Settings.

P: Cargué un nuevo modelo pero no aparece

Solución:

  1. Haga clic en PaiCustom y seleccione Load New Models.

  2. Si el modelo sigue sin aparecer, haga clic en Restart Process.

P: El cargador de modelos muestra "undefined"

Primero, compruebe que el archivo del modelo esté en el directorio correcto según lo requiera el nodo del cargador de modelos.

Si cargó el modelo después del despliegue, reinicie el servicio.

P: No encuentro un nodo

P: ComfyUI Manager falla al descargar modelos o instalar nodos

No se recomienda usar ComfyUI Manager con ComfyUI desplegado en PAI-EAS. ComfyUI Manager descarga modelos y código de plugin desde fuentes externas como GitHub, lo cual falla con frecuencia debido a restricciones de red.

En su lugar, cargue los archivos de modelos y nodos en el almacenamiento montado. Para más información, consulte Use custom models and install nodes (ComfyUI plugins).

P: Cómo ver los archivos de modelos y nodos disponibles (plugins de ComfyUI)

  • Archivos de modelos: Revise desde el nodo del cargador de modelos correspondiente. Por ejemplo, vea los archivos de modelos disponibles en la lista desplegable del cargador de Checkpoint.

  • Nodos: Haga clic derecho en la página de WebUI y seleccione Add Node en el menú contextual para ver todos los plugins de ComfyUI instalados.

Errores de tiempo de ejecución

P: La página se congela o tarda demasiado en cargar

  • Actualice la página, borre la caché del navegador o acceda al servicio en modo incógnito o navegación privada.

  • Si hay almacenamiento montado, elimine los archivos de los directorios input/, output/ y temp/.

  • Intente reiniciar el servicio.

P: El proceso se reinicia durante el flujo de trabajo

Si los registros de la instancia contienen run.sh: line 54: 531285 Killed python -u main_run.py "$@", el proceso finalizó por falta de memoria (OOM). El proceso se reinicia automáticamente tras un evento OOM.

P: RuntimeError: CUDA error: out of memory

Esto indica que la memoria de la GPU se agotó. Para modelos de imágenes, reduzca la resolución o el tamaño del lote. Para modelos de video, reduzca la cantidad de fotogramas o la resolución.

P: La llamada a la API devuelve "url not found" o "404 page not found"

  1. Compruebe que la URL del endpoint de la API esté completa. Para llamadas síncronas, debe agregar la ruta /prompt.

Otros

P: Rendimiento de aceleración con xFormers

xFormers es una herramienta de aceleración de código abierto basada en Transformer que reduce el tiempo de generación de imágenes y videos, así como el uso de memoria de la GPU.

Las imágenes de ComfyUI tienen la aceleración xFormers habilitada de forma predeterminada. El efecto de la aceleración depende del tamaño del flujo de trabajo; las mejoras son más notables en operaciones intensivas en GPU, especialmente con GPUs NVIDIA.

Siguientes pasos

Una vez desplegado el servicio ComfyUI, puede:

  • Monitoreo del servicio: Configure el monitoreo y las alertas para rastrear el estado del servicio en tiempo real. Para más información, consulte View service monitoring metrics.

  • Auto Scaling: Configure directivas de escalado automático según la carga de trabajo para optimizar el uso de recursos y los costos. Para más información, consulte Auto scaling.

  • Optimización de costos: Comprenda los métodos de facturación de PAI-EAS y elija el tipo de instancia y la edición de despliegue adecuados para reducir costos. Para más información, consulte Billing overview.

Referencia

Instalación de paquetes de Python

Instalación de un paquete .whl mediante comando

  1. Asegúrese de que el servicio tenga configurado un montaje de almacenamiento. Por ejemplo, suponga que la ruta de OSS (URI) es oss://examplebucket/comfyui/ y la ruta de montaje es /mnt/data/.

  2. Cargue el archivo .whl en el directorio oss://examplebucket/comfyui/models/whl. Si el directorio whl no existe, créelo primero.

  3. Actualice el campo Command to Run del servicio: Anteponga pip install /mnt/data/models/whl/xxx.whl al comando de tiempo de ejecución. En este comando, /mnt/data es la ruta de montaje de OSS y xxx.whl es el nombre del paquete .whl.

  4. Reinicie el servicio.

Instalación de paquetes mediante configuración de bibliotecas de terceros

  1. En la página de detalles del servicio, haga clic en Update en la esquina superior derecha.

  2. Si el servicio se desplegó mediante despliegue de modelos basado en escenarios, cambie a despliegue de modelos personalizado.

  3. En la sección Environment Information, configure las dependencias en el área Third-party Library Configuration.

  4. Haga clic en Update en la parte inferior de la página para aplicar la actualización.

Actualización de la versión de la imagen

Si el servicio tiene almacenamiento OSS o NAS montado, los modelos personalizados se almacenan en dicho almacenamiento y no se ven afectados por una actualización de versión de imagen.

  1. En la página de detalles del servicio, haga clic en Update en la esquina superior derecha.

  2. Si el servicio se desplegó mediante despliegue de modelos basado en escenarios, cambie a despliegue de modelos personalizado.

  3. En la sección Service Configuration, edite la configuración JSON y actualice el campo image bajo containers a la versión deseada (por ejemplo, cambie 1.9 a la versión objetivo).

  4. Haga clic en Update Directly.

Generación de una URL sin inicio de sesión con periodo de validez personalizado

Puede utilizar una API para generar una URL de acceso web sin inicio de sesión con un periodo de validez específico.

  1. Vaya a la página de la API DescribeServiceSignedUrl.

  2. Seleccione el endpoint del servicio.

  3. Establezca los siguientes parámetros:

    • ClusterId (Region) y ServiceName: Introduzca la región y el nombre del servicio.

      En la página de descripción general del servicio EAS, el campo Service Name muestra el valor de ServiceName. La región está incluida en la dirección de la imagen del nodo (por ejemplo, cn-hangzhou corresponde al valor de región ClusterId). Puede hacer clic en View Web Application en la esquina superior derecha para abrir el servicio.

    • Type (Page type): Seleccione webview en la lista desplegable.

    • Expire (Expiration time): Introduzca un número entero en segundos. El valor máximo es 43200 segundos (12 horas). Establézcalo según sea necesario.

    • Internal (VPC access): Establezca false (acceso público) o true (acceso VPC).

  4. Haga clic en Call API. El campo SignedUrl en la respuesta contiene la URL de acceso web sin inicio de sesión.

Cambio del idioma predeterminado de WebUI

  1. En la página de WebUI, haga clic en el botón Settings en la esquina inferior izquierda.

  2. Configure el idioma en las siguientes dos ubicaciones y luego actualice y recargue la página.

    • Comfy > Locale.

    • Language > Locale.

Apéndice

Funcionamiento de Cluster Edition

El siguiente diagrama muestra la arquitectura:

image

Cluster Edition está diseñado para escenarios multiusuario. Introduce una capa de proxy que desacopla los clientes de las instancias de inference del backend.

  • Cada usuario tiene un entorno de backend y un directorio de trabajo independientes, pero comparte el pool de instancias de inference de GPU del backend.

  • Cuando un usuario envía una solicitud de inference, el proxy selecciona una instancia disponible del pool para procesar la solicitud.

Este mecanismo de multiplexación por tiempo aísla los entornos de los usuarios y maximiza la utilización de los recursos de GPU, lo que reduce los costos de inference en escenarios multiusuario.