하나의 API로 여러 AI 모델을 n8n에 연결하는 방법
한 번에 한 공급자씩 AI 모델을 연결하는 방식은 프로토타입 단계에서는 가능하지만, 사용량이 늘수록 취약해집니다. 각 공급자는 서로 다른 자격 증명, 엔드포인트, 요청 형식, 속도 제한, 과금, 응답 구조를 가집니다. n8n에서는 이로 인해 HTTP 노드가 중복되고 공급자별 분기가 생기기 쉬워, 모델을 추가하거나 폴백 경로를 바꾸려면 워크플로의 여러 부분을 수정해야 합니다.
n8n과 CometAPI는 이 문제를 서로 다른 레이어에서 해결합니다. n8n은 작업 실행 시점, 입력 검증, 동기/비동기 작업 라우팅, 재시도, 결과 저장을 담당합니다. CometAPI는 하나의 API 키와 하나의 베이스 URL 뒤에 모델 접근을 중앙집중화합니다. 이 조합을 사용하면 오케스트레이션 레이어에서 공급자 변경을 배제할 수 있습니다. 동일한 큐, 폴링, 스토리지, 모니터링 로직을 유지한 채 모델 ID만 바꿀 수 있습니다.
이 조합은 스프레드시트나 내부 도구에서 들어오는 이미지와 비디오 혼합 작업에 특히 유용합니다. 워크플로는 n8n에서 시각적으로 감사 가능하게 유지되고, 자격 증명, 모델 가용성, 사용 비용은 하나의 API 레이어에서 더 쉽게 관리할 수 있습니다.
여러 AI 공급자를 하나의 앱에 통합하는 가장 쉬운 방법은 오케스트레이션과 모델 접근을 분리하는 것입니다. 트리거, 분기, 재시도, 저장은 n8n이 처리하고, CometAPI는 모든 분기에 하나의 API 키와 하나의 베이스 URL을 제공합니다. 모델 ID는 각 작업의 하나의 필드가 되며, 별도의 공급자 계정, SDK, 과금 설정이 필요 없습니다.
이 가이드에서는 Google Sheets에서 이미지와 비디오 작업을 읽어 CometAPI를 통해 OpenAI와 ByteDance 모델로 전송하고, 비동기 비디오 태스크 ID를 저장한 뒤 완료까지 폴링하고, 최종 결과를 n8n Data Table에 업서트하는 저코드 파이프라인을 구축합니다.
무엇을 만들게 되나요
완성된 워크플로의 경로는 다음과 같습니다:
Google Sheets Trigger → 작업 정규화 → 미디어 유형별 Switch → CometAPI 이미지 또는 비디오 요청 → 대기 및 비디오 태스크 폴링 → 출력 업로드 또는 참조 → Data Table 업서트.
소스 시트에는 다음 열을 사용하세요:
job_id | media_type | model | prompt | size | seconds | status
일반적인 이미지 행은 image, gpt-image-2, 1024x1024를 사용합니다. 비디오 행은 video, seedance-2-5, 1280x720, 그리고 4~30초 사이의 길이를 사용합니다.
시작하기 전에
n8n 인스턴스, Google Sheet, CometAPI API 키, 그리고 ai_jobs라는 이름의 n8n Data Table이 필요합니다. Data Table에 다음 열을 생성하세요: job_id, media_type, model, status, task_id, result_url, error, updated_at.
셀프 호스팅 n8n의 경우, n8n 프로세스가 사용하는 환경에 다음 값을 추가하세요:
COMETAPI_BASE_URL=https://api.cometapi.com/v1COMETAPI_KEY=your_cometapi_key
환경을 변경한 뒤 n8n을 재시작하세요. n8n Cloud 또는 노드 표현식에서 환경 변수를 노출하고 싶지 않은 경우, CometAPI Bearer라는 이름의 HTTP Header Auth 자격 증명을 생성하세요. 헤더 이름은 Authorization, 값은 Bearer your_cometapi_key로 설정합니다. 아래 예시는 이 자격 증명과 OpenAI 호환 고정 베이스 URL https://api.cometapi.com/v1.을 사용합니다.
최신 모델 ID 사용
| Job | Provider and model | Request | Result |
|---|---|---|---|
| Image | OpenAI · gpt-image-2 | POST /v1/images/generations | 동기식 base64 이미지 |
| Video | ByteDance · seedance-2-5 | POST /v1/videos | 비동기 태스크, 이후 폴링 |
양쪽의 ID와 기능은 2026년 8월 11일 기준 실시간 CometAPI 모델 디렉터리 API에서 확인되었습니다. 이미지 모델은 텍스트-투-이미지 생성을 지원합니다. Seedance 2.5는 텍스트-투-비디오와 이미지-투-비디오 생성, 4–30초 길이의 클립, 문서화된 480p와 720p 사이즈를 지원합니다.
가격(2026년 8월 11일 기준): GPT Image 2 모델 페이지에는 입력 토큰 100만 개당 $4, 출력 토큰 100만 개당 $24로 기재되어 있습니다. Seedance 2.5 모델 페이지에는 480p 초당 $0.103, 720p 초당 $0.231로 기재되어 있습니다. 가격은 변동될 수 있으므로, 실행 시점에는 모델 디렉터리 또는 모델 페이지를 진실의 원천으로 사용하세요.
중요한 아키텍처 차이는 이미지 생성은 요청-응답 작업으로 처리할 수 있지만, 비디오 생성은 상태를 갖는 작업으로 취급해야 한다는 점입니다. 폴링 전에 비디오 태스크 ID를 영속화하면 n8n 실행이 재시작되어도 작업을 잃지 않습니다.
n8n에서 워크플로 구축
1. Google Sheets에서 새 작업 트리거
Google Sheets Trigger 노드를 추가하고 Row added or updated를 선택합니다. 작업 큐가 있는 워크시트를 지정하세요. 트리거 바로 뒤에 IF 노드를 추가하고 status가 비어 있거나 queued일 때만 계속 진행하도록 설정합니다. 이렇게 하면 시트가 변경되더라도 완료된 행이 다시 제출되지 않습니다.
2. 각 행 정규화 및 검증
Normalize Job이라는 이름의 Code 노드를 추가합니다. 이 노드는 안전한 기본값을 적용하고, 워크플로를 승인된 모델 ID로 제한하며, 두 분기 모두에서 동일한 필드를 생성합니다.
const row = $json;const allowedModels = { image: new Set(['gpt-image-2']), video: new Set(['seedance-2-5']),};const mediaType = String(row.media_type || '').trim().toLowerCase();if (!allowedModels[mediaType]) { throw new Error(`media_type must be image or video; received: ${row.media_type}`);}const defaultModel = mediaType === 'image' ? 'gpt-image-2' : 'seedance-2-5';const model = String(row.model || defaultModel).trim();if (!allowedModels[mediaType].has(model)) { throw new Error(`Model ${model} is not allowed for ${mediaType} jobs`);}const prompt = String(row.prompt || '').trim();if (!prompt) throw new Error('prompt is required');const seconds = mediaType === 'video' ? Number(row.seconds || 4) : null;if (mediaType === 'video' && (!Number.isInteger(seconds) || seconds < 4 || seconds > 30)) { throw new Error('Seedance 2.5 seconds must be an integer from 4 to 30');}return [{ json: { job_id: String(row.job_id || $execution.id), media_type: mediaType, model, prompt, size: String(row.size || (mediaType === 'image' ? '1024x1024' : '1280x720')), seconds, status: 'processing', updated_at: new Date().toISOString(), },}];
Normalize Job 뒤에 Switch 노드를 추가합니다. image는 이미지 분기로, video는 비디오 분기로 라우팅합니다.
3. 하나의 엔드포인트로 이미지 생성
Create Image라는 이름의 HTTP Request 노드를 추가하고 다음과 같이 설정합니다:
- Method:
POST - URL:
https://api.cometapi.com/v1/images/generations - Authentication:
CometAPI BearerHeader Auth 자격 증명 - Body Content Type: JSON
{ "model": "={{ $('Normalize Job').item.json.model }}", "prompt": "={{ $('Normalize Job').item.json.prompt }}", "size": "={{ $('Normalize Job').item.json.size }}"}
GPT Image 2는 base64 이미지 데이터를 반환합니다. 해당 데이터를 n8n 바이너리 아이템으로 변환하기 위해 Prepare Image File이라는 Code 노드를 추가하세요:
const job = $('Normalize Job').item.json;const b64 = $json.data?.[0]?.b64_json;if (!b64) throw new Error('CometAPI returned no image data');return [{ json: { ...job, status: 'completed', task_id: '', result_url: '', error: '', updated_at: new Date().toISOString(), }, binary: { media: { data: b64, mimeType: 'image/png', fileName: `${job.job_id}.png`, }, },}];
이 노드를 S3나 Google Drive 같은 선호하는 오브젝트 스토리지 노드에 연결하세요. 반환된 파일 URL을 result_url에 저장한 다음, 해당 행을 ai_jobs에 업서트합니다. 대용량 base64 페이로드는 Data Table에 저장하지 마세요.
4. 비동기 비디오 태스크 생성
Create Video라는 이름의 HTTP Request 노드를 추가합니다:
- Method:
POST - URL:
https://api.cometapi.com/v1/videos - Authentication:
CometAPI Bearer - Body Content Type: Form-Data
폼 필드 네 가지를 추가하세요: model, prompt, seconds, size. 값은 Normalize Job에서 매핑합니다.
다음으로 Save Video Task라는 Code 노드를 추가합니다:
const job = $('Normalize Job').item.json;const taskId = $json.id || $json.task_id;if (!taskId) throw new Error('Video task ID missing from create response');return [{ json: { ...job, task_id: taskId, status: $json.status || 'queued', result_url: '', error: '', updated_at: new Date().toISOString(), },}];
폴링 전에 이 아이템을 ai_jobs에 업서트하세요. 태스크 ID를 즉시 저장해 두면 재시작이나 타임아웃이 발생해도 작업이 유실되지 않습니다.
5. 대기, 폴링 및 비디오 URL 저장
대기 시간을 15초로 설정한 Wait 노드를 추가합니다. 그런 다음 Get Video라는 이름의 HTTP Request 노드를 추가합니다:
- Method:
GET - URL:
=https://api.cometapi.com/v1/videos/{{ $json.task_id }} - Authentication:
CometAPI Bearer
요청 후, status에 대해 Switch 노드를 사용합니다:
queued또는in_progress: Wait 노드로 되돌아갑니다.completed:Finalize Video로 진행합니다.failed또는error: 오류를ai_jobs에 기록하고 중단합니다.
완료 브랜치에는 다음 Code 노드를 사용하세요:
const prior = $('Save Video Task').item.json;const resultUrl = $json.video_url || $json.url || $json.data?.video_url;if (!resultUrl) throw new Error('Completed video response has no video URL');return [{ json: { ...prior, status: 'completed', result_url: resultUrl, error: '', updated_at: new Date().toISOString(), },}];
job_id로 최종 아이템을 ai_jobs에 업서트합니다. CometAPI 비디오 URL은 서명되고 일시적일 수 있으므로, 프로덕션 워크플로에서는 파일을 다운로드해 재호스팅한 뒤 영구 URL을 저장하는 것이 좋습니다. 앱이 인바운드 요청을 받을 수 있다면, 선택한 모델이 콜백을 지원하는 경우 폴링 대신 웹훅을 사용하세요.
전체 노드 맵
전체 워크플로는 다음 노드로 구성할 수 있습니다:
- Google Sheets Trigger — Row added or updated
- IF — 새 행 또는 queued 행만 처리
- Code — Normalize Job
- Switch — 이미지 또는 비디오
- 이미지 분기: HTTP Request → Prepare Image File → Object Storage → Data Table Upsert
- 비디오 분기: HTTP Request → Save Video Task → Data Table Upsert → Wait → HTTP Request → Status Switch
- 비디오 완료: Finalize Video → 오브젝트 스토리지 또는 영구 URL → Data Table Upsert
- 비디오 실패: Set Error → Data Table Upsert
실패 분기의 경우, Edit Fields 노드에서 다음 표현식을 사용하세요:
{ "job_id": "={{ $('Save Video Task').item.json.job_id }}", "status": "failed", "task_id": "={{ $('Save Video Task').item.json.task_id }}", "result_url": "", "error": "={{ $json.error?.message || $json.message || 'Video generation failed' }}", "updated_at": "={{ $now.toISO() }}"}
워크플로 테스트
소스 시트에 다음 두 행을 추가하세요:
img-001 | image | gpt-image-2 | A cinematic product photo of a glass robot on a dark desk | 1024x1024 | | queuedvid-001 | video | seedance-2-5 | A paper airplane flies through a sunlit studio, smooth tracking shot | 1280x720 | 4 | queued
이미지 요청은 다음과 유사한 구조를 반환해야 합니다:
{ "created": 1786400000, "data": [ { "b64_json": "iVBORw0KGgoAAA..." } ]}
비디오 생성 요청은 다음과 유사한 태스크 구조를 반환해야 합니다:
{ "id": "video_task_abc123", "object": "video", "status": "queued", "progress": 0}
폴링 후, 완료된 응답에는 동일한 태스크 ID, status: completed, 그리고 video_url이 포함되어야 합니다. 선택적 필드는 모델마다 달라질 수 있으므로, 정규화 코드는 공급자 응답 전체를 데이터베이스에 복사하는 대신 안정적인 태스크 상태와 결과 URL을 읽습니다.
일반 오류 및 해결
| Error | Fix |
|---|---|
| 401 Unauthorized | Header Auth 값이 Bearer로 시작하는지, 키가 활성 상태인지 확인하세요. |
| 404 model or task not found | 실시간 모델 디렉터리를 확인하고, 저장된 태스크 ID가 GET /v1/videos/{id}에 사용되는지 확인하세요. |
| 400 invalid size or seconds | 지원되는 size를 사용하고 Seedance 2.5 duration을 4~30초로 유지하세요. |
| 429 rate limited | n8n 동시성을 낮추고 지터가 있는 지수 백오프로 재시도하세요. |
| Polling never ends | 시도 횟수를 영속화하고 정의된 타임아웃 후 중단하세요. failed와 error는 종료 상태로 처리하세요. |
| Image payload is too large | base64를 바이너리로 변환해 업로드하고, 영구 URL만 저장하세요. |
프로덕션 체크리스트
자격 증명 보호. API 키는 n8n 자격 증명 또는 서버측 환경 변수에 보관하세요. 스프레드시트에 넣거나 브라우저로 반환하지 마세요.
모든 작업의 멱등성 보장. job_id를 Data Table 업서트 키로 사용하세요. 새 태스크를 생성하기 전에 이미 processing 또는 completed로 표시된 행은 건너뜁니다.
폴링과 동시성 제어. 비디오 작업은 10–20초 간격으로 폴링하고, 시도 횟수 상한을 두며, 동시 실행을 제한하세요. 429, 500, 503 응답에서는 중복 태스크를 만들지 말고 백오프하세요.
요청 전마다 모델 정책 검증. 미디어 유형별 허용 목록을 유지하세요. 모델 가용성과 가격은 실시간 디렉터리에서 주기적으로 갱신하되, 스프레드시트 사용자가 임의의 ID를 제출하지 못하도록 검토를 거쳐 배포하세요.
작업당 비용 추적. 각 결과에 모델, 해상도, 길이, 사용 필드를 저장하세요. 720p Seedance 2.5로 4초 작업은 2026년 8월 11일 기준 약 $0.924, 동일 4초 480p는 약 $0.412입니다. 요청 전에 최대 길이와 해상도를 강제하세요.
생성된 미디어 재호스팅. 공급자 서명 URL은 전달 링크로만 취급하고 영구 저장소로 사용하지 마세요. 완료된 미디어를 다운로드해 관리 중인 버킷에 업로드하고, 내구성 있는 URL과 체크섬을 저장하세요.
감사 추적 유지. 요청 모델, 정제된 파라미터, 태스크 ID, 상태 전이, 재시도 횟수, 응답 시간, 최종 자산 위치를 저장하세요. API 키나 전체 비공개 프롬프트는 기록하지 마세요.
이 패턴이 확장되는 이유
새 공급자나 모델 추가가 새로운 계정 통합이 아니라 라우팅 결정에 불과하기 때문에 워크플로가 단순하게 유지됩니다. 스프레드시트는 작업 큐로, n8n은 오케스트레이션 레이어로, CometAPI는 단일 접근 레이어로 남습니다. 허용 목록과 분기 구성을 확장해 모델을 추가하면 됩니다. 트리거, 태스크 영속화, 폴링, 저장, 모니터링 로직은 변경되지 않습니다.
이것이 다수 공급자 AI 통합의 실용적인 해법입니다. 하나의 관리되는 엔드포인트와 키, 명시적 모델 라우팅, 동기/비동기 경로 분리, 모든 작업에 대한 내구성 있는 기록을 갖추세요.
자주 묻는 질문
n8n이 하나의 API를 통해 여러 AI 공급자를 호출할 수 있나요?
가능합니다. CometAPI와 같은 통합 API 레이어를 사용하면, n8n은 공급자 자격 증명과 HTTP 통합을 중앙집중화한 상태로 지원 모델에 요청을 보낼 수 있습니다.
n8n의 HTTP Request 노드로 CometAPI를 사용할 수 있나요?
가능합니다. HTTP Request 노드는 CometAPI의 API 엔드포인트로 필요한 인증 및 모델별 파라미터를 포함한 요청을 전송할 수 있습니다.
한 모델이 실패하면 n8n이 자동으로 다른 AI 모델로 전환할 수 있나요?
가능합니다. API 요청 후 IF/Switch 분기를 사용해 재시도 가능한 오류나 모델 특화 오류를 폴백 모델로 라우팅하세요. 폴백은 동일한 모달리티와 필요한 기능을 지원해야 합니다.
