TH ▾
รับคีย์ API

บริบทยาว 100k: ต่อเนื่อง, สรุป, แบ่งส่วน, งบประมาณ

บริบท 100,000 token ดูเยอะ แต่จริงแล้วใส่ novel ยาวหรือเอกสารหลายสิบหน้าพร้อม output ไม่หมด คู่มือนี้จัดการบริบทเป็นงบประมาณ: ประมาณ token, จองพื้นที่ output, สรุปเอกสาร, และใช้ sliding window พร้อม outline ต่อ novel โค้ด Python ใช้ได้ทุกภาษา

อัปเดต

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

  • 100,000 คือผลรวมของ prompt และ completion ไม่ใช่ขีดจำกัด input อย่างเดียว
  • จำนวน token ภาษาจีนประมาณได้ ประมาณ 1 ถึง 1.5 token ต่อตัวอักษร โดยอ้างอิง usage ในการตอบกลับเป็นสุดท้าย
  • สรุปเอกสารยาวใช้การแบ่งส่วนและรวม ต่อเนื่อง novel ใช้บทล่าสุดและ outline แบบเลื่อน
  • max_tokens ค่าเริ่มต้น 2048 สูงสุด 16,000 คำนวณงบประมาณก่อนตั้งค่า

คำนวณขีดจำกัดให้ชัดเจน

สามตัวเลขที่กำหนดทุกอย่าง:

  • ปริมาณบริบท 100,000 token, prompt และ completion รวมกัน
  • max_tokens ค่าเริ่มต้น 2048, ต่อคำขอสูงสุด 16,000
  • request body ไม่เกิน 8 MB ขีดจำกัดนี้ไม่ค่อยถึงจริง จุดที่ถึงก่อนคือ token

สูตรงบประมาณง่ายมาก: prompt ที่ใช้ได้ = 100000 - max_tokens. ถ้าต้องการ output 4000 token, prompt เหลือแค่ 60,000. ถ้าเกิน API จะตอบกลับ 400, ไม่ตัดให้เอง ดังนั้นการยัดทั้งเล่มเข้าไปไม่ใช่กลยุทธ์ แต่เป็นการเสี่ยง

ความเข้าใจผิดอีกอย่าง: max_tokens ยิ่งมากยิ่งปลอดภัย มันคือพื้นที่ output ที่จองไว้ ตั้ง 16,000 หมายถึง prompt เหลือ 48,000 ตั้งตามต้องการ

ตัวอย่าง: สรุปบทสัมภาษณ์ 300,000 คำ ประมาณการ 1.3 token ต่อคำ รวม 390,000 token เกินหกเท่า ไม่สามารถส่งทั้งฉบับได้ ถ้าต้องการ output 800 token ต่อครั้ง input สูงสุด 63,000 เหลือพื้นที่ 10% เหลือประมาณ 50,000 แต่ไม่ใช่วิธีที่ดีที่สุด เมื่อ block ใหญ่เกินไป ความสนใจในเนื้อหาตรงกลางจะลดลง วิธีที่ดีกว่าคือแบ่ง block เล็กลง

ประมาณการ token: อัลกอริทึมโดยประมาณ

เมื่อไม่มี local tokenizer ให้ใช้ค่าประมาณด้านล่าง เป็นค่าประมาณ ไม่ใช่ค่าที่แม่นยำ ความแตกต่างของข้อความต่างกันอาจถึง 10-20%:

ประเภทข้อความการแปลงประมาณการ
เนื้อหาภาษาจีนประมาณ 1 ถึง 1.5 token ต่อคำ
ภาษาอังกฤษประมาณ 1 token ต่อ 4 ตัวอักษร หรือ 1.3 token ต่อคำ
โค้ด, JSON, ข้อความที่มีสัญลักษณ์หนาแน่นใช้ token มากกว่าข้อความทั่วไป แนะนำให้ประมาณการด้วยค่าสูงที่ระมัดระวัง

ฟังก์ชันประมาณการที่ใช้งานได้พร้อมคำนวณงบประมาณโดยสำรองพื้นที่:

CONTEXT = 100000

