Qwen3.6

Qwen3.6

Qwen3.6 시리즈는 Alibaba가 개발했어요. 커뮤니티 피드백을 바탕으로 안정성과 실용성을 우선시하며 에이전트 코딩과 thinking 보존에서 큰 개선을 제공해요. 두 가지 크기/희소성 변형이 출시됐어요: Gated Delta Networks 백본의 희소 MoE인 Qwen3.6-35B-A3B(총 35B, 활성 3B)와 단일 GPU 친화적 dense 하이브리드 GDN인 Qwen3.6-27B예요.

두 변형 모두 동일한 하이브리드 추론·툴 호출·멀티모달 인터페이스를 공유하며 최대 262,144 토큰 컨텍스트 길이를 네이티브로 처리하고 1M 토큰 이상으로 확장 가능해요. SGLang >=0.5.10이 필요하며 라이선스는 Apache 2.0이에요.

출처: 문서

본문

1. 모델 소개

Qwen3.6 시리즈는 Alibaba가 개발했어요. 커뮤니티의 직접 피드백을 바탕으로 Qwen3.6은 안정성과 실세계 유용성을 우선시하며, 에이전트 코딩과 thinking 보존에서 큰 업그레이드를 제공해요. 두 가지 크기/희소성 변형이 출시됐어요:

  • Qwen3.6-35B-A3B희소 MoE (총 35B, 활성 3B) 기반의 Gated Delta Networks 백본.
  • Qwen3.6-27BDense 하이브리드 GDN; 더 작은 가중치 풋프린트, 단일 GPU 친화적.

두 변형 모두 동일한 하이브리드 추론, 툴 호출, 멀티모달 인터페이스를 공유하며 최대 262,144 토큰의 컨텍스트 길이를 네이티브로 처리하고 1M 토큰 이상으로 확장 가능해요.

주요 특징:

  • 에이전트 코딩: 프론트엔드 워크플로와 저장소 수준 추론을 더 큰 유창함과 정확도로 처리
  • Thinking 보존: 과거 메시지의 추론 컨텍스트를 유지하는 새 옵션, 반복 개발 간소화
  • 효율적인 하이브리드 아키텍처: Gated Delta Networks 백본; 희소 MoE (35B / 3B 활성) 또는 dense 27B 변형
  • 하이브리드 추론: 기본적으로 단계별 추론과 함께 Thinking 모드 활성화, 직접 응답에는 비활성화 가능
  • 툴 호출: qwen3_coder 파서와 함께 내장 툴 호출 지원
  • Multi-Token Prediction (MTP): 낮은 지연 시간을 위한 추측 디코딩 지원; MoE와 Dense 변형 모두 mtp.safetensors 포함
  • 멀티모달: 텍스트, 이미지, 비디오 입력을 지원하는 통합 비전-언어 모델

사용 가능한 모델:

Model Architecture Weights
Qwen3.6-35B-A3B (BF16) MoE 35B / 3B active Qwen/Qwen3.6-35B-A3B
Qwen3.6-35B-A3B (FP8) MoE 35B / 3B active Qwen/Qwen3.6-35B-A3B-FP8
Qwen3.6-35B-A3B (NVFP4) MoE 35B / 3B active (Blackwell) nvidia/Qwen3.6-35B-A3B-NVFP4
Qwen3.6-27B (BF16) Dense 27B Qwen/Qwen3.6-27B
Qwen3.6-27B (FP8) Dense 27B Qwen/Qwen3.6-27B-FP8
Qwen3.6-27B (NVFP4) Dense 27B (Blackwell) nvidia/Qwen3.6-27B-NVFP4

라이선스: Apache 2.0

2. SGLang 설치

Qwen3.6에는 SGLang >=0.5.10이 필요해요. PyPI, 소스, 또는 Docker 이미지로 설치할 수 있어요:

# Install from PyPI
uv pip install --prerelease=allow sglang

# Or install from source
uv pip install --prerelease=allow 'git+https://github.com/sgl-project/sglang.git#subdirectory=python'

# Or use Docker (NVIDIA GPUs; also serves the NVFP4 variants)
docker pull lmsysorg/sglang:latest

