SGLang 프론트엔드 언어

SGLang 프론트엔드 언어 (SGLang Frontend Language)

이 페이지는 SGLang의 프론트엔드 언어(Frontend Language) 사용법을 다뤄요. 이 언어를 사용하면 간단하고 쉬운 프롬프트를 편리하고 구조화된 방식으로 정의할 수 있어요. @function 데코레이터 안에서 Python 코드를 그대로 활용해 대화, 제어 흐름, 병렬 생성, 정규식 기반 제약 디코딩까지 자유롭게 구현할 수 있죠. 옆에서 설명해 주는 느낌으로 차근차근 따라가 보아요.

출처: 문서

본문

서버 실행 (Launch A Server)

터미널에서 서버를 실행하고 초기화가 끝날 때까지 기다려요.

from sglang import assistant_begin, assistant_end
from sglang import assistant, function, gen, system, user
from sglang import image
from sglang import RuntimeEndpoint
from sglang.lang.api import set_default_backend
from sglang.srt.utils import load_image
from sglang.test.doc_patch import launch_server_cmd
from sglang.utils import print_highlight, terminate_process, wait_for_server

server_process, port = launch_server_cmd(
    "python -m sglang.launch_server --model-path Qwen/Qwen2.5-7B-Instruct --host 0.0.0.0 --log-level warning"
)

wait_for_server(f"http://localhost:{port}", process=server_process)
print(f"Server started on http://localhost:{port}")

기본 백엔드(default backend)를 설정해요. 참고로 로컬 서버뿐 아니라 OpenAI나 다른 API 엔드포인트를 사용할 수도 있어요.

set_default_backend(RuntimeEndpoint(f"http://localhost:{port}"))

기본 사용법 (Basic Usage)

SGLang 프론트엔드 언어를 쓰는 가장 단순한 방법은 사용자와 어시스턴트 사이의 질문-답변 대화를 만드는 거예요.

@function
def basic_qa(s, question):
    s += system(f"You are a helpful assistant than can answer questions.")
    s += user(question)
    s += assistant(gen("answer", max_tokens=512))
state = basic_qa("List 3 countries and their capitals.")
print_highlight(state["answer"])

다중 턴 대화 (Multi-turn Dialog)

SGLang 프론트엔드 언어로 다중 턴(multi-turn) 대화도 정의할 수 있어요.

@function
def multi_turn_qa(s):
    s += system(f"You are a helpful assistant than can answer questions.")
    s += user("Please give me a list of 3 countries and their capitals.")
    s += assistant(gen("first_answer", max_tokens=512))
    s += user("Please give me another list of 3 countries and their capitals.")
    s += assistant(gen("second_answer", max_tokens=512))
    return s


state = multi_turn_qa()
print_highlight(state["first_answer"])
print_highlight(state["second_answer"])

제어 흐름 (Control flow)

함수 안에서 Python 코드를 자유롭게 써서 더 복잡한 제어 흐름을 정의할 수 있어요.

@function
def tool_use(s, question):
    s += assistant(
        "To answer this question: "
        + question
        + ". I need to use a "
        + gen("tool", choices=["calculator", "search engine"])
        + ". "
    )

    if s["tool"] == "calculator":
        s += assistant("The math expression is: " + gen("expression"))
    elif s["tool"] == "search engine":
        s += assistant("The key word to search is: " + gen("word"))


state = tool_use("What is 2 * 2?")
print_highlight(state["tool"])
print_highlight(state["expression"])

병렬 처리 (Parallelism)

fork를 사용해 병렬 프롬프트를 실행해요. sgl.gen은 비차단(non-blocking) 방식이라 아래 for 루프는 두 개의 생성 호출을 병렬로 수행해요.

@function
def tip_suggestion(s):
    s += assistant(
        "Here are two tips for staying healthy: "
        "1. Balanced Diet. 2. Regular Exercise.\n\n"
    )

    forks = s.fork(2)
    for i, f in enumerate(forks):
        f += assistant(
            f"Now, expand tip {i+1} into a paragraph:\n"
            + gen("detailed_tip", max_tokens=256, stop="\n\n")
        )

    s += assistant("Tip 1:" + forks[0]["detailed_tip"] + "\n")
    s += assistant("Tip 2:" + forks[1]["detailed_tip"] + "\n")
    s += assistant(
        "To summarize the above two tips, I can say:\n" + gen("summary", max_tokens=512)
    )


state = tip_suggestion()
print_highlight(state["summary"])

