네트워크 노드 모델 제어¶
Backend.AI GO를 사용하면 헤드 노드에서 해당 머신에 직접 접근하지 않고도 연결된 네트워크 노드의 모델을 실행 및 중지할 수 있습니다. 이것으로 분산 추론 워크플로우가 완성됩니다. 노드를 연결하고, 노드 간에 추론 요청을 라우팅하며, 이제 각 노드에서 실행 중인 모델을 단일 인터페이스에서 관리할 수 있습니다.
개요¶
네트워크 노드가 등록되면 헤드 노드는 해당 노드의 기본 URL과 API 키를 저장합니다. 네트워크 노드 모델 제어는 이 정보를 사용하여 사용자를 대신해 네트워크 노드의 Management API로 모델 관리 명령을 전송합니다.
다음 작업이 지원됩니다:
- 모델 실행 — 네트워크 노드에 모델을 실행하도록 지시
- 모델 중지 — 네트워크 노드에서 실행 중인 모델 중지
- 실행 중인 모델 목록 — 네트워크 노드에서 현재 활성화된 모델 조회
API 레퍼런스¶
세 가지 작업 모두 Tauri IPC 명령(데스크탑 앱)과 REST API 엔드포인트(헤드리스 모드)로 사용할 수 있습니다.
네트워크 노드에서 모델 실행¶
Tauri IPC: load_model_on_remote_node
REST: POST /api/v1/nodes/{fingerprint}/models/load
요청 본문:
{
"modelId": "llama-3-8b-q4",
"modelPath": "/path/to/model.gguf",
"contextLength": 4096,
"gpuLayers": -1
}
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
modelId | string | 예 | 실행할 모델 식별자 |
modelPath | string | 아니요 | 네트워크 노드의 모델 파일 절대 경로 |
contextLength | number | 아니요 | 기본 컨텍스트 길이 재정의 |
gpuLayers | number | 아니요 | GPU 레이어 수 (-1은 llama.cpp가 결정, 0은 CPU 전용) |
응답:
실패 시 success는 false이며 error 필드에 문제가 설명됩니다.
네트워크 노드에서 모델 중지¶
Tauri IPC: unload_model_on_remote_node
REST: POST /api/v1/nodes/{fingerprint}/models/unload
요청 본문:
응답:
네트워크 노드의 모델 목록 조회¶
Tauri IPC: get_remote_node_models
REST: GET /api/v1/nodes/{fingerprint}/models
응답:
{
"data": [
{
"id": "llama-3-8b-q4",
"path": "/models/llama-3-8b-q4.gguf",
"endpoint": "http://127.0.0.1:8081",
"healthy": true
}
]
}
네트워크 노드에서 실행할 수 있는 모델 목록 조회¶
Tauri IPC: get_remote_node_loadable_models
REST: GET /api/v1/nodes/{fingerprint}/models/loadable
분산 풀 탭의 노드에서 실행 대화상자는 노드를 선택하면 해당 노드의 모델 목록을 받아 드롭다운으로 보여 주는데, 이미 실행 중인 모델은 목록에서 빠집니다. 헤드 노드는 네트워크 노드에 GET /api/v1/loadable을 요청하며, 노드 키는 실행 중인 모델 목록을 읽을 때와 같은 권한으로 이 경로에 접근합니다. 네트워크 노드는 라이브러리에 있는 채팅·임베딩 모델을 이름순으로 돌려주고, 추측 디코딩용 드래프터와 이미지 생성 모델은 제외합니다.
응답:
{
"data": [
{
"id": "llama-3.2-3b-instruct-q4_k_m",
"name": "Llama 3.2 3B Instruct",
"format": "gguf",
"sizeBytes": 2019377152,
"quantization": "Q4_K_M",
"parameters": "3B"
}
]
}
GET /api/v1/loadable이 없는 버전의 네트워크 노드는 404로 응답하고, 헤드는 REMOTE_LOADABLE_UNSUPPORTED가 들어간 오류를 반환합니다. 이 경우 대화상자는 목록을 아예 읽지 못했을 때와 마찬가지로 모델 ID를 직접 입력받습니다. 헤드는 한 노드에서 최대 500개 항목까지만 받으며, 이름에 섞인 제어 문자는 제거됩니다.
실시간 업데이트¶
네트워크 노드에서 모델이 성공적으로 실행되거나 중지되면 헤드 노드는 distributed-pool-changed 이벤트를 전송합니다. 프론트엔드 nodeStore는 이 이벤트를 구독하여 자동으로 다음을 수행합니다:
- 영향을 받은 노드의 모델 목록 새로고침 (
fetchRemoteModels). - 전체 분산 풀 상태 새로고침 (
getDistributedPoolStatus).
이를 통해 수동으로 페이지를 새로고침하지 않아도 UI가 동기화 상태를 유지합니다.
헤드리스 모드에서는 동일한 이벤트가 GET /api/v1/events의 SSE(Server-Sent Events) 스트림을 통해 브로드캐스트됩니다.
타임아웃¶
대용량 모델을 고려하여 작업에는 여유 있는 타임아웃이 적용됩니다:
| 작업 | 타임아웃 |
|---|---|
| 모델 실행 | 600초 (10분) |
| 모델 중지 | 60초 |
| 모델 목록 조회 | 30초 |
| 실행할 수 있는 모델 목록 조회 | 30초 |
타임아웃이 발생하면 응답에 "success": false와 함께 타임아웃 시간을 나타내는 오류 메시지가 포함됩니다.
오류 처리¶
| 조건 | 동작 |
|---|---|
| 노드 핑거프린트가 등록되지 않음 | 404 Not Found 반환 |
| 네트워크 노드에 연결할 수 없음 (연결 거부) | 연결 메시지와 함께 오류 반환 |
| 네트워크 노드 요청 타임아웃 | 타임아웃 시간과 함께 오류 반환 |
| 네트워크 노드가 2xx가 아닌 응답 반환 | 노드의 오류 본문을 파싱하여 반환 |
| 빈 모델 ID 또는 경로 탐색이 포함된 모델 ID | 요청 전에 거부 |
모델 ID는 네트워크 요청 전에 검증됩니다. 빈 모델 ID와 .. 시퀀스가 포함된 ID는 URL 경로 조작을 방지하기 위해 거부됩니다.
프론트엔드 스토어¶
useNodeStore Zustand 스토어는 네트워크 노드 모델 제어를 위한 다음 셀렉터와 액션을 제공합니다:
| 내보내기 | 타입 | 설명 |
|---|---|---|
useRemoteModels(fingerprint) | 셀렉터 | 특정 노드에 대한 캐시된 모델 |
useAllRemoteModels() | 셀렉터 | 핑거프린트별로 키가 지정된 모든 네트워크 노드 모델 |
useIsRemoteModelOperating(fingerprint) | 셀렉터 | 실행/중지가 진행 중인지 여부 |
loadModelOnNode(fingerprint, request) | 액션 | 네트워크 노드에서 모델 실행 |
unloadModelOnNode(fingerprint, modelId) | 액션 | 네트워크 노드에서 모델 중지 |
fetchRemoteModels(fingerprint) | 액션 | 노드의 모델 목록 새로고침 |
중지는 낙관적 업데이트를 수행합니다. 모델은 즉시 로컬 캐시에서 제거되고, distributed-pool-changed 이벤트가 백엔드에서 전체 새로고침을 트리거합니다.
보안¶
네트워크 노드에 대한 모든 요청은 Authorization: Bearer <api_key> 헤더를 사용합니다. API 키는 로컬 노드 레지스트리에 안전하게 저장되며 로그나 UI에 노출되지 않습니다. 모델 ID는 경로 인젝션을 방지하기 위해 URL에서 퍼센트 인코딩됩니다.
파이프라인 스테이지 워커 제어¶
다중 노드 파이프라인 병렬 서빙(에픽 #3413)을 위해 헤드 노드는 동일한 인증된 피어 채널을 통해 등록된 서브 노드에서 로컬 mlxcel-server 스테이지 프로세스를 시작, 중지, 폴링할 수 있습니다. 서브 노드는 클러스터 TOML을 로컬에 기록하고 스테이지를 시작합니다. 헤드는 코디네이터가 연결하기 전에 트랜스포트 포트 준비 상태를 폴링합니다.
서브 노드에서 스테이지 시작¶
Tauri IPC: spawn_stage_on_remote_node
REST: POST /api/v1/nodes/{fingerprint}/distributed/stages
요청 본문은 GO에서 생성된 clusterId, 전체 clusterToml, 서브 노드의 nodeId, #3414 빌더의 launch 매개변수, 선택적 layerRange를 포함하는 SpawnStageRequest입니다. 응답은 StageStatus입니다(아래 참조). launch의 API 키는 파일 경로만 전송되며 비밀값은 전송되지 않습니다.
서브 노드에서 스테이지 중지¶
Tauri IPC: stop_stage_on_remote_node
REST: DELETE /api/v1/nodes/{fingerprint}/distributed/stages/{cluster_id}
멱등성: 이미 종료된 스테이지를 중지하면 오류 없이 stopped: false를 반환합니다.
서브 노드의 스테이지 상태 폴링¶
Tauri IPC: get_stage_status_on_remote_node
REST: GET /api/v1/nodes/{fingerprint}/distributed/stages/{cluster_id}
서브 노드에서 해당 클러스터의 스테이지가 추적되지 않으면 404를 반환합니다. StageStatus 페이로드에는 다음이 포함됩니다:
| 필드 | 설명 |
|---|---|
clusterId | 이 스테이지가 속한 클러스터 |
nodeId | 클러스터 내 서브 노드 id |
stage | 0부터 시작하는 스테이지 인덱스 |
processState | "running" 또는 "exited" |
transportPortReady | 노드 간 트랜스포트 포트가 TCP 연결을 수락하는지 여부 |
transportAddress | 스테이지가 바인딩하는 호스트와 포트 |
layerRange | 고정된 경우 포함적 레이어 할당 [start, end] |
lastError | 마지막으로 발생한 정제된 오류, 없을 경우 생략 |
서브 노드는 이 세 가지 라우트를 POST/DELETE/GET /api/v1/distributed/stages[/{cluster_id}]에서 처리하며, 모델 제어 라우트와 동일한 ak_ 노드 키로 인증합니다.
타임아웃¶
| 작업 | 타임아웃 |
|---|---|
| 스테이지 시작 | 600초 (스테이지 로드 시 모델 가중치 읽기) |
| 스테이지 중지 | 60초 |
| 상태 폴링 | 15초 |