전체 Docker 설정과 다른 설치 방법은 공식 SGLang 설치 가이드를 참고하세요.

SGLang CPU 설치는 CPU 버전 설치 가이드를 참고하세요.

3. 모델 배포

이 절은 하드웨어 플랫폼과 사용 사례에 최적화된 배포 구성을 제공해요.

3.1 기본 구성

인터랙티브 명령 생성기: 아래 구성 선택기를 사용해 하드웨어 플랫폼과 기능에 맞는 배포 명령을 자동 생성하세요.

3.2 구성 팁

  • 추측 디코딩(MTP)은 인터랙티브 사용 사례의 지연 시간을 크게 줄일 수 있어요.
  • Mamba Radix Cache: Qwen3.6의 하이브리드 Gated Delta Networks 아키텍처는 --mamba-radix-cache-strategy로 두 가지 mamba 스케줄링 전략을 지원해요:
    • V1 (no_buffer): 기본값. 오버랩 스케줄러 없음, 더 낮은 메모리 사용.
    • V2 (extra_buffer): --mamba-radix-cache-strategy extra_buffer --page-size 64로 오버랩 스케줄링과 분기점 캐싱을 활성화. FLA 커널 백엔드 필요(NVIDIA GPU 전용). 더 높은 처리량을 위해 더 높은 mamba 상태 메모리를 맞바꿔요.
  • --mem-fraction-static 플래그는 최적의 메모리 활용을 위해 권장되며, 하드웨어와 워크로드에 맞게 조정하세요.
  • 컨텍스트 길이는 기본적으로 262,144 토큰이에요. OOM 오류가 발생하면 줄이되, thinking 능력을 유지하려면 최소 128K를 유지하세요.
  • CUDA IPC Transport: SGLANG_USE_CUDA_IPC_TRANSPORT=1 환경 변수를 추가해 CUDA IPC로 멀티모달 특징을 전송하면 TTFT(Time To First Token)가 크게 개선돼요. 참고: 이미지 크기에 비례해 추가 메모리를 소비하므로 --mem-fraction-static 또는 --max-running-requests를 낮춰야 할 수 있어요.
  • 멀티모달 어텐션 백엔드: H100/H200에서는 --mm-attention-backend fa3, B200/B300에서는 --mm-attention-backend fa4를 사용해 더 나은 비전 성능을 얻으세요.
  • 큰 이미지나 비디오 처리 시 이미지 특징 텐서를 위한 공간을 남기려면 --mem-fraction-static을 낮춰야 할 수 있어요.
  • 하드웨어 요구사항:
    • 35B-A3B BF16: 가중치 ~70GB. TP=1은 모든 지원 하드웨어에 맞음.
    • 35B-A3B FP8: 가중치 ~35GB. TP=1은 모든 지원 하드웨어에 맞음.
    • 35B-A3B NVFP4: 가중치 ~23GB. TP=1은 B200/B300에 맞음.
    • 27B BF16: 가중치 ~54GB. TP=1은 모든 지원 하드웨어에 맞음.
    • 27B FP8: 가중치 ~27GB. TP=1은 모든 지원 하드웨어에 맞음.
    • 27B NVFP4: 가중치 ~22GB. TP=1은 B200/B300에 맞음.

모든 Qwen3.6 변형(MoE 35B-A3B와 Dense 27B)은 지원되는 단일 GPU에 맞아요. NVFP4는 B200/B300에서 사용 가능해요:

Hardware Memory BF16 TP FP8 TP NVFP4 TP
H100 80GB 1 1
H200 141GB 1 1
B200 183GB 1 1 1
B300 275GB 1 1 1
  • Xeon CPU 서비스 구성: SGLang CPU 서버 문서의 서빙 엔진 실행 절에 있는 Notes 부분을 참고해 인자(특히 TP(tensor parallel)와 NUMA 바인딩 설정)를 어떻게 구성하는지 이해하세요.

4. 모델 호출

다음 명령으로 Qwen3.6을 배포하세요(H200, 모든 기능 활성화). dense 27B 변형은 --model-pathQwen/Qwen3.6-27B-FP8로 바꾸면 되고 다른 플래그는 그대로 적용돼요:

