পাঠ ১৭ · ৫৭-এর মধ্যে · মডিউল ৪
Home / AI Courses / Human-Centered AI / এক্সপ্লেইনেবিলিটি

প্রোগ্রেসিভ ডিসক্লোজার — ধাপে ধাপে এক্সপ্লেনেশন

Progressive disclosure for AI explanations
৮ মিনিট পড়া মধ্যম · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • কেন একটি এক্সপ্লেনেশন একবারে সম্পূর্ণ দেখানো প্রায়ই খারাপ ডিজাইন সিদ্ধান্ত
  • কীভাবে একটি স্তর-ভিত্তিক এক্সপ্লেনেশন ডেটা স্ট্রাকচার ডিজাইন করা যায়
  • একটি সত্যিকারের কোড উদাহরণ — ব্যবহারকারীর অনুরোধ (সংখ্যা বা নাম) অনুযায়ী সঠিক স্তর নির্বাচন করা
  • প্রোগ্রেসিভ ডিসক্লোজারের বাস্তব UI প্যাটার্নসমূহ

১ · কেন একবারে সবকিছু দেখানো ক্ষতিকর

L14-এ দেখা গিয়েছিল একটি টেকনিক্যাল, দীর্ঘ ব্যাখ্যা একটি দ্রুত-প্রেক্ষাপটে UX ব্যর্থতা তৈরি করে। কিন্তু এর বিপরীত সমাধানও — শুধু একটি সংক্ষিপ্ত একলাইন ব্যাখ্যা সবসময় দেখানো — সমস্যাযুক্ত, কারণ কিছু ব্যবহারকারী (একজন অডিটর, একজন সন্দিহান ব্যবহারকারী, বা কেউ যিনি সিদ্ধান্তে আপত্তি জানাতে চান) এর চেয়ে অনেক বেশি বিস্তারিত তথ্য চান। একটি স্থির, একক-স্তরের ব্যাখ্যা কখনোই সব ধরনের ব্যবহারকারীর জন্য সঠিক দৈর্ঘ্য হতে পারে না। প্রোগ্রেসিভ ডিসক্লোজার এই দ্বন্দ্বের সমাধান করে: ডিফল্টভাবে ছোট, কিন্তু প্রয়োজনে গভীরে যাওয়ার পথ খোলা রাখা — যা কগনিটিভ লোড ব্যবস্থাপনার একটি মূল নীতি (M6-এ বিস্তারিত)।

২ · তিন স্তরের এক্সপ্লেনেশন ডেটা স্ট্রাকচার

নিচের কোডে একটি ঋণ-আবেদনের সিদ্ধান্তের জন্য তিনটি স্তরের এক্সপ্লেনেশন সংজ্ঞায়িত করা হয়েছে — লেভেল ১ (একলাইন সারাংশ), লেভেল ২ (প্রধান কারণসমূহ), লেভেল ৩ (সম্পূর্ণ সাংখ্যিক ব্রেকডাউন)। একটি ফাংশন ব্যবহারকারীর অনুরোধ করা লেভেল নিয়ে সঠিক স্তরটি ফেরত দেয় — এবং অনুরোধ পরিসীমার বাইরে গেলে তা নিরাপদে ক্ল্যাম্প করে।

Python
explanation_levels = {
    "loan_app_482": {
        1: "আবেদনটি প্রত্যাখ্যাত হয়েছে, প্রধানত উচ্চ ক্রেডিট-ব্যবহারের হারের কারণে।",
        2: "প্রধান কারণ (প্রভাবের ক্রম অনুযায়ী): credit_utilization (সবচেয়ে বড় নেতিবাচক প্রভাব), "
           "late_payments, account_age। মোট স্কোর: -0.30 (থ্রেশহোল্ড 0.00)।",
        3: "সম্পূর্ণ ব্রেকডাউন -- প্রতিটি ফিচারের অবদান = ওয়েট x (মান - বেসলাইন): income +0.040, "
           "credit_utilization -0.200, late_payments -0.090, account_age -0.020। মডেল: রৈখিক স্কোরিং "
           "ফাংশন। কন্ট্রাস্টিভ: credit_utilization ০.২০ বা তার কম হলে অনুমোদিত হতো (বর্তমান মান ০.৮০)।",
    }
}

