বেশিরভাগ টিমই তাদের প্রথম রিট্রিভাল সিস্টেম একইভাবে তৈরি করে: প্রতিটি ডকুমেন্টকে নির্দিষ্ট ৫১২-টোকেন চঙ্কে ভাগ করা, সেগুলোকে একটি ভেক্টর ডেটাবেসে পাঠানো এবং আশা করা যে এমবেডিং মডেলটি সব কঠিন কাজ করে দেবে। এই আশা আপনাকে একটি ডেমো পার করে দিতে পারে, কিন্তু বাস্তব ব্যবহারকারীদের মুখোমুখি হলে তা টিকে থাকে না।

প্রোডাকশনে, একটি আইনি চুক্তি তখনই ভেঙে পড়ে যখন আপনি একটি দায়বদ্ধতা সংক্রান্ত ধারাকে (liability clause) তার ব্যতিক্রমগুলো থেকে বিচ্ছিন্ন করে ফেলেন। এপিআই (API) ডকুমেন্টেশন তখনই অকেজো হয়ে যায় যখন একটি কোড স্যাম্পল তার ফাংশন সিগনেচার থেকে বিচ্ছিন্ন হয়ে যায়। কাস্টমার সাপোর্ট থ্রেড তখন অর্থহীন হয়ে পড়ে যখন আপনি একটি কথোপকথনের ইতিহাস থেকে একটি মাত্র অভিযোগকে আলাদা করে ফেলেন। সমস্যাটি খুব কমই পাইপলাইনের শেষে থাকা ল্যাঙ্গুয়েজ মডেলের। সমস্যাটি হলো আপনি তাকে কী ইনপুট দিচ্ছেন।

আমরা এটি কঠিন অভিজ্ঞতার মাধ্যমে শিখেছি। আমাদের প্রাথমিক রিট্রিভাল লেয়ার দেখতে সাধারণ মনে হলেও এর আচরণ ছিল অসামঞ্জস্যপূর্ণ। তাই আমরা একটি সহজ ধারণার ভিত্তিতে এটি পুনরায় তৈরি করেছি: রিট্রিভালকে জাদুর মতো নয়, বরং একটি পরিমাপযোগ্য অবকাঠামো (measured infrastructure) হিসেবে বিবেচনা করা। এখানে ঠিক কী কী পরিবর্তন করা হয়েছে এবং কীভাবে আমরা ৯৫তম পার্সেন্টাইল ল্যাটেন্সি ৮৫০ মিলি-সেকেন্ড থেকে কমিয়ে ৩২০ মিলি-সেকেন্ডে এনে রিকল (recall) ৯৫ শতাংশে উন্নীত করেছি, তা বিস্তারিত দেওয়া হলো।

ফিক্সড-চঙ্ক ট্র্যাপ (The Fixed-Chunk Trap)

অভিন্ন টোকেন সংখ্যা কোড করা এবং ব্যাখ্যা করা সহজ। এই সুবিধাটি একটি মৌলিক সত্যকে আড়াল করে রাখে: ডকুমেন্টের একটি গঠন বা স্ট্রাকচার থাকে। যখন আপনি সেই গঠনকে উপেক্ষা করেন, তখন আপনি মূল তথ্য বা সিগন্যাল নষ্ট করে ফেলেন।

একটি দশ পৃষ্ঠার মাস্টার সার্ভিস এগ্রিমেন্টের কথা চিন্তা করুন। একটি নির্দিষ্ট ৫১২-টোকেন চঙ্ক হয়তো কোনো বাধ্যবাধকতার মাঝপথে এসে থামবে, যা একটি ধারাকে তার সীমাবদ্ধতা নির্ধারণকারী টেবিল থেকে বিচ্ছিন্ন করে ফেলবে। ফলে রিট্রিভাল ধাপে অর্ধেক তথ্য পাওয়া যায় এবং জেনারেটর বাকি অংশটি নিজে থেকে বানিয়ে ফেলে (hallucinates)। এপিআই ডকুমেন্টেশনে, একটি চঙ্ক যদি খুব বড় হয়, তবে সেটি অপ্রয়োজনীয় হেডার দিয়ে এমবেডিংকে হালকা করে ফেলে এবং ডেভেলপার যে নির্দিষ্ট মেথডটি খুঁজছেন তা লুকিয়ে ফেলে। সাপোর্ট টিকিটের ক্ষেত্রে, একটি ফিক্সড উইন্ডো কথোপকথনকে কেবল কতগুলো বাক্যের সমষ্টি হিসেবে দেখে, ফলে কথোপকথনের সেই আদান-প্রদান হারিয়ে যায় যা আসলে কী ভুল হয়েছে তা বুঝতে সাহায্য করে।

