Skip to main content

DeepSeek-V4-Flash Parameter Tuning: สิ่งที่ต้องเข้าใจก่อนปรับแต่ละตัว

· 7 min read

บันทึกกลางดึก — 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.212ลด 88%
1.53ลด 97%

ที่ 1.5 model ตอบ "banana" แค่คำเดียว แล้วเลือกหยุดเองทันที — เพราะทุก token อื่นโดนลงโทษหนักมากจน probability ต่ำหมด

ส่วน presence_penalty ที่ค่าเดียวกันจะเบากว่า (เพราะมันลงโทษ binary — มี/ไม่มี — ไม่ลงโทษตามความถี่):

presence_penaltytokens ที่ตอบลดลง
0.0100 (โดน cap)—
1.07030%
2.02278%

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 ไว้ เพราะ:

  1. ไม่ใช่ deprecated
  2. Standard ใหม่กว่า
  3. เผื่อวันนึง vLLM ลบ max_tokens ออก โค้ดไม่พัง

Note: ทำไม cap ที่ 8192 ไม่ใช่ 16384 — max_tokens: 16384 คือ budget รวม แต่ถ้าไม่ cap max_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 ได้สบาย

สิ่งที่เรียนรู้​

ผมลองผิดลองถูกอยู่สักพักกว่าจะเข้าใจ — สรุปเป็นข้อๆ:

  1. Reasoning model ≠ LLM ทั่วไป — penalty ที่เบามาก (1.05) ก็ช่วยได้ ถ้าหนักเกิน reasoning quality จะตก
  2. Stop sequence มีข้อจำกัด — มันตัดเฉพาะตรงนั้น ไม่ได้ป้องกัน pattern วนทั้ง turn — penalty ดีกว่าสำหรับงานแบบนี้
  3. max_completion_tokens สำคัญกว่า max_tokens — เพราะกัน reasoning กิน token จน output จริงเหลือน้อย
  4. tool_choice default ไม่ตรงตามที่ spec บอก — ต้องระบุ explicit ถ้าอยากคุม behavior
  5. 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 จริงเหลือน้อย

อ้างอิง​

แชร์บทความ
☕

เนื้อหานี้มีประโยชน์ไหม? ช่วยสนับสนุนค่ากาแฟให้ผู้เขียนสักแก้ว

Buy Me a Coffee
Loading...