การสรุปเอกสารยาวเป็นหนึ่งใน Use Case ที่พบบ่อยที่สุดในการใช้ LLM แต่เมื่อเอกสารมีความยาวหลายหมื่นตัวอักษร การเลือก Strategy ที่เหมาะสมจะส่งผลต่อทั้งคุณภาพผลลัพธ์และต้นทุนอย่างมาก

ในบทความนี้ ผมจะอธิบาย 3 Strategy หลักในการจัดการ Long Document Summarization ได้แก่ Stuff, Map-Reduce และ Refine พร้อมโค้ดตัวอย่างที่พร้อมใช้งานจริง ผ่าน API ของ HolySheep AI ที่รองรับทุก Model ชั้นนำในราคาประหยัดสูงสุด 85%

ทำไมต้องเลือก Strategy ให้ถูกต้อง

จากประสบการณ์การพัฒนา RAG System หลายโปรเจกต์ ผมพบว่าการเลือก Strategy ที่ไม่เหมาะสมนำไปสู่ปัญหาหลายประการ:

3 Strategy หลักในการสรุปเอกสารยาว

1. Stuff Strategy — ยัดทุกอย่างในครั้งเดียว

หลักการ: รวมเอกสารทั้งหมดเข้าไปใน Prompt เดียว เหมาะกับเอกสารที่สามารถใส่ใน Context Window ได้พอดี

ข้อดี: เรียบง่าย รวดเร็ว และ Model สามารถเห็นความเชื่อมโยงข้อมูลทั้งเอกสาร

ข้อเสีย: จำกัดด้วย Context Window ของ Model

import requests

BASE_URL = "https://api.holysheep.ai/v1"

def stuff_summarize(document_text: str, api_key: str) -> str:
    """
    Stuff Strategy: ใส่เอกสารทั้งหมดในครั้งเดียว
    เหมาะกับ: เอกสารสั้น-กลาง ที่ไม่เกิน 128K tokens
    """
    
    prompt = f"""คุณเป็นผู้เชี่ยวชาญในการสรุปเอกสารภาษาไทย
จงสรุปเอกสารต่อไปนี้อย่างกระชับ โดยคร่าว เน้นประเด็นสำคัญ:

เอกสาร

{document_text}

รูปแบบการตอบ

- หัวข้อหลัก: [สรุป 1-2 ประโยค] - ประเด็นสำคัญ: [Bullet points 3-5 ข้อ] - ข้อสรุป: [ประโยคสรุปท้ายสุด] """ response = requests.post( f"{BASE_URL}/chat/completions", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={ "model": "gpt-4.1", "messages": [{"role": "user", "content": prompt}], "temperature": 0.3, "max_tokens": 2000 } ) result = response.json() return result["choices"][0]["message"]["content"]

ตัวอย่างการใช้งาน

with open("report.txt", "r", encoding="utf-8") as f: doc = f.read() summary = stuff_summarize(doc, "YOUR_HOLYSHEEP_API_KEY") print(summary)

2. Map-Reduce Strategy — แบ่งและเอาชนะ

หลักการ: แบ่งเอกสารเป็น Chunk เล็กๆ แต่ละ Chunk สรุปแยกก่อน จากนั้นรวม Summary ทั้งหมดเพื่อสร้างสรุปสุดท้าย

import requests
import tiktoken

BASE_URL = "https://api.holysheep.ai/v1"

def count_tokens(text: str, model: str = "gpt-4.1") -> int:
    """นับจำนวน Token โดยประมาณ"""
    encoding = tiktoken.encoding_for_model("gpt-4")
    return len(encoding.encode(text))

def split_into_chunks(text: str, max_tokens: int = 4000, overlap: int = 200) -> list:
    """
    แบ่งเอกสารเป็น Chunk ตามจำนวน Token
    max_tokens: จำนวน Token สูงสุดต่อ Chunk (เผื่อไว้ 500 token สำหรับ Prompt)
    overlap: จำนวน Token ที่ทับซ้อนกันระหว่าง Chunk
    """
    chunks = []
    content = text.strip()
    
    # คำนวณจำนวนตัวอักษรโดยประมาณ (1 token ≈ 4 ตัวอักษร)
    chars_per_chunk = (max_tokens - 500) * 4
    
    start = 0
    while start < len(content):
        end = start + chars_per_chunk
        
        # หาจุดตัดที่เหมาะสม (ไม่ตัดกลางประโยค)
        if end < len(content):
            # หาจุด space ย้อนกลับไป
            cutoff = content.rfind(' ', start, end)
            if cutoff > start + chars_per_chunk * 0.7:
                end = cutoff
        
        chunk = content[start:end].strip()
        if chunk:
            chunks.append(chunk)
        
        start = end - (overlap * 4)  # ถอยกลับตาม overlap
    
    return chunks

