[SGLang] 멀티 백엔드: OpenAI, Anthropic, VertexAI, LiteLLM 통합
들어가며
LLM 기반 애플리케이션을 만들 때 가장 먼저 부딪히는 문제는 프로바이더마다 API가 다르다는 것이다. OpenAI는 chat.completions.create, Anthropic은 messages.create, Google은 generate_content를 사용한다. SGLang은 이 차이를 BaseBackend 추상 클래스 하나로 통일한다. 프론트엔드 DSL 코드는 어떤 백엔드를 쓰든 동일하게 작성할 수 있다.
이 글에서는 python/sglang/lang/backend/ 디렉토리의 6개 파일을 분석하며, 각 백엔드가 어떻게 공통 인터페이스를 구현하는지 살펴본다.
백엔드 추상화 구조도
┌─────────────────────────────────────────────────────┐
│ SGLang Frontend │
│ (StreamExecutor / DSL Program) │
└──────────────────────┬──────────────────────────────┘
│ generate() / select() / generate_stream()
▼
┌─────────────────┐
│ BaseBackend │ ← 추상 인터페이스
└────────┬────────┘
┌──────┬───────┼───────┬──────────┐
▼ ▼ ▼ ▼ ▼
┌──────┐┌──────┐┌───────┐┌───────┐┌──────────────┐
│OpenAI││Anthro││Vertex ││LiteLLM││RuntimeEndpnt │
│ .py ││pic.py││AI.py ││ .py ││ .py │
└──┬───┘└──┬───┘└──┬────┘└──┬────┘└──────┬───────┘
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
OpenAI Anthropic Google 100+개 SGLang SRT
API API API 프로바이더 로컬 서버
모든 백엔드는 BaseBackend를 상속하고, 프론트엔드의 StreamExecutor는 백엔드 종류를 알 필요 없이 동일한 메서드를 호출한다.
핵심 코드 분석
BaseBackend: 공통 인터페이스
python/sglang/lang/backend/base_backend.py에 정의된 추상 클래스는 모든 백엔드가 구현해야 할 계약을 정의한다.
class BaseBackend:
def __init__(self) -> None:
self.support_concate_and_append = False
self.chat_template = get_chat_template("default")
def get_model_name(self):
raise NotImplementedError()
def generate(
self,
s: StreamExecutor,
sampling_params: SglSamplingParams,
):
raise NotImplementedError()
def generate_stream(
self,
s: StreamExecutor,
sampling_params: SglSamplingParams,
):
raise NotImplementedError()
def select(
self,
s: StreamExecutor,
choices: List[str],
temperature: float,
choices_method: Optional[ChoicesSamplingMethod] = None,
) -> ChoicesDecision:
raise NotImplementedError()
핵심 메서드 3개(generate, generate_stream, select)는 NotImplementedError를 발생시켜 하위 클래스에서 반드시 구현하도록 강제한다. 그 외 cache_prefix, fork_program, fill_image 등은 기본적으로 no-op이며, 지원하는 백엔드만 오버라이드한다.
support_concate_and_append 플래그는 KV cache 수준의 연산 지원 여부를 나타내며, RuntimeEndpoint만 True로 설정한다.
OpenAI 백엔드: Chat/Completion 이중 모드
python/sglang/lang/backend/openai.py의 OpenAI 클래스는 Chat 모델과 Instruct 모델을 모두 지원한다.
class OpenAI(BaseBackend):
def __init__(
self,
model_name: str,
is_chat_model: Optional[bool] = None,
chat_template: Optional[ChatTemplate] = None,
is_azure: bool = False,
*args, **kwargs,
):
super().__init__()
if is_azure:
self.client = openai.AzureOpenAI(*args, **kwargs)
else:
self.client = openai.OpenAI(*args, **kwargs)
self.model_name = model_name
self.tokenizer = tiktoken.encoding_for_model(model_name)
self.logit_bias_int = create_logit_bias_int(self.tokenizer)
Azure OpenAI도 is_azure=True 한 줄로 전환할 수 있다. tiktoken을 사용해 tokenizer를 초기화하고, 정수 제약 생성(dtype=int) 시 사용할 logit bias를 미리 계산한다.
OpenAI 백엔드의 독특한 기능은 API speculative execution이다. 여러 sgl.gen 호출을 하나의 API 요청으로 묶어 보내고, 응답을 패턴 매칭으로 분리한다.
def spec_pattern_match(self, comp):
for i, term in enumerate(self.spec_format):
text = term["text"]
if text != "":
if comp.startswith(text):
comp = comp[len(text):]
else:
return False
else:
pos = comp.find(term["stop"])
if pos != -1:
term["text"] = comp[:pos]
comp = comp[pos:]
else:
if i == len(self.spec_format) - 1:
term["text"] = comp
else:
return False
return True
이 메서드는 speculative execution의 결과를 stop token 기준으로 각 변수에 분배한다. 매칭 실패 시 최대 spec_max_num_tries(기본 3회)까지 재시도한다.
Anthropic 백엔드: system 메시지 분리
python/sglang/lang/backend/anthropic.py의 구현은 가장 간결하다. Anthropic API가 system prompt를 별도 파라미터로 받기 때문에 메시지 전처리가 필요하다.
class Anthropic(BaseBackend):
def __init__(self, model_name, *args, **kwargs):
super().__init__()
self.model_name = model_name
self.chat_template = get_chat_template("claude")
self.client = anthropic.Anthropic(*args, **kwargs)
def generate(self, s: StreamExecutor, sampling_params: SglSamplingParams):
if s.messages_:
messages = s.messages_
else:
messages = [{"role": "user", "content": s.text_}]
if messages and messages[0]["role"] == "system":
system = messages.pop(0)["content"]
else:
system = ""
ret = self.client.messages.create(
model=self.model_name,
system=system,
messages=messages,
**sampling_params.to_anthropic_kwargs(),
)
comp = ret.content[0].text
return comp, {}
첫 번째 메시지가 system role이면 이를 추출하여 별도 system 파라미터로 전달한다. select 메서드는 구현하지 않아, Anthropic 백엔드에서는 sgl.select(choice selection)를 사용할 수 없다.
RuntimeEndpoint: SGLang 네이티브 서버 연결
python/sglang/lang/backend/runtime_endpoint.py는 SGLang 자체 서빙 엔진(SRT)과 HTTP로 통신하는 백엔드다. 다른 백엔드와 달리 KV cache 조작, logprob 반환, 정규식 제약 생성 등 풀 기능을 지원한다.
class RuntimeEndpoint(BaseBackend):
def __init__(
self,
base_url: str,
api_key: Optional[str] = None,
verify: Optional[str] = None,
chat_template_name: Optional[str] = None,
):
super().__init__()
self.support_concate_and_append = True
self.base_url = base_url
res = http_request(self.base_url + "/get_model_info",
api_key=self.api_key, verify=self.verify)
self._assert_success(res)
self.model_info = res.json()
초기화 시 서버의 /get_model_info 엔드포인트를 호출하여 모델 정보를 가져오고, 모델 경로 기반으로 chat template을 자동 매칭한다.
select 구현에서는 logprob 기반 선택을 지원한다.
def select(self, s, choices, temperature, choices_method):
assert temperature <= 1e-5
# 1. 공통 prefix 캐싱
data = {"text": s.text_, "sampling_params": {"max_new_tokens": 0}}
obj = self._generate_http_request(s, data)
prompt_len = obj["meta_info"]["prompt_tokens"]
# 2. 각 choice의 logprob 계산
data = {
"text": [s.text_ + c for c in choices],
"sampling_params": {"max_new_tokens": 0, "temperature": 0},
"return_logprob": True,
"logprob_start_len": max(prompt_len - 2, 0),
}
obj = self._generate_http_request(s, data)
normalized_prompt_logprobs = [
compute_normalized_prompt_logprobs(r["meta_info"]["input_token_logprobs"])
for r in obj
]
RuntimeEndpoint는 또한 Runtime 래퍼 클래스와 함께 사용된다. Runtime은 SGLang 서버를 별도 프로세스로 자동 실행하고, health check를 거쳐 RuntimeEndpoint를 생성한다.
class Runtime:
def __init__(self, log_level="error", launch_timeout=300.0, *args, **kwargs):
from sglang.srt.entrypoints.http_server import launch_server
from sglang.srt.server_args import ServerArgs
self.server_args = ServerArgs(*args, log_level=log_level, **kwargs)
# ...
proc = ctx.Process(target=launch_server, args=(self.server_args,))
proc.start()
self.pid = proc.pid
atexit.register(self.shutdown)
atexit.register(self.shutdown)으로 프로그램 종료 시 서버 프로세스를 자동 정리한다.
LiteLLM 백엔드: 100개 이상 프로바이더 통합
python/sglang/lang/backend/litellm.py의 LiteLLM 클래스는 LiteLLM 라이브러리를 래핑하여 100개 이상의 LLM 프로바이더를 SGLang에서 사용할 수 있게 한다.
class LiteLLM(BaseBackend):
def __init__(self, model_name, chat_template=None, api_key=None,
organization=None, base_url=None, timeout=600,
max_retries=litellm.num_retries, default_headers=None):
super().__init__()
self.model_name = model_name
self.chat_template = chat_template or get_chat_template_by_model_path(model_name)
self.client_params = {
"api_key": api_key, "organization": organization,
"base_url": base_url, "timeout": timeout,
"max_retries": max_retries, "default_headers": default_headers,
}
generate와 generate_stream만 구현하며, select는 지원하지 않는다. litellm.completion에 client_params를 통째로 전달하는 단순한 구조다.
백엔드 간 기능 비교 테이블
| 기능 | OpenAI | Anthropic | VertexAI | LiteLLM | RuntimeEndpoint |
|---|---|---|---|---|---|
generate |
O | O | O | O | O |
generate_stream |
O | O | O | O | O |
select (choice) |
O (Instruct만) | X | X | X | O |
| Chat Template | 자동 매칭 | claude 고정 |
default 고정 |
자동 매칭 | 자동 매칭 |
| 이미지 입력 | X | X | O | X | O |
| dtype 제약 생성 | O (int, str) |
X | X | X | O (int, float, str, bool) |
| Speculative Exec | O | X | X | X | X |
| KV Cache 조작 | X | X | X | X | O |
| Azure 지원 | O (is_azure) |
X | X | X | X |
| Token Usage 추적 | O | X | X | X | X |
| Logprob 반환 | X | X | X | X | O |
| 에러 재시도 | O (3회) | X | X | O (설정 가능) | X |
RuntimeEndpoint가 가장 많은 기능을 지원하고, 외부 API 백엔드들은 각 프로바이더의 API 제약에 따라 기능이 제한된다.
관련 포스트
- SGLang Chat Template 관리: Jinja 템플릿과 모델별 대화 포맷 (본 시리즈 다음 글)
참고
관련 포스트
- [sglang] DeepSeek-V4의 Latency 최적화: Fused mHC Post/Pre Kernel 도입
- [sglang] sglang ROCm MXFP4 어텐션에서 불필요한 contiguous copy 제거를 통한 성능 최적화
- [sglang] sglang의 torch.compile 활용: Advanced Indexing Gather 최적화로 LLM 추론 가속화
- [sglang] sglang diffusion 모델 성능 향상: Cache-DiT와 torch.compile의 최적화된 적용 순서
- [sglang] NixlKVManager 성능 향상: 비동기 및 멀티스레드 KV 전송 도입
SGLang 의 다른글
- 이전글 [SGLang] Interpreter: SGL 프로그램 실행 엔진의 설계와 구현
- 현재글 : [SGLang] 멀티 백엔드: OpenAI, Anthropic, VertexAI, LiteLLM 통합
- 다음글 [SGLang] Chat Template 관리: Jinja 템플릿과 모델별 대화 포맷
댓글