Qwen3 퀵스타트

Qwen3 퀵스타트

이 가이드는 Qwen3를 빠르게 시작하는 방법을 알려드려요. Hugging Face Transformers와 ModelScope의 예시는 물론, 배포용 vLLM과 SGLang 예시도 함께 제공해요.

출처: 문서

본문

Qwen3 모델은 Hugging Face Hub의 Qwen3 컬렉션과 ModelScope의 Qwen3 컬렉션에서 찾을 수 있어요.

Transformers

Qwen3를 빠르게 시작하려면 먼저 transformers로 추론을 시도할 수 있어요. transformers>=4.51.0이 설치되어 있는지 확인하세요. Python 3.10 이상과 PyTorch 2.6 이상을 권장해요.

Qwen3-Instruct-2507

⚠️ 중요: Qwen3-Instruct-2507은 non-thinking 모드만 지원하며 출력에 thinking response 블록을 생성하지 않아요. Qwen3-2504와 달리 enable_thinking=False를 지정할 필요도, 지원되지도 않아요.

다음 코드는 Qwen3-235B-A22B-Instruct-2507을 사용해 주어진 입력을 바탕으로 콘텐츠를 생성하는 방법을 보여줘요.

from transformers import AutoModelForCausalLM, AutoTokenizer

model_name = "Qwen/Qwen3-235B-A22B-Instruct-2507"

# load the tokenizer and the model
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    torch_dtype="auto",
    device_map="auto"
)

# prepare the model input
prompt = "Give me a short introduction to large language model."
messages = [
    {"role": "user", "content": prompt}
]
text = tokenizer.apply_chat_template(
    messages,
    tokenize=False,
    add_generation_prompt=True,
)
model_inputs = tokenizer([text], return_tensors="pt").to(model.device)

# conduct text completion
generated_ids = model.generate(
    **model_inputs,
    max_new_tokens=16384
)
output_ids = generated_ids[0][len(model_inputs.input_ids[0]):].tolist()

content = tokenizer.decode(output_ids, skip_special_tokens=True)

print("content:", content)

📝 참고: Qwen3-Instruct-2507 모델에는 temperature=0.7, top_p=0.8, top_k=20, min_p=0을 권장해요. 지원되는 프레임워크에서는 반복을 줄이기 위해 presence_penalty를 0과 2 사이로 조정하세요. 다만 더 높은 값을 사용하면 때때로 언어 혼합과 약간의 성능 저하가 생길 수 있어요.

📝 참고: Qwen3-Instruct-2507은 복잡한 작업에서 CoT(chain-of-thoughts)를 자동으로 사용할 수 있어요. 대부분의 쿼리에는 16,384 토큰의 출력 길이를 권장해요.

Qwen3-Thinking-2507

⚠️ 중요: Qwen3-Thinking-2507은 thinking 모드만 지원해요. 또한 모델의 thinking을 강제하기 위해 기본 채팅 템플릿이 자동으로 thinking을 포함해요. 따라서 모델 출력에 명시적인 시작 thinking 태그 없이 response만 포함되는 것이 정상이에요.

다음 코드는 Qwen3-235B-A22B-Thinking-2507을 사용해 콘텐츠를 생성하는 방법을 보여줘요.

from transformers import AutoModelForCausalLM, AutoTokenizer

model_name = "Qwen/Qwen3-235B-A22B-Thinking-2507"

# load the tokenizer and the model
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    torch_dtype="auto",
    device_map="auto"
)

# prepare the model input
prompt = "Give me a short introduction to large language model."
messages = [
    {"role": "user", "content": prompt}
]
text = tokenizer.apply_chat_template(
    messages,
    tokenize=False,
    add_generation_prompt=True,
)
model_inputs = tokenizer([text], return_tensors="pt").to(model.device)

# conduct text completion
generated_ids = model.generate(
    **model_inputs,
    max_new_tokens=32768
)
output_ids = generated_ids[0][len(model_inputs.input_ids[0]):].tolist()

# parsing thinking content
try:
    # rindex finding 151668 ( response)
    index = len(output_ids) - output_ids[::-1].index(151668)
except ValueError:
    index = 0