def est_tokens(text: str) -> int:
    """粗估:中文按每字 1.3 token,其余字符按每 4 个字符 1 token。仅为近似。"""
    zh = sum(1 for c in text if "\u4e00" <= c <= "\u9fff")
    other = len(text) - zh
    return int(zh * 1.3 + other / 4) + 1

def max_prompt_budget(max_tokens: int, margin: float = 0.1) -> int:
    """给定计划的 max_tokens,返回 prompt 最多能用多少 token(留 margin 余量)。"""
    return int((CONTEXT - max_tokens) * (1 - margin))

# 例:计划让模型写 3000 token,prompt 预算
print(max_prompt_budget(3000))   # 54900

วิธีปรับเทียบ: ส่ง input ตัวอย่างหนึ่งครั้ง อ่าน usage.prompt_tokens ใน response เปรียบเทียบกับค่าประมาณของคุณ เพื่อหาอัตราส่วนจริง แล้วปรับค่าประมาณ ใช้เพื่อตัดสินใจ "แบ่งส่วนหรือไม่" ไม่ใช่เพื่อตรวจสอบยอด

สรุปเอกสารยาว: แบ่งส่วนและรวม

เมื่อเอกสารเกินงบประมาณ วิธีมาตรฐานคือ map-reduce: แบ่งส่วนสรุปแต่ละส่วน แล้วรวมสรุปเป็นภาพรวม ระวังรายละเอียดต่อไปนี้:

  1. ตัดตามขอบเขตย่อหน้า อย่าตัดตามจำนวนคำตายตัว มิฉะนั้นจะตัดประโยคขาด
  2. แบ่งงบประมาณให้พอ โดยไม่เกิน 1 ใน 3 ของขีดจำกัด เพื่อเหลือพื้นที่สำหรับพรอมต์และ output
  3. สรุปส่วนต้องคงชื่อคน ตัวเลข เหตุการณ์สำคัญ มิฉะนั้นข้อมูลจะหายเมื่อรวม
  4. หากการสรุปแบบซ้อนยังยาวเกินไป ให้ทำซ้ำอีกชั้น
import os
from openai import OpenAI

client = OpenAI(base_url="https://api.wushenchaapi.com/v1", api_key=os.environ["API_KEY"])

def split_paragraphs(text, budget):
    """按段落切块,每块估算不超过 budget token。"""
    chunks, cur, used = [], [], 0
    for p in text.split("\n"):
        t = int(len(p) * 1.3) + 1          # 中文粗估
        if used + t > budget and cur:
            chunks.append("\n".join(cur))
            cur, used = [], 0
        cur.append(p)
        used += t
    if cur:
        chunks.append("\n".join(cur))
    return chunks

def ask(prompt, max_tokens=800):
    r = client.chat.completions.create(
        model="uncensored",
        temperature=0.3,
        max_tokens=max_tokens,
        messages=[{"role": "user", "content": prompt}],
    )
    return r.choices[0].message.content

def summarize_long(text, budget=12000):
    parts = split_paragraphs(text, budget)
    partial = [ask("用不超过 200 字概括下面这段,保留人名和关键事件:\n\n" + p) for p in parts]
    merged = "\n".join(f"第{i+1}部分:{s}" for i, s in enumerate(partial))
    return ask("下面是分段摘要,请合并成一份 400 字以内的整体摘要:\n\n" + merged, max_tokens=900)

ตั้งค่า temperature เป็น 0.3 เพื่อความเสถียรของการสรุป แต่ละบล็อกทำงานอิสระกัน สามารถเรียกแบบ parallel ได้ แต่ระวังขีดจำกัด 300 requests ต่อนาทีต่อ key เอกสารหลายสิบบล็อกไม่กระทบขีดจำกัดนี้