def get_explanation(decision_id, requested_level):
    levels = explanation_levels[decision_id]
    max_level = max(levels.keys())
    clamped = max(1, min(requested_level, max_level))
    return clamped, levels[clamped]

print("অনুরোধ করা লেভেল অনুযায়ী দেখানো এক্সপ্লেনেশন:\n")
for requested in [1, 2, 3, 5, 0]:
    clamped, text = get_explanation("loan_app_482", requested)
    print(f"অনুরোধ লেভেল {requested} -> দেখানো হচ্ছে লেভেল {clamped}:")
    print(f"  {text}\n")

    
লক্ষ্য করুন — অনুরোধ লেভেল ৫ (যা পরিসীমার বাইরে) স্বয়ংক্রিয়ভাবে সর্বোচ্চ উপলব্ধ লেভেল ৩-এ ক্ল্যাম্প হয়ে যায়, আর অনুরোধ লেভেল ০ সর্বনিম্ন লেভেল ১-এ ক্ল্যাম্প হয়। এই ধরনের ডিফেন্সিভ ডিজাইন গুরুত্বপূর্ণ — বাস্তব UI-তে ব্যবহারকারীর ইনপুট বা স্ক্রিন-সাইজ নির্ধারিত সর্বোচ্চ লেভেল যা-ই থাকুক না কেন, ফাংশনটি কখনো ক্র্যাশ করবে না বা অনির্ধারিত আচরণ দেখাবে না।

৩ · ব্যবহারকারীর অনুরোধ অনুযায়ী স্তর নির্বাচন — নামভিত্তিক সংস্করণ

বাস্তব UI-তে ব্যবহারকারী প্রায়ই সংখ্যা নয়, বরং একটি নাম-ভিত্তিক বিকল্প বেছে নেন (যেমন "সংক্ষিপ্ত" বা "বিস্তারিত" বাটন)। নিচের কোডে একই get_explanation লজিকের উপর একটি নামভিত্তিক স্তর তৈরি করা হয়েছে, যা অজানা/ভুল নামের জন্যও একটি নিরাপদ ডিফল্টে পড়ে।

Python
explanation_levels = {
    "loan_app_482": {
        1: "আবেদনটি প্রত্যাখ্যাত হয়েছে, প্রধানত উচ্চ ক্রেডিট-ব্যবহারের হারের কারণে।",
        2: "প্রধান কারণ (প্রভাবের ক্রম অনুযায়ী): credit_utilization (সবচেয়ে বড় নেতিবাচক প্রভাব), "
           "late_payments, account_age। মোট স্কোর: -0.30 (থ্রেশহোল্ড 0.00)।",
        3: "সম্পূর্ণ ব্রেকডাউন -- প্রতিটি ফিচারের অবদান = ওয়েট x (মান - বেসলাইন): income +0.040, "
           "credit_utilization -0.200, late_payments -0.090, account_age -0.020। মডেল: রৈখিক স্কোরিং "
           "ফাংশন। কন্ট্রাস্টিভ: credit_utilization ০.২০ বা তার কম হলে অনুমোদিত হতো (বর্তমান মান ০.৮০)।",
    }
}

def get_explanation(decision_id, requested_level):
    levels = explanation_levels[decision_id]
    max_level = max(levels.keys())
    clamped = max(1, min(requested_level, max_level))
    return clamped, levels[clamped]

depth_names = {"সংক্ষিপ্ত": 1, "স্ট্যান্ডার্ড": 2, "বিস্তারিত": 3}

def get_explanation_by_name(decision_id, depth_name):
    level = depth_names.get(depth_name, 1)  # অজানা নাম হলে ডিফল্ট লেভেল ১ (সবচেয়ে নিরাপদ, সবচেয়ে সংক্ষিপ্ত)
    return get_explanation(decision_id, level)

