Hitung batas dengan jelas terlebih dahulu
Tiga angka menentukan segalanya:
- Total konteks 100,000 token, jumlah prompt dan completion.
max_tokensdefault 2048, maksimum per permintaan 16.000.- Body permintaan tidak boleh melebihi 8 MB; batas ini jarang tercapai untuk teks murni, yang lebih cepat penuh adalah token.
Rumus anggaran sederhana: prompt tersedia = 100000 - max_tokens. Jika Anda ingin model menghasilkan 4000 token sekaligus, prompt maksimal hanya tersisa 60,000. Jika melebihi, antarmuka mengembalikan 400 dan tidak memotong otomatis. Jadi, "memasukkan seluruh buku" bukan strategi, hanya keberuntungan.
Kesalahpahaman umum lainnya: max_tokens semakin besar semakin aman. Sebenarnya ini adalah ruang output yang dicadangkan; menetapkan 16.000 berarti prompt hanya boleh 48.000. Tetapkan sesuai kebutuhan, jangan maksimalkan secara buta.
Contoh perhitungan: anggap Anda punya naskah wawancara 300.000 karakter yang perlu diringkas. Estimasi kasar 1,3 token per karakter, total sekitar 390.000 token, lebih dari enam kali batas. Anda tak bisa mengirimnya sekaligus. Jika output ringkasan butuh 800 token, input maksimal 63.000 token, sisakan 10% cadangan, jadi sekitar 50.000 token. Namun ini bukan solusi optimal. Saat blok terlalu besar, model kehilangan fokus pada bagian tengah. Solusinya: pecah blok menjadi lebih kecil, meski harus memanggil API lebih sering.
Estimasi token: algoritma pendekatan
Tanpa tokenizer lokal, gunakan perkiraan berikut. Semua nilai di bawah ini adalah pendekatan, bukan nilai tepat, dengan variasi teks hingga 10-20%:
| Jenis Teks | Konversi Pendekatan |
|---|---|
| Teks Tionghoa | Sekitar 1 hingga 1,5 token per karakter |
| Bahasa Inggris | Sekitar 1 token per 4 karakter, atau sekitar 1,3 token per kata |
| Kode, JSON, teks padat simbol | Lebih boros token daripada teks biasa; disarankan menggunakan nilai tinggi yang konservatif |
Fungsi estimasi yang memadai adalah sebagai berikut, lengkap dengan perhitungan anggaran yang menyisakan cadangan:
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)) # 54900Metode kalibrasi: kirimkan satu permintaan dengan input tipikal, baca usage.prompt_tokens di respons, bandingkan dengan estimasi Anda, hitung faktor pengali aktual untuk data bisnis Anda, lalu ubah koefisien sesuai nilai terukur. Estimasi hanya digunakan untuk memutuskan "apakah perlu pemotongan", bukan untuk rekonsiliasi; rekonsiliasi lihat usage.
Ringkasan dokumen panjang: pemotongan dan penggabungan
Saat dokumen melebihi anggaran, metode standar adalah map-reduce: potong bagian lalu rangkum masing-masing, gabungkan ringkasan menjadi ringkasan total. Perhatikan detail berikut:
- Potong berdasarkan batas paragraf, jangan memotong berdasarkan jumlah karakter tetap agar tidak memotong kalimat di tengah.
- Sisakan anggaran yang cukup untuk setiap bagian; disarankan tidak melebihi sepertiga batas untuk memberi ruang pada instruksi dan output.
- Ringkasan bagian harus mempertahankan nama orang, angka, dan peristiwa kunci, agar informasi tidak hilang saat digabungkan.
- Jika ringkasan dari ringkasan masih terlalu panjang, lakukan satu tingkat rekursi lagi.
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)Di sini temperature diatur ke 0.3 agar tugas ringkasan lebih stabil. Setiap panggilan per segmen bersifat independen dan dapat dijalankan secara parallel requests, namun perhatikan batas laju 300 permintaan per menit untuk setiap kunci API Anda; dokumen puluhan segmen tidak akan menyentuh batas tersebut.
Tidak ada jawaban baku untuk ukuran bagian. Secara pengalaman, 10.000 hingga 15.000 token per bagian menyeimbangkan pelestarian detail dan jumlah panggilan. Jalankan sampel dengan ukuran bagian 5000, 12000, dan 25000, lalu bandingkan jumlah fakta kunci yang hilang dalam ringkasan untuk memilih nilai yang sesuai dengan jenis dokumen Anda. Dokumen dengan kepadatan informasi tinggi seperti kontrak atau dokumen teknis memerlukan bagian lebih kecil; catatan percakapan yang redundan dapat menggunakan bagian lebih besar.
Kelanjutan novel: jendela geser dan ringkasan bergulir
Saat mencapai bab ke-10, seluruh teks tidak lagi muat dan tidak perlu dimasukkan sepenuhnya. Gunakan memori dua lapis:
- Jarak dekat: dua atau tiga bab asli terbaru, menjaga konsistensi gaya bahasa, ritme dialog, dan detail adegan.
- Jarak jauh: bab-bab sebelumnya dipadatkan menjadi outline, mempertahankan hubungan karakter, setup, dan alur cerita yang belum terselesaikan.
Setelah menyelesaikan satu bab, minta model meringkasnya menjadi tiga hingga lima kalimat lalu tambahkan ke outline. Jika outline melebihi 3.000 token, kompres keseluruhan outline tersebut.
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)Setup adalah hal yang paling mudah hilang. Sarankan untuk membuat kolom khusus "setup yang belum direalisasikan" di outline. Saat melanjutkan, minta model secara eksplisit menangani salah satu setup tersebut. Daftar nama karakter dan lokasi juga harus dimasukkan ke dalam system prompt agar model tidak mengubah nama saat keluar dari jendela konteks.
Masalah lain yang sering terlewat saat melanjutkan cerita adalah pergeseran gaya. Model cenderung meniru gaya bab-bab terakhir. Jika gaya bab awal berbeda dengan bab akhir, hal ini akan diperkuat. Solusinya: tambahkan "contoh gaya" di system prompt. Pilih satu bagian teks asli favorit Anda sebagai jangkar tetap yang tidak bergeser bersama jendela konteks.
max_tokens dan pemotongan
Ada dua skenario pemotongan jawaban yang harus dibedakan:
finish_reasonbernilailength: Anda mencapai batas max_tokens. Solusinya: tingkatkan max_tokens, atau minta model menulis secara bertahap, berhenti di sini, dan lanjutkan saat Anda memberi perintah.- Permintaan langsung 400: prompt ditambah max_tokens telah melebihi 100.000. Solusinya adalah memperpendek input atau mengurangi max_tokens.
Tabel referensi anggaran praktis:
| Tugas | max_tokens yang Disarankan | prompt tersedia (sekitar) |
|---|---|---|
| ringkasan, ekstraksi | 800 | 63,200 |
| kelanjutan bab (sekitar 2000 kata) | 4000 | 60,000 |
| output panjang tingkat ribuan kata | 16000 (batas atas) | 48,000 |
Output panjang juga dipengaruhi oleh "waktu respons", disarankan menggunakan output streaming agar dapat ditampilkan saat sedang dihasilkan.
Saat kelanjutan terpotong, jangan hanya memberikan potongan konten ke model dan meminta "lanjut". Cara yang lebih stabil adalah mengembalikan bagian yang telah dihasilkan sebagai pesan assistant ke dalam messages, lalu menambahkan pesan user "lanjutkan dari kalimat terakhir, jangan ulangi" agar sambungannya paling alami. Perhatikan bahwa langkah ini akan membuat prompt menjadi lebih panjang, sehingga perlu memeriksa ulang anggaran.
Daftar periksa konteks panjang
- Gunakan fungsi estimasi untuk menghitung prompt sebelum setiap permintaan; jika melebihi anggaran, gunakan cabang pemecahan.
- Catat usage di setiap respons untuk terus mengkalibrasi koefisien estimasi.
- Letakkan system dan outline di awal konten, dan ulangi persyaratan kunci dalam instruksi di bagian akhir.
- Periksa finish_reason; jika berupa length, berikan peringatan atau lakukan kelanjutan.
- Atur batas atas untuk percakapan historis; jika melebihi batas, buang pesan tertua, jangan menunggu antarmuka mengembalikan 400.
Konten terkait: struktur prompt lihat Penulisan Prompt, penanganan error lihat Panduan Pemecahan Masalah Kode Error, penentuan harga lihat Halaman Harga.
Ingat satu hal terakhir: konteks panjang bukan berarti memori panjang. Model membaca konten yang Anda berikan dari awal pada setiap permintaan, tidak mengingat apa pun dari panggilan sebelumnya; jika membutuhkan kontinuitas, Anda harus membawa riwayat tersebut sendiri.