def map_summarize_chunk(chunk: str, chunk_index: int, total: int, api_key: str) -> str:
    """Map Step: สรุปแต่ละ Chunk แยกกัน"""
    
    prompt = f"""คุณเป็นผู้เชี่ยวชาญในการสรุปเอกสาร
นี่คือส่วนที่ {chunk_index + 1} จาก {total} ส่วนของเอกสารฉบับเต็ม
จงสรุปส่วนนี้อย่างกระชับ โดยระบุประเด็นหลักและรายละเอียดสำคัญ:

เนื้อหาส่วนที่ {chunk_index + 1}

{chunk}

รูปแบบการตอบ

สรุปใน 3-5 บรรทัด เน้น: 1. หัวข้อหลักของส่วนนี้ 2. ข้อมูลสำคัญที่ต้องเก็บ 3. ความเชื่อมโยงกับส่วนอื่น (ถ้ามี) """ response = requests.post( f"{BASE_URL}/chat/completions", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={ "model": "deepseek-v3.2", # ใช้ Model ราคาถูกสำหรับ Step นี้ "messages": [{"role": "user", "content": prompt}], "temperature": 0.3, "max_tokens": 500 } ) result = response.json() return result["choices"][0]["message"]["content"] def reduce_final_summary(chunk_summaries: list, original_doc_title: str, api_key: str) -> str: """Reduce Step: รวม Summary ทั้งหมดเป็นสรุปสุดท้าย""" combined_summaries = "\n\n---\n\n".join(chunk_summaries) prompt = f"""คุณเป็นผู้เชี่ยวชาญในการสรุปเอกสารฉบับยาว ด้านล่างคือ Summary จากแต่ละส่วนของเอกสาร โปรดรวมเป็นสรุปเดียวที่สมบูรณ์

ชื่อเอกสาร: {original_doc_title}

Summary จากแต่ละส่วน

{combined_summaries}

รูปแบบการตอบ

สรุปเอกสาร: [ชื่อเอกสาร]

ภาพรวม

[สรุป 2-3 ย่อหน้า]

ประเด็นสำคัญ

- [รายการ 5-7 ข้อ]

ข้อสรุปและความสำคัญ

[ประโยคสรุปท้ายสุด] """ response = requests.post( f"{BASE_URL}/chat/completions", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={ "model": "gpt-4.1", # ใช้ Model ดีที่สุดสำหรับ Step สุดท้าย "messages": [{"role": "user", "content": prompt}], "temperature": 0.3, "max_tokens": 2000 } ) result = response.json() return result["choices"][0]["message"]["content"] def map_reduce_summarize(document_text: str, title: str, api_key: str) -> str: """ Map-Reduce Strategy: แบ่งสรุป แล้วรวม เหมาะกับ: เอกสารยาวมาก หรือหลายเอกสาร """ print(f"📄 เอกสารมี {count_tokens(document_text)} tokens") # Step 1: แบ่งเอกสาร chunks = split_into_chunks(document_text, max_tokens=4000) print(f"✂️ แบ่งเป็น {len(chunks)} ส่วน") # Step 2: Map - สรุปแต่ละ Chunk chunk_summaries = [] for i, chunk in enumerate(chunks): print(f"📝 กำลังสรุปส่วนที่ {i+1}/{len(chunks)}...") summary = map_summarize_chunk(chunk, i, len(chunks), api_key) chunk_summaries.append(summary) # Step 3: Reduce - รวม Summary print(f"🔄 กำลังรวม Summary ทั้งหมด...") final_summary = reduce_final_summary(chunk_summaries, title, api_key) return final_summary

ตัวอย่างการใช้งาน

with open("annual_report_2024.txt", "r", encoding="utf-8") as f: doc = f.read() result = map_reduce_summarize( document_text=doc, title="รายงานประจำปี 2567", api_key="YOUR_HOLYSHEEP_API_KEY" ) print(result)

3. Refine Strategy — ปรับปรุงทีละขั้นตอน

หลักการ: อ่านเอกสารทีละส่วน โดยใช้ Summary ก่อนหน้าเป็นพื้นฐาน แล้วปรับปรุงเพิ่มเติมเรื่อยๆ

import requests

BASE_URL = "https://api.holysheep.ai/v1"

def refine_summarize(document_text: str, api_key: str) -> str:
    """
    Refine Strategy: อ่านทีละส่วน ปรับปรุง Summary ไปเรื่อยๆ
    เหมาะกับ: เอกสารที่มีโครงสร้างชัดเจน ต้องการความต่อเนื่องของข้อมูล
    """
    
    # แบ่งเอกสารเป็นส่วน
    paragraphs = [p.strip() for p in document_text.split('\n\n') if p.strip()]
    
    current_summary = ""
    iteration = 0
    
    for i, paragraph in enumerate(paragraphs):
        iteration += 1
        
        if i == 0:
            # ส่วนแรก: สร้าง Summary เริ่มต้น
            prompt = f"""จากข้อความต่อไปนี้ จงสรุปประเด็นหลักและรายละเอียดสำคัญ:

ข้อความ:
{paragraph}

รูปแบบการตอบ (สรุป 3-5 ประโยค):
"""
        else:
            # ส่วนถัดๆ ไป: ปรับปรุง Summary เดิม
            prompt = f"""คุณกำลังอ่านเอกสารทีละส่วนเพื่อสร้างสรุป

Summary ปัจจุบัน:

{current_summary}

ส่วนใหม่ที่คุณกำลังอ่าน:

{paragraph}

คำสั่ง:

อ่านส่วนใหม่แล้ว ปรับปรุง Summary ข้างบน โดย: 1. เพิ่มประเด็นใหม่ที่สำคัญจากส่วนนี้ 2. ลบข้อมูลที่ไม่เกี่ยวข้องออก (ถ้ามี) 3. เชื่อมโยงข้อมูลเดิมกับข้อมูลใหม่ให้สมบูรณ์ รูปแบบการตอบ (สรุป 3-5 ประโยค): """ print(f"🔄 ปรับปรุง iteration ที่ {iteration}/{len(paragraphs)}...") response = requests.post( f"{BASE_URL}/chat/completions", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={ "model": "gemini-2.5-flash", # เร็วและถูก เหมาะกับงาน iteration "messages": [{"role": "user", "content": prompt}], "temperature": 0.3, "max_tokens": 800 } ) result = response.json() current_summary = result["choices"][0]["message"]["content"] # Final Polish: ปรับแต่งครั้งสุดท้าย final_prompt = f"""จาก Summary ต่อไปนี้ จงปรับแต่งให้กระชับและสมบูรณ์ที่สุด: {current_summary} รูปแบบการตอบ: - หัวข้อหลัก: [1 ประโยค] - สรุป: [3-4 ประโยค] - ประเด็นสำคัญ: [3-5 bullet points] """ response = requests.post( f"{BASE_URL}/chat/completions", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={ "model": "gpt-4.1", "messages": [{"role": "user", "content": final_prompt}], "temperature": 0.3, "max_tokens": 1500 } ) return response.json()["choices"][0]["message"]["content"]

ตัวอย่างการใช้งาน

with open("product_manual.txt", "r", encoding="utf-8") as f: doc = f.read() final_summary = refine_summarize(doc, "YOUR_HOLYSHEEP_API_KEY") print(final_summary)

เปรียบเทียบ Strategy: Stuff vs Map-Reduce vs Refine

เกณฑ์ Stuff Map-Reduce Refine
Context Window จำกัด Model (8K-128K) ไม่จำกัด ไม่จำกัด
ความเร็ว เร็วที่สุด (1 API Call) ปานกลาง (N+1 Calls) ช้าที่สุด (N Calls)
ความสมบูรณ์ สูง (เห็นทั้งเอกสาร) ปานกลาง (อาจขาดความเชื่อมโยง) สูง (อ่านเรียงตามลำดับ)
ต้นทุน (Token) ต่ำ-กลาง ปานกลาง-สูง สูง
เอกสารที่เหมาะสม สั้น-กลาง (<50K tokens) ยาวมาก / หลายเอกสาร มีโครงสร้างชัดเจน
Use Case เหมาะสม Email, บทความเดี่ยว รายงานปี, เอกสารทางกฎหมาย คู่มือ, เอกสารเทคนิค

การเลือก Model ที่เหมาะสมสำหรับแต่ละ Strategy

จากราคา 2026 ของ HolySheep AI ผมแนะนำการจับคู่ดังนี้:

# ตารางเปรียบเทียบราคา Model ต่อ Million Tokens (2026)

MODELS = {
    "deepseek-v3.2": {
        "price_per_mtok": 0.42,  # ถูกที่สุด
        "best_for": ["Map Step", "Refine Iteration", "Draft"]
    },
    "gemini-2.5-flash": {
        "price_per_mtok": 2.50,
        "best_for": ["Refine Step", "Quick Summary", "Batch Processing"]
    },
    "gpt-4.1": {
        "price_per_mtok": 8.00,
        "best_for": ["Final Summary", "Complex Analysis", "Stuff Strategy"]
    },
    "claude-sonnet-4.5": {
        "price_per_mtok": 15.00,
        "best_for": ["High-Quality Summary", "Long Context", "Critical Docs"]
    }
}

def calculate_cost(strategy: str, doc_tokens: int, use_holysheep: bool = True) -> dict:
    """
    คำนวณต้นทุนโดยประมาณสำหรับแต่ละ Strategy
    use_holysheep: True = ใช้ HolySheep (ประหยัด 85%+), False = OpenAI
    """
    
    # สมมติฐาน
    overhead_prompt_tokens = 200  # Token สำหรับ System Prompt
    
    if strategy == "stuff":
        # 1 API Call
        total_tokens = doc_tokens + overhead_prompt_tokens
        model = "gpt-4.1"
        cost = (total_tokens / 1_000_000) * MODELS[model]["price_per_mtok"]
        
    elif strategy == "map_reduce":
        # N Chunks + 1 Final
        chunk_size = 4000
        n_chunks = (doc_tokens // chunk_size) + 1
        
        # Map Step: ใช้ DeepSeek (ถูก)
        map_tokens = n_chunks * (chunk_size + overhead_prompt_tokens)
        map_cost = (map_tokens / 1_000_000) * MODELS["deepseek-v3.2"]["price_per_mtok"]
        
        # Reduce Step: ใช้ GPT-4.1 (ดี)
        reduce_tokens = n_chunks * 500 + overhead_prompt_tokens
        reduce_cost = (reduce_tokens / 1_000_000) * MODELS["gpt-4.1"]["price_per_mtok"]
        
        total_tokens = map_tokens + reduce_tokens
        cost = map_cost + reduce_cost
        
    elif strategy == "refine":
        # N Paragraphs + 1 Final
        n_paragraphs = max(1, doc_tokens // 1000)
        
        # Iteration: ใช้ Gemini Flash (เร็ว+ถูก)
        iter_tokens = n_paragraphs * 1000 + overhead_prompt_tokens
        iter_cost = (iter_tokens / 1_000_000) * MODELS["gemini-2.5-flash"]["price_per_mtok"]
        
        # Final: ใช้ GPT-4.1
        final_tokens = 800 + overhead_prompt_tokens
        final_cost = (final_tokens / 1_000_000) * MODELS["gpt-4.1"]["price_per_mtok"]
        
        total_tokens = iter_tokens + final_tokens
        cost = iter_cost + final_cost
    
    # ถ้าใช้ OpenAI โดยตรง คูณ 7 เท่า (ประหยัด ~85%)
    if not use_holysheep:
        cost *= 7
    
    return {
        "strategy": strategy,
        "document_tokens": doc_tokens,
        "total_tokens": total_tokens,
        "cost_usd": round(cost, 4),
        "cost_thb": round(cost * 35, 2),  # ประมาณ 35 บาท/USD
        "savings_vs_openai": round(cost * 6, 4) if use_holysheep else 0
    }

ตัวอย่าง: เอกสาร 50,000 tokens

for strategy in ["stuff", "map_reduce", "refine"]: result = calculate_cost(strategy, 50000, use_holysheep=True) print(f"Strategy: {result['strategy']}") print(f" Total Tokens: {result['total_tokens']:,}") print(f" ราคา HolySheep: ฿{result['cost_thb']:.2f}") print(f" ประหยัด vs OpenAI: ฿{result['savings_vs_openai']*35:.2f}") print()

ข้อผิดพลาดที่พบบ่อยและวิธีแก้ไข

กรณีที่ 1: Context Overflow - เอกสารใหญ่เกิน Context Window

# ❌ วิธีผิด: พยายามยัดเอกสารทั้งหมดในครั้งเดียว
def bad_stuff_summarize(document):
    prompt = f"สรุปเอกสารนี้: {document}"  # อาจเกิน limit!
    return call_llm(prompt)

✅ วิธีถูก: ตรวจสอบขนาดก่อน แล้วเลือก Strategy

def smart_summarize(document: str, api_key: str) -> str: """ เลือก Strategy อัตโนมัติตามขนาดเอกสาร """ from tiktoken import Encoding encoding = tiktoken.encoding_for_model("gpt-4") tokens = len(encoding.encode(document)) if tokens <= 8000: # Context เพียงพอ ใช้ Stuff print(f"📄 {tokens} tokens — ใช้ Stuff Strategy") return stuff_summarize(document, api_key) elif tokens <= 50000: # ปานกลาง ใช้ Map-Reduce print(f"📄 {tokens} tokens — ใช้ Map-Reduce Strategy") return map_reduce_summarize(document, "Document", api_key) else: # ยาวมาก ใช้ Map-Reduce หรือ Refine print(f"📄 {tokens} tokens — ใช้ Map-Reduce Strategy (Extended)") # แบ่ง Chunk ให้เล็กลง chunks = split_into_chunks(document, max_tokens=2000) # สรุปแต่ละ Chunk ด้วย Model ราคาถูก summaries = [] for i, chunk in enumerate(chunks): summary = map_summarize_chunk(chunk, i, len(chunks), api_key) summaries.append(summary) # รวม Summary ด้วย GPT-4.1 return reduce_final_summary(summaries, "Document", api_key)

กรณีที่