ขนาดบล็อกไม่มีคำตอบมาตรฐาน ประสบการณ์แนะนำบล็อกละ 10,000 ถึง 15,000 token เพื่อรักษาความละเอียดและจำนวนการเรียก ลองใช้บล็อกขนาด 5000, 12000, 25000 กับเอกสารตัวอย่าง แล้วเปรียบเทียบจำนวนข้อเท็จจริงสำคัญที่หายไป เพื่อเลือกขนาดที่เหมาะสม เอกสารที่มีความหนาแน่นข้อมูลสูงเช่น สัญญาหรือเอกสารเทคนิค ควรใช้บล็อกเล็กลง ส่วนบันทึกการสนทนาที่มีความซ้ำซ้อน สามารถใช้บล็อกใหญ่ขึ้นได้

การต่อ novel: ใช้ sliding window และ outline

เมื่อเขียนถึงสิบกว่าบท เนื้อหาทั้งหมดไม่สามารถใส่ได้และไม่จำเป็นต้องใส่ทั้งหมด แนวคิดคือ memory สองชั้น:

  • ช่วงล่าสุด:ต้นฉบับ 2-3 บทล่าสุด เพื่อรักษาสไตล์ บทสนทนา และรายละเอียดฉาก
  • ช่วงก่อนหน้า:บทเก่าบีบเป็น outline เก็บความสัมพันธ์ตัวละคร เบื้องลึก และปมที่ยังไม่คลี่คลาย

หลังจากเขียนจบหนึ่งบท ให้โมเดลสรุปบทนั้นเป็นสามถึงห้าบรรทัดเพิ่มเข้าไปใน outline เมื่อ outline เกิน 3000 token ให้บีบ outline ทั้งหมดอีกครั้ง

def continue_story(chapters, outline, new_hint, keep_last=3):
    """chapters: 已写章节列表。只带最近 keep_last 章原文,更早的用 outline(滚动大纲)代替。"""
    recent = "\n\n".join(chapters[-keep_last:])
    prompt = (
        f"【全书大纲(早期章节摘要)】\n{outline}\n\n"
        f"【最近章节原文】\n{recent}\n\n"
        f"【下一章要求】\n{new_hint}\n\n请写下一章,约 2000 字。"
    )
    return ask(prompt, max_tokens=4000)

ปมที่รอเฉลยเป็นสิ่งที่หลุดง่ายที่สุด แนะนำให้แยกหมวด "ปมที่ยังไม่ถูกแก้" ใน outline และกำหนดให้แก้หนึ่งในนั้นในแต่ละบท พร้อมระบุชื่อตัวละครและสถานที่ใน system prompt เพื่อป้องกันโมเดลเปลี่ยนชื่อเมื่อหลุดหน้าต่างบริบท

อีกปัญหาที่มักถูกละเลยในการต่อเรื่อง: การเบี่ยงเบนของสไตล์ โมเดลจะเขียนเข้าใกล้สไตล์ของบทล่าสุดมากขึ้น หากสไตล์ของบทก่อนหน้าไม่สอดคล้องกับบทหลัง จะยิ่งขยายตัว วิธีแก้ไขคือเขียน "ตัวอย่างสไตล์" ใน system โดยเลือกต้นฉบับที่คุณพอใจที่สุดใส่เข้าไป เป็น anchor คงที่ที่ไม่เลื่อนตาม window

max_tokens และการตัด

การตอบถูกตัดมีสองกรณีที่ต้องแยกแยะ:

  1. finish_reason เป็น length: หมายถึงชน max_tokens ที่คุณตั้งค่าไว้ วิธีแก้คือเพิ่ม max_tokens หรือให้โมเดลเขียนแบบแบ่งส่วน "เขียนถึงตรงนี้หยุดก่อน รอคำสั่งต่อค่อยเขียนต่อ"
  2. คำขอตอบกลับ 400 ทันที: prompt รวม max_tokens เกิน 100,000 วิธีแก้คือลด input หรือลด max_tokens

ตารางเปรียบเทียบงบประมาณที่ใช้งานได้:

งานmax_tokens ที่แนะนำพรอมต์ใช้ได้ (ประมาณ)
สรุป, การสกัด80063,200
เขียนต่อทีละบท (ประมาณ 2,000 คำ)400060,000
การแสดงผลข้อความระดับหมื่นคำ16,000 (ค่าสูงสุด)48,000