thinking_content = tokenizer.decode(output_ids[:index], skip_special_tokens=True).strip("\n")
content = tokenizer.decode(output_ids[index:], skip_special_tokens=True).strip("\n")

print("thinking content:", thinking_content)  # no opening  thinking tag
print("content:", content)

📝 참고: Qwen3-Thinking-2507 모델에는 temperature=0.6, top_p=0.95, top_k=20, min_p=0을 권장해요. 지원되는 프레임워크에서는 반복을 줄이기 위해 presence_penalty를 0과 2 사이로 조정하세요. 다만 더 높은 값을 사용하면 때때로 언어 혼합과 약간의 성능 저하가 생길 수 있어요.

📝 참고: Qwen3-Thinking-2507은 더 깊은 thinking 능력을 갖추고 있어요. 충분한 최대 생성 길이와 함께 매우 복잡한 추론 작업에 사용하는 것을 강력히 권장해요.

Qwen3

다음은 Qwen3-8B를 실행하는 아주 간단한 코드예요.

from transformers import AutoModelForCausalLM, AutoTokenizer

model_name = "Qwen/Qwen3-8B"

# load the tokenizer and the model
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    torch_dtype="auto",
    device_map="auto"
)
tokenizer = AutoTokenizer.from_pretrained(model_name)

# prepare the model input
prompt = "Give me a short introduction to large language models."
messages = [
    {"role": "user", "content": prompt},
]
text = tokenizer.apply_chat_template(
    messages,
    tokenize=False,
    add_generation_prompt=True,
    enable_thinking=True, # Switches between thinking and non-thinking modes. Default is True.
)
model_inputs = tokenizer([text], return_tensors="pt").to(model.device)

# conduct text completion
generated_ids = model.generate(
    **model_inputs,
    max_new_tokens=32768
)
output_ids = generated_ids[0][len(model_inputs.input_ids[0]):].tolist()

# parse thinking content
try:
    # rindex finding 151668 ( response)
    index = len(output_ids) - output_ids[::-1].index(151668)
except ValueError:
    index = 0

thinking_content = tokenizer.decode(output_ids[:index], skip_special_tokens=True).strip("\n")
content = tokenizer.decode(output_ids[index:], skip_special_tokens=True).strip("\n")

print("thinking content:", thinking_content)
print("content:", content)

Qwen3는 QwQ 모델처럼 응답하기 전에 먼저 생각해요. 즉 모델이 추론 능력을 사용해 생성된 응답의 품질을 높인다는 뜻이에요. 모델은 먼저 thinking... response 블록에 감싸인 thinking 콘텐츠를 생성한 다음 최종 응답을 생성해요.

하드 스위치(Hard Switch): 모델의 thinking 동작을 엄격히 꺼서 이전 Qwen2.5-Instruct 모델과 기능을 일치시키려면, 텍스트를 포맷할 때 enable_thinking=False를 설정하면 돼요.

text = tokenizer.apply_chat_template(
    messages,
    tokenize=False,
    add_generation_prompt=True,
    enable_thinking=False,  # Setting enable_thinking=False disables thinking mode
)

이는 효율성을 높이기 위해 thinking을 끄는 것이 중요한 시나리오에서 특히 유용해요.

소프트 스위치(Soft Switch): Qwen3는 사용자의 thinking 행동 지시도 이해해요. 특히 소프트 스위치 /think와 /no_think를 사용할 수 있어요. 이를 사용자 프롬프트나 시스템 메시지에 추가하면 턴마다 모델의 thinking 모드를 전환할 수 있어요. 모델은 다중 턴 대화에서 가장 최근의 지시를 따를 거예요.

📝 참고: thinking 모드에서는 Temperature=0.6, TopP=0.95, TopK=20, MinP=0(generation_config.json의 기본값)을 사용하세요. 성능 저하와 끝없는 반복으로 이어질 수 있으므로 greedy 디코딩을 사용하지 마세요. non-thinking 모드에서는 Temperature=0.7, TopP=0.8, TopK=20, MinP=0을 권장해요.

ModelScope

다운로드 문제가 있다면 ModelScope를 시도해 보세요. 시작 전에 pip으로 modelscope를 설치해야 해요.

