全部產品
Search
文件中心

Platform For AI:AI視頻產生-ComfyUI部署

更新時間:Jan 20, 2026

ComfyUI提供基於Stable Diffusion的節點式操作介面,通過拖拽節點和串連的方式構建複雜的AIGC流程,完成短視頻內容產生、動畫製作等任務。本文介紹如何在EAS中部署和使用ComfyUI。

開始之前

重要限制與注意事項

部署前必讀:瞭解以下關鍵限制,以避免不必要的資源浪費和常見錯誤。

  • 部署資源:推薦使用GU30、A10或T4卡型,其中ml.gu7i.c16m60.1-gu30性價比高。

    重要

    每個 EAS 執行個體僅運行一個 ComfyUI 進程,僅支援單張 GPU(單機單卡或多機單卡),不支援多卡並行推理。請勿選擇多卡 GPU 規格(如 2*A10 等),這會造成資源浪費且無法提升單任務的效能。

  • 水平擴充方式:如需提升並發處理能力,請使用API版並增加副本數量,而非選擇多卡規格。

  • 儲存準備:如需使用自訂模型、安裝自訂節點或通過API調用,必須提前建立OSS儲存空間或NAS檔案系統。詳見Object Storage Service快速入門

    EAS 不支援通過 ComfyUI 管理器或 Git Clone 等方式從網路直接安裝自訂節點(外掛程式)。所有自訂內容都必須通過掛載儲存的方式上傳。
  • Serverless 版核心限制

    • 僅可使用內建模型和外掛程式。如需上傳自訂模型或安裝第三方節點,請選擇標準版、API版或叢集版。

    • 僅在華東2(上海)、華東1(杭州)地區可用。

選擇部署版本

根據使用情境選擇合適的版本:

部署版本

適用情境

調用方式

主要特點

計費模式

標準版

單使用者開發與測試

  • WebUI

  • API調用(同步,支援線上調試)

  • 並發能力有限

  • 建議部署單一實例

按照服務的運行時間長度計費(部署成功後即使不使用也計費)。

API版

生產環境高並發

API調用(非同步)

  • 基於EAS佇列服務

  • 需要額外CPU資源

  • 支援負載平衡

叢集版WebUI

多使用者團隊和教學

WebUI

  • 使用者環境隔離

  • GPU資源共用

  • 資源消耗較高

原理參見叢集版服務原理介紹

Serverless版

波動性工作負載,成本最佳化

WebUI

  • 無法使用自訂模型/外掛程式

  • 僅華東2(上海)、華東1(杭州)地區可用

部署免費,僅在服務調用時按實際推理即時長計費。

更多計費詳情請參見模型線上服務(EAS)計費說明

說明

此處API調用的同步與非同步取決於是否使用EAS的佇列服務:

  • 同步調用:直接請求推理執行個體,不使用EAS的佇列服務;

  • 非同步呼叫:使用EAS的佇列服務,向輸入隊列發送請求,以訂閱的方式獲得結果推送。

由於ComfyUI本身具有非同步隊列系統,即使發起同步調用,實質上也是非同步進行的。使用者發送請求後,系統會返回一個Prompt ID,然後需要使用Prompt ID輪詢以擷取推理結果。

部署服務

Serverless版:只能使用情境化模型部署。

標準版、叢集版、API版:可使用情境化模型部署(操作簡單)或者自訂模型部署(支援更多功能)。

方式一:情境化模型部署(推薦)

  1. 登入PAI控制台,在頁面上方選擇目標地區,並在右側選擇目標工作空間,然後單擊進入EAS

  2. 模型在线服务 (EAS)頁面,單擊部署服务,在场景化模型部署地區,單擊AI视频生成-ComfyUI部署

  3. 配置以下關鍵參數:

    • 版本选择:參見選擇部署版本

    • 模型配置:如需使用自己的模型、安裝自訂節點或通過API調用,必須配置此項。以Object Storage Service為例,選擇Bucket和目錄,部署成功後系統會自動在其中建立ComfyUI所需目錄。

    • 资源配置选择:資源規格必須選擇GPU類型,推薦使用GU30、A10或T4卡型。ml.gu7i.c16m60.1-gu30性價比高,如庫存不足可選擇ecs.gn6i-c16g1.4xlarge

  4. 單擊部署。等待約5分鐘,當服务状态變為运行中,表示部署成功。

