งบประมาณ context window
สามบทที่ผ่านมาคุณ เพิ่ม ของเข้า context ตลอด — retrieval ในบทที่ 2 ดึงข้อความนโยบายเข้ามา, memory ในบทที่ 3 อ่านโน้ตเก่ากลับเข้าหน้าต่าง ทุกชั้นที่ประกอบเข้าไปมีต้นทุนเป็น token และจนถึงตอนนี้เรายังไม่เคย วัด ต้นทุนนั้นเลย บทนี้ไม่มีชั้นใหม่ให้สร้าง — เป็นบทที่เราถอยมาหนึ่งก้าวแล้ว วัด ของที่มีอยู่ เพราะก่อนจะตัดสินใจได้ว่า token ไหนคุ้มค่าที่จะเก็บ คุณต้องเห็นตัวเลขจริงก่อน และวิธีมอง Context WindowContext Windowเซตของ token ทั้งหมดที่ model อ้างอิงได้ตอน sampling — มองให้ถูกคือ 'งบประมาณจำกัด' ที่ใช้แล้วหมด ไม่ใช่ 'ถัง' ที่เติมได้เรื่อย ๆ ทุก token ที่ใส่เข้าไปกินงบก้อนนี้และให้ผลตอบแทนลดลงเรื่อย ๆ (diminishing returns) สำหรับ agent ที่วนเป็น loop ข้อมูลจะพอกขึ้นทุกเทิร์นจึงต้องคัดสรรซ้ำตลอดArchitecture ที่ถูกต้องสำหรับงานนี้ไม่ใช่ “ถังที่เติมได้” แต่คือ Token BudgetToken Budgetการมอง context window เป็นงบ token ที่ใช้แล้วหมดและต้องจัดลำดับความสำคัญว่าจะใส่อะไร — เพดานหน้าต่างสูงสุดคือ 'เพดาน ไม่ใช่เป้า' วัดการใช้จริงจาก field `usage` ของ agent (#15) เทิร์นต่อเทิร์นแล้วตัด token สัญญาณต่ำ (เช่น blob JSON ดิบเก่า ๆ) ทิ้งก่อนProcess — งบ token ที่จ่ายออกแล้วหมดไป
บทนี้ต่อยอด agent Order ตัวเดิม (repo kaen-food-ordering, กำลังจัดทำ) แต่ ไม่เพิ่ม tool หรือ store ใหม่ — เราเอา agent จากคอร์สที่ 15 ที่รันอยู่แล้วมาติดเครื่องวัด: อ่านจำนวน token ที่ใช้จริงในแต่ละเทิร์นจาก field usage แล้วดูงบก้อนนี้โตขึ้นต่อเนื่อง ตัวเลขที่วัดได้ในบทนี้คือสิ่งที่ compaction (บทที่ 5) กับการจัดระเบียบผลของ tool (บทที่ 6) จะไปลดให้เห็นผล
หน้าต่างคืองบที่จ่ายออก ไม่ใช่เป้าให้เติมเต็ม
หัวข้อที่มีชื่อว่า “หน้าต่างคืองบที่จ่ายออก ไม่ใช่เป้าให้เติมเต็ม”บทที่ 1 วางกรอบนี้ไว้แล้ว บทนี้เอามาลงมือใช้จริง Anthropic พูดถึง context ในฐานะทรัพยากรที่มีต้นทุนต่อหน่วยชัดเจน — “Every new token introduced depletes this budget by some amount, increasing the need to carefully curate the tokens available to the LLM.” และสรุปหลักไว้ว่า “Context, therefore, must be treated as a finite resource with diminishing marginal returns.” คำสำคัญคือ diminishing marginal returns — ผลตอบแทนที่ลดลงต่อเนื่อง ยิ่งอัด token เข้าไปมาก ไม่ได้แปลว่า agent ทำงานดีขึ้นตามส่วน
ผลในทางปฏิบัติมีหนึ่งข้อที่ต้องปักไว้: ความจุสูงสุดของหน้าต่างคือ เพดาน ไม่ใช่ เป้า model รุ่นปัจจุบันมีหน้าต่างใหญ่ (บางตัวถึงหลัก 1M token — ตัวเลขนี้เลื่อนไหวเร็ว อย่าท่องเป็นสัจธรรม) แต่ “ใส่ได้” ไม่เท่ากับ “ควรใส่” การมีที่ว่างเหลือไม่ใช่เหตุผลให้ยัดคลังนโยบายทั้งก้อนเข้า prompt (นี่คือเหตุผลเบื้องหลัง “เมื่อไรไม่ต้องทำ retrieval” ในบทที่ 2) เป้าหมายไม่ใช่เติมงบให้เต็ม แต่คือใช้งบให้น้อยที่สุดเท่าที่งานต้องการ
สองงานวิจัยที่บังคับวินัยเดียวกัน
หัวข้อที่มีชื่อว่า “สองงานวิจัยที่บังคับวินัยเดียวกัน”ทำไมการเติมงบให้เต็มถึงเป็นความคิดที่ผิด? มีงานวิจัยที่ลงวันที่กำกับสองชิ้น ชี้ปัญหาคนละมุมแต่บังคับให้เราทำสิ่งเดียวกัน — รักษาหน้าต่างให้กระชับ
หนึ่ง — token ยิ่งเยอะ ความน่าเชื่อถือยิ่งตก งานของ Chroma Research ท้าสมมติฐานที่เรามักเชื่อโดยไม่รู้ตัว — “Large Language Models (LLMs) are typically presumed to process context uniformly—that is, the model should handle the 10,000th token just as reliably as the 100th. However, in practice, this assumption does not hold.” ข้อสรุปคือ “models do not use their context uniformly; instead, their performance grows increasingly unreliable as input length grows.” อาการนี้มีชื่อว่า Context RotContext Rotปรากฏการณ์ที่ความแม่นในการเรียกใช้ข้อมูลของ model ค่อย ๆ แย่ลงเมื่อ context ยาวขึ้น — model ไม่ได้ประมวลผลทุกตำแหน่งเท่ากัน (Chroma Research) คอร์สสอน 'หลักการ' นี้ ไม่อ้างตัวเลข % เจาะจง (เลื่อนไหวเร็ว) บทเรียนที่ได้คือรักษาหน้าต่างให้กระชับด้วย Compaction + Curation แทนที่จะปล่อยให้เต็มจนเสื่อมArchitecture — และมันเกิดขึ้น “Even on tasks as simple as non-lexical retrieval or text replication” คือแม้แต่งานที่ง่ายอย่างการดึงข้อความตรงๆ ก็ยังเสื่อมเมื่อ input ยาวขึ้น
context rot สอนเป็น หลักการ: ยิ่งหน้าต่างเต็ม ความแม่นในการดึงข้อมูลยิ่งเสื่อม ส่วนตัวเลขเปอร์เซ็นต์การเสื่อมนั้นขึ้นกับ model และช่วงเวลา และเปลี่ยนเร็วมาก — บทนี้จึงไม่อ้างตัวเลขเสื่อมแบบเจาะจง จำหลักการไว้ อย่าจำเป็นเปอร์เซ็นต์ตายตัว
สอง — ที่ที่ token อยู่ ก็สำคัญ ไม่ใช่แค่จำนวน แต่ ตำแหน่ง ในหน้าต่างมีผลด้วย งานของ Liu et al. (“Lost in the MiddleLost in the Middleผลวิจัย (Liu et al., TACL 2024) ที่ว่า model ใช้ข้อมูลที่อยู่ 'ต้น' หรือ 'ท้าย' context ได้ดีกว่าที่อยู่ 'กลาง' อย่างมีนัยสำคัญ แม้กับ model long-context — บทเรียนเชิงปฏิบัติ: วางข้อเท็จจริงชี้ขาด (order id, เหตุผล) ไว้ที่หัวหรือท้าย ไม่ฝังไว้กลาง promptArchitecture”) พบว่า “performance can degrade significantly when changing the position of relevant information, indicating that current language models do not robustly make use of information in long input contexts.” และเจาะจงว่า “Performance is often highest when relevant information occurs at the beginning or end of the input context, and significantly degrades when models must access relevant information in the middle of long contexts, even for explicitly long-context models.” — model ใช้ข้อมูลที่ต้นๆ หรือท้ายๆ ได้ดีกว่าข้อมูลที่ถูกฝังกลางหน้าต่างยาวๆ
สองข้อนี้รวมกันให้กติกาการวางของในงบ: เก็บ token ให้น้อยและ วาง ข้อเท็จจริงที่ชี้ขาด (order id, เหตุผลการคืนเงิน) ไว้ที่ ต้นหรือท้าย ไม่ใช่ฝังกลางกองประวัติยาวๆ
flowchart TB
SP["system prompt<br/>คงที่ · เล็ก"] --> USED
TD["นิยาม tool 3 ตัว<br/>คงที่"] --> USED
H["ประวัติบทสนทนา<br/>โตทุกเทิร์น ↑"] --> USED
TR["ผลของ tool ที่สะสม<br/>โตเร็วสุด ↑↑"] --> USED
USED["token ที่ใช้ไปแล้ว<br/>วัดได้จาก field usage"] --> CEIL{"เข้าใกล้เพดาน<br/>context window?"}
CEIL -->|ยังห่าง| ANS["เหลืองบให้ model ตอบ"]
CEIL -->|เกือบชน| ROT["สัญญาณเริ่มเสื่อม<br/>→ compaction บทที่ 5"]
classDef grow fill:#ea580c,stroke:#7c2d12,color:#f8fafc;
class H,TR grow;
classDef fixed fill:#0891b2,stroke:#064e5b,color:#f8fafc;
class SP,TD fixed;
คำบรรยายภาพ: งบก้อนเดียวถูกกินจากสี่แหล่ง — system prompt กับนิยาม tool (สีฟ้า) คงที่และเล็ก ส่วนประวัติบทสนทนากับผลของ tool ที่สะสม (สีส้ม) คือสองแหล่งที่ โต ทุกเทิร์น โดยผลของ tool โตเร็วที่สุด เมื่อยอด token ที่ใช้ไปเข้าใกล้เพดาน สัญญาณเริ่มเสื่อม — ซึ่งเป็นเหตุผลที่บทที่ 5 ต้อง compaction สองแหล่งสีส้มนั่นคือคือที่ที่เราตัดได้ก่อน
ลงมือวัด: อ่าน usage เทิร์นต่อเทิร์น
หัวข้อที่มีชื่อว่า “ลงมือวัด: อ่าน usage เทิร์นต่อเทิร์น”ทฤษฎีพอแล้ว มาดูตัวเลขจริงของ agent #15 กัน สิ่งที่ วัดได้จริง (ต่างจาก “attention budget” ที่เป็นแค่สัญชาตญาณตามบทที่ 1) คือจำนวน token จาก field usage ที่ model คืนมาทุกครั้ง
ฝั่ง Microsoft.Extensions.AI (ที่คอร์ส #15 พาย้ายมาใช้ในบทที่ 5) พับ block usage ของ Messages API ลงใน ChatResponse.Usage ให้ — อ่านออกมาต่อเทิร์นได้ตรงๆ:
// history = running List<ChatMessage> จาก #15// chat = IChatClient เดิม (x-api-key, anthropic-version 2023-06-01,// model "claude-opus-4-8", ไม่ส่ง temperature — invariant #1–4 ของ #15)ChatResponse reply = await chat.GetResponseAsync(history, options);
UsageDetails? u = reply.Usage; // UsageDetails? — อาจเป็น null ถ้า connector ไม่ populateif (u is not null) Console.WriteLine( $"เทิร์นนี้ → เข้า {u.InputTokenCount} · ออก {u.OutputTokenCount} · รวม {u.TotalTokenCount}");เรียกวนไปทุกเทิร์น คุณจะเห็น InputTokenCount โตขึ้นต่อเนื่อง ทั้งที่คำถามของลูกค้าในแต่ละเทิร์นสั้นพอๆ กัน — เพราะประวัติกับผลของ tool ที่สะสม (สองแหล่งสีส้มในไดอะแกรม) ถูกส่งซ้ำเข้าไปทั้งกองทุกครั้ง นั่นคืองบที่ถูกกินขึ้นต่อเนื่อง ต่อหน้าต่อตา
ChatResponse.Usage เป็น UsageDetails? — ค่ามันจะมีก็ต่อเมื่อ connector ของ Anthropic เป็นคน populate ให้ (Claude ยังอยู่หลัง NuGet Anthropic (beta) ผ่าน AsIChatClient ตาม invariant #6 ของ #15 ไม่มี connector first-party ของ Microsoft) ก่อนพึ่งตัวเลขนี้ ให้ยิงจริงหนึ่งครั้งแล้วเช็กว่า Usage, InputTokenCount, OutputTokenCount ไม่เป็น null กับ version package ที่คุณติดตั้งอยู่ ถ้าเป็น null ให้ถือ block usage ของ Messages API ดิบเป็นแหล่งความจริง — input_tokens (บวก cache_creation_input_tokens / cache_read_input_tokens ถ้าใช้ prompt caching) และ output_tokens ตามที่ #15 บทที่ 2 สอนอ่านมาแล้ว
ถ้าอยากรู้ต้นทุน token ของข้อความ ก่อน ยิงจริง (เช่นเพื่อเช็กว่าจะชนเพดานไหมก่อนส่ง) Messages API มี endpoint POST /v1/messages/count_tokens ให้นับล่วงหน้าได้ และข้อควรระวังจาก #15 ยังใช้: อย่าเดา token ของ Claude ด้วย tiktoken ของ OpenAI เพราะคนละ tokenizer นับต่ำกว่าจริงราว 15–20%
อ่านงบแล้วทำอะไรต่อ
หัวข้อที่มีชื่อว่า “อ่านงบแล้วทำอะไรต่อ”พอมีตัวเลข การจัดงบก็กลายเป็นการตัดสินใจที่เห็นภาพ ไม่ใช่เดา ลองไล่ดูว่า token ที่ใช้ไปประกอบด้วยอะไร แล้วถามว่าอันไหน สัญญาณต่ำ — คือกินงบแต่ไม่ช่วยเทิร์นถัดไป ตัวที่มักโผล่มาอันดับแรกคือ record ออเดอร์ดิบๆ ก้อนเต็มจาก getOrder เทิร์นเก่าๆ ที่ agent อ่านไปแล้ว ตัดสินใจไปแล้ว แต่ยังลอยอยู่ในประวัติ กิน token ทุกเทิร์นถัดจากนั้นโดยไม่ให้อะไรกลับมา นั่นคือเป้าแรกที่ตัด — งานของบทที่ 6 (ปั้นสิ่งที่ tool คืนกลับให้เหลือแต่ field ที่ใช้) และบทที่ 5 (สรุปประวัติที่ยาวแล้วเคลียร์ผลของ tool ที่จัดการไปแล้ว)
แต่ระวังอย่าแกว่งไปสุดอีกทาง เป้าหมายไม่ใช่ “ตัดให้เหลือน้อยที่สุด” เฉยๆ — ดาวเหนือของบทที่ 1 คือ token ที่ สัญญาณสูง ชุดที่เล็กที่สุด ไม่ใช่แค่เล็กที่สุด Chip Huyen เตือนอีกด้านไว้ว่า “The more relevant information there is in the context, the less the model has to rely on its internal knowledge, which can be unreliable…” และ “having access to relevant information in the context can help the model generate more detailed responses while reducing hallucinations.” — ข้อมูล ที่เกี่ยวข้อง ในหน้าต่างช่วยลด hallucination ได้ ฉะนั้นสิ่งที่เราไล่ตัดคือ token สัญญาณต่ำ ไม่ใช่ตัดข้อมูลที่เกี่ยวข้องทิ้งเพื่อประหยัดตัวเลข
งบที่คุณวัดได้ในบทนี้คือ ตัวกระตุ้น ของสองบทถัดไป — พอ InputTokenCount ข้ามเกณฑ์ที่ตั้งไว้ compaction (บทที่ 5) จะสรุปประวัติให้กระชับลง และ การจัดระเบียบผลของ tool (บทที่ 6) จะลดขนาดสิ่งที่ tool คืนกลับตั้งแต่ต้นทาง ทั้งคู่วัดผลได้จาก field usage ตัวเดียวกับที่บทนี้สอนอ่าน
จบบทนี้คุณเปลี่ยนจากคน “หวังว่าคงยังไม่ล้น” มาเป็นคนที่ เห็นงบเป็นตัวเลข ทุกเทิร์น รู้ว่า token ก้อนไหนโตเร็ว ก้อนไหนสัญญาณต่ำควรตัดก่อน และรู้ว่าเพดานคือข้อจำกัด ไม่ใช่เป้า บทหน้าเราเริ่มลงมือลดงบก้อนนั้นจริงๆ ด้วย compaction
บทนี้อิงต้นทางที่ลงวันที่กำกับ อ่านต่อได้โดยตรง:
- Anthropic, “Effective context engineering for AI agents” (2025-09-29) — context ในฐานะทรัพยากรจำกัดที่ผลตอบแทนลดลง (“Every new token introduced depletes this budget…” / “finite resource with diminishing marginal returns”)
- Chroma Research, “Context Rot: How Increasing Input Tokens Impacts LLM Performance” (2025-07-14) — model ไม่ได้ประมวลผล context อย่างสม่ำเสมอ ความน่าเชื่อถือเสื่อมลงเมื่อ input ยาวขึ้น (สอนเป็นหลักการ ไม่อ้างเปอร์เซ็นต์เจาะจง)
- Liu et al., “Lost in the Middle: How Language Models Use Long Contexts” (arXiv 2023-07-06; TACL 2024) — ประสิทธิภาพสูงสุดเมื่อข้อมูลที่เกี่ยวข้องอยู่ต้นหรือท้ายหน้าต่าง และเสื่อมเมื่อถูกฝังกลาง
- Chip Huyen, “Building A Generative AI Platform” (2024-07-25) — ข้อมูลที่เกี่ยวข้องในหน้าต่างช่วยลดการพึ่งความรู้ภายในที่ไม่น่าเชื่อถือ และลด hallucination
เช็กความเข้าใจ — บทที่ 4
ข้อ 1 / 3ทำไมจึงควรถือความจุสูงสุดของ context window เป็น 'เพดาน' ไม่ใช่ 'เป้าให้เติมเต็ม'?