modelscope는 transformers와 유사하지만 동일하지는 않은 프로그램형 인터페이스를 채택해요. 기본 사용법에서는 위 코드의 첫 줄만 다음으로 바꾸면 돼요:

from modelscope import AutoModelForCausalLM, AutoTokenizer

자세한 내용은 modelscope 문서를 참고하세요.

OpenAI API 호환성

vLLM, SGLang 같은 프레임워크로 OpenAI 호환 API를 통해 Qwen3를 서빙하고, 일반 HTTP 클라이언트나 OpenAI SDK로 API와 상호작용할 수 있어요.

Qwen3-Instruct-2507

여기서는 Qwen3-235B-A22B-Instruct-2507을 예시로 API를 시작할게요:

SGLang(sglang>=0.4.6.post1 필요):

python -m sglang.launch_server --model-path Qwen/Qwen3-235B-A22B-Instruct-2507 --port 8000 --tp 8 --context-length 262144

vLLM(vllm>=0.9.0 권장):

vllm serve Qwen/Qwen3-235B-A22B-Instruct-2507 --port 8000 --tensor-parallel-size 8 --max-model-len 262144

📝 참고: 사용 가능한 GPU 메모리에 따라 컨텍스트 길이를 조정하는 것을 고려하세요.

Qwen3-Thinking-2507

여기서는 Qwen3-235B-A22B-Thinking-2507을 예시로 API를 시작할게요:

SGLang(sglang>=0.4.6.post1 필요):

python -m sglang.launch_server --model-path Qwen/Qwen3-235B-A22B-Thinking-2507 --port 8000 --tp 8 --context-length 262144  --reasoning-parser deepseek-r1

vLLM(vllm>=0.9.0 권장):

vllm serve Qwen/Qwen3-235B-A22B-Thinking-2507 --port 8000 --tensor-parallel-size 8 --max-model-len 262144 --enable-reasoning --reasoning-parser deepseek_r1

📝 참고: 사용 가능한 GPU 메모리에 따라 컨텍스트 길이를 조정하는 것을 고려하세요.

⚠️ 중요: 현재 qwen3 reasoning 파서를 새 동작에 맞게 적응시키는 작업을 진행 중이에요. 지금은 위 명령을 따라주세요.

Qwen3

여기서는 Qwen3-8B를 예시로 API를 시작할게요:

SGLang(sglang>=0.4.6.post1 필요):

python -m sglang.launch_server --model-path Qwen/Qwen3-8B --port 8000 --reasoning-parser qwen3

vLLM(vllm>=0.9.0 권장):

vllm serve Qwen/Qwen3-8B --port 8000 --enable-reasoning --reasoning-parser qwen3

그 다음 create chat 인터페이스로 Qwen과 통신할 수 있어요.

Qwen3-Instruct-2507 (채팅)

Qwen3-235B-A22B-Instruct-2507로 채팅 완성 API와 상호작용하는 기본 명령을 보여드려요.

curl:

curl http://localhost:8000/v1/chat/completions -H "Content-Type: application/json" -d '{
  "model": "Qwen/Qwen3-235B-A22B-Instruct-2507",
  "messages": [
    {"role": "user", "content": "Give me a short introduction to large language models."}
  ],
  "temperature": 0.7,
  "top_p": 0.8,
  "top_k": 20,
  "max_tokens": 16384
}'

Python:

from openai import OpenAI
# Set OpenAI's API key and API base to use vLLM's API server.
openai_api_key = "EMPTY"
openai_api_base = "http://localhost:8000/v1"

client = OpenAI(
    api_key=openai_api_key,
    base_url=openai_api_base,
)

chat_response = client.chat.completions.create(
    model="Qwen/Qwen3-235B-A22B-Instruct-2507",
    messages=[
        {"role": "user", "content": "Give me a short introduction to large language models."},
    ],
    max_tokens=16384,
    temperature=0.7,
    top_p=0.8,
    extra_body={
        "top_k": 20,
    }
)
print("Chat response:", chat_response)

Qwen3-Thinking-2507 (채팅)

Qwen3-235B-A22B-Thinking-2507로 채팅 완성 API와 상호작용하는 기본 명령을 보여드려요.

curl:

curl http://localhost:8000/v1/chat/completions -H "Content-Type: application/json" -d '{
  "model": "Qwen/Qwen3-235B-A22B-Thinking-2507",
  "messages": [
    {"role": "user", "content": "Give me a short introduction to large language models."}
  ],
  "temperature": 0.6,
  "top_p": 0.95,
  "top_k": 20,
  "max_tokens": 32768
}'

Python:

from openai import OpenAI
# Set OpenAI's API key and API base to use vLLM's API server.
openai_api_key = "EMPTY"
openai_api_base = "http://localhost:8000/v1"

client = OpenAI(
    api_key=openai_api_key,
    base_url=openai_api_base,
)

chat_response = client.chat.completions.create(
    model="Qwen/Qwen3-235B-A22B-Thinking-2507",
    messages=[
        {"role": "user", "content": "Give me a short introduction to large language models."},
    ],
    max_tokens=32768,
    temperature=0.6,
    top_p=0.95,
    extra_body={
        "top_k": 20,
    }
)
print("Chat response:", chat_response)

Qwen3 (채팅)

Qwen3-8B로 채팅 완성 API와 상호작용하는 기본 명령을 보여드려요. 기본값은 thinking이 활성화된 상태예요.

curl:

curl http://localhost:8000/v1/chat/completions -H "Content-Type: application/json" -d '{
  "model": "Qwen/Qwen3-8B",
  "messages": [
    {"role": "user", "content": "Give me a short introduction to large language models."}
  ],
  "temperature": 0.6,
  "top_p": 0.95,
  "top_k": 20,
  "max_tokens": 32768
}'

Python:

from openai import OpenAI
# Set OpenAI's API key and API base to use vLLM's API server.
openai_api_key = "EMPTY"
openai_api_base = "http://localhost:8000/v1"

client = OpenAI(
    api_key=openai_api_key,
    base_url=openai_api_base,
)

chat_response = client.chat.completions.create(
    model="Qwen/Qwen3-8B",
    messages=[
        {"role": "user", "content": "Give me a short introduction to large language models."},
    ],
    max_tokens=32768,
    temperature=0.6,
    top_p=0.95,
    extra_body={
        "top_k": 20,
    }
)
print("Chat response:", chat_response)

thinking을 끄려면 소프트 스위치(예: 사용자 쿼리에 /nothink 추가)를 사용할 수 있고, 하드 스위치도 아래처럼 사용할 수 있어요.

curl:

curl http://localhost:8000/v1/chat/completions -H "Content-Type: application/json" -d '{
  "model": "Qwen/Qwen3-8B",
  "messages": [
    {"role": "user", "content": "Give me a short introduction to large language models."}
  ],
  "temperature": 0.7,
  "top_p": 0.8,
  "top_k": 20,
  "max_tokens": 8192,
  "presence_penalty": 1.5,
  "chat_template_kwargs": {"enable_thinking": false}
}'

Python:

from openai import OpenAI
# Set OpenAI's API key and API base to use vLLM's API server.
openai_api_key = "EMPTY"
openai_api_base = "http://localhost:8000/v1"

client = OpenAI(
    api_key=openai_api_key,
    base_url=openai_api_base,
)

chat_response = client.chat.completions.create(
    model="Qwen/Qwen3-8B",
    messages=[
        {"role": "user", "content": "Give me a short introduction to large language models."},
    ],
    max_tokens=8192,
    temperature=0.7,
    top_p=0.8,
    presence_penalty=1.5,
    extra_body={
        "top_k": 20,
        "chat_template_kwargs": {"enable_thinking": False},
    }
)
print("Chat response:", chat_response)

더 많은 사용법은 SGLang과 vLLM 문서를 참고하세요.

Thinking 예산 (Thinking Budget)

Qwen3는 thinking budget 설정을 지원해요. 예산에 도달하면 thinking 과정을 끝내고 early-stopping 프롬프트로 모델이 "요약"을 생성하도록 유도해요.

이 기능은 각 모델별 커스터마이징이 필요하기 때문에 현재 오픈소스 프레임워크에서는 사용할 수 없고 Alibaba Cloud Model Studio API에서만 구현되어 있어요.