方式二:自訂模型部署

  1. 登入PAI控制台,在頁面上方選擇目標地區,並在右側選擇目標工作空間,然後單擊進入EAS

  2. 推理服务頁簽,單擊部署服务,然後在自定义模型部署地區,單擊自定义部署

  3. 配置以下關鍵參數:

    • 部署方式:選擇镜像部署,勾選开启Web应用複選框。

    • 镜像配置:在官方镜像列表中選擇comfyui:1.9。其中:x.x:表示標準版,x.x-api:表示API版,x.x-cluster:表示叢集版。

      說明
      • 由於版本迭代迅速,部署時鏡像版本選擇最高版本即可。

      • 更多關於每個版本的使用情境說明,請參見選擇部署版本

    • 存储挂载:如需使用自己的模型、安裝自訂節點或通過API調用,必須進行儲存掛載。以Object Storage Service為例,選擇Bucket和目錄,部署成功後系統會自動在其中建立ComfyUI所需目錄。請確保建立的儲存空間與EAS服務位於同一地區。

      • Uri:單擊image選擇已建立的OSS儲存目錄。例如oss://bucket-test/data-oss/

      • 挂载路径:配置為/mnt/data,表示將您配置的OSS檔案目錄掛載到容器路徑/mnt/data下 。

    • 运行命令

      • 選擇鏡像版本後,系統自動設定運行命令。

      • 若進行了儲存掛載,則必須在运行命令中添加--data-dir參數, 並且其值與挂载路径完全一致。例如python main.py --listen --port 8000 --data-dir /mnt/data --cache-root /stable-diffusion-cache

    • 资源类型:選擇公共资源

    • 部署资源:資源規格必須選擇GPU類型,推薦使用GU30、A10或T4卡型。ml.gu7i.c16m60.1-gu30性價比高,如庫存不足可選擇ecs.gn6i-c16g1.4xlarge

  4. 單擊部署。服務部署時間約為5分鐘,當服务状态运行中時,表明服務已成功部署。

通過WebUI使用

重要

標準版、叢集版和Serverless版支援通過WebUI使用。

進入Web介面

單擊目標服務名稱進入概覽頁面,在右上方單擊Web應用

如頁面長時間無法開啟,請參見重新整理頁面時間過長或頁面卡死

使用模板工作流程

ComfyUI為常見任務提供預置模板。

  1. 選擇一個模板(如Wan VACE 文生視頻)。

    說明

    ComfyUI不同鏡像版本中的模板有差別,若無樣本模板,可選擇其他模板使用。也可以載入本地檔案系統中的工作流程使用。

image

  1. 工作流程載入成功後,如遇到報錯缺少模型,可忽視(建議勾選不再顯示此訊息)。

  2. 由於路徑變更,直接運行工作流程可能會出現以下報錯。

    image.png

    請先在Load models here地區重新選擇模型wan2.1_vace_14B_fp16.safetensorsWan21_CausVid_14B_T2V_lora_rank32.safetensors

    image

  3. 工作流程運行成功後,會在Save Video地區,展示產生的視頻。image

使用自訂模型和節點

重要

Serverless版本不支援此功能。

  1. 確認服務已配置儲存掛載。如使用自訂部署,需在运行命令中增加參數--data-dir掛載目錄,詳情見方式二:自訂模型部署

    服務部署成功後,系統會自動在已掛載的OSS或NAS儲存空間中建立如下目錄結構。

    data-oss/
    ├── custom_nodes/     # 存放節點檔案(ComfyUI外掛程式)
    ├── models/           # 存放模型檔案
    ├── input/
    ├── output/
    ├── unet/
    └── temp/
  2. 上傳模型或節點檔案。以OSS為例,可控制台上傳檔案到OSS。對於大檔案,請參見如何上傳大檔案到OSS

    • 模型檔案上傳:根據模型使用節點的源專案庫使用說明,將模型上傳至models下的對應子目錄。例如:

      • Checkpoint載入器:模型上傳至models/checkpoints

      • 風格模型載入器:模型上傳至models/styles

    • 節點檔案上傳:推薦您將自訂節點上傳至掛載儲存的custom_nodes目錄。

  3. 載入新內容。

    • 模型:單擊PaiCustom>載入新模型,如仍然找不到模型,單擊重啟進程,重啟成功後,重新整理瀏覽器頁面。

    • 節點:直接單擊重啟進程。重啟成功後,重新整理瀏覽器頁面。