sglang serve \
  --model-path Qwen/Qwen3.6-35B-A3B-FP8 \
  --reasoning-parser qwen3 \
  --tool-call-parser qwen3_coder \
  --speculative-algorithm EAGLE \
  --speculative-num-steps 3 \
  --speculative-eagle-topk 1 \
  --speculative-num-draft-tokens 4 \
  --mem-fraction-static 0.8 \
  --host 0.0.0.0 \
  --port 30000

4.1 기본 사용

기본 API 사용법과 요청 예제는 다음을 참고하세요:

4.2 비전 입력

Qwen3.6은 통합 비전-언어 모델로 이미지와 비디오 입력을 지원해요.

이미지 입력 예제:

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:30000/v1",
    api_key="EMPTY"
)

response = client.chat.completions.create(
    model="Qwen/Qwen3.6-35B-A3B-FP8",
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "image_url",
                    "image_url": {
                        "url": "https://qianwen-res.oss-accelerate.aliyuncs.com/Qwen3.5/demo/CI_Demo/mathv-1327.jpg"
                    }
                },
                {
                    "type": "text",
                    "text": "Describe this image in detail."
                }
            ]
        }
    ],
    max_tokens=2048,
    stream=True
)

thinking_started = False
has_thinking = False
has_answer = False

for chunk in response:
    if chunk.choices and len(chunk.choices) > 0:
        delta = chunk.choices[0].delta

        if hasattr(delta, 'reasoning_content') and delta.reasoning_content:
            if not thinking_started:
                print("=============== Thinking =================", flush=True)
                thinking_started = True
            has_thinking = True
            print(delta.reasoning_content, end="", flush=True)

        if delta.content:
            if has_thinking and not has_answer:
                print("\n=============== Content =================", flush=True)
                has_answer = True
            print(delta.content, end="", flush=True)

print()

비디오 입력 예제:

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:30000/v1",
    api_key="EMPTY"
)

response = client.chat.completions.create(
    model="Qwen/Qwen3.6-35B-A3B-FP8",
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "video_url",
                    "video_url": {
                        "url": "https://qianwen-res.oss-accelerate.aliyuncs.com/Qwen3.5/demo/video/N1cdUjctpG8.mp4"
                    }
                },
                {
                    "type": "text",
                    "text": "Describe what happens in this video."
                }
            ]
        }
    ],
    max_tokens=2048,
    stream=True
)

thinking_started = False
has_thinking = False
has_answer = False

for chunk in response:
    if chunk.choices and len(chunk.choices) > 0:
        delta = chunk.choices[0].delta

        if hasattr(delta, 'reasoning_content') and delta.reasoning_content:
            if not thinking_started:
                print("=============== Thinking =================", flush=True)
                thinking_started = True
            has_thinking = True
            print(delta.reasoning_content, end="", flush=True)

        if delta.content:
            if has_thinking and not has_answer:
                print("\n=============== Content =================", flush=True)
                has_answer = True
            print(delta.content, end="", flush=True)

print()

4.3 고급 사용

4.3.1 Reasoning Parser

Qwen3.6은 기본적으로 Thinking 모드를 지원해요. 배포 시 reasoning parser를 활성화해 thinking과 content 섹션을 분리하세요. thinking 프로세스는 스트리밍 응답에서 reasoning_content로 반환돼요.

thinking을 비활성화하고 Instruct 모드를 쓰려면 요청 시 chat_template_kwargs를 전달하세요:

  • Thinking mode (기본값): 모델이 답변 전에 단계별 추론을 수행. 추가 파라미터 불필요.
  • Instruct mode ({"enable_thinking": false}): thinking 프로세스 없이 직접 응답.

예제 1: Thinking Mode (기본값)

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:30000/v1",
    api_key="EMPTY"
)

response = client.chat.completions.create(
    model="Qwen/Qwen3.6-35B-A3B-FP8",
    messages=[
        {"role": "user", "content": "Solve this problem step by step: What is 15% of 240?"}
    ],
    max_tokens=2048,
    stream=True
)

has_thinking = False
has_answer = False
thinking_started = False