আমরা চঙ্ক সাইজকে কেবল অনুমানের ভিত্তিতে একটি হাইপারপ্যারামিটার হিসেবে দেখা বন্ধ করেছি। পরিবর্তে, আমরা এটিকে ডকুমেন্টের ধরন এবং এর ভেতরের তথ্য কাঠামোর (information architecture) মধ্যে একটি ম্যাপিং প্রক্রিয়া হিসেবে বিবেচনা করতে শুরু করেছি।

আপনার চঙ্কিং-কে ডেটার সাথে সামঞ্জস্যপূর্ণ করুন

সমাধানটি কোনো একটি নিখুঁত চঙ্ক সাইজে নেই। সমাধানটি হলো তিনটি ভিন্ন ধরনের ডেটা ফরম্যাটের জন্য তিনটি আলাদা কৌশল।

আইনি নথি (Legal documents) এখন রিকার্সিভ স্প্লিটিং (recursive splitting) প্রক্রিয়ার মধ্য দিয়ে যায়। অ্যালগরিদমটি প্রথমে সবচেয়ে বড় প্রাকৃতিক সীমানাগুলো খোঁজে—প্রথমে সেকশন, তারপর সাব-সেকশন এবং তারপর নম্বরযুক্ত ধারা—এবং শুধুমাত্র প্রয়োজনের সময় ছোট ছোট ভাগে ভাগ করে। এটি একটি সমাপ্তি ধারাকে (termination clause) তার প্রাসঙ্গিক শর্তাবলীর সাথে যুক্ত রাখে। রিট্রিভাল ধাপে সম্পূর্ণ লজিক্যাল ইউনিটগুলো পাওয়া যায়, যা মডেলের ভুল বা কাল্পনিক তথ্য তৈরি করার প্রবণতা অনেকাংশে কমিয়ে দেয়।

API এবং কোড ডকুমেন্টেশন স্ট্রাকচার-অ্যাওয়ার (structure-aware) চঙ্কিং ব্যবহার করে। মার্কডাউন হেডার, কোড ফেন্স এবং প্যারামিটার টেবিলগুলোকে স্বতন্ত্র ইউনিট হিসেবে পার্স করা হয়। আমরা কোড ব্লকের ভেতরে ভাগ করি না। আমরা ডকস্ট্রিংগুলোকে (docstrings) তাদের সিগনেচারের পাশেই রাখি। এর ফলে একটি নির্দিষ্ট ক্লাস মেথডের জন্য করা কোয়েরি ডেভেলপারকে প্রয়োজনীয় সম্পূর্ণ প্রেক্ষাপট প্রদান করে: বর্ণনা, টাইপ করা প্যারামিটার এবং একটি কার্যকরী উদাহরণ।

সাপোর্ট এবং কথোপকথনমূলক ডেটা সিম্যান্টিক চঙ্কিং (semantic chunking) ব্যবহার করে। টোকেন গণনার পরিবর্তে, আমরা বিষয় বা উদ্দেশ্যের পরিবর্তন লক্ষ্য করি। যদি একজন গ্রাহক তৃতীয় মেসেজে একটি বাগের বর্ণনা দেন এবং সপ্তম মেসেজে একটি স্ট্যাক ট্রেস (stack trace) পেস্ট করেন, তবে আমরা মেসেজ ইনডেক্সের পরিবর্তে অর্থের ভিত্তিতে চঙ্ক করি। ফলে রিট্রিভাল লেয়ার একটি বিচ্ছিন্ন বাক্যের পরিবর্তে সমস্যার সম্পূর্ণ প্রেক্ষাপট প্রদান করে।

কেন শুধু ভেক্টর সার্চ যথেষ্ট নয়