匯出工作流程

在WebUI中調試好工作流程後,將工作流程儲存為一個JSON檔案,用於後續的API調用。

image

API調用

API調用概述

通過API調用ComfyUI服務,可以將ComfyUI整合到您的應用程式中,實現自動化的AIGC內容產生。API調用的核心流程是:提交工作流程JSON配置,系統返回任務ID,然後通過任務ID擷取產生結果。

重要

標準版服務僅支援同步調用,並且提供線上調試。

API版服務僅支援非同步呼叫,且僅支援api_prompt路徑。

關鍵準備工作:ComfyUI的API請求體取決於工作流程配置。請先在WebUI版面設定並匯出工作流程的JSON檔案

結果下載:產生的圖片或視頻儲存在掛載的output目錄中,API調用的結果返回的是檔案名稱和子目錄名。對於OSS,需自行拼接完整的檔案路徑進行下載,請參見使用阿里雲SDK下載OSS檔案

準備API請求體

根據調用方式的不同,請求體格式有所差異:

  • 同步調用:請求體需要將工作流程JSON檔案內容封裝在"prompt"索引值下面。

  • 非同步呼叫:請求體就是工作流程JSON檔案內容。

因為上述Wan VACE Text to Video的工作流程運行比較耗時,為方便測試提供以下工作流程(運行一次需要約3分鐘)。

單擊查看測試工作流程的請求體樣本

同步調用

{
    "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": "K採樣器"
            }
        },
        "4": {
            "inputs": {
                "ckpt_name": "LandscapeBING_v10.safetensors"
            },
            "class_type": "CheckpointLoaderSimple",
            "_meta": {
                "title": "Checkpoint載入器(簡易)"
            }
        },
        "5": {
            "inputs": {
                "width": 720,
                "height": 1280,
                "batch_size": 1
            },
            "class_type": "EmptyLatentImage",
            "_meta": {
                "title": "空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文本編碼器"
            }
        },
        "7": {
            "inputs": {
                "text": "",
                "speak_and_recognation": {
                    "__value__": [
                        false,
                        true
                    ]
                },
                "clip": [
                    "4",
                    1
                ]
            },
            "class_type": "CLIPTextEncode",
            "_meta": {
                "title": "CLIP文本編碼器"
            }
        },
        "8": {
            "inputs": {
                "samples": [
                    "3",
                    0
                ],
                "vae": [
                    "4",
                    2
                ]
            },
            "class_type": "VAEDecode",
            "_meta": {
                "title": "VAE解碼"
            }
        },
        "9": {
            "inputs": {
                "filename_prefix": "ComfyUI",
                "images": [
                    "8",
                    0
                ]
            },
            "class_type": "SaveImage",
            "_meta": {
                "title": "儲存映像"
            }
        },
        "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": "K採樣器"
            }
        },
        "14": {
            "inputs": {
                "samples": [
                    "13",
                    0
                ],
                "vae": [
                    "18",
                    2
                ]
            },
            "class_type": "VAEDecode",
            "_meta": {
                "title": "VAE解碼"
            }
        },
        "15": {
            "inputs": {
                "filename_prefix": "ComfyUI",
                "fps": 10.000000000000002,
                "lossless": false,
                "quality": 85,
                "method": "default",
                "images": [
                    "14",
                    0
                ]
            },
            "class_type": "SaveAnimatedWEBP",
            "_meta": {
                "title": "儲存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_映像到視頻_條件"
            }
        },
        "17": {
            "inputs": {
                "min_cfg": 1,
                "model": [
                    "18",
                    0
                ]
            },
            "class_type": "VideoLinearCFGGuidance",
            "_meta": {
                "title": "線性CFG引導"
            }
        },
        "18": {
            "inputs": {
                "ckpt_name": "svd_xt.safetensors"
            },
            "class_type": "ImageOnlyCheckpointLoader",
            "_meta": {
                "title": "Checkpoint載入器(僅映像)"
            }
        },
        "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": "合并為視頻"
            }
        }
    }
}