for chunk in response:
    if chunk.choices and len(chunk.choices) > 0:
        delta = chunk.choices[0].delta

        if hasattr(delta, 'reasoning_content') and delta.reasoning_content:
            if not thinking_started:
                print("=============== Thinking =================", flush=True)
                thinking_started = True
            has_thinking = True
            print(delta.reasoning_content, end="", flush=True)

        if delta.content:
            if has_thinking and not has_answer:
                print("\n=============== Content =================", flush=True)
                has_answer = True
            print(delta.content, end="", flush=True)

print()

예제 2: Instruct Mode (Thinking Off)

thinking을 비활성화하고 직접 응답을 얻으려면 chat_template_kwargs{"enable_thinking": false}를 전달하세요:

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:30000/v1",
    api_key="EMPTY"
)

response = client.chat.completions.create(
    model="Qwen/Qwen3.6-35B-A3B-FP8",
    messages=[
        {"role": "user", "content": "What is 15% of 240?"}
    ],
    extra_body={"chat_template_kwargs": {"enable_thinking": False}},
    max_tokens=2048,
    stream=True
)

for chunk in response:
    if chunk.choices and len(chunk.choices) > 0:
        delta = chunk.choices[0].delta
        if delta.content:
            print(delta.content, end="", flush=True)

print()

4.3.2 Thinking Preservation

Qwen3.6은 과거 메시지의 thinking 추적을 보존하고 활용하도록 훈련됐어요. 전체 추론 컨텍스트를 유지하는 것이 결정 일관성을 향상시키는 에이전트 시나리오에서 이 기능을 활성화하세요:

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:30000/v1",
    api_key="EMPTY"
)

response = client.chat.completions.create(
    model="Qwen/Qwen3.6-35B-A3B-FP8",
    messages=[
        {"role": "user", "content": "Help me plan a web app architecture."}
    ],
    extra_body={"chat_template_kwargs": {"preserve_thinking": True}},
    max_tokens=2048,
    stream=True
)

thinking_started = False
has_thinking = False
has_answer = False

for chunk in response:
    if chunk.choices and len(chunk.choices) > 0:
        delta = chunk.choices[0].delta

        if hasattr(delta, 'reasoning_content') and delta.reasoning_content:
            if not thinking_started:
                print("=============== Thinking =================", flush=True)
                thinking_started = True
            has_thinking = True
            print(delta.reasoning_content, end="", flush=True)

        if delta.content:
            if has_thinking and not has_answer:
                print("\n=============== Content =================", flush=True)
                has_answer = True
            print(delta.content, end="", flush=True)

print()

4.3.3 Tool Calling

Qwen3.6은 툴 호출 능력을 지원해요. 배포 시 툴 호출 파서를 활성화하세요.

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:30000/v1",
    api_key="EMPTY"
)

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Get the current weather for a location",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "The city name"
                    },
                    "unit": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"],
                        "description": "Temperature unit"
                    }
                },
                "required": ["location"]
            }
        }
    }
]

response = client.chat.completions.create(
    model="Qwen/Qwen3.6-35B-A3B-FP8",
    messages=[
        {"role": "user", "content": "What's the weather in Beijing?"}
    ],
    tools=tools,
    stream=True
)

thinking_started = False
has_thinking = False

for chunk in response:
    if chunk.choices and len(chunk.choices) > 0:
        delta = chunk.choices[0].delta

        if hasattr(delta, 'reasoning_content') and delta.reasoning_content:
            if not thinking_started:
                print("=============== Thinking =================", flush=True)
                thinking_started = True
            has_thinking = True
            print(delta.reasoning_content, end="", flush=True)

        if hasattr(delta, 'tool_calls') and delta.tool_calls:
            if has_thinking and thinking_started:
                print("\n=============== Content =================", flush=True)
                thinking_started = False

            for tool_call in delta.tool_calls:
                if tool_call.function:
                    print(f"Tool Call: {tool_call.function.name}")
                    print(f"   Arguments: {tool_call.function.arguments}")

        if delta.content:
            print(delta.content, end="", flush=True)

print()

더 알아보기 (Learn more)