하지만 기존 오픈소스 프레임워크로 두 번 생성해 이 기능을 구현할 수 있어요:

  • 첫 번째: thinking budget까지 토큰을 생성하고 thinking 과정이 끝났는지 확인해요. 끝나지 않았다면 early-stopping 프롬프트를 추가해요.
  • 두 번째: 콘텐츠의 끝이나 상한 길이에 도달할 때까지 생성을 계속해요.

다음 코드는 Hugging Face Transformers로 구현한 예시예요.

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

model_name = "Qwen/Qwen3-8B"

thinking_budget = 16
max_new_tokens = 32768

# load the tokenizer and the model
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    torch_dtype="auto",
    device_map="auto"
)
tokenizer = AutoTokenizer.from_pretrained(model_name)

# prepare the model input
prompt = "Give me a short introduction to large language models."
messages = [
    {"role": "user", "content": prompt},
]
text = tokenizer.apply_chat_template(
    messages,
    tokenize=False,
    add_generation_prompt=True,
    enable_thinking=True, # Switches between thinking and non-thinking modes. Default is True.
)
model_inputs = tokenizer([text], return_tensors="pt").to(model.device)
input_length = model_inputs.input_ids.size(-1)

# first generation until thinking budget
generated_ids = model.generate(
    **model_inputs,
    max_new_tokens=thinking_budget
)
output_ids = generated_ids[0][input_length:].tolist()

# check if the generation has already finished (151645 is <|im_end|>)
if 151645 not in output_ids:
    # check if the thinking process has finished (151668 is  response)
    # and prepare the second model input
    if 151668 not in output_ids:
        print("thinking budget is reached")
        early_stopping_text = "\n\nConsidering the limited time by the user, I have to give the solution based on the thinking directly now.\n response\n\n"
        early_stopping_ids = tokenizer([early_stopping_text], return_tensors="pt", return_attention_mask=False).input_ids.to(model.device)
        input_ids = torch.cat([generated_ids, early_stopping_ids], dim=-1)
    else:
        input_ids = generated_ids
    attention_mask = torch.ones_like(input_ids, dtype=torch.int64)

    # second generation
    generated_ids = model.generate(
        input_ids=input_ids,
        attention_mask=attention_mask,
        max_new_tokens=input_length + max_new_tokens - input_ids.size(-1)  # could be negative if max_new_tokens is not large enough (early stopping text is 24 tokens)
    )
    output_ids = generated_ids[0][input_length:].tolist()

# parse thinking content
try:
    # rindex finding 151668 ( response)
    index = len(output_ids) - output_ids[::-1].index(151668)
except ValueError:
    index = 0

thinking_content = tokenizer.decode(output_ids[:index], skip_special_tokens=True).strip("\n")
content = tokenizer.decode(output_ids[index:], skip_special_tokens=True).strip("\n")

print("thinking content:", thinking_content)
print("content:", content)

콘솔에서 다음과 같은 출력을 볼 수 있을 거예요.

thinking budget is reached
thinking content:  thinking
Okay, the user is asking for a short introduction to large language models

Considering the limited time by the user, I have to give the solution based on the thinking directly now.
 response
content: Large language models (LLMs) are advanced artificial intelligence systems trained on vast amounts of text data to understand and generate human-like language. They can perform tasks such as answering questions, writing stories, coding, and translating languages. LLMs are powered by deep learning techniques and have revolutionized natural language processing by enabling more context-aware and versatile interactions with text. Examples include models like GPT, BERT, and others developed by companies like OpenAI and Alibaba.

📝 참고: 데모 목적으로만 thinking_budget을 16으로 설정했어요. 하지만 실제로는 thinking_budget을 그렇게 낮게 설정하면 안 돼요. 사용자가 수용할 수 있는 지연 시간을 기준으로 thinking_budget을 조정하고, 작업 전반에 의미 있는 개선을 위해 1024보다 높게 설정하는 것을 권장해요. thinking이 전혀 필요 없다면 하드 스위치를 사용하는 것이 좋아요.

다음 단계

이제 Qwen3 모델로 즐겁게 놀 수 있어요. 더 많은 사용법을 알고 싶으신가요? 이 문서의 다른 문서들도 자유롭게 확인해 보세요.

더 알아보기 (Learn more)