非同步呼叫

{
    "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": "K採樣器"
        }
    },
    "4": {
        "inputs": {
            "ckpt_name": "LandscapeBING_v10.safetensors"
        },
        "class_type": "CheckpointLoaderSimple",
        "_meta": {
            "title": "Checkpoint載入器(簡易)"
        }
    },
    "5": {
        "inputs": {
            "width": 720,
            "height": 1280,
            "batch_size": 1
        },
        "class_type": "EmptyLatentImage",
        "_meta": {
            "title": "空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文本編碼器"
        }
    },
    "7": {
        "inputs": {
            "text": "",
            "speak_and_recognation": {
                "__value__": [
                    false,
                    true
                ]
            },
            "clip": [
                "4",
                1
            ]
        },
        "class_type": "CLIPTextEncode",
        "_meta": {
            "title": "CLIP文本編碼器"
        }
    },
    "8": {
        "inputs": {
            "samples": [
                "3",
                0
            ],
            "vae": [
                "4",
                2
            ]
        },
        "class_type": "VAEDecode",
        "_meta": {
            "title": "VAE解碼"
        }
    },
    "9": {
        "inputs": {
            "filename_prefix": "ComfyUI",
            "images": [
                "8",
                0
            ]
        },
        "class_type": "SaveImage",
        "_meta": {
            "title": "儲存映像"
        }
    },
    "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": "K採樣器"
        }
    },
    "14": {
        "inputs": {
            "samples": [
                "13",
                0
            ],
            "vae": [
                "18",
                2
            ]
        },
        "class_type": "VAEDecode",
        "_meta": {
            "title": "VAE解碼"
        }
    },
    "15": {
        "inputs": {
            "filename_prefix": "ComfyUI",
            "fps": 10.000000000000002,
            "lossless": false,
            "quality": 85,
            "method": "default",
            "images": [
                "14",
                0
            ]
        },
        "class_type": "SaveAnimatedWEBP",
        "_meta": {
            "title": "儲存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_映像到視頻_條件"
        }
    },
    "17": {
        "inputs": {
            "min_cfg": 1,
            "model": [
                "18",
                0
            ]
        },
        "class_type": "VideoLinearCFGGuidance",
        "_meta": {
            "title": "線性CFG引導"
        }
    },
    "18": {
        "inputs": {
            "ckpt_name": "svd_xt.safetensors"
        },
        "class_type": "ImageOnlyCheckpointLoader",
        "_meta": {
            "title": "Checkpoint載入器(僅映像)"
        }
    },
    "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": "合并為視頻"
        }
    }
}

同步調用

同步調用直接向EAS服務執行個體發送請求,適合開發測試和低並發情境。

線上調試

線上調試功能允許您在控制台直接測試API調用,無需編寫代碼。適合快速驗證工作流程配置和調試問題。

模型在线服务 (EAS)頁面,單擊目標服務操作列下的在线调试,進入線上調試頁面。

  1. 發送POST請求,擷取Prompt ID。

    1. 在調試頁面的在线调试请求参数地區的Body處填寫已準備好的請求體。並在請求URL文本編輯框中添加/promptimage

    2. 單擊发送请求,即可在调试信息地區查看返回結果,樣本如下。image

  2. 發送GET請求,根據Prompt ID擷取推理結果。

    1. 在线调试请求参数地區中,將要求方法修改為GET,並在文字框中配置/history/<prompt id>,樣本如下。image

      其中<prompt id>需要替換為步驟1擷取的Prompt ID。

    2. 單擊发送请求,即可擷取推理結果。

      您可以在掛載儲存的output目錄中,查看產生的推理結果。

代碼調用

