บทความ › AI

Context rot: ยิ่งใส่ข้อมูลให้ AI ยาว ยิ่งตอบพลาด แล้วควรใส่อะไรใน context

งานวิจัยของ Chroma ทดสอบ 18 โมเดล พบว่าคุณภาพคำตอบลดลงเมื่อ input ยาวขึ้น และข้อมูลที่คล้ายแต่ผิดทำให้แย่ลงอีก พร้อมกฎใช้งานจริงว่าควรใส่อะไรใน context

กลาง อ่าน 9 นาที 23 ตุลาคม 2569

อ่านจบแล้วจะรู้
  • context window ใหญ่ไม่ได้แปลว่าโมเดลใช้ทุก token ได้ดีเท่ากัน คุณภาพลดลงเมื่อ input ยาวขึ้น แม้งานจะง่าย
  • ข้อความที่คล้ายคำตอบแต่ไม่ใช่ (distractor) ทำร้ายมากกว่าข้อความที่ไม่เกี่ยวเลย ตัดออกก่อนส่ง
  • ในการทดลอง LongMemEval prompt ที่คัดแล้ว ~300 token ให้ผลดีกว่า prompt เต็ม ~113,000 token ในทุกโมเดล
  • ตั้งงบ token ต่อคำถาม คัดเฉพาะส่วนที่เกี่ยว และเริ่ม session ใหม่เมื่อประวัติแชตยาวเกินงาน

Context rot คืออาการที่โมเดลภาษาตอบแย่ลงเมื่อ input ยาวขึ้น แม้ข้อมูลที่ต้องใช้จะอยู่ใน context ครบ เรื่องนี้สำคัญกับทุกระบบที่โยนเอกสาร ประวัติแชต หรือผลจากเครื่องมือให้ AI เพราะความเชื่อว่า “ใส่ไปเยอะ ๆ เดี๋ยวมันหาเอง” ใช้ไม่ได้จริง

ตรวจข้อเท็จจริงกับรายงาน Context Rot ของ Chroma (กรกฎาคม 2025) และ repo ของงาน ณ ตุลาคม 2026 โค้ดตัวอย่างทดสอบบน Python 3.12

งานวิจัยนี้วัดอะไร

Chroma ออกรายงาน Context Rot: How Increasing Input Tokens Impacts LLM Performance เมื่อ 14 กรกฎาคม 2025 ทดสอบ 18 โมเดล จาก 4 ค่าย: Anthropic 5 ตัว (Claude Opus 4, Sonnet 4, Sonnet 3.7, Sonnet 3.5, Haiku 3.5), OpenAI 7 ตัว (o3, GPT-4.1 และรุ่น mini/nano, GPT-4o, GPT-4 Turbo, GPT-3.5 Turbo), Google 3 ตัว (Gemini 2.5 Pro, 2.5 Flash, 2.0 Flash) และ Qwen3 3 ขนาด

จุดที่ต่างจาก benchmark “needle in a haystack” แบบเดิม คือเขาไม่ได้ซ่อนคำตอบที่ตรงตัวอักษรกับคำถาม แต่ทำให้งานใกล้ของจริงขึ้น แล้วคุมให้ความยากของงานคงที่ เปลี่ยนแค่ความยาว input ถ้าผลตก แปลว่าตกเพราะความยาว ไม่ใช่เพราะงานยากขึ้น

ผลหลัก 5 ข้อ

การทดลองสิ่งที่เปลี่ยนผล
ความคล้ายคำถามกับคำตอบคำถามที่ใช้คำต่างจากคำตอบมาก (similarity ต่ำ)ยิ่ง input ยาว ผลยิ่งตกเร็วกว่าคู่ที่คล้ายกัน
Distractorใส่ข้อความที่คล้ายคำตอบแต่ไม่ใช่ 0, 1, 4 ชิ้น1 ชิ้นก็ทำให้แย่ลง 4 ชิ้นแย่ลงอีก และแต่ละชิ้นทำร้ายไม่เท่ากัน
โครงสร้างกองข้อมูลเรียงเป็นเรื่องต่อเนื่อง vs สลับประโยคมั่วแบบสลับมั่วกลับได้ผลดีกว่า ในทั้ง 18 โมเดล
LongMemEvalprompt คัดแล้ว ~300 token vs เต็ม ~113,000 tokenทุกโมเดลทำได้ดีกว่ามากเมื่อได้ prompt ที่คัดแล้ว
คัดลอกคำซ้ำให้พิมพ์ลำดับคำซ้ำ ยาว 25 ถึง 10,000 คำผลตกต่อเนื่องเมื่อยาวขึ้น ในทุกโมเดล

