सीमा को पहले स्पष्ट करें
तीन संख्याएं सब कुछ निर्धारित करती हैं:
- कॉन्टेक्स्ट की कुल मात्रा 100,000 टोकन है, प्रॉम्प्ट और कंप्लीशन का योग।
max_tokensका डिफ़ॉल्ट मान 2048 है, एक अनुरोध में अधिकतम 16,000।- अनुरोध बॉडी 8 MB से अधिक नहीं होनी चाहिए। यह सीमा शुद्ध पाठ के लिए लगभग कभी नहीं टूटती, वास्तव में टोकन की सीमा पहले आती है।
बजट का सूत्र बहुत सरल है: प्रॉम्प्ट उपलब्ध = 100000 - max_tokens। यदि आप मॉडल से एक बार में 4000 टोकन आउटपुट लेना चाहते हैं, तो प्रॉम्प्ट के लिए केवल 60,000 शेष रहते हैं। सीमा पार होने पर एंडपॉइंट 400 लौटाता है और स्वचालित रूप से ट्रंकेशन (truncation) नहीं करता। इसलिए "पूरी किताब को धकेलकर देखना" रणनीति नहीं, केवल भाग्य का खेल है।
एक अन्य सामान्य गलतफहमी: max_tokens जितना बड़ा, उतना सुरक्षित। वास्तव में यह आरक्षित आउटपुट स्पेस है। 16,000 सेट करने का मतलब है कि प्रॉम्प्ट केवल 48,000 हो सकता है। आवश्यकतानुसार सेट करें, अधिकतम न करें।
मान लीजिए आपके पास 300,000 शब्दों का इंटरव्यू ट्रांसक्रिप्ट (interview transcript) सारांश के लिए है। प्रति शब्द 1.3 टोकन के अनुमानित हिसाब से यह लगभग 390,000 टोकन है, जो सीमा से छह गुना अधिक है, इसलिए इसे एक ही बार में भेजना संभव नहीं है। यदि एक बार में 800 टोकन का आउटपुट चाहिए, तो प्रत्येक ब्लॉक के लिए अधिकतम 63,000 टोकन होते हैं, और वास्तविक उपयोग के लिए 10% मार्जिन छोड़ने पर यह लगभग 50,000 से कम रह जाता है। लेकिन यह सर्वोत्तम समाधान नहीं है; ब्लॉक बड़े होने पर मॉडल मध्य भाग पर कम ध्यान देता है, इसलिए नीचे दी गई विधि ब्लॉक को छोटा करती है, भले ही उसे कई बार कॉल करना पड़े।
टोकन अनुमान: अनुमानित अल्गोरिदम
स्थानीय टोकनाइज़र न होने पर अनुमानित गणना के लिए निम्नलिखित मानों का उपयोग करें। ये सभी मान अनुमानित हैं, सटीक नहीं, विभिन्न पाठों में 10% से 20% का अंतर हो सकता है:
| टेक्स्ट प्रकार | अनुमानित रूपांतरण |
|---|---|
| चीनी पाठ | प्रति शब्द लगभग 1 से 1.5 टोकन |
| अंग्रेजी | प्रति 4 वर्ण लगभग 1 टोकन, या प्रति शब्द लगभग 1.3 टोकन |
| कोड, JSON, प्रतीकों से भरी सामग्री | साधारण टेक्स्ट की तुलना में अधिक टोकन लेता है, इसलिए सुरक्षित उच्च मान का उपयोग करें। |
एक उपयोगी अनुमान फ़ंक्शन नीचे दिया गया है, जिसमें बजट की गणना भी शामिल है:
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कैलिब्रेशन विधि: एक प्रतिनिधि इनपुट लेकर एक बार अनुरोध भेजें, प्रतिक्रिया में usage.prompt_tokens पढ़ें और अपनी गणना से तुलना करें। इससे आपके डेटा का वास्तविक गुणक पता चलेगा, जिसे आप मापे गए मान से बदल सकते हैं। अनुमान का उपयोग केवल "क्या विभाजित करना है" तय करने के लिए करें, बिलिंग के लिए नहीं; बिलिंग के लिए usage फ़ील्ड देखें।
लंबे दस्तावेज़ का सारांश: विभाजन और विलय
जब दस्तावेज़ बजट से अधिक हो, तो मानक विधि map-reduce है: पहले विभाजित करके सारांश बनाएं, फिर उन्हें मिलाकर अंतिम सारांश तैयार करें। इन बिंदुओं पर ध्यान दें:
- पैराग्राफ सीमाओं के अनुसार विभाजित करें, निश्चित शब्द संख्या से नहीं, अन्यथा वाक्य टूट सकते हैं।
- प्रत्येक ब्लॉक के लिए पर्याप्त बजट छोड़ें, अनुशंसा है कि यह सीमा का एक तिहाई न हो, ताकि निर्देशों और आउटपुट के लिए जगह बचे।
- सारांश में नाम, संख्याएं और महत्वपूर्ण घटनाएं शामिल रखें, अन्यथा विलय के समय जानकारी खो जाएगी।
- यदि सारांश का सारांश अभी भी लंबा है, तो एक और स्तर पर पुनरावृत्ति करें।
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 requests) भेजे जा सकते हैं, लेकिन याद रखें कि प्रति कुंजी प्रति मिनट 300 अनुरोध की सीमा है। सैकड़ों खंडों वाले दस्तावेज़ के लिए यह सीमा आसानी से टूटती नहीं है।
ब्लॉक का आकार निर्धारित करने का कोई मानक उत्तर नहीं है। अनुभव से, 10,000 से 15,000 टोकन प्रति ब्लॉक संतुलित है। नमूना डेटा के साथ 5000, 12000 और 25000 टोकन ब्लॉक साइज का परीक्षण करें और देखें कि किसमें सबसे कम महत्वपूर्ण तथ्य खो रहे हैं। उच्च जानकारी घनत्व वाले दस्तावेज़ों के लिए छोटे ब्लॉक, और कम घनत्व वाले डेटा के लिए बड़े ब्लॉक चुनें।
नॉवेल कंटिन्यूएशन: स्लाइडिंग विंडो और रोलिंग आउटलाइन
जब नॉवेल लंबा हो जाता है, तो पूरा कॉन्टेक्स्ट फिट नहीं होता और न ही आवश्यक होता है। दो स्तर की मेमोरी का उपयोग करें:
- नज़दीकी दृश्य (Near view): पिछले दो-तीन अध्यायों का मूल पाठ, जिससे लेखन शैली, संवाद की लय और दृश्य विवरण निरंतर बने रहें।
- दूरदर्शिता:पिछले अध्यायों को सारांश में बदल दिया गया है, पात्र संबंध, foreshadowing और अनसुलझे सुराग बनाए रखे गए हैं।
प्रत्येक चैप्टर लिखने के बाद, मॉडल से उस चैप्टर का सारांश तैयार करवाएं और आउटलाइन में जोड़ें। यदि आउटलाइन 3000 टोकन से अधिक हो जाए, तो उसे संपीड़ित करें।
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)Foreshadowing (foreshadowing) खोने की सबसे अधिक संभावना होती है। सारांश में "अनसुलझे foreshadowing" की एक अलग श्रेणी बनाएं और सुनिश्चित करें कि अगले अध्याय में उसमें से एक का समाधान किया जाए। पात्रों और स्थानों के नाम को एक स्थिर सूची के रूप में system में रखें, ताकि विंडो स्लाइड होने पर मॉडल नाम बदल न दे।
Continuation (continuation) के दौरान एक और गंभीर समस्या है: शैली में बदलाव। मॉडल हाल के अध्यायों की शैली की ओर झुक जाता है। यदि पिछले अध्यायों की शैली बाद के अध्यायों से मेल नहीं खाती, तो यह अंतर बढ़ जाता है। समाधान system में एक "शैली नमूना" लिखना है — अपनी पसंदीदा मूल पाठ की एक पंक्ति को एक स्थिर एंकर के रूप में डालें, जो विंडो स्लाइड होने पर नहीं बदले।
max_tokens और ट्रंकेशन
जवाब के ट्रंकेट (truncated) होने की दो स्थितियां होती हैं, जिन्हें अलग-अलग समझना जरूरी है:
finish_reasonका मानlengthहै: इसका अर्थ है कि आपकी max_tokens सीमा टूट गई है। समाधान: max_tokens का मान बढ़ाएं, या मॉडल को खंडों में लिखने को कहें ("यहां तक लिखें, रुक जाएं, जब मैं कहूं तब आगे लिखें")।- अनुरोध 400 error देता है: प्रॉम्प्ट और max_tokens का योग 100,000 से अधिक हो गया है। समाधान: इनपुट छोटा करें या max_tokens कम करें।
बजट संदर्भ तालिका:
| कार्य | सुझाव max_tokens | प्रॉम्प्ट उपलब्ध (लगभग) |
|---|---|---|
| सारांश, निष्कर्ष | 800 | 63,200 |
| अध्याय की सतत लेखन (लगभग 2000 शब्द) | 4000 | 60,000 |
| 10,000 शब्दों वाले लंबे आउटपुट | 16,000 (सीमा) | 48,000 |
लंबे आउटपुट पर 'प्रतिक्रिया समय' का प्रभाव पड़ता है, इसलिए स्ट्रीमिंग आउटपुट के साथ उपयोग करें ताकि जनरेशन के दौरान ही प्रदर्शित हो सके।
जब continuation (continuation) ट्रंकेट (truncated) हो जाए, तो आधा जवाब मॉडल को न दें। बेहतर तरीका यह है कि उत्पन्न भाग assistant message के रूप में messages में वापस डालें और एक user message जोड़ें "पिछली पंक्ति के बाद से लिखना शुरू करें, दोहराएं नहीं"। इससे जुड़ाव सबसे स्वाभाविक होता है। ध्यान रहे, इस कदम से प्रॉम्प्ट लंबा हो जाता है, इसलिए बजट की पुनः जाँच करें।
लंबे कॉन्टेक्स्ट विंडो के लिए चेकलिस्ट
- प्रत्येक अनुरोध से पहले अनुमानित फ़ंक्शन से प्रॉम्प्ट की गणना करें। यदि बजट टूटता है, तो विभाजित शाखा (branch) पर जाएं।
- प्रत्येक प्रतिक्रिया में usage रिकॉर्ड करें और अनुमानित गुणांक को लगातार कैलिब्रेट (calibrate) करें।
- system और विषय-वस्तु को सामग्री के सबसे पहले रखें, निर्देशों में महत्वपूर्ण आवश्यकताओं को अंत में फिर से दोहराएं।
- finish_reason की जाँच करें, यदि length है तो अलर्ट दें या सतत लेखन करें।
- ऐतिहासिक संवाद के लिए संरक्षण सीमा निर्धारित करें, यदि सीमा से अधिक हो तो सबसे पुराने को छोड़ दें, 400 त्रुटि प्रतिक्रिया का इंतज़ार न करें।
संबंधित सामग्री: प्रॉम्प्ट संरचना के लिए प्रॉम्प्ट लेखन देखें, त्रुटि निवारण के लिए त्रुटि कोड डीबगिंग गाइड देखें, मूल्य निर्धारण के लिए मूल्य पृष्ठ देखें।
अंतिम चेतावनी: लंबा कॉन्टेक्स्ट विंडो लंबी मेमोरी नहीं है। मॉडल प्रत्येक अनुरोध में आपके द्वारा प्रदान की गई सामग्री को शून्य से पढ़ता है, पिछली कॉल के बारे में कुछ भी याद नहीं रखता। निरंतरता के लिए आपको स्वयं ऐतिहासिक संवाद को साथ लाना होगा।