Laguna-XS-2.1

Laguna-XS-2.1

Laguna-XS-2.1poolside가 만든 오픈 가중치 33B 파라미터 하이브리드 sliding-window-attention MoE 모델(토큰당 약 3B 활성화)로, 에이전틱 코딩과 장기 지평 소프트웨어 엔지니어링을 위해 만들어졌어요 — Laguna-M.1의 초소형 형제 모델이에요.

출처: 문서

본문

Deployment

Laguna-XS-2.1 지원은 SGLang `main`에 완전히 병합되었어요([PR #29446](https://github.com/sgl-project/sglang/pull/29446): DFlash 추측 디코딩 + 공유 전문가 수정; [PR #29761](https://github.com/sgl-project/sglang/pull/29761): INT4 로더 수정). 병합 시점 이상의 모든 빌드는 아래 모든 셀을 다룹니다.

모델은 Hub에 커스텀 config 코드를 실어 보내므로 --trust-remote-code가 필요해요(실행 명령에 포함).

```bash pip install -U uv uv venv --python 3.12 && source .venv/bin/activate
  git clone https://github.com/sgl-project/sglang.git
  cd sglang
  uv pip install --prerelease=allow -e python
  ```

  그런 다음 해당 환경에서 아래 명령 패널의 **Python** 출력을 실행하세요.
</Tab>

<Tab title="Docker">
  ```bash
  docker pull lmsysorg/sglang:latest
  ```

  이미지 실행 방법은 [Install → Method 3: Using Docker](../../../docs/get-started/install#method-3-using-docker)를 참고하세요. 안쪽의 `sglang serve ...`를 아래 명령 생성기가 만들어 내는 것으로 대체하세요.
</Tab>

하드웨어 + 양자화 + 전략을 선택해 실행 명령을 생성하세요. 두 가지 서빙 전략이 일반적인 동작 포인트를 다룹니다:

  • Low-latency — 일치하는 draft 모델이 있는 DFlash 추측 디코딩. 채팅과 대화형 에이전트에 선택하세요.
  • High-throughput — 일반 서빙. 배치 워크로드에 가장 적합하며, 추측의 draft + 거부 오버헤드가 절약보다 더 비싼 경우예요.

8-GPU HGX 플랫폼(H200 / B300)에서 BF16과 NVFP4는 일반 --tp 8로 실행돼요. FP8과 INT4는 양자화 스케일이 MoE를 8-way로 샤드할 수 없어 --tp 8 --ep-size 8로 실행돼요(Configuration Tips 참조). 4-GPU GB300 노드는 전체적으로 일반 --tp 4를 사용해요.

Playground

Playground는 검증된 매트릭스를 넘어 SGLang 기능을 실험하는 곳이에요. 위 Deploy 패널은 승인된 조합만 생성하며, Playground는 Deploy 패널이 현재 표시 중인 셀 위에 추가 노브(TP 정도, 파서)를 켤 수 있게 해 줘요.

1. Model Introduction

Laguna-XS-2.1poolside의 오픈 가중치 33B 파라미터 하이브리드 sliding-window-attention MoE 모델(토큰당 약 3B 활성화)로, 에이전틱 코딩과 장기 지평 소프트웨어 엔지니어링을 위해 만들어졌어요 — Laguna-M.1의 초소형 형제 모델.

주요 특징:

  • 희소 MoE: 40개 레이어, 256개 라우팅 전문가, top-8 라우팅.
  • 하이브리드 attention: 30개 sliding-window 레이어(window 512)와 10개 full-attention 레이어가 interleave; 48 Q / 8 KV heads.
  • 긴 컨텍스트: 262,144 토큰(full-attention 레이어에 RoPE + YaRN).
  • DFlash drafts: 양자화마다 일치하는 draft 모델(5-레이어, 약 0.9 GB) 제공으로 낮은 지연 서빙.
  • 하이브리드 추론: thinking… responsechat_template_kwargs={"enable_thinking": …}으로 요청마다 토글.

사용 가능한 양자화:

Precision Target model Draft model
BF16 poolside/Laguna-XS-2.1 poolside/Laguna-XS-2.1-DFlash
FP8 poolside/Laguna-XS-2.1-FP8 poolside/Laguna-XS-2.1-DFlash-FP8
NVFP4 poolside/Laguna-XS-2.1-NVFP4 poolside/Laguna-XS-2.1-DFlash-NVFP4
INT4 poolside/Laguna-XS-2.1-INT4 poolside/Laguna-XS-2.1-DFlash-INT4

draft 자체는 작은 bf16 모델로, 각각 자기 양자화된 타깃에 맞춰 보정돼요 — 항상 타깃과 일치하는 draft를 짝지으세요(정밀도를 섞으면 accept-length가 저하됨).

라이선스: Apache 2.0

리소스: Hugging Face · Release blog post · API platform.

2. Configuration Tips

Attention backend

High-throughput 셀에서는 --attention-backend을 설정하지 않은 채 두세요 — 자동 선택이 올바르기 때문이에요(Hopper에서 fa3, Blackwell에서 trtllm_mha). DFlash가 활성화되면 자동 선택은 대신 flashinfer로 폴백하는데, 이 하이브리드-SWA 모델을 Blackwell의 tp ≥ 4에서 망가뜨려요(greedy GSM8K 76% → 28%), 그래서 Low-latency 명령은 타깃 백엔드를 명시적으로 고정해요. --speculative-draft-attention-backend은 설정하지 않은 채 두세요. Laguna에는 triton attention을 절대 사용하지 마세요(GSM8K 13%).

양자화 체크포인트는 일반 TP를 4로 제한

moe_intermediate_size=512에 FP8 블록 [128,128] / INT4 group_size=128 스케일은 8-way로 샤드될 수 없어요(512/8 = 64 < 128 granularity): FP8은 가중치 생성 시 실패하고, INT4는 모든 하드웨어에서 Marlin 커널에서 충돌해요. 따라서 생성된 8-GPU FP8/INT4 명령은 --tp 8 --ep-size 8을 사용해요 — 전문가 병렬 처리는 랭크당 전문가 전체를 유지하므로 한 인스턴스에서 8개 GPU를 모두 사용합니다. FP8은 추가로 SGLANG_SHARED_EXPERT_TP1=1이 필요해요(그 공유 전문가도 블록 양자화되고; INT4는 bf16으로 유지). 대안: 일반 --tp 4, 또는 --tp 4 --dp-size 2. 정확도는 평가 노이즈 내에서 병렬 처리와 무관해요(GB300에서 tp1 ≡ tp4, H200에서 tp4 ≡ tp8+ep8로 검증).

DFlash 메모리

Low-latency 셀은 --mem-fraction-static 0.7을 담아요: 기본 비율은 GB300의 tp 4에서 draft vocab all-gather가 OOM 나요. Dense 셀은 기본 휴리스틱을 사용해요.

INT4는 혼합 정밀도

INT4 체크포인트는 MoE 레이어를 혼합 4-bit / 8-bit 구성 그룹으로 양자화해요. PR #29761보다 오래된 빌드는 로드 시 KeyError: 'Linear'로 충돌해요.

Chat template

transformers ≥ 5.10에서는 독립 chat_template.jinja가 자동 로드돼요 — 플래그 불필요(서버가 Auto-detected template features: reasoning_parser=poolside_v1, ...을 기록). 더 오래된 transformers(≤ 약 5.8)에서는 tokenizer_config.json{% include %} 스텁이 해석되지 못해 서버가 조용히 일반 템플릿으로 폴백해요 — 거기서는 --chat-template <model-dir>/chat_template.jinja를 명시적으로 전달하세요.

Thinking

기본적으로 꺼짐; 요청마다 extra_body={"chat_template_kwargs": {"enable_thinking": True}}로 옵트인하세요. 템플릿은 enable_thinking에 게이트하며, 일반 thinking 키는 무시돼요.

Served model id

서버는 --model-path에 전달한 대로 모델을 등록하며, 클라이언트의 model 필드가 그것(poolside/Laguna-XS-2.1, 또는 -FP8 / -NVFP4 / -INT4 id)과 일치해야 해요.

3. Advanced Usage

3.1 DFlash Speculative Decoding

DFlash는 블록 단위 추측 디코더예요: 5-레이어 draft가 토큰 블록 하나를 제안하고 타깃이 전체 블록을 단일 forward pass로 검증하므로 타깃이 승인한 토큰만 생성돼요 — 출력 품질은 구조상 타깃의 것(모든 양자화에서 GSM8K가 noise 내에서 dense와 일치). 속도 레버는 accept-length, 즉 타깃 단계당 검증을 통과하는 draft 토큰 수예요:

  • tp 1에서 약 6 토큰/단계, tp 4에서 약 4(greedy GSM8K, 일치 정밀도 쌍; 혼합 reasoning-heavy 트래픽에서 약 3; FP8은 H200의 tp 8 + ep 8에서 6.75 달성) — dense의 1 토큰/단계 대비.
  • 대화형 / 소수 스트림 서빙에 가장 좋아요. 배치가 가득 찬 부하에서는 High-throughput을 선호하세요: GPU가 compute-bound가 되면 draft + 거부 토큰 오버헤드가 총 처리량을 깎아요.
  • 생성된 명령은 항상 선택한 타깃 정밀도에 맞게 보정된 draft를 짝지워요.

3.2 Reasoning

--reasoning-parser poolside_v1로 실행하세요(모든 생성 명령에 내장). Reasoning은 enable_thinking=True로 옵트인하며, thinking 트레이스는 message.content의 최종 답과 분리되어 message.reasoning_content에 들어가요.

```python from openai import OpenAI

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

response = client.chat.completions.create( model="poolside/Laguna-XS-2.1", messages=[{"role": "user", "content": "What is 15% of 240? Explain briefly."}], max_tokens=2048, extra_body={"chat_template_kwargs": {"enable_thinking": True}}, )

message = response.choices[0].message print("=============== Reasoning ===============") print(message.reasoning_content) print("=============== Answer ==================") print(message.content)

</Accordion>

<Note>
XS-2.1은 초소형 모델이에요 — thinking을 활성화하면 넉넉한 `max_tokens`를 주세요
(어려운 문제는 정기적으로 수천 토큰을 추론함), 짧은 형식 작업에는 thinking을 꺼 두세요.
</Note>

### 3.3 Tool Calling

`--tool-call-parser poolside_v1`로 실행하세요(모든 생성 명령에 내장). 파서는 Laguna의 `<tool_call>` 출력을 표준 OpenAI `tool_calls` 구조로 변환해요. 도구 호출은 reasoning이 꺼진 상태에서도(기본값) 작동해요.

<Accordion title="Tool Calling Example (Python)">
```python
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"]},
                },
                "required": ["location"],
            },
        },
    }
]

response = client.chat.completions.create(
    model="poolside/Laguna-XS-2.1",
    messages=[{"role": "user", "content": "What's the weather in Beijing?"}],
    tools=tools,
)

message = response.choices[0].message
if message.tool_calls:
    for call in message.tool_calls:
        print(f"Tool: {call.function.name}")
        print(f"Args: {call.function.arguments}")

더 알아보기