Qwen3.6-35B-A3B บน DGX Spark: เรื่อง sampling ที่ผมตั้งผิดมาตลอด
สารบัญ
- TL;DR
- เริ่มจากความสับสนเรื่อง
maxOutputTokens - สิ่งที่ผมเจอใน Sampling Parameters ของ Qwen
- ทบทวน use case ของตัวเอง
- 1. Trading bot (
bot4k) - 2. Hermes coding agent
- 3. Long document analysis
- Decision tree ที่ผมลองร่าง
- ตารางเปรียบเทียบ: 32K → 128K บน vLLM v0.23.0
- ข้อสำคัญที่ผมเพิ่งเห็นใน model card
- สรุปสิ่งที่ผมจะลอง
- สิ่งที่ผมยังไม่รู้
- What's Next
- Conclusion
- References
ผมตั้งค่า vLLM มาหลายเดือนด้วยสูตรเดียวตลอด — temperature: 0.6, top_p: 0.95, top_k: 20 แล้วก็ปล่อยให้ client ไป override เอาเอง ไม่ว่าจะเป็น trading bot, Hermes agent, code review — ใช้ค่าเดียวกันหมด
จนเมื่อวานนี้ผมเปิด Hugging Face model card ของ Qwen3.6-35B-A3B อ่านเล่น ๆ ในส่วน Sampling Parameters ถึงได้รู้ว่า — Qwen team แนะนำ sampling ตาม mode และ task type ไม่ใช่ตาม benchmark หรือ use case แบบที่ผมเข้าใจ
อ้าว ผมเลยต้องกลับมานั่งคิดใหม่
TL;DR
Qwen3.6-35B-A3B แนะนำ sampling parameters ตาม mode (thinking vs instruct/non-thinking) และ task type (general vs coding vs reasoning) ไม่ใช่ตาม benchmark หรือ use case ภายนอก จุดที่ผมเข้าใจผิดมาตลอดคือ — thinking mode สำหรับ general tasks ใช้ temperature=1.0 สูงกว่า coding ที่ใช้ temperature=0.6 ซึ่งกลับกับ intuition เดิมที่ว่า "coding ต้อง explore หลายทางเลือก จึงต้อง temp สูง" จริง ๆ แล้ว precise coding ต้องความแม่นยำสูง จึงใช้ temp ต่ำ ส่วน general tasks ใน thinking mode ต้องการความหลากหลายในการคิด จึงใช้ temp สูง
เริ่มจากความสับสนเรื่อง maxOutputTokens
ก่อนจะเข้าเรื่อง sampling ขอเคลียร์ confusion ที่ผมเพิ่งรู้ตัวเมื่อวานก่อน — maxOutputTokens ที่หลายคนถามหา "ค่า default บน server เป็นเท่าไหร่" จริง ๆ แล้ว มันเป็น client-side parameter เท่านั้น
# ที่ client ส่ง — ไม่มี server default
curl http://10.0.0.246:8001/v1/chat/completions -d '{
"model": "qwen3.6-35b-base",
"messages": [...],
"max_tokens": 3000 # <-- ตรงนี้
}'
ส่วนที่ vLLM server มีให้ตั้งจริง ๆ คือ max_model_len ซึ่งเป็น total context (prompt + output รวมกัน) ไม่ใช่ output อย่างเดียว
Note: ค่าที่อยู่บน DGX Spark ตอนนี้ — recipe
qwen3.6-35b-a3b-base-128k-v23.yaml:
max_model_len: 131072(128K = prompt + output รวมกัน)temperature: 0.6จาก--override-generation-configtop_p: 0.95,top_k: 20,min_p: 0.0enable_thinking: trueจาก--default-chat-template-kwargsmax_num_seqs: 12(ลดจาก 40 เพราะ KV cache ใหญ่ขึ้นตาม context)
ผมตั้งมาตลอดแบบ "เซ็ตครั้งเดียว ใช้ทุกอย่าง" โดยไม่เคยตั้งคำถามว่า use case ต่างกันควรตั้งต่างกันไหม
สิ่งที่ผมเจอใน Sampling Parameters ของ Qwen
ใน HF model card มีตารางแนะนำ sampling ตาม mode และ task type — ผมเลย extract ออกมา:
| Mode | Task Type | Temperature | Top P | Top K | Min P | Presence Penalty | Repetition Penalty |
|---|---|---|---|---|---|---|---|
| Thinking | General tasks | 1.0 | 0.95 | 20 | 0.0 | 1.5 | 1.0 |
| Thinking | Precise coding (e.g. WebDev) | 0.6 | 0.95 | 20 | 0.0 | 0.0 | 1.0 |
| Instruct (non-thinking) | General tasks | 0.7 | 0.8 | 20 | 0.0 | 1.5 | 1.0 |
| Instruct (non-thinking) | Reasoning tasks | 1.0 | 1.0 | 40 | 0.0 | 2.0 | 1.0 |
Note: สังเกตว่า — Thinking mode สำหรับ general tasks ใช้
temp=1.0สูงกว่า precise coding ที่ใช้temp=0.6ทั้งที่เป็น model ตัวเดียวกัน นี่แหละคือ insight ที่ผมพลาดไป
ทำไม thinking general ต้อง temp สูงกว่า coding? ผมเดาว่า:
- General tasks ใน thinking mode ต้องการ ความหลากหลายในการคิด (diverse reasoning paths) — temp สูงช่วย explore หลายทางเลือกในการวิเคราะห์
- Precise coding ต้องการ ความแม่นยำสูง (deterministic code structure) — temp ต่ำช่วยลด hallucination ใน syntax และ logic
- ที่สำคัญ — presence penalty ของ general tasks สูง (1.5) เพื่อลด repetition ในขณะที่ coding ไม่มี presence penalty (0.0) เพราะ code อาจต้องใช้ตัวแปรหรือ pattern เดิมซ้ำ ๆ
นอกจากนี้ยังมีข้อแนะนำเรื่อง output length:
- 32,768 tokens สำหรับ queries ทั่วไป
- 81,920 tokens สำหรับ complex problems (math, programming competitions)
ทบทวน use case ของตัวเอง
หลังอ่านแล้วผมเลยนั่ง list use case ที่ใช้จริง แล้วลองเทียบกับ sampling ที่ผมตั้ง:
1. Trading bot (bot4k)
// AiTradeService.ts — เดิม
maxOutputTokens: 3000,
temperature: BACKTEST_MODE ? 0 : 0.2, // ตรึงต่ำเพราะ logic-sensitive
providerOptions: { openai: { reasoningEffort: 'medium' } }
ความเห็นตอนนี้: น่าจะถูกแล้ว — trading signal เป็น logic-sensitive task ที่ต้อง reproducible ใน backtest ใช้ temp 0/0.2 OK แต่ควรพิจารณาว่าใช้ thinking mode หรือ instruct mode — ถ้าเป็น instruct mode อาจตั้ง presence_penalty: 1.5 เพิ่มได้
2. Hermes coding agent
// Hermes workflow
maxTokens: 8000, // thinking + code blocks
temperature: 0.6, // <-- ตรงนี้อาจถูกแล้ว ถ้าเป็น precise coding
top_p: 0.95
Insight: Qwen แนะนำ temp=0.6 สำหรับ precise coding ใน thinking mode — ผมอาจต้องเพิ่ม presence_penalty: 0.0 และลองเทียบกับ temp=1.0 สำหรับ multi-step coding task ที่ต้องการ explore หลายทางเลือก แต่ยังไม่ได้ทดสอบ
3. Long document analysis
// 128K context
maxTokens: 4000,
temperature: 0.6,
enable_thinking: true
Insight: ถ้าเป็น general analysis ใน thinking mode ควรใช้ temp=1.0 ตามที่ Qwen แนะนำ — ค่า 0.6 ที่ตั้งไว้อาจต่ำเกินไปสำหรับ general tasks ใน thinking mode
Decision tree ที่ผมลองร่าง
จาก sampling parameters + use case ของตัวเอง ผมลองร่าง decision tree ไว้ใช้ตอนตั้งค่า:
ตารางเปรียบเทียบ: 32K → 128K บน vLLM v0.23.0
ข้อมูล benchmark จริงที่ผมวัดได้ — เทียบทั้ง 3 configuration ที่ผ่านมา เพื่อให้เห็นว่า context ขยายขึ้นมีผลยังไง:
| Workload | v0.22.1rc1 + 32K MTP k=1 | v0.23.0 + 32K + FlashInfer=1 | v0.23.0 + 128K + MTP k=2 + flags |
|---|---|---|---|
| Short (~200 tok) | 43.1 tok/s | 56.8 tok/s (+32%) | 63.6 tok/s ✨ |
| Medium (~1K tok) | 63.7 tok/s | 60.9 tok/s | 58.1 tok/s |
| Long (~16K tok) | 64.2 tok/s | 65.0 tok/s | 52.7 tok/s |
| Huge (~60K tok) | N/A | N/A | 25.7 tok/s |
| Max (~110K tok) | N/A | N/A | 16.4 tok/s |
Note: ตัวเลขเหล่านี้คือ total tok/s รวม prefill — สำหรับ huge prompt, prefill กินเวลา 5-25s ขึ้นกับความยาว ถ้าดูแค่ pure generation speed จะสูงกว่านี้
ถ้าแยก pure generation speed (หัก prefill ออก) ของ 128K config:
| Workload | Total time | Prefill est. | Gen time | Pure gen tok/s |
|---|---|---|---|---|
| 0K (short) | 4.0s | ~0.1s | ~3.9s | 65 |
| 1K (medium) | 2.2s | ~0.3s | ~1.9s | 67 |
| 16K (long) | 14.5s | ~0.5s | ~14s | 54 |
| 64K (huge) | 19.5s | ~5s | ~14.5s | 34 |
| 120K (max) | 30.6s | ~25s | ~5.6s | 89 ⚡ |
ที่น่าสนใจคือ — short prompt 0-1K tokens ได้ความเร็วเท่าเดิมหรือดีกว่า แม้จะขยาย context เป็น 128K แสดงว่า context length ไม่กระทบ generation speed ตรง ๆ ส่วนที่ช้าคือ prefill เท่านั้น
ข้อสำคัญที่ผมเพิ่งเห็นใน model card
"Context Length: Default 262,144 tokens. Maintain at least 128K tokens to preserve thinking capabilities."
แปลว่า — ถ้า context สั้นกว่า 128K model อาจไม่ preserve thinking ผมตั้ง 128K recipe ไว้พอดี (max_model_len: 131072) ตรงนี้โชคดี
นอกจากนี้ยังมี Thinking Preservation ด้วย preserve_thinking option — ช่วยให้ model เก็บ reasoning context จาก historical messages ไว้ใช้ต่อ ซึ่ง beneficial สำหรับ agent scenarios ที่ต้อง decision consistency
สรุปสิ่งที่ผมจะลอง
- ทดสอบ Hermes coding agent ด้วย
temp=0.6, presence_penalty=0.0— ตามที่ Qwen แนะนำสำหรับ precise coding ใน thinking mode - เปรียบเทียบ
temp=0.6vstemp=1.0บน general analysis tasks ใน thinking mode — ดูว่า quality ดีขึ้นไหม - เพิ่ม LiteLLM alias แยก —
qwen3-thinking-general(temp=1.0, presence=1.5) vsqwen3-thinking-coding(temp=0.6, presence=0.0) vsqwen3-instruct(temp=0.7) เพื่อให้ client เลือกได้ตาม mode และ task - อัปเดต bot4k comment — note ว่าทำไม trading ใช้ temp 0/0.2 แทนที่จะใช้ Qwen's default และว่าเป็น instruct mode หรือ thinking mode
สิ่งที่ผมยังไม่รู้
- ผมยังไม่ได้ทดสอบว่า
temp=1.0บน general thinking tasks ใน Spark จริง ๆ ให้ผลดีกว่าtemp=0.6แค่ไหน — เป็นแค่ hypothesis จาก Qwen's sampling recommendations - LiteLLM alias routing ตาม mode และ task อาจทำให้ config ซับซ้อนขึ้น — ต้องดูว่า worth หรือไม่
presence_penaltyและrepetition_penaltyใน vLLM อาจมี interaction กับ thinking mode ที่ผมยังไม่เข้าใจpreserve_thinkingใน long-running agent อาจกิน context เร็วขึ้น — ต้อง balance ระหว่าง context retention กับ truncation
What's Next
- ถ้าพี่ ๆ ที่อ่านอยู่ใช้ Qwen3.6-35B-A3B ด้วย ลองเล่าใน comments ได้ว่า sampling ที่ใช้เป็นยังไง
- ถ้ามีคน test
temp=1.0กับ general thinking tasks บน DGX Spark แล้วเห็นผลชัด ผมจะกลับมาเขียน follow-up - บทความนี้เป็น "เรียนรู้จากการอ่าน model card" ไม่ใช่ guide สำเร็จรูป — ใช้วิจารณญาณด้วยนะครับ
Conclusion
การอ่าน HF model card ของ Qwen3.6-35B-A3B ทำให้ผมรู้ว่า sampling parameters ไม่ควรตั้ง "สูตรเดียวใช้ทุกอย่าง" โดยเฉพาะกับ model ที่มี hybrid reasoning แบบนี้ จุดเปลี่ยนสำคัญคือการแยก mode (thinking vs instruct) และ task type (general vs coding vs reasoning) แล้วตั้ง sampling ตามนั้น โดยเฉพาะอย่าสับสนว่า "coding ต้อง temp สูง" — จริง ๆ แล้ว precise coding ใน thinking mode ต้อง temp=0.6 ต่ำกว่า general tasks ที่ใช้ temp=1.0
References
- Hugging Face model card: Qwen/Qwen3.6-35B-A3B — แหล่งข้อมูลหลักเรื่อง sampling parameters และ context length
- Qwen3.6 SGLang Documentation — รายละเอียด thinking preservation และ deployment
- DeepInfra: Qwen3.6-35B-A3B Demo — ตัวอย่าง API usage และ best practices
เนื้อหานี้มีประโยชน์ไหม? ช่วยสนับสนุนค่ากาแฟให้ผู้เขียนสักแก้ว
Buy Me a Coffee