0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【DGX Spark】SGLangをDockerで常設化して検証したが、最終的にTensorFoldに戻した理由

0
Posted at

追記(2026-10-28): この記事はSGLang移行の記録です。その後の検証でTensorFoldに戻しました。理由と最終構成は「7. その後」にまとめています。

前シリーズの続編です。1台の DGX Spark(GB10, 128GB)で、
SGLang を Docker で常設化して検証し、
litellm / opencode と連携、non-thinking(fast)を復活、
そして入力長エラーをKVキャッシュ調整で解決した記録です。
IP・ホスト名・認証情報はプレースホルダに置き換えています。


TL;DR

  • 速度ではTensorFoldが上だが、**SGLangの価値は「penaltyが効く」**こと。
  • SGLangをDocker常設サービス化してnon-thinking(presence_penalty=1.5)を検証。
  • 入力長エラー(Input length ... exceeds the maximum allowed length)を
    --mem-fraction-static の調整で解決。
  • 最終的にはTensorFoldに戻した(起動時間・decode速度・メモリ会計の3点が理由。「7. その後」参照)。

1. なぜSGLangに移行するか

前回(②エンジン比較編)で、速度はTensorFoldが上と分かりました。
それでもSGLangへ移す理由は機能です。

  • TensorFold 0.6.6 は presence_penalty を実装していない → non-thinking がループする(①真因解明編)。
  • SGLang は presence_penalty / repetition_penalty を実装 → 公式の非thinking推奨がそのまま効く。
  • つまり non-thinking(本来のfast)を安定運用できるのが最大のメリット。

2. SGLangをDocker常設化

既存の compose(/opt/docker/TensorFold/docker-compose.yml)に sglang を既定サービスとして追加し、
従来の tensorfold は profile tf のフォールバックにしました。

services:
  # 既定 = SGLang + Qwen3.8-27B (NVFP4 + DFlash2)
  sglang:
    image: lmsysorg/sglang:dev-cu13
    container_name: sglang
    devices: [nvidia.com/gpu=all]
    volumes:
      - ./cache:/root/.cache
      - ./sglang-cache:/cache
    restart: unless-stopped
    shm_size: "16gb"
    ipc: host
    environment:
      - TORCHINDUCTOR_CACHE_DIR=/cache/inductor
      - SGLANG_ENABLE_REQUEST_HEADER_OVERRIDES=1
      - HF_HUB_OFFLINE=1          # ← 起動ハング回避
    command:
      - python3 -m sglang.launch_server
      - --trust-remote-code --model-path nvidia/Qwen3.8-27B-NVFP4 --tp-size 1
      - --served-model-name Qwen3.8-27B
      - --mem-fraction-static 0.60
      - --attention-backend flashinfer --chunked-prefill-size 8192
      - --disable-prefill-cuda-graph --cuda-graph-max-bs-decode 8
      - --disable-flashinfer-autotune
      - --speculative-algorithm DFLASH
      - --speculative-draft-model-path z-lab/Qwen3.8-27B-DFlash2
      - --speculative-num-draft-tokens 16
      - --mamba-radix-cache-strategy extra_buffer --mamba-ssm-dtype bfloat16
      - --max-mamba-cache-size 96 --max-running-requests 8
      - --num-continuous-decode-steps 2 --sleep-on-idle
      - --reasoning-parser qwen3 --tool-call-parser qwen3_coder
      - --host 0.0.0.0 --port 30000

  # フォールバック = TensorFold 27B(profile "tf")
  tensorfold:
    profiles: ["tf"]
    # ...(従来どおり MLX-4bit + DFlash2)

  litellm:
    depends_on: [sglang]

切替:

cd /opt/docker/TensorFold
docker compose up -d                                   # 既定 = SGLang
docker compose logs -f sglang
docker compose stop sglang && docker compose --profile tf up -d tensorfold   # TensorFoldへ戻す

起動に約5–7分(CUDAグラフ/compile)。HF_HUB_OFFLINE=1 が無いと起動ハングすることがあります。

3. litellm / opencode 連携

litellm の qwen3.8-27b-* ルートを SGLang に向けます(--served-model-name を合わせる)。

  - model_name: qwen3.8-27b-fast
    litellm_params:
      model: openai/Qwen3.8-27B
      api_base: http://sglang:30000/v1
      api_key: dummy
      extra_body:
        chat_template_kwargs:
          enable_thinking: false
        temperature: 0.7
        top_p: 0.8
        top_k: 20
        min_p: 0.0
        presence_penalty: 1.5     # ← SGLangなら実際に効く
        repetition_penalty: 1.0