ข้อที่สามขัดสัญชาตญาณ ผู้วิจัยเองก็บอกว่ายังอธิบายกลไกไม่ได้ เราจึงไม่ควรตีความเกินว่า “ต้องสลับข้อมูลก่อนส่ง” สิ่งที่ควรจำคือ โมเดลไม่ได้อ่าน context แบบสม่ำเสมอทุก token

พฤติกรรมต่างกันตามค่ายด้วย เมื่อเจอ distractor โมเดล Claude มีอัตราตอบมั่ว (hallucination) ต่ำสุด และมักเลือกไม่ตอบเมื่อไม่แน่ใจ ส่วน GPT มีอัตราตอบมั่วสูงสุด มักตอบผิดอย่างมั่นใจ ระบบที่ต้องการความแม่นจึงต้องรับมือได้ทั้งสองแบบ คือคำตอบ “ไม่ทราบ” และคำตอบผิดที่ฟังดูถูก

context window บอกว่าใส่ได้เท่าไร ไม่ได้บอกว่าโมเดลใช้ได้ดีแค่ไหน

prompt เต็มทั้งแชต~113,000 tokenprompt ที่คัดแล้ว~300 tokenLongMemEval: ทุกโมเดลตอบดีกว่าเมื่อ prompt สั้นลง
ทุกโมเดลตอบได้ดีกว่าเมื่อได้ prompt ที่สั้นกว่า 377 เท่า

ตัวอย่างคำนวณ: แชตยาว 40 รอบ

ข้อมูลจาก LongMemEval ก่อน: prompt เต็มเฉลี่ย ~113,000 token ส่วนที่คัดแล้วเฉลี่ย ~300 token

  • 113,000 ÷ 300 ≈ 377 เท่า
  • แปลว่า prompt เต็มมีส่วนที่เกี่ยวกับคำถามประมาณ 300 ÷ 113,000 ≈ 0.27% ที่เหลือคือสิ่งที่โมเดลต้องฝ่าไปเอง

ลองเทียบกับงานจริงแบบสมมติ ผู้ช่วย AI ที่คุยกับลูกค้ามา 40 รอบ รอบละประมาณ 2,500 token (รวมคำตอบและผลจากเครื่องมือ)

  1. ประวัติทั้งหมด = 40 × 2,500 = 100,000 token
  2. คำถามล่าสุดต้องใช้ข้อมูลจริงแค่ 2 รอบ = 2 × 2,500 = 5,000 token
  3. ส่วนที่เกี่ยวคิดเป็น 5,000 ÷ 100,000 = 5% อีก 95% เป็นเสียงรบกวน และบางส่วนเป็น distractor ตัวจริง เช่น ที่อยู่จัดส่งเก่าที่ลูกค้าแก้ไปแล้ว

ถ้าส่งเฉพาะสรุปประวัติ 500 token บวก 2 รอบที่เกี่ยว รวม 5,500 token input ลดลง 1 − 5,500 ÷ 100,000 = 94.5% ได้ทั้งคำตอบที่แม่นขึ้น ถูกลง และเร็วขึ้น (ตัวเลขชุดนี้เป็นตัวอย่างสมมติเพื่อคิดตาม ไม่ได้มาจากงานวิจัย)

กฎใช้งาน: ควรใส่อะไรใน context

1. ตั้งงบ token ต่อคำถาม แล้วคัดให้พอดีงบ แทนที่จะใส่จนเต็ม window Anthropic สรุปหลักนี้ไว้ในบทความ context engineering ว่าให้หา “ชุด token ที่เล็กที่สุดแต่มีสัญญาณสูงสุด”