通過代碼調用API,可將ComfyUI整合到您的應用程式中。調用流程與線上調試相同:先擷取Prompt ID,再查詢推理結果。

  1. 查看調用資訊。

    1. 推理服務頁簽,單擊目標服務名稱進入概覽頁面,在基本資料地區單擊查看調用資訊

    2. 調用資訊面板,可擷取訪問地址和Token。根據您的實際情況選擇公網或VPC地址,後續使用<EAS_ENDPOINT>和<EAS_TOKEN>指代這兩個值。

      image

  2. 發送請求擷取Prompt ID。

    • HTTP請求方式:POST。

    • 請求路徑(URL)<EAS_ENDPOINT>/prompt。其中<EAS_ENDPOINT>如地址末尾有/,請刪除。最終URL如http://comfyui****.175805416243****.cn-beijing.pai-eas.aliyuncs.com/prompt

    • 要求標頭部(Headers)

      頭部

      描述

      Authorization

      <EAS_TOKEN>

      授權識別碼。

      Content-Type

      application/json

      指定請求體格式。

    程式碼範例:

    cURL

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

    其中,--data-raw 為請求體。

    Python

    程式碼範例如下:

    import requests
    import json
    
    # <EAS_ENDPOINT> 和 <EAS_TOKEN> 替換為步驟1擷取的地址和token。
    service_url = "<EAS_ENDPOINT>"
    token = "<EAS_TOKEN>"
    
    if service_url[-1] == "/":
        service_url = service_url[:-1]
    
    # 請求體,將payload中的prompt的值配置為工作流程對應的JSON檔案內容。
    payload = """{
        "prompt":
        ...省略
    }"""
    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)

    返回結果樣本如下:

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

    從返回結果中擷取Prompt ID。

  3. 擷取推理結果。

    • HTTP請求方式GET

    • 請求URL<EAS_ENDPOINT>/history/<prompt_id>,其中<prompt_id>替換為步驟1中擷取的prompt_id。

    • 要求標頭部

      頭部

      描述

      Authorization

      <EAS_TOKEN>

      授權識別碼,步驟1中擷取。

    程式碼範例:

    cURL

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

    Python

    import requests
    
    # <EAS_ENDPOINT> 和 <EAS_TOKEN> 替換為步驟1擷取的地址和token。
    # <prompt_id>替換為步驟2中擷取的prompt_id
    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)

    返回結果樣本如下:

    單擊查看返回結果樣本

    {
        "130bcd6b-5bb5-496c-9c8c-3a1359a0****": {
            "prompt": ...省略,
            "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": ...省略,
            }
        }
    }

    在本樣本返回的outputs中提供了prompt產生的映像、webp檔案和mp4視頻,您可以在掛載儲存的output目錄中,根據檔案名稱來尋找這些檔案。

非同步呼叫

非同步呼叫適用於生產環境高並發情境,基於EAS佇列服務實現負載平衡。提交請求後立即返回,通過訂閱結果隊列擷取產生結果。

重要

非同步呼叫僅支援api_prompt路徑,其task_id參數是標識請求和結果的關鍵標誌,請給每個請求分配一個唯一的值,以對應後面的隊列結果。請求路徑如下:

{service_url}/api_prompt?task_id={需分配唯一值}

  1. 查看調用資訊。

    推理服務頁簽,單擊目標服務名稱進入概覽頁面,在基本資料地區單擊查看調用資訊。在調用資訊對話方塊的非同步呼叫頁簽,查看服務訪問地址和Token。

    image

    下文使用<EAS_ENDPOINT>指代公网输入调用地址(如果調用端與EAS處於同一VPC,可使用VPC输入调用地址),<EAS_TOKEN>指代Token

  2. 發送請求。

    程式碼範例如下:

    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})
    
    # 請求體-工作流程JSON,無需"prompt"封裝。
    # 使用 """ """ 將其定義為多行字串,否則需要將工作流程JSON中布爾值(true和false)的首字母改為大寫。
    payload = """{
        '3': 
        ...省略
      }
      """
    payload = json.loads(payload)
    
    for i in range(5):
      # task_id是標識請求和結果的關鍵標誌,請給每個請求分配一個唯一的值,以對應後面的隊列結果
      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. 訂閱結果。

    1. 安裝eas_prediction SDK。

      pip install eas_prediction  --user
    2. 執行以下代碼,擷取返回結果。

      from eas_prediction import QueueClient
      from urllib.parse import urlparse, urlunparse
      
      service_url     = "<EAS_ENDPOINT>"
      token           = "<EAS_TOKEN>"
      
      # 解析服務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}.")
         
      # 建立結果隊列用戶端 
      sink_queue = QueueClient(service_domain, f'{service_name}/sink')
      sink_queue.set_token(token)
      sink_queue.init()
      
      # 監聽結果
      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}')
          # 提交確認接收
          sink_queue.commit(x.index)

      返回結果樣本如下:

      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"}]}}]'

      您可以在掛載儲存的output目錄中,查看推理結果檔案。