opencode 側は既定モデルを qwen3.8-27b-fast に設定(provider名も更新)。変更後は litellm / opencode を再起動します。

4. non-thinking を復活させる

SGLangは presence_penalty を実装しているため、本来のfast(non-thinking)に戻せる可能性があります。

  • litellm qwen3.8-27b-fast を enable_thinking: false + 公式non-thinkingサンプリング(presence_penalty 1.5)に。
  • 検証:
    • litellm経由の単発 → reasoning空(non-thinking)、finish=stop
    • tool多ターン → repeats=0
    • 退化シナリオ(assistant-only追記)→ repeats=1(軽微)で途中 finish=stop に復帰、暴走ループなし

→ TensorFoldで問題だった「penalty無視によるループ」は緩和。※最終判断は実運用での検証。

5. 入力長エラーとKVキャッシュ調整

運用中に litellmが500 を返す事象が発生。ログで原因を特定:

litellm.APIConnectionError: OpenAIException - Input length (188104 tokens)
exceeds the maximum allowed length (154191 tokens).
  • opencodeが送った会話が 188kトークン、SGLangの上限が 154k。
  • 原因は --mem-fraction-static 0.50 では KVキャッシュが ~154kトークンしか持てないこと。

修正: --mem-fraction-static を調整

mem-fraction KV容量(max_total_num_tokens) 空きメモリ
0.50 ~154,000(=エラーの上限) —
0.70 446,231 free 1.2Gi(危険)
0.60(採用) 291,034 free 10Gi / available 44Gi
  • 0.60で KV 291k > モデル窓262k → 実効上限が 262,144(モデルネイティブ)に回復。
  • 0.70 は KV が過剰で空きメモリが逼迫(GB10の統一メモリ罠はフリーズ要因)→ 0.60が安全側の最適。
  • 検証: litellm経由で finish=stop 正常応答。188k級の会話も通る見込み。

6. 運用の注意

  • 起動に約5–7分。--sleep-on-idle のためアイドル後の初回は起こし分だけ遅い。
  • decodeはTensorFoldより遅い(~96 vs ~149 tok/s)。速度より機能を取る選択。
  • GB10の統一メモリ罠: SGLangのメモリ会計が一時確保(25–40GB)を見ないため、--mem-fraction-static を上げすぎるとホストがフリーズする。実績ある値に従う。
  • opencode の limit.context は SGLangの実効上限以下に(例: 240,000 < 262,144)。

7. その後: TensorFoldに戻した理由

SGLangは「penaltyが効く」点で優れていましたが、数日運用した結果、TensorFold(0.6.6)を既定に戻しました。理由は3つです。

観点 SGLang TensorFold 0.6.6
起動 5〜7分(CUDAグラフ/compile) 20〜30秒
decode(27B) 約96 tok/s 約149 tok/s(思考ON・DFlash2)
メモリ会計 --mem-fraction-static を上げるとホストごとフリーズ --kv-dtype int8(FNのみ)や --spill-gib で制御しやすい

さらに、TensorFold側でnon-thinking問題への別解が取れることが分かりました。

  • TensorFold 0.6.6 は presence_penalty を実装していませんが、思考ONで運用すればループしない(①真因解明編)。
  • non-thinkingを使わない前提に立てば、速度で勝るTensorFoldを既定にするのが合理的です。

その後の検証(2026-10)

  • TensorFold 1.1.0 / 1.1.1 のネイティブCUDA実装も試しましたが、この環境(GB10 + ドライバ580 + 互換モード)では prefillが0.6.6の3.3〜10倍遅く、実用外でした。
  • 最終構成は TensorFold 0.6.6 + Qwen3.8-27B(MLX-4bit + DFlash2)。--spill-gib と --checkpoint-slots でメモリを制御しています。

つまりこの記事は「SGLangに移行した記録」ではなく、**「SGLangを試して、TensorFoldのほうが自分の用途に合うと確認した記録」**として読んでください。

まとめ

  1. SGLangをDocker常設化し、non-thinking(penalty)を検証した。
  2. 入力長エラーは --mem-fraction-static で解決(0.50→0.60、KV 291k)。
  3. ただし起動時間・decode速度・メモリ会計の面で運用負荷が高く、最終的にTensorFold(0.6.6)に戻した。
  4. 結論: 「penaltyが要るならSGLang、速度と運用の軽さならTensorFold」。自分の用途では後者だった、という記録。

数値は筆者環境での実測です。ドライバ・イメージ・チェックポイント・負荷で変動します。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?