out-of-tree serve 백엔드 추가하기
out-of-tree serve 백엔드 추가하기
에코시스템의 런타임을 버전 관리되는 serve 백엔드 플러그인 API로 sglang serve에 연결하는 방법을 설명할게요. 플러그인 덕분에 SGLang이 관리하는 CLI를 그대로 쓰면서, 내 런타임이 가진 파서·토폴로지·API 엔드포인트·하드웨어 요구사항·릴리스 주기는 그대로 유지할 수 있어요.
serve 백엔드 플러그인은 out-of-tree 런타임을 SGLang 소유 CLI에 이렇게 연결해요:
sglang serve MODEL_PATH --model-type BACKEND_NAME [BACKEND_OPTIONS]
확장 프로그램은 자기만의 인자 파서, 프로세스 토폴로지, API 엔드포인트, 하드웨어 요구사항, 릴리스 주기를 그대로 보유해요. 핵심 CLI가 담당하는 건 백엔드 선택과 공통 자식 프로세스 정리뿐이에요.
사전 조건
- 확장 프로그램과 호환되는 SGLang 버전을 같은 Python 3.10+ 환경에 설치하세요.
- 확장 프로그램이 테스트한 SGLang 버전 범위를 패키지 의존성에 선언하세요.
- 백엔드 팩토리와 감지기는 GPU 초기화와 모델 로딩으로부터 독립적으로 유지하세요.
플러그인 API 자체는 플랫폼 독립적이에요. 지원 운영체제, 가속기, 병렬화 옵션, 인증 요구사항은 내 백엔드가 정의해요.
실행 파일의 소유자는 한 곳으로
sglang 콘솔 스크립트는 sglang 배포판만 게시해야 해요. 내 확장 프로그램은 sglang.serve_backends 아래에 패키지 메타데이터를 등록하고, 또 다른 sglang 스크립트를 게시하면 안 돼요.
이렇게 하면 설치 순서 때문에 명령이 덮어쓰이는 일도, 확장 프로그램을 지웠을 때 핵심 실행 파일이 사라지는 일도 없어요. 프로젝트 전용 실행 파일을 호환성 별칭으로 유지할 수는 있어요.
my-runtime serve MODEL_PATH
sglang serve MODEL_PATH --model-type my_runtime
두 명령은 같은 백엔드 구현을 호출해야 해요.
백엔드 팩토리 등록하기
확장 프로그램의 pyproject.toml에 인자 없는 팩토리를 추가하세요.
[project]
name = "my-sglang-runtime"
version = "0.1.0"
dependencies = ["sglang"]
[project.entry-points."sglang.serve_backends"]
my_runtime = "my_sglang_runtime.sglang_backend:create_backend"
엔트리 포인트 이름인 my_runtime이 허용되는 --model-type 값이 돼요. 식별력 있는 이름을 고르세요. auto와 SGLang의 in-tree 백엔드 이름은 예약돼 있어요.
백엔드 구현하기
my_sglang_runtime/sglang_backend.py를 만드세요.
import argparse
from sglang.cli.serve_backends import (
ServeBackend,
ServeBackendDetection,
ServeRequest,
)
def detect(request: ServeRequest) -> ServeBackendDetection:
if request.model_path is None:
return ServeBackendDetection.UNKNOWN
if supports_model(request.model_path):
return ServeBackendDetection.MATCH
return ServeBackendDetection.NO_MATCH
def run(request: ServeRequest) -> None:
parser = argparse.ArgumentParser(prog="sglang serve")
parser.add_argument("--model-path", required=True)
parser.add_argument("--pipeline-parallel", type=int, default=1)
args, remaining = parser.parse_known_args(request.argv)
launch_runtime(args, remaining)
def create_backend() -> ServeBackend:
return ServeBackend(api_version=1, run=run, detect=detect)
supports_model()과 launch_runtime()은 확장 프로그램의 가벼운 메타데이터 체크와 블로킹 서버 런처로 바꾸면 돼요. 실제 run() 호출은 서버 수명 동안 블로킹해야 해요. 그리고 서버를 띄우지 않고도 -h, --help를 처리해야 하는데, argparse가 자동으로 처리해 줘요.
serve 백엔드 엔트리 포인트 중에서, 명시적 선택은 선택된 프로바이더만 import해요. 자동 선택은 설치된 백엔드 팩토리를 모두 로드하고 감지기를 호출하므로, 이 모듈을 import하고 detect()를 호출할 때 가속기를 초기화하거나, 모델 가중치를 import하거나, 워커를 시작하면 안 돼요.
전달된 인자 처리하기
SGLang은 디스패치 전에 --model-type을 제거하고 위치 인자로 온 Hugging Face 모델 ID나 로컬 모델 디렉토리를 정규화해요. 예를 들어:
sglang serve org/model --model-type my_runtime --pipeline-parallel 2
내 백엔드는 이렇게 받아요:
("--model-path", "org/model", "--pipeline-parallel", "2")
선택된 백엔드는 나머지 모든 인자 파싱과 검증을 담당해요. 백엔드 전용 도움말은 이렇게 확인하세요.
sglang serve --model-type my_runtime --help
config-only 런타임 지원하기
SGLang은 기본적으로 모델 경로를 요구해요. 내 런타임이 모델과 병렬화 설정을 구성 파일에서 해석한다면, 그 검증을 끄면 돼요.
def create_backend() -> ServeBackend:
return ServeBackend(
api_version=1,
run=run,
detect=detect,
requires_model_path=False,
)
그러면 이런 명령도 받아들일 수 있어요.
sglang serve --model-type my_runtime --config pipeline.yaml
config-only 요청은 일반적으로 명시적 --model-type이 필요해요. 감지기가 남은 인자에서 백엔드를 식별할 수 있는 경우는 예외예요.
자동 라우팅 이해하기
기본 --model-type auto는 다음 규칙을 따라요.
- 감지기가 없는 백엔드는 명시적 선택 전용이에요.
MATCH가 하나면 그 백엔드를 선택해요.- 매치가 여러 개면 실패하고 명시적
--model-type이 필요해요. UNKNOWN과 감지기 실패는 요청을 차지하지 않아요.- 매치가 없으면 기존 LLM 폴백을 유지해요.
레지스트리는 패키지 설치 순서나 숨은 우선순위로 겹침을 해결하지 않아요. 감지기를 생략하면 백엔드가 자동 라우팅을 거부할 수 있어요.
ServeBackend(api_version=1, run=run, requires_model_path=False)
호환성 유지하기
확장 프로그램이 구현한 API 버전을 리터럴로 선언하세요. 런타임에 SGLang의 현재 버전 상수를 복사하지 마세요. 고정 값이 있어야 미래의 SGLang 릴리스가 이전 플러그인 계약을 감지할 수 있어요. SGLang은 호환되지 않거나, 중복되거나, 예약된 백엔드 등록을 행동 가능한 오류로 거부해요.
공개 확장 계약은 이렇게 구성돼요.
ServeRequest: 정규화된 백엔드 인자와 선택적 모델 경로ServeBackend: 러너, 선택적 감지기, 모델 경로 요구 여부ServeBackendDetection:MATCH,NO_MATCH,UNKNOWN
핵심 sglang 패키지와 함께 명시적 선택, 백엔드 전용 도움말, 자동 감지, 모호한 모델, 설치·제거를 테스트하세요.