print("নাম-ভিত্তিক অনুরোধ অনুযায়ী দেখানো এক্সপ্লেনেশন:\n")
for name in ["সংক্ষিপ্ত", "বিস্তারিত", "অজানা-নাম"]:
    clamped, text = get_explanation_by_name("loan_app_482", name)
    print(f"'{name}' অনুরোধ -> লেভেল {clamped} দেখানো হলো:")
    print(f"  {text}\n")

    
"সংক্ষিপ্ত" ও "বিস্তারিত" সঠিকভাবে লেভেল ১ ও ৩-এ ম্যাপ হয়। "অজানা-নাম" — যা depth_names ডিকশনারিতে নেই — .get(depth_name, 1)-এর কারণে নিরাপদে ডিফল্ট লেভেল ১-এ পড়ে, ক্র্যাশ না করে। বাস্তব প্রোডাক্টে এই ধরনের "গ্রেসফুল ফলব্যাক" গুরুত্বপূর্ণ — একটি অপ্রত্যাশিত ইনপুট কখনোই ব্যবহারকারীকে একটি ভাঙা বা খালি এক্সপ্লেনেশন দেখানো উচিত নয় (এরর ডিজাইনের বিস্তারিত M6-এ, L25)।

৪ · বাস্তব UI প্যাটার্ন

অ্যাকর্ডিয়ন / এক্সপ্যান্ড
ডিফল্টভাবে লেভেল ১ দেখানো হয়, ব্যবহারকারী ক্লিক করলে লেভেল ২-৩ ধীরে ধীরে খুলে যায় — সবচেয়ে সাধারণ প্যাটার্ন।
"আরও বিস্তারিত দেখুন" লিংক
একটি ছোট লিংক যা ব্যবহারকারীকে একটি সম্পূর্ণ, ডেডিকেটেড ব্যাখ্যা-পেজে নিয়ে যায় — বেশি জায়গা প্রয়োজন হলে উপযোগী।
টুলটিপ থেকে ড্রয়ার
হোভার/ট্যাপে একটি সংক্ষিপ্ত টুলটিপ, আরও ক্লিকে একটি সাইড-ড্রয়ার — মোবাইল ও ডেস্কটপ দুই জায়গাতেই কার্যকর।
ব্যবহারকারী-নির্ধারিত ডিফল্ট
ব্যবহারকারী একবার "সবসময় বিস্তারিত দেখাও" বেছে নিলে, সিস্টেম সেই পছন্দ মনে রাখে — বারবার একই ক্লিক করা এড়ায়।
মূল কথা · Key takeaway

প্রোগ্রেসিভ ডিসক্লোজার "কতটা তথ্য দেব" প্রশ্নটিকে একটি বাইনারি সিদ্ধান্ত (সব অথবা কিছুই না) থেকে একটি স্তরবিন্যস্ত সিদ্ধান্তে রূপান্তরিত করে। এটি বাস্তবায়নের জন্য কোনো জটিল প্রযুক্তি লাগে না — শুধু দরকার এক্সপ্লেনেশন ডেটাকে আগে থেকেই স্তরে সংগঠিত করা এবং একটি সহজ, নিরাপদ (ক্ল্যাম্পড/ডিফল্টেড) নির্বাচন লজিক।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ ডিফল্ট স্তর হিসেবে সবসময় লেভেল ১ (সবচেয়ে সংক্ষিপ্ত) বেছে নেওয়া হয়েছে, লেভেল ২ বা ৩ নয় কেন?

এটি একটি সচেতন ডিজাইন সিদ্ধান্ত: বেশিরভাগ ব্যবহারকারীর জন্য একলাইন সারাংশই যথেষ্ট, এবং কগনিটিভ লোডের দৃষ্টিকোণ থেকে অপ্রয়োজনীয় তথ্য দিয়ে শুরু করা খারাপ ডিফল্ট (M6-এ বিস্তারিত)। যাদের বেশি প্রয়োজন, তারা সক্রিয়ভাবে গভীরে যেতে পারেন — কিন্তু কাউকে জোর করে দীর্ঘ ব্যাখ্যা দিয়ে শুরু করানো ঠিক নয়। একই যুক্তিতে অজানা/ভুল ইনপুটের জন্যও সবচেয়ে নিরাপদ (সংক্ষিপ্ততম) বিকল্পে ফলব্যাক করা হয়েছে।