常見問題

本節匯總了ComfyUI部署和使用過程中的常見問題,按問題類型分類。

部署問題

Q:服務一直顯示等待中或者ComfyUI無法出圖

通常是資源規格不夠的原因。請檢查服務鏡像和資源規格配置是否正確,資源規格推薦使用GU30、A10或T4卡型,其中ml.gu7i.c16m60.1-gu30性價比高。

Q:服務部署一段時間後為什麼會自動停止?

Serverless版的模型服務如果長時間沒有接收到請求或計算任務,系統可能會自動釋放相關資源以降低成本。

模型與節點問題

Q:WebUI顯示“缺少模型”錯誤

問題描述:報錯如下:

image.png

解決方案:此報錯可以忽略。PAI部署的ComfyUI此檢查無效,請以運行時的報錯為準。

建議勾選不再顯示此訊息,或者通過設定關閉模型校正。

image

Q:上傳了新模型但找不到

解決方案:

  1. 確認使用的不是Serverless版(Serverless版不支援上傳自己的模型,請使用標準版或叢集版)。

  2. 單擊PaiCustom,選擇載入新模型image

  3. 如不可見,單擊重啟進程image

Q:模型載入器顯示undefined

首先確認模型的目錄位置是否正確,這依賴於模型載入器的要求。

如在部署後上傳模型,請重啟服務。

Q:找不到節點

Q:ComfyUI 管理器下載模型或安裝節點失敗

在EAS部署的ComfyUI中,不建議使用ComfyUI管理器。因為直接下載外網模型或安裝外掛程式(需要從GitHub等平台拉取代碼),有可能存在網路連接失敗的問題。

建議您將模型或節點檔案上傳到服務掛載的儲存上,詳情請參見使用第三方模型和安裝節點(ComfyUI外掛程式)

Q:如何查看當前可用的模型檔案和節點(ComfyUI外掛程式)列表

  • 模型檔案:在相應模型載入節點查看。例如在Checkpoint載入器的下拉式清單中查看當前可用的模型檔案。

  • 節點:按右鍵WebUI頁面,在捷徑功能表中單擊添加節點,查看所有已安裝的ComfyUI外掛程式。

運行異常

Q:頁面卡死或載入頁面時間過長

  • 重新整理頁面,清理瀏覽器緩衝或使用無痕/隱私模式訪問。

  • 如掛載了儲存,刪除input/output/temp/檔案夾中的檔案。

  • 嘗試重啟服務。

Q:工作流程跑一半,進程重啟了

如果執行個體日誌裡面有run.sh: line 54: 531285 Killed python -u main_run.py "$@",那就是記憶體oom了,記憶體oom之後,進程會自動重啟。

Q:RuntimeError: CUDA error: out of memory

顯存超了,如果是映像模型就降低映像的解析度或者batch size;視頻模型降低一下幀數/解析度。

Q:API調用報錯:url not found 或404 page not found?

  1. 確認使用的不是Serverless版本(Serverless類型不支援API調用)。

  2. 檢查API端點URL是否完整。同步調用需拼接/prompt路徑。

其他

Q:xFormer的加速效果

xFormers是基於Transformer的開源加速工具,能夠有效縮短圖片和視頻產生時間長度,節省顯存使用。

ComfyUI鏡像部署預設已開啟xFormers加速。加速效果跟工作流程的大小相關,針對GPU調用的內容尤其是使用NVIDIA顯卡的提升比較明顯。