নিখুঁত চঙ্ক হওয়া সত্ত্বেও শুধুমাত্র ভেক্টর সার্চে তা ব্যর্থ হতে পারে। ডেন্স এমবেডিং (Dense embeddings) অর্থ এবং সমার্থক শব্দ ধরার ক্ষেত্রে চমৎকার হলেও, হুবহু স্ট্রিং বা শব্দের ক্ষেত্রে এগুলো বেশ অস্পষ্ট। যদি একজন ইঞ্জিনিয়ার সুনির্দিষ্ট এরর কোড ERR_CONNECTION_REFUSED লিখে সার্চ করেন, তবে ভেক্টর সিমিলারিটি হয়তো অনেকগুলো প্রাসঙ্গিক ধারণা প্রদান করবে কিন্তু ১৪ নম্বর র‍্যাঙ্কে থাকা হুবহু ম্যাচটি খুঁজে পাবে না।

BM25-এর মাধ্যমে কিওয়ার্ড সার্চের সমস্যাটি ঠিক উল্টো। এটি হুবহু টোকেন খুঁজে পায় কিন্তু অর্থের উদ্দেশ্য (semantic intent) বুঝতে পারে না। একজন ব্যবহারকারী যদি জিজ্ঞাসা করেন “why is my database down”, তবে সেটি এমন কোনো ডকুমেন্টের সাথে মিলবে না যেখানে লেখা আছে “troubleshooting connection timeouts।”

আমরা এখন উভয় পদ্ধতিই ব্যবহার করি। ভেক্টর এবং কিওয়ার্ডের ফলাফলগুলোকে Reciprocal Rank Fusion-এ পাঠানো হয়, যা কোনো ক্যালিব্রেটেড স্কোর ছাড়াই দুটি র‍্যাঙ্কড লিস্টকে একত্রিত করে। এরপর এই একত্রিত লিস্টটিকে একটি cross-encoder reranker-এর মাধ্যমে পাঠানো হয়। র র‍্যাঙ্কারটি প্রাথমিক রিট্রিভালের চেয়ে ধীরগতির হলেও এটি অনেক বেশি নির্ভুল, কারণ এটি কম্প্রেসড এমবেডিংয়ের পরিবর্তে সরাসরি কোয়েরি এবং ডকুমেন্টের প্রাসঙ্গিকতা বিচার করে। শুধুমাত্র এই হাইব্রিড পাইপলাইনের মাধ্যমেই আমাদের রিকল ১৫ শতাংশ বৃদ্ধি পেয়েছে।

ইনডেক্সে পৌঁছানোর আগেই ত্রুটিপূর্ণ কোয়েরি সংশোধন করা

ব্যবহারকারীরা আদর্শ সার্চ কুয়েরি লেখেন না। তারা অসম্পূর্ণ লগ লাইন পেস্ট করেন। তারা লেখেন “it’s broken.” তারা এমন সব টেকনিক্যাল শব্দ (jargon) ব্যবহার করেন যা আপনার ডকুমেন্টেশনে নেই। আপনি যদি সরাসরি কুয়েরির ওপর ভরসা করেন, তবে আপনি মূলত নয়েজ বা অপ্রাসঙ্গিক তথ্যের ওপর ভরসা করছেন।

আমরা এখন প্রতিটি ইনকামিং কুয়েরিকে রিট্রিভাল লেয়ারে পাঠানোর আগে তিন থেকে পাঁচটি ভিন্ন রূপে (variations) সম্প্রসারিত করি। একটি ভ্যারিয়েশন হতে পারে সরাসরি প্যারাফ্রেজ। অন্যটি হতে পারে একটি কাল্পনিক আদর্শ ডকুমেন্ট টাইটেল। তৃতীয়টি কথোপকথনের অপ্রয়োজনীয় অংশ বাদ দিয়ে শুধুমাত্র টেকনিক্যাল কিওয়ার্ডগুলো আলাদা করে। প্রতিটি ভ্যারিয়েশন এমবেড (embed) করা হয় এবং সার্চ করা হয়। এরপর আমরা ডুপ্লিকেটগুলো বাদ দিয়ে ক্যান্ডিডেট পুলগুলোকে মার্জ করি।