2. ตัด distractor ก่อนตัดสิ่งที่ไม่เกี่ยว ของที่อันตรายที่สุดคือของที่ดูเหมือนคำตอบ: เอกสารฉบับเก่า, record ของลูกค้าชื่อคล้ายกัน, config ของ staging ปนกับ production ถ้าระบบมี version ให้ส่งเฉพาะฉบับล่าสุด

3. คัดก่อนส่ง ไม่ใช่ส่งทั้งกอง ระบบ RAG ควรตั้งเกณฑ์คะแนนขั้นต่ำ ไม่ใช่ดึง top-k แล้วส่งทั้งหมดเสมอ

4. แยกงานยาวออกเป็นห้อง ให้ subagent ไปอ่านของเยอะในห้องตัวเอง แล้วส่งกลับแค่สรุป Anthropic บอกว่าสรุปแบบนี้มัก 1,000-2,000 token ทั้งที่ subagent อาจใช้ไปหลายหมื่น

5. เริ่ม session ใหม่เมื่องานเปลี่ยน แทนการลากแชตเดิมยาวไปเรื่อย ๆ จดสิ่งที่ต้องส่งต่อลงไฟล์ แบบใน บทเรื่องไฟล์ส่งงานข้าม session

6. ล้างผลจากเครื่องมือที่ใช้เสร็จแล้ว ผล grep หรือ log ยาว ๆ จากสิบรอบก่อนแทบไม่มีใครกลับไปใช้ แต่ยังกิน context อยู่

โค้ด: คัด chunk ให้พอดีงบ

ตัวอย่างนี้ใช้ stdlib ล้วน รับ chunk ที่ได้จากการค้นพร้อมคะแนน ตัดตัวที่คะแนนต่ำ ตัดตัวที่เกือบซ้ำกัน (มักเป็นเอกสารฉบับเก่าของเรื่องเดียวกัน) แล้วหยิบจนเต็มงบ

from difflib import SequenceMatcher

def pick_context(chunks, count, budget=2000, min_score=0.5, dup_ratio=0.9):
    """chunks: (score, text) pairs from retrieval; count: your tokenizer's counter."""
    picked, used = [], 0
    for score, text in sorted(chunks, reverse=True):
        if score < min_score:
            break                                   # the rest are noise and distractors
        if any(SequenceMatcher(None, text, p).ratio() > dup_ratio for p in picked):
            continue                                # near-copy, e.g. an old version of the same doc
        cost = count(text)
        if used + cost > budget:
            continue                                # over budget: leave it out
        picked.append(text)
        used += cost
    return picked, used

chunks = [
    (0.91, "Refund policy v3 (2026): refunds within 14 days of delivery."),
    (0.89, "Refund policy v3 (2026): refunds within 14 days of delivery!"),
    (0.74, "Shipping takes 2-4 business days inside Thailand."),
    (0.41, "Company picnic is on Friday."),
]
words = lambda t: len(t.split())                    # stand-in counter for the demo
picked, used = pick_context(chunks, words, budget=50)
print(len(picked), used)   # 2 17

ผลคือเหลือ 2 chunk: นโยบายคืนเงินหนึ่งชิ้น (ตัวซ้ำถูกตัด) กับเรื่องจัดส่ง ส่วนเรื่องปิกนิกคะแนนต่ำกว่าเกณฑ์ ในระบบจริงให้ส่งตัวนับ token ของโมเดลที่ใช้เข้าไปแทน words เพราะภาษาไทยใช้ token ต่อคำต่างจากภาษาอังกฤษมาก

difflib จับได้แค่ข้อความที่หน้าตาเกือบเหมือนกัน distractor ที่ความหมายคล้ายแต่คำต่างกัน ต้องแก้ที่ต้นทาง คือเก็บ metadata อย่าง version, วันที่, สถานะ แล้วกรองก่อนค้น