제약 디코딩 (Constrained Decoding)

regex를 사용해 정규식을 디코딩 제약 조건으로 지정할 수 있어요. 이 기능은 로컬 모델에서만 지원돼요.

@function
def regular_expression_gen(s):
    s += user("What is the IP address of the Google DNS servers?")
    s += assistant(
        gen(
            "answer",
            temperature=0,
            regex=r"((25[0-5]|2[0-4]\d|[01]?\d\d?).){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)",
        )
    )


state = regular_expression_gen()
print_highlight(state["answer"])

regexJSON 디코딩 스키마를 정의할 수도 있어요.

character_regex = (
    r"""\{\n"""
    + r"""    "name": "[\w\d\s]{1,16}",\n"""
    + r"""    "house": "(Gryffindor|Slytherin|Ravenclaw|Hufflepuff)",\n"""
    + r"""    "blood status": "(Pure-blood|Half-blood|Muggle-born)",\n"""
    + r"""    "occupation": "(student|teacher|auror|ministry of magic|death eater|order of the phoenix)",\n"""
    + r"""    "wand": \{\n"""
    + r"""        "wood": "[\w\d\s]{1,16}",\n"""
    + r"""        "core": "[\w\d\s]{1,16}",\n"""
    + r"""        "length": [0-9]{1,2}\.[0-9]{0,2}\n"""
    + r"""    \},\n"""
    + r"""    "alive": "(Alive|Deceased)",\n"""
    + r"""    "patronus": "[\w\d\s]{1,16}",\n"""
    + r"""    "bogart": "[\w\d\s]{1,16}"\n"""
    + r"""\}"""
)


@function
def character_gen(s, name):
    s += user(
        f"{name} is a character in Harry Potter. Please fill in the following information about this character."
    )
    s += assistant(gen("json_output", max_tokens=256, regex=character_regex))


state = character_gen("Harry Potter")
print_highlight(state["json_output"])

배칭 (Batching)

run_batch를 사용해 프롬프트 배치를 실행할 수 있어요.

@function
def text_qa(s, question):
    s += user(question)
    s += assistant(gen("answer", stop="\n"))


states = text_qa.run_batch(
    [
        {"question": "What is the capital of the United Kingdom?"},
        {"question": "What is the capital of France?"},
        {"question": "What is the capital of Japan?"},
    ],
    progress_bar=True,
)

for i, state in enumerate(states):
    print_highlight(f"Answer {i+1}: {states[i]['answer']}")

스트리밍 (Streaming)

stream을 사용하면 출력을 사용자에게 실시간으로 스트리밍할 수 있어요.

@function
def text_qa(s, question):
    s += user(question)
    s += assistant(gen("answer", stop="\n"))


state = text_qa.run(
    question="What is the capital of France?", temperature=0.1, stream=True
)

for out in state.text_iter():
    print(out, end="", flush=True)

복잡한 프롬프트 (Complex Prompts)

{system|user|assistant}_{begin|end}를 사용해 복잡한 프롬프트를 정의할 수 있어요.

@function
def chat_example(s):
    s += system("You are a helpful assistant.")
    # Same as: s += s.system("You are a helpful assistant.")

    with s.user():
        s += "Question: What is the capital of France?"

    s += assistant_begin()
    s += "Answer: " + gen("answer", max_tokens=100, stop="\n")
    s += assistant_end()


state = chat_example()
print_highlight(state["answer"])
terminate_process(server_process)

멀티모달 생성 (Multi-modal Generation)

SGLang 프론트엔드 언어로 멀티모달 프롬프트도 정의할 수 있어요. 지원되는 모델은 여기에서 확인할 수 있어요.

server_process, port = launch_server_cmd(
    "python -m sglang.launch_server --model-path Qwen/Qwen2.5-VL-7B-Instruct --host 0.0.0.0 --log-level warning"
)

wait_for_server(f"http://localhost:{port}", process=server_process)
print(f"Server started on http://localhost:{port}")
set_default_backend(RuntimeEndpoint(f"http://localhost:{port}"))

이미지에 대해 질문해 보아요.

@function
def image_qa(s, image_file, question):
    s += user(image(image_file) + question)
    s += assistant(gen("answer", max_tokens=256))


image_url = "https://raw.githubusercontent.com/sgl-project/sglang/main/examples/assets/example_image.png"
image_bytes, _ = load_image(image_url)
state = image_qa(image_bytes, "What is in the image?")
print_highlight(state["answer"])
terminate_process(server_process)

더 알아보기