এটি বিনামূল্যে হয় না। অতিরিক্ত এমবেডিং কলের জন্য খরচ হয় এবং কয়েক মিলিসেকেন্ড সময়ও বেশি লাগে। কিন্তু রিকল (recall)-এর ওপর এর প্রভাব ছিল নাটকীয়: রিট্রিভালের আগে কুয়েরি সম্প্রসারণ করার মাধ্যমে আমরা ৭৮ শতাংশ থেকে ৯৬ শতাংশে পৌঁছেছি। যেহেতু উন্নত রিট্রিভাল জেনারেশন উইন্ডোকে ছোট করে এবং মডেলকে সঠিক কনটেক্সটের ওপর ভিত্তি করে কাজ করতে সাহায্য করে, তাই শেষ পর্যন্ত আমরা খরচ সাশ্রয় করতে পেরেছি। একটি কিছুটা ব্যয়বহুল রিট্রিভাল ধাপ একটি দীর্ঘ এবং হ্যালুসিনেশনযুক্ত (hallucinated) জেনারেশন ধাপের চেয়ে অনেক সাশ্রয়ী।

অনুমান করা বন্ধ করুন। সার্চ করা শুরু করুন।

সঠিক চাঙ্কিং (chunking), হাইব্রিড রিট্রিভাল এবং কুয়েরি সম্প্রসারণ ব্যবস্থা চালু করার পরেও আমরা একটি জটিল সমন্বয়গত সমস্যার (combinatorial mess) সম্মুখীন হই। চাঙ্ক সাইজ, চাঙ্ক ওভারল্যাপ, top-k রিট্রিভাল ডেপথ, reranker কাটঅফ এবং ফিউশন ওয়েট—সবগুলো একে অপরের সাথে সম্পর্কিত। একটি ম্যানুয়াল গ্রিড সার্চ করতে কয়েক সপ্তাহ সময় লাগত এবং তবুও আমরা একটি লোকাল ম্যাক্সিমামে (local maximum) আটকে থাকতাম।

এই স্পেসটি এক্সপ্লোর করার জন্য আমরা Bayesian optimization ব্যবহার শুরু করি। প্রতিটি কম্বিনেশন পরীক্ষা না করে, সার্চ অ্যালগরিদমটি কোন কনফিগারেশনগুলো ভালো কাজ করতে পারে সে সম্পর্কে একটি ধারণা বজায় রাখে এবং ধীরে ধীরে সম্ভাবনাময় অঞ্চলগুলোর দিকে অগ্রসর হয়।

এর আউটপুট কোনো একটি একক নিখুঁত সেটিংস নয়। এটি হলো পছন্দের একটি Pareto frontier। একদিকে আমাদের কাছে একটি লিন (lean) কনফিগারেশন আছে যা আমাদের হাই-থ্রুপুট API সাপোর্ট এন্ডপয়েন্টের জন্য অপ্টিমাইজ করা: দ্রুত ইনফারেন্স, মাঝারি রিকল এবং সর্বনিম্ন ল্যাটেন্সি। অন্যদিকে, লিগ্যাল রিভিউয়ের জন্য আমাদের কাছে একটি অ্যাগ্রেসিভ কনফিগারেশন আছে: গভীরতর রিট্রিভাল, ভারী র র‍্যাঙ্কিং এবং টাইট ওভারল্যাপ, যেখানে নিখুঁত ফলাফলের জন্য কয়েক মিলিসেকেন্ড ত্যাগ করা হয়। যেহেতু এই ফ্রন্টিয়ারটি স্পষ্ট, তাই আমরা "একই মাপ সবার জন্য" (one size fits all) বলে দাবি না করে পণ্যের জন্য সঠিক পয়েন্টটি বেছে নিতে পারি।

সংখ্যাগুলো আসলে কী বলছে

এই পরিবর্তনগুলো সিস্টেমটিকে একটি ভঙ্গুর প্রোটোটাইপ থেকে একটি পরিমাপযোগ্য প্রোডাকশন পাইপলাইনে রূপান্তরিত করেছে।