ข้อผิดพลาดที่เจอบ่อย

  • เชื่อตัวเลข context window แล้วยัดเอกสารทั้งโฟลเดอร์ เพราะ “มันรับได้” รับได้ไม่เท่ากับใช้ได้ดี
  • ทดสอบด้วยงานหาคำตรงตัว แล้วสรุปว่าโมเดลอ่าน context ยาวได้ดี งานจริงคำถามกับคำตอบมักใช้คำต่างกัน และงานแบบนั้นตกเร็วกว่า
  • เก็บเอกสารทุกฉบับไว้ในคลังเดียว แล้วปล่อยให้ค้นเจอทั้งฉบับเก่าและใหม่ นี่คือการผลิต distractor เอง
  • ลากแชตเดียวทั้งวัน ข้ามหลายงาน ทุกคำถามใหม่ต้องฝ่าประวัติทั้งหมด
  • วัดผลที่ความยาวสั้น แล้วไปใช้ที่ความยาวจริง ถ้าระบบจริงส่ง 50,000 token ต้องทดสอบที่ 50,000 token repo ของ Chroma มีโค้ดให้รันซ้ำกับโมเดลของเราเอง

ก่อนเพิ่มข้อมูลเข้า context ถามว่า ชิ้นนี้ช่วยตอบคำถามนี้ หรือแค่ทำให้รู้สึกปลอดภัยว่าใส่ครบ

แหล่งอ้างอิง

คำถามที่พบบ่อย

โมเดลรองรับ 1 ล้าน token แล้ว ยังต้องคัดข้อมูลอยู่ไหม

ต้อง ตัวเลข context window บอกว่าใส่ได้เท่าไร ไม่ได้บอกว่าใช้ได้ดีแค่ไหน งานของ Chroma พบว่าทุกโมเดลที่ทดสอบตอบแย่ลงเมื่อ input ยาวขึ้น และ input ยาวยังแพงกับช้ากว่าด้วย

วางคำถามไว้ต้นหรือท้าย context ดีกว่า

งานนี้ไม่พบผลชัดเจนจากตำแหน่งของข้อมูลที่ต้องหา (needle position) สิ่งที่มีผลชัดกว่าคือความยาวรวม ความคล้ายระหว่างคำถามกับคำตอบ และ distractor จึงควรลงแรงกับการคัดข้อมูลก่อนเรื่องตำแหน่ง

ผลนี้ใช้กับโมเดลรุ่นใหม่กว่าที่ทดสอบได้ไหม

งานทดสอบโมเดลกลางปี 2025 รุ่นใหม่อาจดีขึ้น แต่ควรวัดกับงานของเราเองที่ความยาวจริง repo ของงานวิจัยเปิดให้รันซ้ำได้

คำสั่งและค่าตั้งในบทความทดสอบบนระบบตัวอย่าง ลองบนเครื่องทดสอบก่อนใช้กับระบบจริงเสมอ

อ่านต่อ

#AIขั้นสูง

CaMeL: กัน prompt injection ด้วยการออกแบบระบบ ไม่ใช่ด้วย prompt ที่ดีกว่า

งานวิจัย CaMeL จาก Google DeepMind แยก control flow ออกจากข้อมูลที่ไม่น่าเชื่อถือ ติดป้าย capability ให้ทุกค่า แล้วตรวจ policy ตอนเรียก tool ผลบน AgentDojo และข้อจำกัด

อ่าน 8 นาที
#AIกลาง

RAG คืออะไร: ให้ AI ตอบจาก เอกสาร ของเราเอง ตั้งแต่ chunk จนถึง vector DB

ทำไม LLM ไม่รู้จักไฟล์ของเรา pipeline ของ RAG ทีละขั้น การตัด chunk เลือก embedding ให้เหมาะกับไทย Qdrant กับทางเลือกที่เบากว่า ทำไมคำตอบพลาด และวัดยังไง พร้อมโค้ด Python

อ่าน 14 นาที
#AIกลาง

Prompt injection: เมื่อ AI อ่านข้อความจากข้างนอก แล้วข้อความนั้นสั่งงาน AI ได้

AI ที่อ่านเว็บ อีเมล หรือเอกสาร อาจเจอข้อความที่ซ่อนคำสั่งไว้ อธิบายว่าเกิดยังไง ทำไมกันด้วยการเขียน prompt อย่างเดียวไม่พอ และวิธีออกแบบหลายชั้นจากมุมคนสร้างระบบ

อ่าน 6 นาที