দীর্ঘ এজেন্ট টার্নকে প্রসঙ্গ-উইন্ডোর ভেতরে রাখা
একটি মডেল একবারে যতটুকু পড়তে পারে — তার প্রসঙ্গ-উইন্ডো — সীমিত। Mythex-এর এজেন্ট দীর্ঘ কাজ করে: অনেক ফাইল পড়া, কমান্ড চালানো, নির্দিষ্ট কাজ সাব-এজেন্টদের দেওয়া। দীর্ঘ কাজ তিনভাবে ভেঙে যেতে দেখেছি: সাব-এজেন্ট এত বড় হয়েছিল যে মডেল প্রতিটি অনুরোধ প্রত্যাখ্যান করেছিল; একটি সাব-এজেন্ট ভেবেছিল তার ঘর শেষ, তাই আগেই থেমে গিয়েছিল; আর রুশ, চীনা ও জাপানি লেখায় আমাদের টোকেন গোনা অনেক ভুল ছিল। কী বদলেছি, তা এখানে।
কয়েকটি শব্দ আগে
- টোকেন হলো মডেলের পড়ার খণ্ডাংশ। সীমা ও খরচ অক্ষর বা শব্দে নয়, টোকেনে গোনা হয়।
- প্রসঙ্গ-উইন্ডো হলো একটি অনুরোধে মডেল সর্বোচ্চ যতটুকু পড়তে পারে। আমাদের নিজস্ব কম বাজেট থাকে প্রতি অনুরোধে, যাতে খরচ ও গতি যুক্তিসঙ্গত থাকে।
- টুল ফলাফল হলো এজেন্ট তার টুল থেকে যা ফেরত পায়: যে ফাইল সে পড়েছে তার বিষয়বস্তু, বা যে কমান্ড চালিয়েছে তার আউটপুট। দীর্ঘ কাজে এগুলোই পাঠানো অংশের বেশিরভাগ।
- সাব-এজেন্ট হলো মূল এজেন্টের শুরু করা একটি সহকারী, একটি স্বয়ংসম্পূর্ণ কাজের জন্য — যেমন “এই অধ্যায়গুলো নোটের সঙ্গে মিলিয়ে দেখো”। সে একটি নির্দেশ পায়, তারপর নিজে অনেক টুল কল করে কাজ শেষ করে।
সমস্যা ১: সাব-এজেন্ট এত বড় হয়েছিল যে মডেল তা ফিরিয়ে দিত
প্রতি ধাপে এজেন্ট এ পর্যন্ত কথোপকথন মডেলকে পাঠায়। সেটি বড় হলে আমাদের কোড তা ছাঁটত — কিন্তু কেবল একটি ব্যবহারকারী-বার্তার শুরুতে, যাতে টুল কল ও তার ফলাফল কখনো আলাদা না হয়। এটি প্রথম বার্তা রাখত, একটি নোট যোগ করত যে আগের কথোপকথন ছাঁটা হয়েছে, এবং যতগুলো সম্পূর্ণ টার্ন ফিট করে সবচেয়ে নতুনগুলো রাখত।
একটি সাব-এজেন্টের ঠিক একটি ব্যবহারকারী-বার্তা থাকে: তার নির্দেশ। সেখানে কাটার কোনো জায়গা ছিল না। তাই সে প্রতি ধাপে তার পুরো ইতিহাস পাঠাত, এবং প্রতিবার আরও বড় হতো, যতক্ষণ না অনুরোধ মডেলের গ্রহণযোগ্য সীমাও ছাড়িয়ে যায় — প্রায় দশ লাখ টোকেন। একটি পরীক্ষায় এমন ৮টি সাব-এজেন্টের সবকটিকেই প্রত্যাখ্যান করা হয়।
সমাধান: আগে পুরনো টুল ফলাফল খালি করা
এখন অনুরোধগুলো তিনটি ধাপে বাজেটে ফিট করানো হয়, প্রতিটি শুধু আগেরটি যথেষ্ট না হলে চালানো হয়:
- সবচেয়ে পুরনো টুল ফলাফল খালি করা। তাদের বিষয়বস্তু একটি ছোট নোট দিয়ে বদলে দেওয়া হয়: মডেলের প্রসঙ্গের মধ্যে রাখতে ফলাফলটি খালি করা হয়েছে, এবং প্রয়োজন হলে এজেন্ট টুলটি আবার চালাতে পারে। এক ঘণ্টা আগের একটি ফাইল পড়া সাধারণত অনুরোধের সবচেয়ে বড় ও কম কাজের জিনিস, আর ফাইলটি আবার পড়ার জন্য তো আছেই। নতুনতম ফলাফলগুলো পূর্ণ থাকে।
- সম্পূর্ণ ব্যবহারকারী-টার্ন রাখা। আগের মতোই: প্রথম বার্তা, একটি নোট, এবং যতগুলো সম্পূর্ণ নতুন টার্ন ফিট করে।
- সম্পূর্ণ টুল রাউন্ড রাখা। একটি দীর্ঘ টার্নের ভেতরে — সাব-এজেন্টের যে একমাত্র ধরন আছে — প্রথম বার্তা, একটি নোট, এবং “একটি টুল কল, তার ফলাফল” এই নতুনতম সম্পূর্ণ রাউন্ডগুলো রাখা।
এটি শুধু কী পাঠানো হবে তা ঠিক করে। এজেন্টের সংরক্ষিত ইতিহাস সবকিছু রাখে। একই পরীক্ষায় ৮টির মধ্যে ০টি প্রত্যাখ্যাত হয় এবং সবকটি শেষ হয়।
ব্যাচে খালি করা, যাতে ক্যাশিং কাজ করে
মডেল প্রদানকারীরা একটি অনুরোধের শুরুর অংশ পুনরায় ব্যবহার করতে পারে, যদি তা আগের অনুরোধের সঙ্গে হুবহু মেলে — একে প্রিফিক্স ক্যাশ বলে। যদি প্রতি কলে আরও একটি ফলাফল খালি করতাম, অনুরোধের শুরুটি প্রতি কলে বদলাত, এবং ক্যাশ কখনো কাজে লাগত না।
তাই পুরনো ফলাফলগুলো একটি একটি নয়, চারটি করে খালি করা হয়। খালি করা অংশ তখন কয়েকটি কলের জন্য একই থাকে। নোটের চেয়ে খুব বেশি বড় নয় এমন ফলাফল ছাড়া হয়: এটি খালি করলে প্রায় কিছুই বাঁচত না, অথচ অনুরোধের শুরু বদলে যেত। কতটুকু পূর্ণ থাকবে তা সংখ্যা দিয়ে নয়, আকার দিয়ে ঠিক হয়: বাজেটের এক-চতুর্থাংশে যতগুলো নতুনতম ফলাফল ফিট করে, সেগুলো থাকে, এবং অন্তত একটি সবসময় থাকে। আগের সংস্করণে স্থির ছয়টি পূর্ণ রাখা হতো, যা ছোট কমান্ড আউটপুটে ঠিক ছিল, কিন্তু দীর্ঘ ফাইল পড়ার ক্ষেত্রে পুরনো ফলাফলের জন্যই বেশিরভাগ বাজেট রেখে দিত।
প্রত্যাখ্যানগুলো এখন তা জানায়
যে অনুরোধ মডেল অবৈধ বলে প্রত্যাখ্যান করে, তা আর আবার চেষ্টা করা হয় না; একই অনুরোধ পাঠালে একই উত্তর আসবে। কথোপকথন মডেলের জন্য খুব লম্বা হলে ব্যবহারকারী দেখেন: “এই কথোপকথন মডেলের একবারে পড়ার জন্য খুব দীর্ঘ হয়ে গেছে। পরের ধাপের জন্য একটি নতুন চ্যাট শুরু করুন — এখন পর্যন্ত যা বানানো হয়েছে সবই থাকবে।” এটি ব্যবহারকারীর করণীয়, কোনো আউটেজ নয়, তাই এটি আমাদের পেজ করে না।
সমস্যা ২: এজেন্ট “ঘর বাঁচাতে” থেমে গেল
৪০টি দীর্ঘ অধ্যায় পড়তে বলা একটি সাব-এজেন্ট ২টির পরে থেমে গেল, বলল সে ঘর বাঁচাতে চায়। ৪,০০,০০০ টোকেনের বাজেটের মধ্যে সে প্রায় ১,০০,০০০ টোকেন ব্যবহার করেছিল।
পুরনো ফলাফল যে এখন তার জন্য খালি করা হবে, তা সে জানত না। তাই আমরা তাকে বলে দিয়েছি। এজেন্টের নির্দেশে এখন লেখা আছে: কথোপকথন মডেলের নেওয়ার সীমা ছাড়ালে পুরনো টুল ফলাফল খালি করা হয় এবং নতুনগুলো পূর্ণ থাকে — তাই দীর্ঘ কাজ থামিয়ে ঘর বাঁচাবেন না; চালিয়ে যান, আর খালি হওয়া কিছু প্রয়োজন হলে ফাইলটি আবার পড়ুন।
মডেলের চোখে যা দেখা যায় না, তা তার কাছে ঠিক করা নয়। এই ব্যবস্থা কেবল তখনই কাজে লাগে যখন এজেন্ট একে বিশ্বাস করে।
সমস্যা ৩: সবকিছু ইংরেজি ধরে টোকেন গোনা
আমরা টোকেনকে অক্ষর ÷ ৪ দিয়ে হিসাব করতাম, টোকেনাইজার না চালিয়ে। ইংরেজির জন্য এটি যুক্তিসঙ্গত আনুমানিক নিয়ম। অন্য লিপির জন্য নয়: রুশ প্রায় ২.২ অক্ষরে এক টোকেন, আর চীনা বা জাপানি প্রায় এক অক্ষরে।
তাই রুশ অধ্যায় পড়া একটি সাব-এজেন্ট প্রায় ৬,৪০,০০০ টোকেনের অনুরোধ পাঠাত, যদিও আমাদের হিসাব বলত তা ৪,০০,০০০ বাজেটের নিচে। এই হিসাব মডেলের কঠিন সীমাও ছাড়িয়ে যেতে পারত।
হিসাবটি এখন লিপি অনুযায়ী গোনে: সাধারণ ASCII ৪ অক্ষরে এক টোকেন, চীনা, জাপানি ও কোরীয় এক অক্ষরে, আর বাকি সবকিছু — সিরিলিক, গ্রিক, আরবি, উচ্চারণ-চিহ্নযুক্ত অক্ষর, ইমোজি — ২ অক্ষরে। এটি বেশি দিকে ভুল করার জন্য তৈরি। একটি রুশ অধ্যায়ে এখন অনুমান ৪৩,৪২৩ টোকেন, প্রায় ৪৪,৬০০ মাপা হয়েছে; আগে বলত ২৫,০২৩। একবার লেখা বার্তা কখনো বদলায় না, তাই তার অনুমান একবার হিসাব করে মনে রাখা হয়, প্রতি ধাপে নয়।
আমরা যা শিখেছি
- আকার যেখানে আসলে আছে, সেখানে ছাঁটুন। এজেন্টের কাজে তা টুল ফলাফল, ব্যবহারকারী-বার্তা নয়।
- এজেন্টকে তার নিজের নিরাপত্তা-জাল সম্পর্কে জানান। নইলে সে এমন সীমার চারপাশে পরিকল্পনা করবে যা আর প্রযোজ্য নয়।
- “অক্ষর ÷ ৪” একটি ইংরেজিভিত্তিক ধারণা। যে কিছু বহুভাষিক ব্যবহারকারীর টোকেন গোনে, তাকে লিপি অনুযায়ী গুনতে হবে, অথবা একটি আসল টোকেনাইজার ব্যবহার করতে হবে।
- ক্যাশের প্রতি খেয়াল রাখুন। যে অনুরোধ প্রতি কলে শুরুতে বদলায়, তার খরচ বেশি ও গতি ধীর।
যদি আপনি নিজের অ্যাপে AI ফিচার বানান, তবে LLM কী এবং LLM API কীভাবে ব্যবহার করবেন গাইড দুটি শুরু থেকেই প্রসঙ্গ-উইন্ডো ও টোকেন ব্যাখ্যা করে। Mythex-এ সাব-এজেন্ট কীভাবে কাজ করে তার আরও বিস্তারিত আছে সাব-এজেন্ট ডকসে।