زیادہ تر ٹیمیں اپنا پہلا ریٹریول سسٹم (retrieval system) ایک ہی طریقے سے بناتی ہیں: ہر دستاویز کو 512-ٹکن کے مقررہ ٹکڑوں (chunks) میں تقسیم کرنا، انہیں ویکٹر ڈیٹا بیس میں ڈالنا، اور یہ امید کرنا کہ ایمبیڈنگ ماڈل (embedding model) سارا مشکل کام کر دے گا۔ یہ امید آپ کو ایک ڈیمو (demo) میں تو گزار دے گی، لیکن حقیقی صارفین کے سامنے یہ کام نہیں آتی۔
پروڈکشن میں، ایک قانونی معاہدہ اس وقت ناکام ہو جاتا ہے جب آپ ذمہ داری کی کسی شق (liability clause) کو اس کے استثنیٰ (exceptions) سے الگ کر دیتے ہیں۔ جب کوڈ کا نمونہ (code sample) اپنے فنکشن سگنیچر (function signature) سے الگ ہو جائے تو API ڈاکومنٹیشن بے کار ہو جاتی ہے۔ جب آپ کسی ایک شکایت کو اس کی گفتگو کی تاریخ سے الگ کر دیتے ہیں تو کسٹمر سپورٹ کا تھریڈ محض شور بن کر رہ جاتا ہے۔ مسئلہ شاذ و نادر ہی پائپ لائن کے آخر میں موجود لینگویج ماڈل کا ہوتا ہے۔ مسئلہ اس چیز کا ہے جو آپ اسے فراہم کرتے ہیں۔
ہم نے یہ سبق بڑی مشکل سے سیکھا۔ ہمارا ابتدائی ریٹریول لیئر (retrieval layer) دیکھنے میں تو معیاری لگتا تھا لیکن اس کا طرزِ عمل غیر مستقل تھا۔ چنانچہ ہم نے اسے ایک سادہ سے تصور کے گرد دوبارہ ترتیب دیا: ریٹریول کو جادو کے بجائے ایک پیمائش کے قابل انفراسٹرکچر کے طور پر دیکھیں۔ یہاں تفصیل ہے کہ اصل میں کیا بدلا، اور ہم نے 95 ویں پرسنٹائل لیٹنسی (95th-percentile latency) کو 850 ms سے کم کر کے 320 ms تک لاتے ہوئے ریکال (recall) کو 95 فیصد تک کیسے پہنچایا۔
مقررہ ٹکڑوں (Fixed-Chunk) کا جال
یکساں ٹکن کی تعداد کوڈ کرنے اور سمجھانے میں آسان ہوتی ہے۔ یہ سہولت ایک بنیادی حقیقت کو چھپاتی ہے: دستاویزات کی ایک ساخت (structure) ہوتی ہے۔ جب آپ اس ساخت کو نظر انداز کرتے ہیں، تو آپ معلومات کے اہم اشارے (signal) کو تباہ کر دیتے ہیں۔
دس صفحات کے ایک ماسٹر سروس معاہدے پر غور کریں۔ 512-ٹکن کا ایک مقررہ ٹکڑا کسی ذمہ داری کے درمیان میں آ جائے گا، جس سے ایک شق (clause) اس کی حد مقرر کرنے والی ٹیبل سے الگ ہو جائے گی۔ اس کے بعد ریٹریول کا مرحلہ ادھورا خیال واپس کرتا ہے، اور جنریٹر (generator) باقی حصہ خود سے ایجاد (hallucinate) کر لیتا ہے۔ API ڈاکومنٹیشن میں، ایک بہت بڑا ٹکڑا بوائلر پلیٹ ہیڈرز (boilerplate headers) کی وجہ سے ایمبیڈنگ کو کمزور کر دیتا ہے، جس سے وہ مخصوص میتھڈ دب جاتا ہے جس کی ڈویلپر کو ضرورت ہوتی ہے۔ سپورٹ ٹکٹس میں، ایک مقررہ ونڈو گفتگو کو محض جملوں کے مجموعے کے طور پر دیکھتی ہے، اور اس باہمی گفتگو کو ختم کر دیتی ہے جو یہ ظاہر کرتی ہے کہ اصل میں کیا ناکام ہوا۔
ہم نے چنک سائز (chunk size) کو محض ایک اندازے پر مبنی ہائپر پیرامیٹر (hyperparameter) سمجھنا چھوڑ دیا۔ ہم نے اسے دستاویز کی قسم اور اس کے اندر موجود انفارمیشن آرکیٹیکچر کے درمیان ایک میپنگ کے عمل کے طور پر دیکھنا شروع کیا۔
اپنے چنکنگ کو ڈیٹا کے مطابق بنائیں
اس کا حل کوئی ایک بہترین چنک سائز نہیں ہے۔ حل تین مختلف حکمت عملیوں میں ہے جو ڈیٹا کی تین مختلف شکلوں کے مطابق تیار کی گئی ہیں۔
قانونی دستاویزات اب ریکرسو سپلٹنگ (recursive splitting) سے گزرتی ہیں۔ الگورتھم پہلے سب سے بڑی قدرتی حدود تلاش کرتا ہے—پہلے سیکشنز، پھر سب سیکشنز، پھر نمبر والے کلازز—اور صرف ضرورت پڑنے پر ہی چھوٹے ٹکڑوں کی طرف جاتا ہے۔ یہ ٹرمینیشن کلاز (termination clause) کو اس کی بقا کی شرائط کے ساتھ جوڑے رکھتا ہے۔ ریٹریول کا مرحلہ مکمل منطقی اکائیاں دیکھتا ہے، جس سے ماڈل کی جانب سے گمشدہ استثنیٰ خود سے ایجاد کرنے کا رجحان تیزی سے کم ہو جاتا ہے۔
API اور کوڈ ڈاکومنٹیشن کے لیے اسٹرکچر کے بارے میں آگاہ (structure-aware) چنکنگ استعمال کی جاتی ہے۔ مارک ڈاؤن ہیڈرز، کوڈ فینسز (code fences)، اور پیرامیٹر ٹیبلز کو ایٹمی اکائیوں (atomic units) کے طور پر پروسیس کیا جاتا ہے۔ ہم کوڈ بلاک کے اندر تقسیم نہیں کرتے۔ ہم ڈاک اسٹرنگز (docstrings) کو ان کے سگنیچرز کے قریب رکھتے ہیں۔ اس کا نتیجہ یہ ہوتا ہے کہ کسی مخصوص کلاس میتھڈ کے لیے کی گئی تلاش ڈویلپر کو مطلوبہ مکمل سیاق و سباق فراہم کرتی ہے: تفصیل، ٹائپ شدہ پیرامیٹرز، اور کام کرنے والا نمونہ۔
سپورٹ اور گفتگو کے ڈیٹا کے لیے سیمنٹک چنکنگ (semantic chunking) استعمال کی جاتی ہے۔ ٹکنز گننے کے بجائے، ہم موضوع یا ارادے (intent) میں تبدیلی تلاش کرتے ہیں۔ اگر کوئی صارف تیسرے پیغام میں بگ (bug) بیان کرتا ہے اور ساتویں پیغام میں اسٹیک ٹریس (stack trace) پیسٹ کرتا ہے، تو ہم پیغام کے انڈیکس کے بجائے معنی کے لحاظ سے ٹکڑے کرتے ہیں۔ اس طرح ریٹریول لیئر کسی اکیلے جملے کے بجائے مسئلے کا مکمل تسلسل واپس کرتی ہے۔
صرف ویکٹر سرچ کیوں ناکام ہو جاتی ہے
بہترین چنکس بھی خالص ویکٹر سرچ میں ناکام ہو جاتے ہیں۔ ڈینس ایمبیڈنگز (Dense embeddings) معنی اور مترادفات کو سمجھنے میں بہترین ہیں، لیکن وہ درست الفاظ (exact strings) کے معاملے میں غیر واضح ہوتی ہیں۔ اگر کوئی انجینئر بالکل درست ایرر کوڈ ERR_CONNECTION_REFUSED تلاش کرتا ہے، تو ویکٹر سیمیلرٹی (vector similarity) شاید درجن بھر تصوراتی نتائج دکھا دے لیکن چودہویں نمبر پر موجود درست میچ کو نظر انداز کر دے۔
BM25 کے ساتھ کی ورڈ سرچ (keyword search) کا مسئلہ اس کے برعکس ہے۔ یہ درست ٹکنز تو ڈھونڈ لیتی ہے لیکن سماجی مفہوم (semantic intent) کو نہیں سمجھ پاتی۔ ایک صارف جو پوچھے "میرا ڈیٹا بیس کیوں بند ہے" (why is my database down)، وہ کبھی بھی اس دستاویز سے میچ نہیں کر پائے گا جس میں "کنکشن ٹائم آؤٹ کا حل" (troubleshooting connection timeouts) لکھا ہو۔
اب ہم دونوں استعمال کرتے ہیں۔ ویکٹر اور کی ورڈ کے نتائج کو Reciprocal Rank Fusion میں ڈالا جاتا ہے، جو کیلبریٹڈ اسکورز کے بغیر دونوں رینکڈ لسٹوں کو ملا دیتا ہے۔ اس کے بعد اس ملی ہوئی لسٹ کو کراس انکوڈر ری رینکر (cross-encoder reranker) سے گزارا جاتا ہے۔ ری رینکر ابتدائی ریٹریول سے سست ہے، لیکن یہ کہیں زیادہ درست ہے کیونکہ یہ کمپریسڈ ایمبیڈنگز کے بجائے براہ راست سوال اور دستاویز کی مطابقت کا فیصلہ کرتا ہے۔ صرف اس ہائبرڈ پائپ لائن نے ہمارے ریکال کو 15 فیصد بڑھا دیا۔
انڈیکس تک پہنچنے سے پہلے خراب سوالات کی اصلاح
صارفین مثالی سرچ کوئریز (search queries) نہیں لکھتے۔ وہ ادھورے لاگ لائنز (log lines) پیسٹ کرتے ہیں۔ وہ لکھتے ہیں "یہ خراب ہے"۔ وہ ایسی اصطلاحات استعمال کرتے ہیں جو آپ کی دستاویزات میں کبھی نہیں آئیں۔ اگر آپ خام کوئری پر بھروسہ کرتے ہیں، تو آپ شور (noise) پر بھروسہ کر رہے ہیں۔
اب ہم ہر آنے والی کوئری کو ریٹریول لیئر (retrieval layer) پر بھیجنے سے پہلے تین سے پانچ مختلف شکلوں (variations) میں پھیلاتے ہیں۔ ایک شکل براہ راست الفاظ کی تبدیلی (paraphrase) ہو سکتی ہے۔ دوسری ایک مفروضہ مثالی دستاویز کا عنوان ہو سکتی ہے۔ تیسری گفتگو کے غیر ضروری الفاظ کو ہٹا کر صرف تکنیکی کلیدی الفاظ (technical keywords) کو الگ کرتی ہے۔ ہر ورژن کو ایمبیڈ (embed) کیا جاتا ہے اور تلاش کیا جاتا ہے۔ پھر ہم امیدواروں کے پولز (candidate pools) کو ڈی ڈپلیکیٹ (deduplicate) اور ضم کر دیتے ہیں۔
یہ مفت نہیں ہے۔ ان اضافی ایمبیڈنگ کالز (embedding calls) پر خرچ ہوتا ہے اور چند ملی سیکنڈز کا وقت بھی لگتا ہے۔ لیکن ریکال (recall) پر اس کا اثر ڈرامائی تھا: کوئریز کو ریٹریول سے پہلے پھیلانے کے ذریعے ہم 78 فیصد سے 96 فیصد تک پہنچ گئے۔ چونکہ بہتر ریٹریول جنریشن ونڈو (generation window) کو چھوٹا کرتا ہے اور ماڈل کو درست سیاق و سباق (context) فراہم کرتا ہے، اس لیے ہم نے بعد میں (downstream) پیسے بچائے۔ ریٹریول کا ایک تھوڑا مہنگا مرحلہ، ایک طویل اور وہم زدہ (hallucinated) جنریشن مرحلے سے سستا ہے۔
اندازے لگانا چھوڑیں۔ تلاش کرنا شروع کریں۔
جب ہمارے پاس صحیح چنکنگ (chunking)، ہائبرڈ ریٹریول (hybrid retrieval)، اور کوئری ایکسپینشن (query expansion) آ گیا، تب بھی ہمیں ایک پیچیدہ الجھن کا سامنا تھا۔ چنک کا سائز، چنک کا اوورلیپ (overlap)، ٹاپ-کے (top-k) ریٹریول کی گہرائی، ری رینکر کٹ آف (reranker cutoffs)، اور فیوژن ویٹس (fusion weights) سب ایک دوسرے پر اثر انداز ہوتے ہیں۔ دستی گرڈ سرچ (manual grid search) میں ہفتوں لگ جاتے اور پھر بھی ہمیں صرف ایک مقامی حد (local maximum) ہی مل پاتی۔
ہم نے اس جگہ (space) کو تلاش کرنے کے لیے بیزین آپٹیمائزیشن (Bayesian optimization) کا استعمال کیا۔ ہر ممکنہ مجموعے (combination) کا مکمل تجربہ کرنے کے بجائے، سرچ الگورتھم اس یقین (belief) کو برقرار رکھتا ہے کہ کون سی کنفیگریشنز بہتر کارکردگی دکھانے کا امکان رکھتی ہیں اور بتدریج امید افزا علاقوں کی طرف بڑھتا جاتا ہے۔
اس کا نتیجہ کوئی ایک بہترین سیٹنگ نہیں ہے۔ یہ انتخاب کا ایک پیریٹو فرنٹیر (Pareto frontier) ہے۔ ایک طرف، ہمارے پاس ہمارے ہائی تھرو پٹ API سپورٹ اینڈ پوائنٹ کے لیے ایک ہلکی (lean) کنفیگریشن ہے: تیز انفرنس (inference)، مناسب ریکال، اور کم سے کم ممکنہ لیٹنسی (latency)۔ دوسری طرف، قانونی جائزے (legal review) کے لیے ایک جارحانہ (aggressive) کنفیگریشن ہے: گہرا ریٹریول، بھاری ری رینکرنگ، اور زیادہ اوورلیپ، جو مکمل معلومات کے لیے ملی سیکنڈز کا سودا کرتی ہے۔ چونکہ یہ فرنٹیر واضح ہے، اس لیے ہم "ایک ہی سائز سب کے لیے" کا بہانہ بنانے کے بجائے پروڈکٹ کے لیے صحیح پوائنٹ کا انتخاب کر سکتے ہیں۔
اعداد و شمار حقیقت میں کیسے نظر آتے ہیں
ان تبدیلیوں نے سسٹم کو ایک کمزور پروٹو ٹائپ سے ایک پیمائش شدہ پروڈکشن پائپ لائن (production pipeline) میں بدل دیا۔
'ریکال ایٹ ٹین' (Recall at ten) 78 فیصد سے بڑھ کر 95 فیصد ہو گیا۔ اس کا مطلب ہے کہ جب ہمارے کورپس (corpus) میں درست جواب موجود ہوتا ہے، تو ہم بیس میں سے انیس بار اسے ڈھونڈ لیتے ہیں۔
95 ویں پرسنٹائل (95th percentile) پر لیٹنسی 850 ملی سیکنڈ سے کم ہو کر 320 ملی سیکنڈ ہو گئی۔ ہائبرڈ اسٹیک کاغذ پر بھاری لگتا ہے، لیکن بہتر انڈیکسنگ، چھوٹے ری رینکرز، اور ضرورت پڑنے پر ہی جارحانہ چنکس فراہم کرنے کی صلاحیت نے پورے سسٹم کو تیز بنا دیا۔
وہم کی شرح (Hallucination rate)—جسے انسانی نوٹیشنز (human annotators) نے ایک مخصوص گولڈن ڈیٹا سیٹ پر ٹریک کیا—12 فیصد سے گر کر 3 فیصد ہو گئی۔ جب ماڈل کو مکمل اور متعلقہ سیاق و سباق ملتا ہے، تو وہ حقائق خود سے گھڑنا بند کر دیتا ہے۔
فی کوئری لاگت $0.008 سے کم ہو کر $0.005 ہو گئی۔ بہتر ریٹریول کا مطلب ہے مختصر اور زیادہ مرکوز LLM پرامپٹس اور ریکوری کی کم کوششیں۔ کوئری ایکسپینشن پر ہونے والا اضافی ایمبیڈنگ خرچ، جنریشن میں ہونے والی بچت کے سامنے نہ ہونے کے برابر ہے۔
ایک گولڈن ڈیٹا سیٹ بنائیں اور ریٹریول کے ساتھ کوڈ جیسا سلوک کریں
اگر آپ اس سے ایک بات سیکھتے ہیں، تو وہ پیمائش کا نظم و ضبط (discipline of measurement) ہونی چاہیے۔ ہم نے حقیقی سوالات اور تصدیق شدہ جواب کے مقامات کا ایک چھوٹا گولڈن ڈیٹا سیٹ بنایا۔ کسی بھی تبدیلی کے پروڈکشن میں جانے سے پہلے، اسے اس ڈیٹا سیٹ پر چلا کر دیکھا جاتا ہے۔ ریکال اور لیٹنسی کی نگرانی ریئل ٹائم میں کی جاتی ہے، نہ کہ صرف نوٹ بک میں دیکھ کر اندازہ لگایا جاتا ہے۔
ریٹریول کوئی ریسرچ ڈیمو نہیں ہے۔ یہ انفراسٹرکچر ہے۔ یہ آپ کے اسٹیک کے باقی حصوں کی طرح یونٹ ٹیسٹ (unit tests)، ریگریشن بینچ مارکس (regression benchmarks)، اور خودکار آپٹیمائزیشن کا مستحق ہے۔ چنکنگ دستاویز کی ساخت کے مطابق کریں، نہ کہ ٹوکن کے وہم کے مطابق۔ ویکٹر (vector) اور کی ورڈ سرچ کو ری رینکر کے ساتھ ملا دیں۔ ان کوئریز کو پھیلائیں جو آپ کے صارفین حقیقت میں لکھتے ہیں۔ پھر اپنے وجدان (intuition) کے بجائے ایک سرچ الگورتھم کو کنٹرولز سنبھالنے دیں۔
جو پائپ لائن ہم نے بیان کی ہے وہ نظریاتی نہیں ہے۔ آپ اصل تحریر یہاں پڑھ سکتے ہیں، اور اگر آپ اس معاملے میں دلچسپی رکھنے والی کمیونٹی کے ساتھ ریٹریول انجینئرنگ پر بحث کرنا چاہتے ہیں، تو GyaanSetu AI group کھلا ہے۔