Q:EAS與Function Compute在部署ComfyUI Serverless版的主要區別

  • EAS:適合有狀態、長周期啟動並執行服務,支援一鍵部署模型為線上推理服務或AI-Web應用,具備彈性擴縮容、藍綠部署等功能。例如,您可以通過EAS的情境化模型部署或自訂模型部署方式來部署ComfyUI。

  • Function Compute:基於Serverless架構,提供按需付費、Auto Scaling等優勢,適合需要高品質映像產生功能的情境,可自訂ComfyUI模型及安裝外掛程式。例如,您可以在Function Compute3.0控制台建立應用、選擇ComfyUI模板、設定配置項並建立應用。

下一步

完成ComfyUI服務部署後,您可以:

  • 服務監控:佈建服務監控和警示,即時掌握服務運行狀態。詳見服務監控說明

  • Auto Scaling:根據業務負載配置自動調整策略,最佳化資源使用和成本。詳見Auto Scaling

  • 成本最佳化:瞭解EAS計費方式,選擇合適的資源規格和部署版本降低成本。詳見計費說明

參考資訊

安裝Python包

通過運行命令安裝whl包

  1. 確保已為服務掛載儲存。假設OSS路徑Urioss://examplebucket/comfyui/,掛載路徑為/mnt/data/image

  2. .whl檔案上傳到oss://examplebucket/comfyui/models/whl目錄下,如無whl的檔案夾,請先建立。

  3. 更新服務配置中的运行命令:在運行命令前增加pip install /mnt/data/models/whl/xxx.whl。其中/mnt/data為OSS的掛載路徑xxx.whl表示whl包的名字。

    image

  4. 重啟服務。

通過三方庫配置安裝

  1. 在服務詳情頁右上方單擊更新

    image

  2. 如果是通過情境化部署,請切換為自訂部署。

    image

  3. 环境信息地區的三方庫配置,設定依賴包。image

  4. 單擊頁面下方更新按鈕,完成服務更新即可。

更新鏡像版本

說明

Serverless版本不支援此功能。

若服務掛載OSS或者NAS儲存空間,自訂模型保留在OSS或者NAS儲存空間,更新鏡像版本不會影響已安裝的自訂模型。

  1. 在服務詳情頁右上方單擊更新image

  2. 如通過情境化方法部署,請切換為自訂部署。

  3. 服务配置地區,編輯JSON配置並更新containersimage欄位,如圖將1.9改成需要的版本。image

  4. 單擊直接更新

延長無登入態的URL時間

可通過API擷取指定有效時間長度的免登入Web訪問連結。

  1. 進入DescribeServiceSignedUrl API頁面。

  2. 選擇服務地址。image

  3. 設定參數:

    • ClusterId服務所在地區、ServiceName 服務名字:填寫服務所在地區與服務名字。如下從EAS服務概覽頁面擷取。

      image

    • Type 頁面類型:下拉選擇 webview。

    • Expire 到期時間:填寫整數,單位為秒。目前最長只能是43200秒(12小時),建議按需填寫。

    • Internal 是否為VPC連結:false(公網訪問)或true(VPC訪問)。

  4. 單擊發起調用,返回結果中SignedUrl為服務免登入Web訪問連結。

切換WebUI頁面的預設語言

  1. 在WebUI頁面,單擊左下角的設定按鈕。

  2. 分別在以下兩個位置設定完成後,重新整理頁面並重新載入即可。

    • Comfy > 地區設定image

    • 語言 > 地區設定:image

附錄

叢集版服務原理介紹

實現原理圖如下:

image

叢集版服務主要針對多使用者情境,通過引入一個 Proxy 代理層,實現了用戶端和後端推理執行個體解耦。

  • 每個使用者有獨立的後端環境和工作目錄,但共用後端的GPU推理執行個體池。

  • 當使用者發起推理請求時,Proxy 代理會從池中尋找一個閒置執行個體來處理該請求。

這種分時複用機制在保證使用者環境隔離的同時,有效提升了 GPU 資源的利用率,降低了多使用者情境下的推理成本。