Recall at ten ৭৮ শতাংশ থেকে বেড়ে ৯৫ শতাংশ হয়েছে। এর মানে হলো, যখন আমাদের কর্পাস বা তথ্যের ভাণ্ডারে সঠিক উত্তরটি থাকে, তখন আমরা বিশবারের মধ্যে উনিশবার সেটি খুঁজে পাই।

95th percentile-এ ল্যাটেন্সি ৮৫০ ms থেকে কমে ৩২০ ms হয়েছে। কাগজে-কলমে হাইব্রিড স্ট্যাকটি ভারী মনে হলেও, স্মার্ট ইনডেক্সিং, ছোট র র‍্যাঙ্কার এবং প্রয়োজন অনুযায়ী শুধুমাত্র অ্যাগ্রেসিভ চাঙ্কগুলো ব্যবহারের ক্ষমতার কারণে পুরো সিস্টেমটি দ্রুততর হয়েছে।

হ্যালুসিনেশন রেট—যা একটি হোল্ড-আউট গোল্ডেন ডেটাসেটে হিউম্যান অ্যানোটেশনকারীদের মাধ্যমে ট্র্যাক করা হয়েছে—১২ শতাংশ থেকে কমে ৩ শতাংশে নেমে এসেছে। যখন মডেলটি সম্পূর্ণ এবং প্রাসঙ্গিক কনটেক্সট পায়, তখন এটি কাল্পনিক তথ্য তৈরি করা বন্ধ করে দেয়।

প্রতি কুয়েরির খরচ $০.০০৮ থেকে কমে $০.০০৫ হয়েছে। উন্নত রিট্রিভাল মানে হলো ছোট এবং আরও ফোকাসড LLM প্রম্পট এবং কম রিকভারি প্রচেষ্টা। কুয়েরি সম্প্রসারণের জন্য অতিরিক্ত এমবেডিং খরচ জেনারেশনে সাশ্রয় হওয়া অর্থের তুলনায় নগণ্য।

একটি গোল্ডেন ডেটাসেট তৈরি করুন এবং রিট্রিভালকে কোডের মতো বিবেচনা করুন

আপনি যদি এখান থেকে একটি জিনিস শিখতে চান, তবে তা হলো পরিমাপের শৃঙ্খলা (discipline of measurement)। আমরা বাস্তব প্রশ্ন এবং যাচাইকৃত উত্তরের অবস্থানের একটি ছোট গোল্ডেন ডেটাসেট তৈরি করেছি। প্রোডাকশনে কোনো পরিবর্তন আনার আগে সেটি সেই ডেটাসেটের বিপরীতে পরীক্ষা করা হয়। রিকল এবং ল্যাটেন্সি রিয়েল-টাইমে মনিটর করা হয়, নোটবুকে আন্দাজ করা হয় না।

রিট্রিভাল কোনো রিসার্চ ডেমো নয়। এটি একটি ইনফ্রাস্ট্রাকচার। আপনার স্ট্যাকের অন্যান্য অংশের মতো এটিও ইউনিট টেস্ট, রিগ্রেশন বেঞ্চমার্ক এবং স্বয়ংক্রিয় অপ্টিমাইজেশনের দাবি রাখে। টোকেন বা সংখ্যার অন্ধবিশ্বাসের পরিবর্তে ডকুমেন্ট স্ট্রাকচার অনুযায়ী চাঙ্কিং করুন। ভেক্টর এবং কিওয়ার্ড সার্চকে একটি র র‍্যাঙ্কারের সাথে যুক্ত করুন। ব্যবহারকারীরা আসলে যা লেখেন সেই কুয়েরিগুলোকে সম্প্রসারিত করুন। তারপর আপনার অনুমানের পরিবর্তে একটি সার্চ অ্যালগরিদমকে প্যারামিটারগুলো (knobs) টিউন করতে দিন।

আমরা যে পাইপলাইনের বর্ণনা দিয়েছি তা তাত্ত্বিক নয়। আপনি মূল লেখাটি এখানে পড়তে পারেন, এবং আপনি যদি এই বিষয়ে আগ্রহী কোনো কমিউনিটির সাথে রিট্রিভাল ইঞ্জিনিয়ারিং নিয়ে আলোচনা করতে চান, তবে GyaanSetu AI group আপনার জন্য উন্মুক্ত।