বেশিরভাগ ইঞ্জিনিয়ারিং টিম retrieval-augmented generation (RAG)-এর ক্ষেত্রে একই বাধার সম্মুখীন হয়। তারা টিউটোরিয়াল অনুসরণ করে: ডকুমেন্টগুলোকে ৫০০১২ বা ১,০২৪ টোকেনের নির্দিষ্ট চাঙ্কে (chunk) ভাগ করে, একটি মাত্র এমবেডিং মডেলের (embedding model) মাধ্যমে পাঠায় এবং একটি ভেক্টর ডেটাবেস থেকে সাধারণ top-k lookup-এর মাধ্যমে তথ্য খুঁজে বের করে। একটি স্লাইড ডেক বা প্রেজেন্টেশনে এটি বেশ কার্যকর মনে হতে পারে, কিন্তু প্রোডাকশনে এটি ব্যর্থ হয়।
নির্দিষ্ট আকারের চাঙ্কগুলো কন্টেন্টের (content) তোয়াক্কা করে না। তারা একটি আইনি চুক্তিকে (legal contract) অনায়াসেই বাক্যের মাঝপথে ভেঙে ফেলতে পারে, যার ফলে দায়বদ্ধতার ধারাগুলো (liability clauses) দুটি সম্পর্কহীন টেক্সটের মাঝে ঝুলে থাকে। তারা একটি সম্পূর্ণ API endpoint-এর বর্ণনাকে এমন একটি বিশাল চাঙ্কে ঠেলে দিতে পারে যে, ব্যবহারকারী যে নির্দিষ্ট প্যারামিটারটি সম্পর্কে জানতে চেয়েছেন তা তথ্যের ভিড়ে হারিয়ে যায়। আর যখন রিট্রিভাল (retrieval) ধীরগতির হয়, তখন প্রতিটি মিলিসেকেন্ডের ল্যাটেন্সি (latency) সরাসরি ব্যবহারকারীর অভিজ্ঞতায় নেতিবাচক প্রভাব ফেলে। আমরা এটি কঠিন অভিজ্ঞতার মাধ্যমে শিখেছি। এরপর আমরা আমাদের রিট্রিভাল লেয়ারটি ভেঙে নতুন করে তৈরি করেছি। আমাদের 'recall at ten' ৭৮% থেকে বেড়ে ৯৫% হয়েছে। ল্যাটেন্সি বাড়েনি, বরং তা নাটকীয়ভাবে কমে গেছে।
কপি-পেস্ট RAG-এর সমস্যা
স্ট্যান্ডার্ড RAG স্ট্যাক এখন এক ধরণের ডিফল্ট সেটিংসে পরিণত হয়েছে। ছোট চাঙ্ক, একটি এমবেডিং মডেল, ভেক্টর সার্চ—ব্যাস, কাজ শেষ। এই পদ্ধতিটি ডেমোতে সফল হতে পারে কারণ ডেমোতে পরিষ্কার প্রশ্ন এবং গোছানো ডকুমেন্ট ব্যবহার করা হয়। কিন্তু প্রোডাকশন ডেটা কখনোই গোছানো থাকে না।
আইনি নথিপত্রের একটি 계층적 (hierarchical) কাঠামো থাকে। সেকশনের মধ্যে থাকে সাব-সেকশন, আর সাব-সেকশনের মধ্যে থাকে ক্লজ (clause)। একটি সাধারণ টোকেন কাউন্টার দিয়ে এগুলোকে ভাগ করলে আপনি সেই সম্পর্কগুলোই নষ্ট করে ফেলেন যা মডেলটির যুক্তি দেওয়ার (reasoning) জন্য প্রয়োজন। API ডকুমেন্টেশনেরও একটি কাঠামো আছে, তবে তা ভিন্ন। একটি ফাংশন সিগনেচার, এর প্যারামিটার, রিটার্ন ভ্যালু এবং একটি উদাহরণ ব্যবহারের মাধ্যমে একটি লজিক্যাল ইউনিট তৈরি হয়। এগুলোকে একটি নির্দিষ্ট টোকেন উইন্ডোতে জোর করে প্রবেশ করালে হয় উদাহরণটি অসম্পূর্ণ থেকে যায়, অথবা চাঙ্কটি অপ্রাসঙ্গিক ফাংশনে ভরে যায়। সাপোর্ট টিকিটগুলো অগোছালো, কথোপকথনমূলক এবং হঠাৎ বিষয় পরিবর্তনের প্রবণতা সম্পন্ন। উইকিগুলো বিশাল এবং ক্রস-রেফারেন্সযুক্ত। একটি মাত্র চাঙ্কিং কৌশল এই সবগুলোর জন্য কাজ করতে পারে না, তবুও টিমগুলো নিয়মিত ঠিক সেটিই ব্যবহার করে। আমরা আর এমন ভান করা বন্ধ করেছি যে এটি সম্ভব।
কৌশলগত চাঙ্কিং: উপাদানের সাথে পদ্ধতির সামঞ্জস্য বিধান
আমরা কন্টেন্ট-অ্যাওয়ার (content-aware) চাঙ্কিংয়ে চলে এসেছি। আইনি নথিপত্রের জন্য আমরা রিকার্সিভ চাঙ্কিং (recursive chunking) ব্যবহার করি যা ডকুমেন্টের হায়ারার্কিকে সম্মান করে। এটি ক্লজগুলোকে অক্ষত রাখে এবং সেকশনগুলোর মধ্যে প্যারেন্ট-চাইল্ড সম্পর্ক বজায় রাখে। API ডকুমেন্টেশনের জন্য আমরা ফাংশন-অ্যাওয়ার (function-aware) চাঙ্কিং তৈরি করেছি যা প্রতিটি ফাংশন বা এন্ডপয়েন্টকে একটি সীমানা হিসেবে বিবেচনা করে। যদি কোনো প্যারামিটারের বর্ণনা দীর্ঘ হয়, তবে চাঙ্কটি টোকেন লিমিটের পরিবর্তে সেই ফাংশনের চারপাশে প্রসারিত হয়। সাপোর্ট টিকিটের জন্য আমরা সিম্যান্টিক চাঙ্কিং (semantic chunking) ব্যবহার করি যা আলোচনার স্বাভাবিক সীমানা শনাক্ত করতে পারে। যখন একজন গ্রাহক হঠাৎ বিলিং সংক্রান্ত অভিযোগ থেকে টেকনিক্যাল বাগ-এর বিষয়ে চলে যান, তখন বিভাজনটি ঠিক সেই সন্ধিক্ষণে ঘটে। উইকি এবং অসংগঠিত নলেজ বেসের জন্য আমরা এজেন্টিক চাঙ্কিং (agentic chunking) ব্যবহার করি যেখানে একটি হালকা ওজনের LLM টেক্সটটি মূল্যায়ন করে এবং সিদ্ধান্ত নেয় কোথায় একটি অর্থপূর্ণ সীমানা হওয়া উচিত। ক্যারেক্টার স্প্লিটের তুলনায় এটি সেটআপ করা ধীরগতির, কিন্তু এটি কার্যকর রিট্রিভাল এবং কেবল অনুমানের ভিত্তিতে করা রিট্রিভালের মধ্যে পার্থক্য গড়ে দেয়।
হাইব্রিড রিট্রিভাল: কেন শুধু ভেক্টর সার্চ যথেষ্ট নয়
ভেক্টর সার্চ অর্থ বুঝতে পারে, কিন্তু এটি হুবহু মিল (exact matches) মিস করতে পারে। যদি কোনো ব্যবহারকারী ERR_CONNECTION_RESET_0x5F3 এর মতো একটি এরর কোড পেস্ট করেন, তবে সিম্যান্টিক সিমিলারিটি (semantic similarity) এটিকে সাধারণ নেটওয়ার্ক এরর নিয়ে আলোচনা করা অনুচ্ছেদগুলোর নিচে র্যাঙ্ক করতে পারে। অন্যদিকে, BM25 হুবহু স্ট্রিং খুঁজে পায় কিন্তু ধারণাগত সম্পর্ক (conceptual relatedness) বুঝতে পারে না। আপনার এই দুটিরই প্রয়োজন।
আমরা ভেক্টর সার্চ এবং BM25 সমান্তরালভাবে চালাই। তারপর আমরা Reciprocal Rank Fusion বা RRF-এর মাধ্যমে ফলাফলগুলো একত্রিত করি, যা দুটি ভিন্ন সার্চ স্পেসের স্কোরগুলোকে একই স্কেলে না এনে বরং নরমালাইজ (normalize) করে। ফিউশনের পরে, আমরা শীর্ষস্থানীয় প্রার্থীদের একটি ক্রস-এনকোডার র র্যাঙ্কার (cross-encoder reranker)-এর মাধ্যমে পাঠাই। এটি সামান্য ল্যাটেন্সি যোগ করে, তবে এর ফলে প্রিসিশন (precision) উল্লেখযোগ্যভাবে বৃদ্ধি পায়। র র্যাঙ্কারটি কুয়েরি এবং প্রতিটি প্রার্থীকে একসাথে পড়ে এবং একটি প্রাসঙ্গিকতা স্কোর (relevance score) প্রদান করে, যা প্রাথমিক এমবেডিংয়ের কোসাইন সিমিলারিটির (cosine similarity) চেয়ে অনেক বেশি নির্ভুল। বাস্তবে, এই সমন্বয়টি সেই সব সঠিক এরর কোডগুলোকে ধরে ফেলে যা বিশুদ্ধ ভেক্টর সার্চ মিস করে, পাশাপাশি সেই সব ধারণাগতভাবে সম্পর্কিত ট্রাবলশুটিং ধাপগুলোকেও সামনে নিয়ে আসে যা কিওয়ার্ড সার্চ উপেক্ষা করত।
কুয়েরি এক্সপ্যানশন: ইনডেক্সে পৌঁছানোর আগেই ব্যবহারকারীর ইনপুট ঠিক করা
ব্যবহারকারীরা নিখুঁত সার্চ কুয়েরি লেখেন না। তারা মাল্টি-হপ (multi-hop) প্রশ্ন করেন, যেমন "কেন আমার শেষ ডিপ্লয়মেন্টটি ব্যর্থ হয়েছে এবং আমি কীভাবে এটি রোলব্যাক করতে পারি?"—যার জন্য দুটি আলাদা জ্ঞান বা তথ্যের উৎস খুঁজে বের করা এবং সেগুলোকে সংযুক্ত করা প্রয়োজন। অথবা তারা এমন অস্পষ্ট প্রশ্ন করেন যা ইনডেক্সের সাথে সঠিকভাবে মেলে না।
We transform queries before searching. A multi-hop question gets broken into sub-questions. A vague intent gets expanded into multiple specific search queries. We found that expanding one user query into five distinct search queries can move recall from seventy-eight percent to ninety-six percent. This is not about prompting the LLM harder. It is about giving the retrieval system more shots at finding the right context. Each generated query captures a different angle or terminology, and the merged results paint a complete picture.
Bayesian Optimization: Stop Guessing
Once you have multiple chunking strategies, hybrid retrieval, and query expansion, you face a new problem. There are too many knobs. Chunk size, overlap percentage, vector weight versus BM25 weight, reranking thresholds, and top-k values all interact in nonlinear ways. Manual tuning becomes a guessing game.
We stopped guessing. We treat the
