फ़ारसी टोकन टैक्स: ग़ैर-अंग्रेज़ी LLM ऐप की लागत
1,012 समानांतर वाक्यों पर फ़ारसी को GPT-4o के टोकनाइज़र पर अंग्रेज़ी से 1.53× और GPT-4 के टोकनाइज़र पर 3.26× टोकन लगे। तरीक़ा, नतीजे और क्या टेस्ट करें।
फ़ारसी (Farsi) टेक्स्ट को उसी सामग्री के लिए अंग्रेज़ी से ज़्यादा टोकन लगते हैं। यही अतिरिक्त लागत फ़ारसी टोकन टैक्स है, और उसका आकार लिपि से ज़्यादा टोकनाइज़र पर निर्भर करता है। मैंने FLORES-200 बेंचमार्क के वही 1,012 वाक्य अंग्रेज़ी और फ़ारसी में लेकर टोकन गिने। o200k_base पर, यानी उस एन्कोडिंग पर जिसे OpenAI की tiktoken लाइब्रेरी GPT-4o से जोड़ती है, फ़ारसी को अंग्रेज़ी से 1.53× टोकन लगे, और cl100k_base पर, जिसे वह GPT-4 से जोड़ती है, 3.26×। टेक्स्ट-जेनरेशन मॉडल जिन चार टोकनाइज़र का इस्तेमाल करते हैं, उनमें यही दोनों छोर थे; bge-m3, जो एक एम्बेडिंग मॉडल का टोकनाइज़र है, 1.10× पर रहा। Claude और Gemini इस माप में नहीं हैं: Anthropic, Claude का टोकनाइज़र प्रकाशित नहीं करता, और Gemini के लिए Google का SDK जो लोकल टोकनाइज़र देता है, उसे मैंने टेस्ट नहीं किया। दोनों वेंडर अपने-अपने मॉडल के टोकन एक API से गिनते हैं।
ये आँकड़े एक तारीख़ वाला स्नैपशॉट हैं: 17 सितंबर 2026 को, पिन किए गए टोकनाइज़र वर्ज़न के साथ मापे गए।
फ़ारसी ज़्यादा टोकन क्यों लेती है: बाइट, मर्ज और ट्रेनिंग डेटा
भाषा मॉडल के API टोकन के हिसाब से पैसे लेते हैं। 2023 में Ahia और सहयोगियों को इसके प्रमाण मिले कि “समर्थित भाषाओं में से बहुत सारी भाषाओं के बोलने वालों से ज़्यादा वसूला जाता है, और नतीजे उन्हें कमतर मिलते हैं”। Petrov और सहयोगियों ने दिखाया कि एक ही टेक्स्ट अलग-अलग भाषाओं में अनूदित हो तो टोकन की लंबाई में “कुछ मामलों में 15 गुना तक” फ़र्क़ आ सकता है। दो सौ से ज़्यादा भाषाओं पर 2025 की एक स्टडी ग़ैर-लैटिन और रूप-रचना में जटिल भाषाओं के लिए “अक्सर 3 से 5 गुना ऊँचे RTC अनुपात” बताती है, जहाँ RTC लेखकों का “Relative Tokenization Cost” है।
यही टोकन टैक्स है: अर्थ वही, बिल बड़ा।
हर बाइट-स्तरीय टोकनाइज़र की शुरुआत बाइट से होती है
बाइट-स्तरीय BPE (byte-pair encoding) टोकनाइज़र — यही किस्म GPT-4o, Qwen3 और DeepSeek-V3 के पीछे है — टेक्स्ट की UTF-8 एन्कोडिंग के बाइट से शुरू होता है और बार-बार आने वाले बाइट-क्रमों को मर्ज करके टोकन बनाता है। बिना चिह्न वाला लैटिन अक्षर एक बाइट का होता है; योरूबा के सुर-चिह्न वाले और नीचे बिंदी वाले अक्षर दो या उससे ज़्यादा बाइट लेते हैं। फ़ारसी का एक अक्षर दो बाइट का है, और फ़ारसी शब्दों के भीतर इस्तेमाल होने वाला zero-width non-joiner तीन का। FLORES में फ़ारसी फ़ाइल ने UTF-8 में अंग्रेज़ी फ़ाइल के 1.69× बाइट लिए, जबकि अक्षर उसके 0.94× थे। फ़ारसी अक्षरों के हिसाब से लंबी नहीं है; वह एन्कोड होने में भारी है।
आगे क्या होता है, यह उन मर्ज पर निर्भर है जो टोकनाइज़र ने अपने ट्रेनिंग डेटा से सीखे हैं। cl100k_base से o200k_base पर जाने से फ़ारसी टोकन 53.5% घटे और अंग्रेज़ी टोकन 1.1%। नई शब्दावली ने फ़ारसी को बदला, अंग्रेज़ी को नहीं।
योरूबा लैटिन लिपि में है, फिर भी ज़्यादा चुकाती है
अगर टैक्स लिपि से तय होता, तो लैटिन लिपि वाली भाषाएँ मुश्किल से कुछ चुकातीं। Roy, Roy और Patel का एक वर्कशॉप पेपर (IJCAI 2026 के एक वर्कशॉप में स्वीकृत, अगस्त 2026 से arXiv पर) अपने ऑडिट में पाता है कि “योरूबा, लैटिन लिपि इस्तेमाल करने के बावजूद, GPT-4o पर सबसे ऊँचा टोकनाइज़ेशन प्रीमियम दिखाती है”, 2.37× पर। लेखक डायक्रिटिक्स और शब्दावली में कवरेज की ओर इशारा करते हैं। उस पेपर में योरूबा एक खोजपरक तुलना है: उसके अनुवाद मशीन से बने और हाथ से जाँचे गए, जबकि बांग्ला और हिंदी वहाँ सत्यापित मामले हैं।
मेरे रन का इशारा भी उसी तरफ़ है। पाँच में से चार टोकनाइज़र पर योरूबा फ़ारसी से महँगी पड़ी, और पाँच में से चार पर अरबी फ़ारसी से सस्ती। अरबी वाला अपवाद bge-m3 है, जो XLM-RoBERTa और उसकी शब्दावली पर बना एम्बेडिंग मॉडल है। XLM-R को CC-100 से ली गई सौ भाषाओं पर ट्रेन किया गया था: फ़ारसी के 13,259 मिलियन टोकन के मुक़ाबले अरबी के 2,869 मिलियन, और योरूबा उनमें थी ही नहीं। यह इससे मेल खाता है कि लिपि से ज़्यादा फ़र्क़ ट्रेनिंग डेटा में हिस्सेदारी डालती है। यह उसे साबित नहीं करता।
नतीजे: अंग्रेज़ी के मुक़ाबले फ़ारसी, अरबी और योरूबा
हर ख़ाना किसी भाषा के कुल टोकन को उसी टोकनाइज़र पर अंग्रेज़ी के कुल से भाग देकर मिला है:
टोकनाइज़र | फ़ारसी (× अंग्रेज़ी) | अरबी (× अंग्रेज़ी) | योरूबा (× अंग्रेज़ी) |
|---|---|---|---|
| 3.26× | 3.03× | 2.95× |
Qwen3 | 2.58× | 1.63× | 2.69× |
DeepSeek-V3 | 1.79× | 1.62× | 2.83× |
| 1.53× | 1.38× | 2.17× |
bge-m3 | 1.10× | 1.17× | 2.27× |
सबसे बड़ा चर टोकनाइज़र ही है। सबसे ख़राब टोकनाइज़र पर फ़ारसी का अनुपात (3.26×) सबसे अच्छे टोकनाइज़र पर उसके अनुपात (1.10×) का क़रीब तीन गुना है, और जनरेशन के लिए इस्तेमाल होने वाले चार टोकनाइज़र के भीतर भी क़रीब दोगुना (3.26× बनाम 1.53×)। Qwen3 अरबी के साथ फ़ारसी से कहीं बेहतर बर्ताव करता है, 1.63× बनाम 2.58×, इसलिए अरबी लिपि के लिए एक ही आँकड़ा दोनों भाषाओं पर लागू नहीं होता। cl100k_base का नतीजा पहले प्रकाशित गिनतियों से मेल खाता है: Petrov और सहयोगियों की FLORES-200 लंबाइयाँ, dev और devtest स्प्लिट जोड़कर, पश्चिमी फ़ारसी को अंग्रेज़ी का 3.28 गुना बताती हैं, जबकि सिर्फ़ devtest स्प्लिट पर मेरा आँकड़ा 3.26× है।
इन अनुपातों के पीछे के कुल, और किसी टोकनाइज़र के छूने से पहले हर भाषा की फ़ाइल का आकार:
गिनती | अंग्रेज़ी | फ़ारसी | अरबी | योरूबा |
|---|---|---|---|---|
अक्षर | 1,31,966 | 1,23,830 | 1,16,320 | 1,26,848 |
बाइट (UTF-8) | 1,32,096 | 2,23,504 | 2,11,276 | 1,68,857 |
टोकन, | 27,182 | 88,513 | 82,288 | 80,247 |
टोकन, Qwen3 | 27,621 | 71,183 | 44,991 | 74,226 |
टोकन, DeepSeek-V3 | 27,041 | 48,342 | 43,713 | 76,526 |
टोकन, | 26,873 | 41,116 | 37,117 | 58,238 |
टोकन, bge-m3 | 30,661 | 33,631 | 35,979 | 69,672 |
आपका अपना कॉर्पस दूसरा आँकड़ा देगा
Roy और सहयोगियों के ऑडिट ने o200k_base को अंग्रेज़ी से अनूदित 120 Python डीबगिंग आइटम पर मापा और हर आइटम का औसत लिया। वह अरबी के लिए 1.44× और योरूबा के लिए 2.37× बताता है, दोनों मशीनी अनुवाद से। FLORES के गद्य पर, जिसे लोगों ने अनूदित किया, उसी o200k_base ने अरबी को 1.38× और योरूबा को 2.17× दिया। टोकनाइज़र वही, टेक्स्ट और अनुवाद की प्रक्रिया अलग, नतीजा अलग। बजट बनाने से पहले अपने ही प्रॉम्प्ट, रिट्रीव किए गए पैसेज और जवाब गिनिए।
मैंने फ़ारसी टोकन कैसे गिने
सचमुच समानांतर कॉर्पस
NLLB टीम FLORES-200 को “इंसानों द्वारा अनूदित बेंचमार्क” बताती है: वही वाक्य, उसी क्रम में, हर भाषा में। मैंने उसका devtest स्प्लिट लिया, जो CC BY-SA 4.0 के तहत है, आधिकारिक आर्काइव से और उसका SHA-256 हैश जाँचकर: Wikinews, Wikivoyage और Wikibooks से लिए 1,012 वाक्य, अंग्रेज़ी, पश्चिमी फ़ारसी, आधुनिक मानक अरबी और योरूबा में।
समानांतर होना आकार से ज़्यादा मायने रखता है। ढालकर किया गया अनुवाद, जैसे कोई द्विभाषी CV, सामग्री जोड़ता है, छोड़ता है और दोबारा गढ़ता है, इसलिए उसका अनुपात टोकनाइज़र जितना ही संपादन को भी मापता है। FLORES की अपनी सीमा है: यह ख़बर, यात्रा-गाइड और पाठ्यपुस्तक का गद्य है, चैट, कोड या अनुबंध नहीं।
खुले टोकनाइज़र, पिन किए गए रिवीज़न, और Claude व Gemini क्यों ग़ैरहाज़िर हैं
पाँच टोकनाइज़र, सभी बिना किसी अकाउंट के डाउनलोड होने वाले:
tiktoken 0.14.0:
cl100k_baseऔरo200k_base। tiktoken पहले वाले से GPT-4 और GPT-3.5 Turbo को जोड़ती है, और दूसरे से GPT-4o, o1, o3, GPT-4.1 और GPT-5 को।Qwen3 (
Qwen/Qwen3-8B) और DeepSeek-V3 (deepseek-ai/DeepSeek-V3), दोनों बाइट-स्तरीय BPE, Hugging Face के tokenizers 0.23.2 से पिन किए गए Hub रिवीज़न पर लोड किए गए।bge-m3 (
BAAI/bge-m3), एक एम्बेडिंग मॉडल, जिसका टोकनाइज़र XLM-R शब्दावली वाला SentencePiece Unigram मॉडल है, बाइट-स्तरीय BPE नहीं। Unigram अलग एल्गोरिद्म है: वह एक तय शब्दावली में से टेक्स्ट का सबसे संभावित विभाजन चुनता है। यह रिट्रीवल के लिए मायने रखता है, जनरेशन के लिए नहीं।
हर वाक्य अलग-अलग एन्कोड किया गया, बिना किसी स्पेशल टोकन के, और गिनतियाँ जोड़ी गईं। प्रति-वाक्य मीडियन भी वही कहानी कहते हैं जो कुल जोड़। मूल हिस्सा चंद पंक्तियों में आ जाता है:
# after: tar -xzf flores200_dataset.tar.gz
import tiktoken
from huggingface_hub import hf_hub_download
from tokenizers import Tokenizer
def sentences(lang):
with open(f"flores200_dataset/devtest/{lang}.devtest", encoding="utf-8") as f:
return f.read().rstrip("\n").split("\n")
english, persian = sentences("eng_Latn"), sentences("pes_Arab")
o200k = tiktoken.get_encoding("o200k_base")
qwen3 = Tokenizer.from_file(
hf_hub_download(
"Qwen/Qwen3-8B",
"tokenizer.json",
revision="b968826d9c46dd6066d109eabc6255188de91218",
)
)
def o200k_tokens(texts):
return sum(len(o200k.encode_ordinary(t)) for t in texts)
def qwen3_tokens(texts):
return sum(len(qwen3.encode(t, add_special_tokens=False).ids) for t in texts)
print(round(o200k_tokens(persian) / o200k_tokens(english), 2))
print(round(qwen3_tokens(persian) / qwen3_tokens(english), 2))माप का रिकॉर्ड, इतना कि रन हूबहू दोहराया जा सके:
corpus: https://dl.fbaipublicfiles.com/nllb/flores200_dataset.tar.gz
sha256: b8b0b76783024b85797e5cc75064eb83fc5288b41e9654dabc7be6ae944011f6
split: devtest
measured: 2026-09-17
libraries:
tiktoken: 0.14.0
tokenizers: 0.23.2
huggingface_hub: 1.31.0
encodings: [cl100k_base, o200k_base]
hub_revisions:
Qwen/Qwen3-8B: b968826d9c46dd6066d109eabc6255188de91218
deepseek-ai/DeepSeek-V3: e815299b0bcbac849fa540c768ef21845365c9eb
BAAI/bge-m3: 5617a9f61b028005a4858fdac845db406aefb181
method: each sentence encoded on its own, no special tokens, counts summed per languageClaude और Gemini जान-बूझकर ग़ैरहाज़िर हैं। Anthropic, Claude का टोकनाइज़र प्रकाशित नहीं करता, इसलिए Claude के लिए मेरा बताया कोई भी अनुपात दशमलव लगा हुआ अंदाज़ा भर होता। Python के लिए Google का Gen AI SDK एक प्रयोगात्मक, सिर्फ़ टेक्स्ट वाला लोकल टोकनाइज़र देता है जो कुछ Gemini मॉडल को खुले Gemma टोकनाइज़र से जोड़ता है; मैंने उसे मापा नहीं। दोनों वेंडर आपके लिए टोकन गिन देते हैं। Anthropic का count_tokens एंडपॉइंट मुफ़्त है पर रेट-लिमिटेड, और उसका डॉक्यूमेंटेशन नतीजे को “एक अनुमान” कहता है; Gemini का count_tokens इनपुट गिनता है। Claude 4.7 और उसके बाद के मॉडल नया टोकनाइज़र इस्तेमाल करते हैं, जिस पर वही इनपुट टेक्स्ट “पहले वाले मॉडलों से क़रीब 30 प्रतिशत ज़्यादा टोकन” बनाता है। टोकन की गिनती किसी मॉडल की होती है, किसी वेंडर की नहीं।
वे सीमाएँ जो टिकती हैं, और एक जो नहीं टिकती
बाइट-स्तरीय BPE टोकनाइज़र, जो मर्ज से पहले टेक्स्ट को प्री-टोकन में बाँटते हैं — यहाँ चारों ऐसे ही हैं — उनके लिए दो हदें गिनती को घेरती हैं। टोकन की संख्या टेक्स्ट के बाइट से ज़्यादा नहीं हो सकती — UTF-8 में, और उसी रूप में जैसा टोकनाइज़र टेक्स्ट को नॉर्मलाइज़ करता है — क्योंकि हर टोकन कम से कम एक बाइट ढकता है। और वह टोकनाइज़र के अपने प्री-टोकन से कम भी नहीं हो सकती, यानी उन टुकड़ों से जिनमें उसका विभाजन-पैटर्न टेक्स्ट को काटता है, क्योंकि मर्ज कभी प्री-टोकन की सीमा नहीं लाँघते। मैंने दोनों हदें चारों बाइट-स्तरीय BPE टोकनाइज़र और चारों भाषाओं पर वाक्य-दर-वाक्य जाँचीं: 16,192 जाँच, 0 उल्लंघन।
इस साइट का टोकनाइज़र प्लेग्राउंड आपके लिखे किसी भी टेक्स्ट के लिए दोनों आँकड़े दिखाता है, ब्राउज़र में ही गणना करके: cl100k_base वाला प्री-टोकन विभाजन, और UTF-8 में टेक्स्ट के बाइट। cl100k_base के लिए असली गिनती इन्हीं दोनों के बीच होती है, और हर पैनल के नीचे लिखा कैप्शन यही कहता है।
निचली हद एक ही टोकनाइज़र की है। cl100k_base का विभाजन o200k_base के लिए निचली हद नहीं बनता: 28 अंग्रेज़ी वाक्यों पर o200k_base को उससे कम टोकन लगे जितने प्री-टोकन cl100k_base बनाता है। bge-m3 के Unigram मॉडल पर इनमें से कोई हद लागू नहीं होती।
टोकन टैक्स का असर: क़ीमत, लेटेंसी, कॉन्टेक्स्ट विंडो और रेट लिमिट
क़ीमत
API वेंडर उन टोकन के पैसे लेते हैं जिन्हें मॉडल प्रोसेस करता और बनाता है। प्रति-टोकन क़ीमत एक ही रखें तो वही सामग्री फ़ारसी में o200k_base पर अंग्रेज़ी से क़रीब डेढ़ गुना महँगी पड़ती है, और cl100k_base पर तीन गुना से भी ज़्यादा। जब प्रॉम्प्ट और जवाब दोनों फ़ारसी में हों, तो यह अतिरिक्त लागत बिल के दोनों पक्षों पर लगती है।
लेटेंसी
रफ़्तार आउटपुट टोकन तय करते हैं। OpenAI की लेटेंसी गाइड कहती है कि “अपने आउटपुट टोकन में से 50% कम करने से आपकी लेटेंसी ~50% तक घट सकती है”। प्रॉम्प्ट छाँटने से कहीं कम फ़र्क़ पड़ता है: “अपने प्रॉम्प्ट में से 50% कम करने पर शायद लेटेंसी में सिर्फ़ 1–5% सुधार मिले”। फ़ारसी जवाब को, जिसे अपने अंग्रेज़ी समकक्ष से ज़्यादा टोकन चाहिए, स्ट्रीम होने में ज़्यादा समय लगता है। यह ऊपर के अनुपातों पर लगाई गई वेंडर की सलाह है, मेरा कोई लेटेंसी माप नहीं।
कॉन्टेक्स्ट विंडो
तय टोकन वाली विंडो में फ़ारसी कम समाती है। अनुपात से भाग दें तो इसी कॉर्पस के लिए वही विंडो cl100k_base पर अंग्रेज़ी के मुक़ाबले 31% फ़ारसी सामग्री रखती है, Qwen3 पर 39%, DeepSeek-V3 पर 56%, o200k_base पर 65% और bge-m3 पर 91%। Roy और सहयोगियों का ऑडिट बांग्ला के लिए यही बात कहता है: GPT-4o पर उसका 1.56× प्रीमियम “128k टोकन की नाममात्र कॉन्टेक्स्ट विंडो को घटाकर 82k टोकन की प्रभावी अंग्रेज़ी-समकक्ष क्षमता” कर देता है। RAG प्रॉम्प्ट में इसका मतलब है कि रिट्रीव किए गए कम पैसेज ही उसमें समाएँगे।
रेट लिमिट
रेट लिमिट भी टोकन में गिनी जाती हैं। Claude की API सीमाएँ “प्रति मिनट रिक्वेस्ट (RPM), प्रति मिनट इनपुट टोकन (ITPM) और प्रति मिनट आउटपुट टोकन (OTPM)” में मापी जाती हैं। प्रति मिनट टोकन की छत के नीचे, जिस वर्कलोड को हर रिक्वेस्ट पर ज़्यादा टोकन चाहिए — जैसा यहाँ मापे गए हर टोकनाइज़र पर फ़ारसी को चाहिए था — वह कम रिक्वेस्ट के बाद ही सीमा से टकरा जाता है। ज़्यादातर Claude मॉडल पर कैश से पढ़ा गया हिस्सा इनपुट सीमा में नहीं गिना जाता।
नॉर्मलाइज़ेशन जो टोकन बचाता है, और नॉर्मलाइज़ेशन जो recall तोड़ता है
लिखित फ़ारसी की दो ख़ूबियाँ सस्ती टोकन-बचत जैसी दिखती हैं। दोनों जाल हैं।
ZWNJ (نیمفاصله) एक कैरेक्टर है, स्पेस नहीं
U+200C ZERO WIDTH NON-JOINER की Unicode सामान्य श्रेणी Cf है, यानी वह फ़ॉर्मैट कंट्रोल है, whitespace नहीं। वह दोनों तरफ़ के अक्षरों को आपस में जुड़ने से रोकता है, इसलिए میشود एक ही शब्द की तरह पढ़ा जाता है, जिसके बीच में दिखने वाला अंतराल होता है। FLORES की फ़ारसी फ़ाइल उसे 1,739 बार इस्तेमाल करती है, अपने 1,012 में से 735 वाक्यों में।
हर ZWNJ की जगह स्पेस रखने पर फ़ारसी टोकन की गिनती cl100k_base पर 1.59% घटी, o200k_base पर 1.82%, Qwen3 पर 1.57% और DeepSeek-V3 पर 8.08%; bge-m3 पर बदलाव 0.00% रहा। bge-m3 इसलिए नहीं हिला क्योंकि उसका नॉर्मलाइज़र ZWNJ को पहले से ही स्पेस में बदल देता है: बदले गए सभी 735 वाक्यों के टोकन id वही के वही रहे।
तीन टोकनाइज़र पर बचत छोटी है, DeepSeek-V3 पर बड़ी, और वह टेक्स्ट को बदल देती है: एक शब्द दो हो जाता है, और आप जो स्टोर करते, दिखाते या वापस उद्धृत करते हैं वह अब वही नहीं रहा जो लिखने वाले ने लिखा था। स्टोर किए गए टेक्स्ट में ZWNJ बनाए रखिए, और अलग से तय कीजिए कि मिलान करने वाला उसे किसके बराबर माने। यह साइट ठीक यही करती है: सिर्फ़ तुलना के भीतर इस्तेमाल होने वाली फ़ोल्डिंग ZWNJ को स्पेस मानती है।
अरबी Yeh और Kaf बनाम फ़ारसी Yeh और Keheh
ARABIC LETTER YEH (U+064A) और ARABIC LETTER FARSI YEH (U+06CC) अलग-अलग कैरेक्टर हैं, और यही बात ARABIC LETTER KAF (U+0643) तथा ARABIC LETTER KEHEH (U+06A9) पर लागू होती है। शब्द के शुरू में या बीच में वे एक जैसे दिखते हैं; शब्द के अंत में अलग। स्ट्रिंग की तुलना हमेशा दो अलग कैरेक्टर देखती है। ख़ुद FLORES में भी दोनों मिले-जुले हैं: उसकी फ़ारसी फ़ाइल में 9,570 फ़ारसी Yeh और 2,957 Keheh के साथ-साथ 11 अरबी Yeh और 22 अरबी Kaf भी हैं।
फ़ारसी फ़ाइल के हर फ़ारसी Yeh और Keheh को अरबी Yeh और Kaf की तरह लिख देने पर टोकन की गिनती cl100k_base पर 2.20% बढ़ी, o200k_base पर 9.49%, DeepSeek-V3 पर 10.39% और bge-m3 पर 11.95%; सिर्फ़ Qwen3 पर वह 7.48% घटी। जो बदलाव एक टोकनाइज़र पर टोकन बचाता है, वह बाक़ी चार पर टोकन ख़र्च कराता है।
असली मसला recall का है। अगर स्टोर किया टेक्स्ट और क्वेरी अलग-अलग code point इस्तेमाल करें, तो सटीक और लेक्सिकल मिलान चुपचाप विफल हो जाते हैं। यह साइट फ़ारसी टेक्स्ट को लिखते समय फ़ोल्ड करती है: अरबी Yeh और Kaf अपने फ़ारसी रूपों में बदल जाते हैं, और ZWNJ बना रहता है। सर्च क्वेरी को भी वह ठीक उसी तरह फ़ोल्ड करती है। इसके बिना, अरबी Yeh से टाइप की गई क्वेरी ऐसे कैरेक्टर को ढूँढती है जो इंडेक्स में है ही नहीं, और कुछ नहीं लौटाती।
सामान्य नियम इससे सँकरा है: सिर्फ़ फ़ारसी टेक्स्ट फ़ोल्ड कीजिए, क्योंकि अरबी में अरबी Yeh और Kaf ही सही अक्षर हैं। इस साइट का अपना रिट्रीवर अभी यह फ़र्क़ नहीं करता; वह फ़ारसी फ़ोल्डिंग को हर भाषा की सामग्री और सवालों पर लागू करता है, अरबी पर भी। फ़ारसी RAG के लिए हाइब्रिड सर्च वाला लेख इस कमी को समझाता है और रिट्रीवल पक्ष की बाक़ी बातें भी कवर करता है।
फ़ारसी अंक
ASCII अंकों को फ़ारसी अंकों में लिखने पर टोकन की गिनती 0.48% से 1.47% तक बढ़ी। पाठक को जो दिखता है उसे बदलने की यह कोई वजह नहीं है।
फ़ारसी टोकन की लागत कैसे घटाएँ: मानिए नहीं, टेस्ट कीजिए
इनमें से हर बात पर भरोसा करने से पहले उसे अपने ही ट्रैफ़िक पर टेस्ट कीजिए।
मॉडल अपने ही टेक्स्ट से चुनिए। एक जैसे वाक्यों पर फ़ारसी-से-अंग्रेज़ी का अनुपात 1.10× से 3.26× तक गया।
प्रोवाइडर के एंडपॉइंट से गिनिए। Claude और Gemini के बारे में यहाँ मापे गए अनुपात कुछ नहीं बताते।
मॉडल बदले तो दोबारा गिनिए। नया टोकनाइज़र आपके तय किए हर बजट को हिला सकता है।
चंक और कॉन्टेक्स्ट बजट टोकन में तय कीजिए, हर भाषा के लिए अलग। अंग्रेज़ी के हिसाब से तय की गई अक्षर-सीमा फ़ारसी में ज़्यादा टोकन समेटती है: bge-m3 पर क़रीब एक-छठाई ज़्यादा से लेकर
cl100k_baseपर क़रीब साढ़े तीन गुना तक।आउटपुट की लंबाई पर छत लगाइए। लेटेंसी और लागत, दोनों आउटपुट टोकन से तय होती हैं। Anthropic की सलाह है कि शब्दों की गिनती के बजाय वाक्यों या अनुच्छेदों की संख्या माँगी जाए।
दोहराए जाने वाले कॉन्टेक्स्ट को कैश कीजिए, फिर हिट रेट मापिए। कोई भी बचत इस पर निर्भर है कि आपका prefix सचमुच कितनी बार दोहराया जाता है।
अंग्रेज़ी सिस्टम प्रॉम्प्ट को एक परिकल्पना मानिए। उसमें टोकन कम लगते हैं, पर फ़ारसी जवाबों पर उसका क्या असर पड़ता है, इसका मेरे पास कोई माप नहीं।
टोकन बचाने के लिए न ZWNJ हटाइए, न अक्षर-रूप बदलिए। बचत छोटी या अस्थिर है; टेक्स्ट और मिलान को होने वाला नुक़सान नहीं।
फ़ारसी टोकन का बजट कैसे बनाएँ
प्रति टोकन अक्षरों का नियम हर टोकनाइज़र पर अलग अंदाज़ा है
फ़ारसी cl100k_base पर प्रति टोकन 1.40 अक्षर से लेकर bge-m3 पर 3.68 तक गई, और o200k_base पर 3.01 रही। अंग्रेज़ी 4.30 से 4.91 के बीच रही। Google का Gemini डॉक्यूमेंटेशन कहता है कि “एक टोकन क़रीब 4 अक्षर के बराबर होता है” और उसके साथ अंग्रेज़ी शब्दों की गिनती रखता है: यह अंग्रेज़ी की शक्ल का नियम है, फ़ारसी के बारे में कोई बयान नहीं।
हर दो फ़ारसी अक्षर पर एक टोकन आरक्षित रखना उदार लगता है। यह साइट पहले यही करती थी, और इसीलिए मैंने इसे इन्हीं वाक्यों पर परखा: cl100k_base पर वह सभी 1,012 फ़ारसी वाक्यों की असली गिनती से नीचे रही, और Qwen3 पर 976 वाक्यों की। o200k_base और bge-m3 पर वह टिकी, और DeepSeek-V3 पर 6 वाक्यों पर कम पड़ गई। जो नियम एक टोकनाइज़र पर सुरक्षित है वह अगले पर आशावादी हो सकता है, इसलिए यह साइट अब ऐसा कोई नियम नहीं चलाती।
एक पक्की छत: बाइट की गिनती
बाइट-स्तरीय BPE के लिए टेक्स्ट की बाइट-गिनती, जैसा टोकनाइज़र उसे नॉर्मलाइज़ करता है, पक्की छत है, पर ढीली। प्री-टोकन गिनती पर 0 और बाइट गिनती पर 1 वाले पैमाने पर अंग्रेज़ी 0.015 से 0.017 पर बैठी: अंग्रेज़ी का लगभग हर प्री-टोकन, मोटे तौर पर एक शब्द, अकेला टोकन है। फ़ारसी o200k_base पर 0.07 और cl100k_base पर 0.31 पर बैठी: टुकड़ों में बँटी, पर बाइट के आसपास भी नहीं। इसलिए बाइट के हिसाब से आरक्षण ज़रूरत से कहीं ज़्यादा रोक लेता है। ऐसी सीमा के लिए जिसे कोई पार न कर सके यह सही सौदा है, और पूर्वानुमान के लिए ग़लत सौदा। Claude और Gemini के लिए कॉल से पहले उनके एंडपॉइंट से गिनिए, और कॉल के बाद उनकी बताई खपत दर्ज कीजिए।
कॉल से पहले आरक्षित कीजिए, कॉल के बाद दर्ज कीजिए
इस साइट का सहायक इन दोनों कामों को अलग रखता है। भाषा मॉडल को कॉल करने से पहले वह रिक्वेस्ट के लिए एक अनुमान — प्रॉम्प्ट के टोकन की ऊपरी हद, और पूरी आउटपुट सीमा — महीने के दर्ज ख़र्च में जोड़ता है और कुल को महीने की सीमा से मिलाता है। अगर ख़र्च का काउंटर पढ़ा ही न जा सके, तो वह बंद होकर विफल होता है (fail closed)। सीमा पर मॉडल को कॉल नहीं किया जाता, और पाठक को त्रुटि के बजाय एक सूचना मिलती है। कॉल के बाद वह प्रोवाइडर की बताई खपत दर्ज करता है। अनुमान सिर्फ़ यह तय करता है कि रिक्वेस्ट शुरू हो सकती है या नहीं; चलता हुआ कुल प्रोवाइडर की टोकन गिनतियों से बनता है।
दोनों हिस्सों की अपनी सीमाएँ हैं, उलटी दिशाओं में। कॉल से पहले वाला अनुमान प्रॉम्प्ट को UTF-8 में उसकी बाइट-लंबाई के बराबर गिनता है: ऊपर वाले सेक्शन की छत, कोई पूर्वानुमान नहीं। सहायक को जिन भी शब्दावलियों की तरफ़ मोड़ा जा सकता है, वे सब बाइट-स्तरीय BPE हैं, इसलिए वह छत हर उस मॉडल पर टिकती है जिससे वह बात करता है, और हर उस भाषा पर जिसमें विज़िटर लिखता है। फ़ारसी के लिए यह उससे कई गुना आरक्षित कर देता है जितना प्रॉम्प्ट सचमुच ख़र्च करेगा, जो एक रिक्वेस्ट भर के लिए रोका जाता है और कभी ख़र्च के रूप में दर्ज नहीं होता। पहले वह प्रॉम्प्ट को ऊपर परखे गए दो-अक्षर-प्रति-टोकन वाले सपाट नियम से गिनता था, जो cl100k_base पर सभी 1,012 फ़ारसी वाक्यों पर असली गिनती से नीचे रहा। बहुत छोटा आरक्षण ऐसी सीमा है जो ठीक उसी दिशा में ग़लत है जिसमें किसी सीमा को कभी ग़लत नहीं होना चाहिए, इसलिए बदलाव की वजह यही माप है: अनुमान लगाने वाले फ़ंक्शन का docstring इसी 1,012 वाक्यों वाले रन का हवाला देता है। महीने का कुल, किसी भी सूरत में, दर्ज की गई खपत से बनता है, अनुमान से नहीं।
रिकॉर्ड को एक ख़ामोशी से भी निपटना पड़ता है। OpenAI और Anthropic, दोनों आउटपुट टोकन की जानकारी बनाए गए टेक्स्ट के बाद देते हैं, और OpenAI का स्ट्रीमिंग रेफ़रेंस चेताता है कि अगर स्ट्रीम बीच में टूट जाए या रद्द कर दी जाए तो “हो सकता है आपको आख़िरी usage chunk न मिले”। जल्दी काट दी गई स्ट्रीम — चाहे किसी स्ट्रीमिंग गार्डरेल ने काटी हो या बंद किए गए टैब ने — जानकारी आने से पहले ख़त्म हो जाती है, और उसने जितने कैरेक्टर बनाए वे सब बिल पर हैं। इसलिए सहायक स्ट्रीम होते टेक्स्ट को सँभालकर रखता है, और जहाँ प्रोवाइडर ने कुछ नहीं बताया वहाँ उसी बाइट-गिनती से ख़ाली जगह भरता है, जो कम दर्ज करने के बजाय ज़्यादा दर्ज करती है। जहाँ भी प्रोवाइडर ने कोई आँकड़ा दिया, वही चलता है: पूरा हुआ टर्न ठीक वही दर्ज करता है जो मापा गया, उसका कोई अनुमान नहीं। RAG हैलुसिनेशन गार्डरेल पर लेख दिखाता है कि यह जाँच सहायक की बाक़ी परतों के बीच कहाँ बैठती है।
यही सिद्धांत किसी प्रोडक्ट पर भी लागू होता है। Booq में, जहाँ मैं AI इंजीनियरिंग की अगुवाई करता हूँ, हर जॉब चलने से पहले अपनी क़ीमत या अपना शुरुआती अनुमान दिखाता है, और विफल जॉब अपना चार्ज अपने-आप लौटा देता है, जैसा Booq केस स्टडी बताती है।
अक्सर पूछे जाने वाले सवाल
क्या OpenAI के मॉडलों पर फ़ारसी अंग्रेज़ी से ज़्यादा टोकन लेती है?
हाँ। FLORES-200 के उन्हीं वाक्यों पर फ़ारसी को o200k_base (tiktoken के नक़्शे में GPT-4o, GPT-4.1 और GPT-5) पर अंग्रेज़ी से 1.53× टोकन लगे, और cl100k_base (GPT-4) पर 3.26×। आपका अपना ट्रैफ़िक दूसरा अनुपात देगा, इसलिए उसे गिनिए।
Claude या Gemini पर फ़ारसी कितने टोकन लेती है?
यह माप नहीं बता सकता। Anthropic, Claude के लिए कोई टोकनाइज़र प्रकाशित नहीं करता, और Google का Gen AI SDK कुछ Gemini मॉडलों के लिए खुले Gemma टोकनाइज़र पर बना एक प्रयोगात्मक लोकल काउंट देता है, जिसे मैंने मापा नहीं। ऊपर के अनुपात इन दोनों वेंडर पर लागू नहीं होते। असली रिक्वेस्ट पर Anthropic का count_tokens एंडपॉइंट या Gemini का count_tokens इस्तेमाल कीजिए, और मॉडल बदलें तो दोबारा गिनिए।
क्या अरबी फ़ारसी से सस्ती है?
यहाँ मापे गए पाँच में से चार टोकनाइज़र पर, हाँ: o200k_base पर अरबी को अंग्रेज़ी से 1.38× टोकन लगे, जबकि फ़ारसी को 1.53×। bge-m3 पर मामला उलटा था, 1.17× बनाम 1.10×, जो इससे मेल खाता है कि XLM-R के ट्रेनिंग डेटा में अरबी से कहीं ज़्यादा फ़ारसी थी।
क्या टोकन बचाने के लिए ZWNJ हटा देना या अरबी अक्षर-रूप अपना लेना चाहिए?
नहीं। ZWNJ की जगह स्पेस रखने पर बाइट-स्तरीय टोकनाइज़र पर गिनती 1.57% से 8.08% तक घटी, और शब्द ही बदल गए। अरबी अक्षर-रूपों ने टोकन सिर्फ़ Qwen3 पर बचाए और बाक़ी जगह 2.20% से 11.95% तक ख़र्च कराए। दोनों सटीक मिलान तोड़ देते हैं, जब तक हर क्वेरी भी ठीक उसी तरह न बदले।
फ़ारसी का एक टोकन कितने अक्षर का होता है?
यह टोकनाइज़र पर निर्भर है: इस माप में cl100k_base पर 1.40 से bge-m3 पर 3.68 तक, जबकि अंग्रेज़ी के लिए 4.30 से 4.91। जो सपाट नियम एक टोकनाइज़र पर सुरक्षित है वह दूसरे पर कम गिन सकता है। इस साइट ने इस रन के बाद अपना दो-अक्षर-प्रति-टोकन वाला आरक्षण हटा दिया और उसकी जगह बाइट-गिनती आरक्षित करती है; आम सलाह भी यही है: किसी छत या प्रोवाइडर की गिनती के ख़िलाफ़ आरक्षित कीजिए, अंदाज़े के किसी नियम के ख़िलाफ़ नहीं।
स्रोत
facebookresearch/flores रिपॉज़िटरी: लाइसेंस और आर्काइव सूचना
No Language Left Behind: Scaling Human-Centered Machine Translation (NLLB Team और सहयोगी, 2022)
Language Model Tokenizers Introduce Unfairness Between Languages (Petrov और सहयोगी, NeurIPS 2023)
Petrov और सहयोगी, FLORES-200 पर टोकनाइज़ेशन की लंबाइयाँ (tokenization_lengths.csv)
Tokenization Disparities as Infrastructure Bias (Teklehaymanot और Nejdl, 2025)
Unsupervised Cross-lingual Representation Learning at Scale (Conneau और सहयोगी, XLM-R और CC-100)
Google Gen AI Python SDK: प्रयोगात्मक लोकल टोकनाइज़र (local_tokenizer.py)
Google Gen AI Python SDK: Gemini मॉडल से Gemma टोकनाइज़र का नक़्शा (_local_tokenizer_loader.py)
अगर आप फ़ारसी बोलने वाले उपयोगकर्ताओं के लिए किसी LLM फ़ीचर की योजना बना रहे हैं, तो अपनी परियोजना का दायरा तय कीजिए।