การแสดงผลข้อความยาวได้รับผลกระทบจาก "เวลาตอบสนอง" แนะนำให้ใช้การสตรีมมิงเพื่อแสดงผลไปพร้อมกับการสร้าง

เมื่อการเขียนต่อถูกตัดออก อย่าส่งเนื้อหาครึ่งเดียวให้โมเดลแล้วสั่งว่า "ทำต่อ" วิธีที่เสถียรกว่าคือการใส่ส่วนที่สร้างไว้แล้วกลับเข้าไปใน messages ในฐานะ assistant message แล้วเพิ่ม user message ใหม่ว่า "เขียนต่อจากประโยคก่อนหน้าโดยไม่ทำซ้ำ" ซึ่งจะทำให้การเชื่อมต่อเป็นธรรมชาติที่สุด แต่ขั้นตอนนี้จะทำให้พรอมต์ยาวขึ้น จึงต้องตรวจสอบงบประมาณใหม่

รายการตรวจสอบสำหรับบริบทยาว

  • คำนวณพรอมต์ด้วยฟังก์ชันประมาณการก่อนทุกคำขอ หากเกินงบประมาณให้ใช้เส้นทางแบ่งส่วน
  • บันทึก usage ในการตอบกลับทุกครั้ง เพื่อปรับเทียบค่าประมาณการอย่างต่อเนื่อง
  • วาง system และโครงเรื่องไว้ที่ส่วนต้นของเนื้อหา และเน้นย้ำข้อกำหนดสำคัญจากคำสั่งไว้ที่ส่วนท้าย
  • ตรวจสอบ finish_reason หากเป็น length ให้แจ้งเตือนหรือเขียนต่อ
  • ตั้งค่าขีดจำกัดการเก็บประวัติการสนทนา หากเกินขีดจำกัดให้ทิ้งข้อความที่เก่าที่สุด อย่ารอให้ API ส่ง 400

เนื้อหาที่เกี่ยวข้อง: โครงสร้าง prompt ดู วิธีเขียน Prompt, การแก้ error ดูคู่มือแก้ error code, การคำนวณราคาดูหน้าราคา

ข้อควรระวังสุดท้าย: ความยาวของหน้าต่างบริบทไม่เท่ากับหน่วยความจำที่ยาวนาน โมเดลจะอ่านข้อมูลที่คุณให้มาใหม่ทั้งหมดในแต่ละคำขอ ไม่จำสิ่งใดจากการเรียกใช้ครั้งก่อน หากต้องการความต่อเนื่อง คุณต้องส่งประวัติการสนทนาไปด้วยเอง

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

บริบท 100k รวมการแสดงผลด้วยหรือไม่

รวม ค่าสูงสุดคือผลรวมของพรอมต์และการแสดงผล ดังนั้นการตั้งค่า max_tokens ให้ใหญ่ขึ้นจะหมายถึงพื้นที่สำหรับข้อมูลนำเข้าที่น้อยลง

ตัวอักษรจีนหนึ่งตัวคือกี่โทเคน

ประมาณได้เท่านั้น ประมาณ 1 ถึง 1.5 ต่อตัวอักษร มีการเปลี่ยนแปลงตามข้อความ วิธีที่แม่นยำที่สุดคืออ่านฟิลด์ usage ใน response และปรับเทียบด้วยค่าที่วัดได้จริง

หากเกินขีดจำกัดจะตัดข้อมูลนำเข้าอัตโนมัติหรือไม่

ไม่ การเรียกนี้จะตอบกลับ 400 คุณต้องแบ่งส่วนหรือทิ้งเนื้อหาเก่าก่อนเรียก

สามารถสร้างข้อความยาวได้สูงสุดต่อครั้งเท่าใด

max_tokens ค่าเริ่มต้น 2048, สูงสุดต่อคำขอ 16,000 สำหรับเนื้อหาที่ยาวขึ้น กรุณาแบ่งสร้างหลายครั้ง และใช้ outline หรือ summary เพื่อรักษาความต่อเนื่อง

กรอกแบบฟอร์มเพื่อรับคีย์

สร้างบัญชี คัดลอกคีย์ และแก้ไข Base URL การตั้งค่าก็ง่ายเพียงเท่านี้