DeepSeek-V4-Flash Parameter Tuning: สิ่งที่ต้องเข้าใจก่อนปรับแต่ละตัว
สารบัญ
- เรื่องเดิม: ทำไมต้องปรับ parameter
- ก่อนปรับ: config เก่าที่ติด loop
- หลังปรับ: เพิ่ม penalties + cap token
- ทดลองจริง: penalty แต่ละตัวทำอะไร
max_completion_tokensvsmax_tokens- สิ่งที่ค้นพบจากการเทส API spec
- 1.
tool_choicedefault ทำตัวเหมือน "auto" - 2.
thinking_token_budgetต้อง config ฝั่ง server - 3.
top_k,top_p,temperatureไม่มี default ใน spec - 3 profiles สุดท้ายที่ผมใช้
- สิ่งที่เรียนรู้
- สรุป
- อ้างอิง
บันทึกกลางดึก — 15 สิงหาคม 2569 — ตี 3
เรื่องมันเริ่มจากตอนที่ผมกำลังรัน agent ผ่าน self-hosted vLLM ที่ใช้ DeepSeek-V4-Flash-0731 อยู่ดีๆ model ก็เริ่มติด loop ใน thinking block — พิมพ์ reasoning วนไปวนมา ไม่ยอมจบสักที
ผมนั่งดู log อยู่สักพัก แล้วก็เริ่มเข้าใจว่า — การปรับ parameter ของ reasoning model มันไม่เหมือนกับ LLM ทั่วไป ถ้าใช้ค่า default แบบ OpenAI API ตรงๆ จะเจอ behavior ที่ไม่คาดคิด
เล่าให้ฟังว่าผมเจออะไรบ้าง แล้ว config ที่ใช้งานได้จริงๆ เป็นยังไง
เรื่องเดิม: ทำไมต้องปรับ parameter
DeepSeek-V4-Flash-0731 เป็น MoE reasoning model ที่มี thinking mode แยกต่างหมาย — มันจะ "คิด" ใน block หนึ่ง แล้วค่อย "ตอบ" ในอีก block หนึ่ง ถ้าเราใช้ reasoning_effort ที่สูงเกินไป + ไม่มี penalty กลางๆ มันจะคิดไม่จบ
ผมมี 3 profile หลักที่ใช้ในงานต่างกัน:
p1: ds4-flash-x ← agent + coding (thinking enabled)
p2: ds4-flash-mini ← simple task (no thinking)
p3: ds4-flash-trading ← trading bot (deterministic)
ตัวที่มีปัญหาคือ p1 — เพราะมันทั้ง reasoning_effort: "high" และ temperature: 0.85 (ค่อนข้างสูง) ใส่รวมกัน พอ reasoning ยาว + sampling random มากขึ้น = โอกาสวนซ้ำสูง
ก่อนปรับ: config เก่าที่ติด loop
{
"top_p": 0.95,
"thinking": {"type": "enabled"},
"stop": ["`", "</think>", "\n\n\n"],
"reasoning_effort": "high",
"max_tokens": 16384,
"temperature": 0.85
}
ดูแล้วไม่มีอะไรผิด — แต่พอรันจริงๆ บน agent workload ที่ reasoning ยาวๆ มันจะติดวนใน pattern ประมาณ "ต้องคิดใหม่... เอาลองคิดอีกที... แต่ก็ยังไม่ได้คำตอบ... ลอง..."
Note: ทำไม stop sequence ไม่ช่วย —
"\n\n\n"ดูดี แต่ถ้า model ยังไม่ถึง 3 newline ติดกันมันก็ไม่หยุด ส่วน"\"มันแค่ปิด<think>` tag ซึ่ง reasoning block ของ V4 ไม่ได้ใช้ tag นี้เสมอ
หลังปรับ: เพิ่ม penalties + cap token
{
"top_p": 0.95,
"thinking": {"type": "enabled"},
"reasoning_effort": "high",
"max_completion_tokens": 8192,
"temperature": 0.85,
"frequency_penalty": 0.2,
"presence_penalty": 0.1,
"repetition_penalty": 1.05
}
สังเกตว่าผม ลบ stop sequence ออก แล้วเปลี่ยนไปใช้ penalty เป็นตัวกัน loop แทน เหตุผลคือ penalty ปรับ behavior ทั้ง turn ส่วน stop ตัดเฉพาะตรงนั้น — penalty ยืดหยุ่นกว่า
ทดลองจริง: penalty แต่ละตัวทำอะไร
ผมใช้ prompt "Say the word banana over and over" เป็น benchmark ง่ายๆ เพราะมัน trigger repetition ได้ดี ทดสอบ 3 ค่าของ repetition_penalty ที่ seed เดียวกัน:
repetition_penalty | จำนวน tokens ที่ตอบ | behavior |
|---|---|---|
| 1.0 (off) | 100 (โดน cap) | repeat ไม่อั้น |
| 1.2 | 12 | ลด 88% |
| 1.5 | 3 | ลด 97% |
ที่ 1.5 model ตอบ "banana" แค่คำเดียว แล้วเลือกหยุดเองทันที — เพราะทุก token อื่นโดนลงโทษหนักมากจน probability ต่ำหมด
ส่วน presence_penalty ที่ค่าเดียวกันจะเบากว่า (เพราะมันลงโทษ binary — มี/ไม่มี — ไม่ลงโทษตามความถี่):
presence_penalty | tokens ที่ตอบ | ลดลง |
|---|---|---|
| 0.0 | 100 (โดน cap) | — |
| 1.0 | 70 | 30% |
| 2.0 | 22 | 78% |
Note: ทำไมเลือก 1.05 ไม่ใช่ 1.2 — reasoning model ถ้า penalty หนักเกินมันจะเริ่มเลือกคำแปลกๆ ใน thinking block ทำให้ reasoning quality ตก 1.05 คือ "ป้องกันวน 3-4 รอบ" แต่ไม่ทำลาย fluency ถ้ายังติดอยู่ ค่อยเพิ่มเป็น 1.10
max_completion_tokens vs max_tokens
ผมเจอ surprise เล็กๆ — max_tokens ใน spec ของ vLLM ถูก mark เป็น deprecated แต่ ยังใช้งานได้ปกติ (HTTP 200, behavior เหมือนเดิม) ส่วน max_completion_tokens คือตัวที่ OpenAI เปลี่ยนมาใช้ใน model ใหม่ๆ
ทั้งสองตัว cap output เหมือนกัน — แค่คนละชื่อ ผมเลือก max_completion_tokens ไว้ เพราะ:
- ไม่ใช่ deprecated
- Standard ใหม่กว่า
- เผื่อวันนึง vLLM ลบ
max_tokensออก โค้ดไม่พัง
Note: ทำไม cap ที่ 8192 ไม่ใช่ 16384 —
max_tokens: 16384คือ budget รวม แต่ถ้าไม่ capmax_completion_tokensแยก reasoning จะกิน token ได้เกือบหมด แล้ว output จริงจะเหลือน้อย การ cap ที่ 8192 บังคับให้ reasoning ต้องกระชับ
สิ่งที่ค้นพบจากการเทส API spec
ผมลองเทส parameter ตัวอื่นๆ ที่อยู่ใน OpenAPI spec ของ vLLM — เจอ 3 อย่างที่คนทั่วไปอาจไม่รู้
1. tool_choice default ทำตัวเหมือน "auto"
spec บอกว่า tool_choice default คือ "none" แต่ behavior จริง — ถ้าใส่ tools ใน request โดยไม่ระบุ tool_choice — model จะเรียก tool อัตโนมัติเหมือน tool_choice="auto"
ผมเทสกับ weather query:
tool_choice | ผลที่ได้ |
|---|---|
"auto" | เรียก get_weather("Bangkok") |
| ไม่ใส่ (default) | เรียก tool เหมือนกัน |
"none" | ตอบเป็น text ไม่เรียก tool |
Note: สำหรับ agent — ถ้าอยากให้ model "ไม่เรียก tool" ต้องระบุ
tool_choice="none"ชัดๆ อย่าวางใจ default
2. thinking_token_budget ต้อง config ฝั่ง server
ผมพยายามใช้ thinking_token_budget: 4000 เพื่อ cap reasoning block แต่ vLLM ตอบกลับมา:
thinking_token_budget is set but reasoning_config is not configured.
Please set --reasoning-parser and/or --reasoning-config to use thinking_token_budget.
แปลว่า parameter นี้ต้อง launch vLLM ด้วย --reasoning-parser deepseek_v4 (หรือคล้ายๆ) ก่อน ไม่ใช่แค่ส่งจาก client
ตอนนี้ผมยัง cap ด้วย max_completion_tokens เอาก่อน — ใช้งานได้พอ
3. top_k, top_p, temperature ไม่มี default ใน spec
ดูจาก OpenAPI schema — parameter พวก sampling (temperature, top_p, top_k, min_p, repetition_penalty) ไม่มี default ใน spec เลย ทั้งหมดเป็น Optional[float] ที่ปล่อยให้ model generation_config.json ตัดสินใจ
นี่คือเหตุผลที่ parameter พวกนี้ไม่มีค่า default — vLLM ออกแบบมาให้ แต่ละ model มี default ของตัวเอง ถ้า vLLM hardcode ค่ามันจะไปทับค่าใน generation_config.json ของ DeepSeek
Note: ถ้าอยากรู้ default จริงของ model — ดู
generation_config.jsonใน HuggingFace repo ของ model นั้น หรือดูใน output ตอนที่ไม่ส่ง parameter มาเลย
3 profiles สุดท้ายที่ผมใช้
// p1: ds4-flash-x — agent/coding (มี loop prevention)
{
"top_p": 0.95,
"thinking": {"type": "enabled"},
"reasoning_effort": "high",
"max_completion_tokens": 8192,
"temperature": 0.85,
"frequency_penalty": 0.2,
"presence_penalty": 0.1,
"repetition_penalty": 1.05
}
// p2: ds4-flash-mini — simple task
{
"top_k": 35,
"top_p": 0.9,
"thinking": {"type": "disabled"},
"reasoning_effort": "low",
"max_completion_tokens": 4096,
"temperature": 0.65
}
// p3: ds4-flash-trading — deterministic
{
"top_p": 0.9,
"thinking": {"type": "disabled"},
"reasoning_effort": "low",
"max_completion_tokens": 2548,
"temperature": 0.3
}
p1 ใส่ penalty ทั้งสามตัว + cap max_completion_tokens เพื่อกัน reasoning ยาวเกิน
p2 กับ p3 เป็น short-form task ไม่ต้องปรับอะไร — ใช้ default ได้สบาย
สิ่งที่เรียนรู้
ผมลองผิดลองถูกอยู่สักพักกว่าจะเข้าใจ — สรุปเป็นข้อๆ:
- Reasoning model ≠ LLM ทั่วไป — penalty ที่เบามาก (1.05) ก็ช่วยได้ ถ้าหนักเกิน reasoning quality จะตก
- Stop sequence มีข้อจำกัด — มันตัดเฉพาะตรงนั้น ไม่ได้ป้องกัน pattern วนทั้ง turn — penalty ดีกว่าสำหรับงานแบบนี้
max_completion_tokensสำคัญกว่าmax_tokens— เพราะกัน reasoning กิน token จน output จริงเหลือน้อยtool_choicedefault ไม่ตรงตามที่ spec บอก — ต้องระบุ explicit ถ้าอยากคุม behavior- Parameter บางตัวต้อง config ฝั่ง server —
thinking_token_budgetใช้ไม่ได้ถ้า vLLM ไม่ได้ launch ด้วย reasoning-parser
ถ้ามีคนกำลังใช้ DeepSeek-V4-Flash-0731 บน vLLM แล้วเจอ loop เหมือนผม ลองเริ่มจาก repetition_penalty: 1.05 + frequency_penalty: 0.2 ดูก่อน — ถ้ายังไม่พอค่อยปรับขึ้น
สรุป
ถ้าใช้ DeepSeek-V4-Flash-0731 บน vLLM แล้วเจอ model ติด loop ใน thinking block ให้เริ่มจาก repetition_penalty: 1.05 + frequency_penalty: 0.2 + cap max_completion_tokens ที่ 8192 — ส่วนใหญ่จะแก้ปัญหาได้โดยไม่ทำลาย reasoning quality
สิ่งที่เรียนรู้จากบล็อกนี้คือ reasoning model ต้องการ penalty เบาๆ (1.05) ไม่ใช่หนักๆ (1.5) เพราะ reasoning block ต้องการ fluency สูง — และ max_completion_tokens สำคัญกว่า max_tokens เพราะกัน reasoning กิน token จน output จริงเหลือน้อย
อ้างอิง
- DeepSeek-V4-Flash-0731 Model Card — spec, encoding folder, reasoning modes
- DeepSeek API Docs — official API docs (SPA, บางหน้าต้องเปิด browser ดูตรงๆ)
- vLLM Sampling Parameters — รายละเอียด sampling options ของ vLLM
เนื้อหานี้มีประโยชน์ไหม? ช่วยสนับสนุนค่ากาแฟให้ผู้เขียนสักแก้ว
Buy Me a Coffee