প্র ০২ প্রোগ্রেসিভ ডিসক্লোজার কীভাবে L16-এর কনফিডেন্স কমিউনিকেশনের সাথে একসাথে কাজ করতে পারে?

L16-এর কনফিডেন্স ব্যান্ড ("মাঝারি নিশ্চয়তা") লেভেল ১-এর অংশ হিসেবে দেখানো যায় — একটি সংক্ষিপ্ত, দ্রুত বোধগম্য সংকেত। raw সংখ্যাসূচক স্কোর (যেমন ০.৭২) ও এর পেছনের ক্যালিব্রেশন বিস্তারিত লেভেল ৩-এ রাখা যায় — এভাবে দুটো কৌশল একসাথে ব্যবহার করলে ডিফল্ট UI সহজ থাকে, অথচ প্রয়োজনে সম্পূর্ণ স্বচ্ছতাও পাওয়া যায়।

প্র ০৩ প্রোগ্রেসিভ ডিসক্লোজারের একটি সম্ভাব্য ঝুঁকি কী — অতিরিক্ত স্তর যোগ করলে কী ভুল হতে পারে?

যদি অনেকগুলো স্তর তৈরি করা হয় (যেমন ৭-৮টি), তাহলে ব্যবহারকারীকে বারবার ক্লিক করে গভীরে যেতে হয়, যা নিজেই একটি ঘর্ষণ (friction) তৈরি করে এবং ব্যবহারকারী মাঝপথে থেমে যেতে পারেন — গুরুত্বপূর্ণ তথ্য কখনো দেখাই হয় না। সাধারণত ২-৩টি স্তরই যথেষ্ট এবং কার্যকর; অতিরিক্ত জটিলতা প্রোগ্রেসিভ ডিসক্লোজারের মূল উদ্দেশ্যকেই ব্যর্থ করে দেয়।

অনুশীলন

  1. চিন্তা করুন: প্রথম কোড সেলে explanation_levels["loan_app_482"]-এ যদি একটি নতুন লেভেল 4 যোগ করা হয় (আরও বিস্তারিত টেক্সট দিয়ে), তাহলে get_explanation("loan_app_482", 10) কল করলে এখন কোন লেভেল ফেরত আসবে বলে আপনার ধারণা?

    যেহেতু max_level = max(levels.keys()) স্বয়ংক্রিয়ভাবে ডিকশনারির সর্বোচ্চ চাবি খুঁজে বের করে, লেভেল ৪ যোগ করলে max_level এখন ৪ হয়ে যাবে — তাই get_explanation("loan_app_482", 10) এখন লেভেল ৪-এ ক্ল্যাম্প হবে বলে অনুমান করা যায়, লেভেল ৩ নয়।

  2. পরীক্ষা করুন: প্রথম কোড সেলে explanation_levels["loan_app_482"] ডিকশনারিতে 4: "সম্পূর্ণ মডেল-অডিট লগ, সব ফিচারের ইতিহাসসহ।" যোগ করে, তারপর get_explanation("loan_app_482", 10) কল করে Run চেপে দেখুন।

    যাচাই করলে দেখা যায় অনুমানটি সঠিক — get_explanation("loan_app_482", 10) এখন ক্ল্যাম্প লেভেল ৪ ও নতুন যোগ করা টেক্সট ফেরত দেয়, লেভেল ৩ নয়। এটি দেখায় ফাংশনটি সত্যিই ডাইনামিক — এটি কোথাও হার্ডকোড করা "সর্বোচ্চ ৩" ধরে নেয়নি, বরং প্রতিবার levels.keys() থেকে প্রকৃত সর্বোচ্চ লেভেল হিসাব করে, যা একে ভবিষ্যতে নতুন স্তর যোগ করার জন্যও নির্ভরযোগ্য করে তোলে।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

আগের পাঠ
কনফিডেন্স ও আনসার্টেইনটি কমিউনিকেশন ডিজাইন