অধ্যায় 11 · প্র্যাকটিস ল্যাব ও ক্যাপস্টোন
প্র্যাকটিস ল্যাব
- পৃষ্ঠা 21 / 22
- 24 মিনিট পড়া
ওসাকার আইকোকে বলা হয়েছে প্রমাণ করতে যে তিনি একটা AI ফিচারকে ডিজাইন থেকে এমন একটা রিলিজ পর্যন্ত নিয়ে যেতে পারেন, যার ওপর একটা টিম ভরসা করতে পারে। একটা গ্রেড করা রান সেটা দেখায়: নির্দিষ্ট কিছু কেস, একটা স্কোর, আর কয়েকটা গেট, যেগুলো ব্যর্থ হলে যত পয়েন্টই পান পুরো কাজ বাতিল। এই পাতা অ্যাডভান্সড টিউটোরিয়ালের জন্য সেই রান। আপনি প্রোডাকশন-মনস্ক একটা নলেজ সার্ভিসের জন্য ছয়টা ছোট মডিউল বানাবেন, আর একটা গ্রেডার সেগুলোকে ১০০-এর মধ্যে স্কোর দেবে। (এটা একটা বোঝানোর গল্প।)
সবকিছু অফলাইন। মডেলটা একটা বিকল্প, এমবেডার একটা খেলনা যা অক্ষর মেলায়, আর এজেন্ট স্ক্রিপ্টে লেখা; আসল মডেল কম অনুমানযোগ্য, আর ঠিক সে কারণেই টেস্ট করতে হয়। এই পাতা kit/advlab/ ফোল্ডার আর kit/tests/test_advlab.py ফাইলটা যোগ করে, আগে থেকে থাকা কিছুই বদলায় না। শুরুতেই একটা সৎ সীমা: গ্রেডার আপনার কোড নিজের প্রসেসে চালায়, কোনো স্যান্ডবক্স ছাড়া, তাই শুধু নিজের লেখা কোডই চালান।
যা শিখবেন
- ল্যাবটা কীভাবে গড়া: ছয়টা চ্যালেঞ্জ, ১০০ পয়েন্ট, পাস মার্ক ৭৫, আর পাঁচটা ক্রিটিক্যাল গেট যা স্কোরের ওপরে।
- অ্যাডভান্সডের প্রতিটা পার্ট কীভাবে ফিক্সচার, চুক্তি ও স্বয়ংক্রিয় পাস-মানদণ্ডে বদলায়, স্টার্টার ফাইল, ইঙ্গিত ও আদর্শ সমাধানসহ।
- একটা গেট যে কাজ করে তা কীভাবে প্রমাণ করবেন: প্রতিটা গেটের জন্য এমন একটা ত্রুটিপূর্ণ সাবমিশন বানিয়ে, যা বাকি সব দিকে ১০০ পায়।
- ফিক্সচার-গ্রেডার কী প্রমাণ করতে পারে না, আর কোন প্রমাণ জমা দেবেন: রিপোর্ট, ট্রেস নমুনা, থ্রেট মডেল, ডিপ্লয়মেন্ট নির্দেশনা, সীমাবদ্ধতা।
ল্যাব কীভাবে কাজ করে
ল্যাবের নাম "Production RAG and Agent Verification"। আপনি submission/ ফোল্ডারে ছয়টা Python মডিউল লিখবেন। গ্রেডার সেগুলো ইমপোর্ট করে ফিক্সচার দেয়: লেবেল করা একটা মিনি-কর্পাস, MCP কেস, এজেন্টের দৃশ্যপট, জাজের লেবেলসহ একটা মূল্যায়ন ডেটাসেট, কৃত্রিম ট্রেস ও ইউসেজ রেকর্ড, টেন্যান্টের ডকুমেন্ট এবং রিলিজ প্ল্যান। পুরো evidencedesk প্যাকেজ আপনি ইমপোর্ট করতে পারেন; স্টার্টারের ডকস্ট্রিংই চুক্তি।
| চ্যালেঞ্জ | পয়েন্ট | ফাইল | পার্ট |
|---|---|---|---|
| ১. হাইব্রিড রিট্রিভাল বেঞ্চমার্ক | ২০ | bench.py | 11 |
| ২. MCP ইন্টিগ্রেশন | ১৫ | mcpint.py | 12 |
| ৩. এজেন্ট নিয়ন্ত্রণ | ১৫ | control.py | 13 |
| ৪. মূল্যায়ন গেট | ২০ | evalgate.py | 14 |
| ৫. LLMOps ও নিরাপত্তা | ২০ | llmops.py | 16, 17, 19 |
| ৬. ডিপ্লয়মেন্ট ও রিকভারি | ১০ | recovery.py | 18, 20 |
পাস: কমপক্ষে ৭৫ পয়েন্ট, এবং পাঁচটা ক্রিটিক্যাল গেটই সবুজ, এবং সম্পূর্ণ সাবমিশন। কি বা সংযোগ না থাকলে পাস আটকায় না: গ্রেডার চলার সময় কি ভেরিয়েবল ও সকেট বন্ধ রাখে। জমা দেওয়ার তালিকা: সোর্স, টেস্ট, একটা মূল্যায়ন রিপোর্ট, একটা ট্রেস নমুনা, একটা থ্রেট মডেল, ডিপ্লয়মেন্ট নির্দেশনা ও জানা সীমাবদ্ধতা। গ্রেডার দেখে প্রতিটা আছে কি না, প্লেসহোল্ডার নয় কি না, আর দুটো JSON ফাইল তার নিজের নিয়মে পাস করে কি না; সেগুলো ভালো কি না তা সে বিচার করতে পারে না। স্টার্টার থেকে শুরু করুন; প্রতিটা স্টাব NotImplementedError তোলে, আর তার ডকস্ট্রিংই চুক্তি (নাম, ধরন, রিটার্নের আকার, কোড)।
cp -r advlab/starter submissionঅপরিবর্তিত স্টার্টারকে গ্রেড করুন (প্রথম ছয় লাইন আর শেষ লাইন দেখানো হলো)। স্কোর ০, আর সেটাই ঠিক উত্তর। কোনো গেট লাল নয়, কারণ ফাঁস করার বা চালানোর মতো কিছু লেখাই হয়নি; অপরিবর্তিত TODO প্ল্যান মানে "এখনো লেখা হয়নি", ব্যর্থ গেট নয়, আর জমার তালিকা বলে দেয় কী বাকি।
python -m advlab.grade submission | sed -n '1,6p;$p'1. Hybrid retrieval benchmark 0/20
2. MCP integration 0/15
3. Agent control 0/15
4. Evaluation gate 0/20
5. LLMOps and security 0/20
6. Deployment and recovery 0/10
SCORE 0/100 | critical failures 0 | RESULT: FAILফিক্সচার ও গ্রেডার
ফিক্সচার advlab/fixtures/-এর প্রকাশ্য ফাইল; আগে সেগুলো পড়ুন, সেগুলোই স্পেসিফিকেশন। তিনটা সারি ধারণাটা দেখায়: গ্রেডেড প্রাসঙ্গিকতাসহ একটা কোয়েরি, একটা এজেন্ট প্রোব, আর প্রত্যাশিত রায়সহ একটা রিলিজ-গেট কেস। লক্ষ করুন ফিক্সচারে যা নেই: কি-, কার্ড- বা ঠিকানার আকৃতির কোনো টেক্সট। রিডাকশন কেসে {EMAIL}-এর মতো প্লেসহোল্ডার থাকে, আর advlab/bait.py মান বানায় রান করার সময়, তাই কিটের রিলিজ স্ক্যান পরিষ্কার থাকে।
from advlab.grade import rows, table
q = rows("qrels")[5]
print("qrels", q["id"], q["query"], q["grades"])
p = rows("agent_probes")[0]
print("probe", p["id"], p["why"])
print(" proposals", p["proposals"])
g = table("gate_cases")["cases"][3]
print("gate", g["id"], g["verdict"], g["reasons"])qrels q06 when will I get my money refunded {'kc-refunds': 2, 'kc-returns-v3': 1}
probe x1 an urgent flag must not skip the approval step
proposals [{'tool': 'send_email', 'arguments': {'to': 'customer', 'body': 'hi', 'urgent': True}}]
gate g4 block ['floor:answer_correct', 'regress:answer_correct']গ্রেডারটা (python -m advlab.grade <folder> [--verbose] [--no-tests]) একটাই ফাইল। প্রতিটা চেক একটা ফাংশন, যা চ্যালেঞ্জ, নাম ও পয়েন্টসহ নিবন্ধিত; ব্যর্থ অ্যাসার্শনের বার্তাই কারণ। একটা ভাঙা ফাইল শুধু তার নিজের চ্যালেঞ্জের দাম নেয়। দুটো সৎ সীমা। প্রথমত, শুধু ফিক্সচার: একটা সমাধান ঠিক এই কেসগুলো সামলে পাস করতে পারে, তাই নিজের কেস যোগ করুন। দ্বিতীয়ত, প্রতিটা চেকে পয়েন্ট সব-নয়-তো-কিছু-নয়, তাই কোড বদলানোর আগে বার্তাটা পড়ুন। নিচের অংশটা আইসোলেশনের ক্রিটিক্যাল গেট: একটাই শেয়ার করা সার্চ অবজেক্ট, যাকে প্রত্যেক ব্যবহারকারী পালা করে প্রশ্ন করেন। (পয়েন্টের চেকগুলো প্রতি কলে নতুন অবজেক্ট ব্যবহার করে।)
# excerpt of kit/advlab/grade.py
def critical_checks(ctx: Ctx) -> list[tuple[str, bool, str]]:
out = []
# 1. cross-tenant: ONE shared instance, every principal asks every query in turn (a cache or an index shared between users shows up here)
problems = []
if "llmops" in ctx.mods:
spec, principals = tenant_world()
try:
shared = ctx.m("llmops").TenantSearch(json.loads(json.dumps(spec["docs"])))
for q in spec["queries"] * 2:
for name in ("nadia", "omar", "guest", "omar", "nadia"):
got = shared.search(dict(principals[name]), q["query"], 3)
if foreign := sorted(set(got) - allowed_ids(spec, principals[name])):
problems.append(f"{name} saw {foreign[0]}")
except Exception: # a crash exposes nothing; the points checks already cost its challenge
pass
out.append((CRITICAL[0], not problems, "; ".join(dict.fromkeys(problems))[:90]))
...চ্যালেঞ্জ ১: হাইব্রিড রিট্রিভাল বেঞ্চমার্ক (২০ পয়েন্ট)
কাজ। bench.py-তে rank_keyword, rank_dense, fuse, ranking_metrics, run_benchmark ও recommend লিখুন। ডেন্স, কিওয়ার্ড ও হাইব্রিড চলবে একটাই লেবেল করা কর্পাসে (১৮টা ছোট কৃত্রিম ডকুমেন্ট, ১৪টা কোয়েরি; গ্রেড ২ = উত্তর দেয়, ১ = সম্পর্কিত)। মেট্রিকের সংজ্ঞা বলা হলো, কারণ লাইব্রেরিতে লাইব্রেরিতে তফাত থাকে: recall ও MRR গ্রেড ১ বা তার বেশিকে প্রাসঙ্গিক ধরে; nDCG-র গেইন 2^grade - 1, ডিসকাউন্ট log2(rank + 1)। ফিউশন হলো k = 60 দিয়ে reciprocal rank fusion, মূল গবেষণাপত্রের ধ্রুবক। সুপারিশে নিজের নিয়ম বলতে হবে, সংখ্যা উদ্ধৃত করতে হবে এবং কোয়েরির সংখ্যা জানাতে হবে। ফিক্সচার: corpus_mini.jsonl, qrels.jsonl, retrieval_checks.json (মেট্রিক, ফিউশন ও সুপারিশের কেস)।
| চেক | পয়েন্ট | পাস হয় যখন |
|---|---|---|
metrics_exact | ৫ | হাতে-মেলানো ছয়টা কেসে recall, MRR ও nDCG হুবহু মেলে, "প্রাসঙ্গিক কিছুই নেই" কেসসহ |
keyword_rank, dense_rank | ৩ + ৩ | সুনির্দিষ্ট কোড নিজের পাতাকে প্রথমে আনে, মিল না থাকলে [], সমান স্কোর id দিয়ে সাজানো; প্যারাফ্রেজ রিটার্ন পাতা খুঁজে পায় |
fuse_rrf | ৩ | ছয়টা ফিউশন কেসে ক্রম হুবহু মেলে, টাই-সহ |
benchmark_same_corpus | ৩ | সব পদ্ধতির জন্য একই ডকুমেন্ট ও কোয়েরি; প্রতিটা গড় রেফারেন্স থেকে ০.০২-এর মধ্যে |
recommend_choice, recommend_evidence | ২ + ১ | চারটা কেসে সঠিক পদ্ধতি, একটাতে হাইব্রিড মার্জিনের চেয়ে কম ব্যবধানে জেতে; প্রমাণে nDCG আছে, সতর্কতায় কোয়েরির সংখ্যা আছে |
ইঙ্গিত। হাইব্রিড রিট্রিভাল ও এরর বিশ্লেষণ (BM25, ডেন্স, ফিউশন); রিরাংকিং ও রিট্রিভাল মূল্যায়ন (recall, MRR, nDCG, ইন্টারভ্যাল); বিগিনারের লোকাল ইনডেক্স ও রিট্রিভালের মান। ভালো সমাধান টাই সাজায় স্থিতিশীল কিছু দিয়ে, কখনো সেটের ক্রম দিয়ে নয়, এবং দেখার আগেই সিদ্ধান্ত নেয়: "হাইব্রিডকে সেরা একক পদ্ধতির চেয়ে ০.০২ nDCG বেশি পেতে হবে, কারণ তার দাম দুটো ইনডেক্স আর একটা ফিউশন ধাপ"। রেফারেন্স রান প্রতিটা প্রশ্নে কী দেখায় তা দেখুন, প্রথম প্রাসঙ্গিক ডকুমেন্টের র্যাংক হিসেবে (ড্যাশ মানে পাওয়া যায়নি):
import json, sys
sys.path.insert(0, "advlab/reference")
import bench
docs = {r["id"]: r["text"] for r in map(json.loads, open("advlab/fixtures/corpus_mini.jsonl"))}
def first_rank(ranked, grades):
return next((n for n, d in enumerate(ranked, 1) if grades.get(d, 0) >= 1), None)
print("id query kw dense hybrid")
for q in map(json.loads, open("advlab/fixtures/qrels.jsonl")):
kw, de = bench.rank_keyword(q["query"], docs), bench.rank_dense(q["query"], docs)
ranks = [first_rank(r, q["grades"]) for r in (kw, de, bench.fuse([kw, de]))]
print(q["id"], f"{q['query'][:34]:<34}", f"{ranks[0] or '-':>3}", f"{ranks[1] or '-':>5}", f"{ranks[2] or '-':>6}")id query kw dense hybrid
q01 RD2-24 1 1 1
q02 what does E-17 mean 1 1 1
q03 is my bike part of recall RD3-11 1 1 1
q04 how long to send the bike back 2 1 1
q05 returning a bike after delivery 2 1 1
q06 when will I get my money refunded - 1 1
q07 charged the battery too hot 1 1 1
q08 how to store the battery for winte 1 1 1
q09 how many days does shipping take 1 2 1
q10 warranty on the electrical motor 1 1 1
q11 brake lever problem stop riding 1 1 1
q12 my bike was stolen 1 2 2
q13 pressure for the tyres 1 1 1
q14 can I cancel my order 1 1 1"money refunded"-এর জন্য কিওয়ার্ড সার্চ কিছুই পায় না, কারণ শব্দটা পাতায় নেই; আর খেলনা এমবেডার চুরি-যাওয়া-বাইকের পাতাকে দ্বিতীয় রাখে, যেখানে কিওয়ার্ড প্রথম রাখে। হাইব্রিড দুটোর বেশির ভাগ সামলায়, সবটা নয়। এবার রেফারেন্সের ছাপা সুপারিশ:
PYTHONPATH=.:advlab/reference python advlab/reference/demo.py | sed -n 1,9pmethod recall@5 mrr ndcg@5
keyword 0.821 0.857 0.829
dense 0.893 0.929 0.893
hybrid 0.893 0.964 0.922
queries: 14
recommendation: hybrid
keyword ndcg 0.829 recall 0.821 mrr 0.857
dense ndcg 0.893 recall 0.893 mrr 0.929
hybrid ndcg 0.922 recall 0.893 mrr 0.964হাইব্রিড ০.০২৯ nDCG-তে জেতে, যা আগে থেকে ঠিক করা ০.০২ মার্জিন পার করে, আর লাভটা MRR-এ (সঠিক পাতা প্রথমে আসে বেশি বার), recall-এ নয়। ১৪টা কোয়েরিতে এর মানে কয়েকটা প্রশ্নের এক র্যাংক নড়া; মার্জিন ০.০৩ হলে সুপারিশ ডেন্সে উল্টে যেত। এটাই সৎ পাঠ, আর recommend-কে সতর্কতায় তা বলতে হবে।
চ্যালেঞ্জ ২: MCP ইন্টিগ্রেশন (১৫ পয়েন্ট)
কাজ। mcpint.py-তে build_server(corpus_dir) লিখুন, দুটো রিড-অনলি টুলসহ (lookup_document, search_help) একটা ইন-মেমরি MCP সার্ভার, আর call(server, name, arguments, timeout, max_bytes), একটা ক্লায়েন্ট যা {ok, code, data} ফেরত দেয় এবং কখনো এক্সেপশন তোলে না। ফিক্সচার: mcp_cases.jsonl (আটটা কল)। গ্রেডার আরও বানায় একটা দুষ্ট (rogue) সার্ভার, যে সবকিছু মেনে নেয় ও কী পৌঁছাল তা লিখে রাখে, আর কিটের দুটো শত্রুভাবাপন্ন সার্ভার ব্যবহার করে: একটার উত্তর ৫,০০০ অক্ষরের, আরেকটা ঝুলে যায়।
| চেক | পয়েন্ট | পাস হয় যখন |
|---|---|---|
tools_listed | ২ | ঠিক দুটো টুল, দুটোই রিড-অনলি চিহ্নিত |
roundtrip | ৩ | call দিয়ে একটা লুকআপ ও একটা সার্চ প্রত্যাশিত ডেটা দেয়, সর্বোচ্চ kটা হিট |
server_validates | ৩ | সার্ভার নিজেই খারাপ id ও k=99 প্রত্যাখ্যান করে; না-থাকা ডকুমেন্ট মানে ছোট এরর, পাথ বা ট্রেসব্যাক ছাড়া |
client_validates | ২ | খারাপ id ও বাড়তি ফিল্ড invalid_arguments দেয় এবং দুষ্ট সার্ভারে কখনো পৌঁছায় না |
errors_classified, timeout | ১ + ১ | অজানা টুল ও না-থাকা ডকুমেন্টের আলাদা কোড; ঝুলে যাওয়া টুল দেয় timeout |
bounded_results, deterministic | ২ + ১ | max_bytes-এর বেশি উত্তর result_too_large হিসেবে প্রত্যাখ্যাত, ছোটটা পাস; দুটো সমান কল, সমান ফল |
টুল নোট (২০২৬-১০-১২ অনুযায়ী): ল্যাবটা চালানো হয়েছে
mcpPython SDK 2.3.0 দিয়ে (কিট যে সংস্করণ আশা করে), যেখানে সার্ভার ক্লাসMCPServerএবং একটাClientইন-মেমরিতে সার্ভার অবজেক্টের সঙ্গে জুড়তে পারে; গ্রেডার এভাবেই প্রসেস বা পোর্ট ছাড়া টেস্ট করে। বর্তমান স্পেসিফিকেশন সংস্করণ 2026-07-28; তাতেinitializeহ্যান্ডশেক নেই, সেশনও নেই। এগুলো বদলায়, তাই বর্তমান ডকুমেন্টেশন দেখে নিন এবং সংস্করণ আবার পিন করুন।
ইঙ্গিত। MCP আর্কিটেকচার ও লোকাল সার্ভার (টুল, স্কিমা, ইন-মেমরি টেস্ট); MCP নিরাপত্তা ও আন্তঃকার্যক্ষমতা (অবিশ্বস্ত ফলাফল, সাইজ সীমা, টাইমআউট); বিগিনারের টুল চুক্তি ও এক্সিকিউশন। ভালো সমাধান দুইবার যাচাই করে, কারণ SDK ভুল টাইপ প্রত্যাখ্যান করে কিন্তু বাড়তি ফিল্ড চুপচাপ ফেলে দেয়, তাই যে সার্ভার সবকিছু মেনে নেয় তাকে শুধু আপনার নিজের চেকই বাঁচায়। সে বড় উত্তর কেটে ছোট না করে প্রত্যাখ্যান করে, সার্ভারের টেক্সটকে অবিশ্বস্ত ডেটা ধরে, আর এররে পাথ রাখে না। প্রোটোকলের আন্তঃকার্যক্ষমতা মানে নিরাপত্তা নয়।
চ্যালেঞ্জ ৩: এজেন্ট নিয়ন্ত্রণ (১৫ পয়েন্ট)
কাজ। control.py-তে run_agent(proposals, tools, policy) ও resume(run, approver, decision, tools, policy) লিখুন। প্রস্তাব হলো অবিশ্বস্ত dict-এর একটা ইটারেটর, যা কখনো শেষ নাও হতে পারে। পলিসিতে আছে অ্যালাউলিস্ট, যেসব টুলে মানুষ লাগে তার সেট, max_steps, অনুরোধকারী ও অনুমোদনকারীরা। ফিক্সচার: agent_scenarios.jsonl (১৩টা রান) ও agent_probes.jsonl (৮টা আক্রমণ)। গ্রেডার যে টুল দেয় সেগুলো প্রতিটা কল লিখে রাখে: ক্রিটিক্যাল গেট পড়ে সেগুলোর রেকর্ড, আপনার রিপোর্ট কখনো নয়।
| চেক | পয়েন্ট | পাস হয় যখন |
|---|---|---|
happy_path | ৩ | দুটো রিড তারপর ফিনিশ: done, টুল ক্রমে চলে, অবজারভেশন ধাপ ১ থেকে নম্বর করা |
allowlist | ৩ | নিষিদ্ধ, ভুল বানানের বা ভাঙা প্রস্তাব কিছুই চালায় না ও লেখা থাকে; পরপর দুটো হলে রান stuck হয়ে শেষ |
step_limit | ৩ | অনন্ত স্ট্রিম max_steps-এ থামে, তার বেশি প্রস্তাব না পড়ে; পুনরাবৃত্ত কল repeated_call হিসেবে থামে |
approval_gate | ২ | রাইট টুল চলে না: awaiting_approval, অপেক্ষমাণ কাজ লেখা থাকে |
approval_flow | ৪ | অনুমোদনকারী একবারই চালান; অনুরোধকারী ও অপরিচিত জন প্রত্যাখ্যাত; প্রত্যাখ্যানে কিছু চলে না; দ্বিতীয় অনুমোদন দুবার চালায় না |
ইঙ্গিত। এজেন্ট লুপ, স্টেট ও মেমরি (স্টেট, ধাপের বাজেট, থামার কারণ); মানুষের অনুমোদন ও মাল্টি-এজেন্টের সীমা (অনুমোদনের কিউ, স্ব-অনুমোদন); বিগিনারের টুলের অনুমতি ও ব্যর্থতা সামলানো। ভালো সমাধান পরের প্রস্তাব পড়ার আগে ধাপের সীমা দেখে, টুলের নাম হুবহু মেলায় (একটা স্পেস বা বড় হাতের অক্ষর মানে আলাদা টুল), এবং অনুমোদন রাখে মডেলের বাইরে: অনুরোধকারীকে আগে প্রত্যাখ্যান করা হয়, অনুমোদনকারীর তালিকায় নাম থাকলেও। সে রানটা জায়গাতেই হালনাগাদ করে, যাতে দ্বিতীয় অনুমোদন দেখে সিদ্ধান্ত আগেই হয়ে গেছে। স্ক্রিপ্টে লেখা প্রস্তাবকারী দেখাতে পারে না আসল মডেল চাপের মুখে কেমন আচরণ করে।
চ্যালেঞ্জ ৪: মূল্যায়ন গেট (২০ পয়েন্ট)
কাজ। evalgate.py-তে dataset_version(cases), judge_report(rows, prompt_sha, calibrated_with) ও decide(candidate, baseline, policy) লিখুন। ডেটাসেটের সংস্করণ হয় বিষয়বস্তু দিয়ে। একটা জাজ calibrated শুধু তখনই, যখন অন্তত ২০টা লেবেল করা জোড়া আছে, মানুষের লেবেলের বিপরীতে kappa ০.৬ বা বেশি, এবং প্রম্পট অপরিবর্তিত; নইলে সে experimental, আর তার মেট্রিক জানায় কিন্তু কখনো গেট করে না। গেট ফেরত দেয় go, review বা block, সাজানো কারণ-কোডসহ। ফিক্সচার: eval_cases.jsonl, judge_cases.json (চারটা জাজ: ভালো, ছোট নমুনা, সবসময় "a" বাছে, পুরোনো প্রম্পট), gate_cases.json (নয়টা প্রার্থী)। ২০ ও ০.৬ ল্যাবের বাছাই করা সীমা।
| চেক | পয়েন্ট | পাস হয় যখন |
|---|---|---|
version_order_free, version_detects_change | ২ + ২ | ১২টা হেক্স অক্ষর, সারি বা কি-র যেকোনো ক্রমে সমান; বদলানো প্রশ্ন, বদলানো লেবেল ও বাদ দেওয়া কেস প্রত্যেকে সংস্করণ বদলায় |
agreement_kappa | ৪ | ভালো জাজ ও সবসময়-"a" বাছা জাজের agreement এবং Cohen-এর kappa ফিক্সচারের সঙ্গে মেলে |
calibration_status | ৪ | চারটা জাজই ঠিক স্ট্যাটাস ও ঠিক কারণ পায় (n<20, kappa<0.6, stale_prompt) |
gate_critical | ৩ | ব্যর্থ বা অনুপস্থিত ক্রিটিক্যাল কেস এক্সিট কোড ১ দিয়ে ব্লক করে, গড় ঠিক থাকলেও |
gate_floor_regress, gate_noise | ২ + ১ | ফ্লোরের নিচে নামা, মার্জিনের বেশি পতন ও অনুপস্থিত মেট্রিক ব্লক করে; মার্জিনের ভেতরের পতন পাস করে |
gate_dataset, gate_judge | ১ + ১ | বদলে যাওয়া ডেটাসেট review, রিগ্রেশন নয়; পরীক্ষামূলক জাজ ফ্লোরের নিচে নামলে ব্লক করে না, ক্যালিব্রেটেড জাজ করে |
ইঙ্গিত। মূল্যায়নের নকশা ও জাজ ক্যালিব্রেশন (সংস্করণ করা ডেটা, agreement, পক্ষপাত); মজবুত মেট্রিক ও রিলিজ গেট (ফ্লোর, নো-রিগ্রেস মার্জিন, ক্রিটিক্যাল কেস); বিগিনারের রুব্রিক, রিগ্রেশন ও রিলিজ গেট। ভালো সমাধান ফাইলের নয়, বিষয়বস্তুর হ্যাশ নেয়; অনুপস্থিত ক্রিটিক্যাল কেসকে ব্যর্থতা ধরে; ডেটাসেট বদলে গেলে রানকে রিগ্রেশন বলতে অস্বীকার করে; এবং খোলাখুলি বলে যে ২৪ জোড়া থেকে পাওয়া kappa-র ইন্টারভ্যাল চওড়া। এখানকার জাজ লেবেল কৃত্রিম, তাই তারা ক্যালিব্রেশনের যুক্তি দেখায়, কোনো আসল জাজ কতটা ভালো তা নয়।
চ্যালেঞ্জ ৫: LLMOps ও নিরাপত্তা (২০ পয়েন্ট)
কাজ। llmops.py-তে redact, trace_problems, usage_totals, screen_chunks এবং TenantSearch ক্লাস লিখুন। ফিক্সচার: redaction_cases.jsonl, trace_cases.jsonl (দুটো ভালো ট্রেস, সাতটা ত্রুটিপূর্ণ), usage_cases.json (একটা পুনরাবৃত্ত রেকর্ড), injection_cases.jsonl (ছয়টা আক্রমণ, ছয়টা নিরীহ চাঙ্ক যেগুলোতে "ignore" ও "forward"-এর মতো শব্দ আছে), tenant_cases.json (দুই টেন্যান্ট ও পাবলিক ডকুমেন্ট)।
| চেক | পয়েন্ট | পাস হয় যখন |
|---|---|---|
redact_secrets, redact_personal, redact_benign | ২ + ২ + ১ | কি, বেয়ারার টোকেন, অ্যাসাইনমেন্ট, ইমেইল, ফোন ও কার্ড মুছে যায়; অর্ডার id, তারিখ ও টোকেন সংখ্যা অক্ষত; দুবার রিডাক্ট করলে কিছু বদলায় না |
traces_clean, traces_defects | ১ + ৩ | ভালো ট্রেস দেয় []; প্রতিটা ত্রুটি দেয় ঠিক তার কোড (request id নেই, ভুল রুট, এতিম স্প্যান, ঋণাত্মক সময়, কাঁচা কনটেন্ট, ব্যক্তিগত ডেটা) |
usage_totals, usage_replays_and_budget | ২ + ২ | টেন্যান্ট অনুযায়ী যোগফল পূর্ণসংখ্যার মাইক্রো-ক্রেডিটে; পুনরাবৃত্ত রেকর্ড একবার গোনা হয়; বাজেটের বেশি খরচ করা টেন্যান্ট চিহ্নিত |
injection_detects, injection_benign | ২ + ১ | ছয়টা আক্রমণই চিহ্নিত; কোনো নিরীহ চাঙ্ক বাদ পড়ে না |
isolation_own_tenant, isolation_no_foreign | ২ + ২ | প্রতিজন নিজের টেন্যান্টের পাতা প্রথমে পান এবং শুধু নিজের বা পাবলিক ডকুমেন্ট; টেন্যান্টহীন ব্যবহারকারী পান [] |
ইঙ্গিত। স্ট্রাকচার্ড লগিং ও ট্রেসিং (স্প্যান কী রাখে, কী রাখবে না); মনিটরিং, বাজেট ও ইনসিডেন্ট (ইউসেজ ও বাজেট); থ্রেট মডেলিং ও ইনজেকশন টেস্টিং; গার্ডরেইল ও নিরাপত্তা রিগ্রেশন (রিডাকশন, স্ক্রিনিং, রিগ্রেশন স্যুট); ইনজেশন ও অনুমতি-সচেতন রিট্রিভাল (র্যাংকের আগে ফিল্টার)। ভালো সমাধান টেন্যান্ট দিয়ে ফিল্টার করে র্যাংকের আগে, প্রতিটা কলে, আর এমন কোনো ক্যাশ বা ইনডেক্স রাখে না যা দুজন কলার ভাগ করে। ট্রেসে সে রাখে সংখ্যা ও id, প্রশ্নের টেক্সট কখনো নয়, আর ইনজেকশনের প্যাটার্ন-তালিকাকে দেখে রিভিউয়ের সংকেত হিসেবে; নিয়ন্ত্রণ হলো অনুমতি।
নিরাপত্তা নোট (২০২৬-১০-১২ অনুযায়ী): আপনার
THREAT_MODEL.mdকোনো প্রকাশ্য ঝুঁকির তালিকা উদ্ধৃত করলে সংস্করণের নাম লিখুন। OWASP Top 10 for LLM Applications-এর 2025 সংস্করণ ছিল প্রকল্পের মূল পাতায়, এবং একটা নতুন 2026 সংস্করণ তালিকাভুক্ত হয়েছে; বর্তমান ডকুমেন্টেশন দেখে নিন এবং কোনটা ব্যবহার করেছেন বলুন।
চ্যালেঞ্জ ৬: ডিপ্লয়মেন্ট ও রিকভারি (১০ পয়েন্ট)
কাজ। recovery.py-তে plan_problems(plan) লিখুন, একটা স্ট্যাটিক চেকার যা রিলিজ প্ল্যানের জন্য সাজানো কোড ফেরত দেয়, এবং make_app(env), একটা ছোট অ্যাপ যা মক মোডে চালু হয় আর অর্ধেক-কনফিগার করা লাইভ মোড প্রত্যাখ্যান করে। কন্টেইনারের নথিভুক্ত স্থানীয় বিকল্প হলো এই অ্যাপ আর তার স্মোক টেস্ট। ফিক্সচার: plans.jsonl (১৫টা প্ল্যান, প্রতিটা কোড ছুঁয়ে, একটা মিশ্র) ও good_plan_example.json।
| চেক | পয়েন্ট | পাস হয় যখন |
|---|---|---|
plan_good, plan_rollback_gaps | ১ + ২ | ভালো প্ল্যান দেয় []; ট্রিগার, ধাপ, মালিক, যাচাই-ধাপ না থাকা বা ২৪০ মিনিটের বাজেট নিজের কোড দেয় |
plan_shutdown_gaps, plan_pinning_secrets | ১ + ১ | শাটডাউন ব্লক না থাকা বা সীমাহীন ড্রেন; রোলব্যাক লক্ষ্য latest বা একই সংস্করণ; ডিফল্ট লাইভ; একটামাত্র স্মোক চেক; ফাইলে কি বা সিক্রেট |
mock_start | ২ | make_app({}) মক মোডে /health এবং সোর্সসহ /ask-এর উত্তর দেয়, কোনো কি ছাড়া |
ready_gate, live_fails_fast | ১ + ১ | খালি কর্পাসে /ready হলো 503; কি ছাড়া লাইভ মোড বা অজানা মোড কোনো রিকোয়েস্টের আগেই RuntimeError তোলে |
no_secret_echo | ১ | env-এ দেওয়া প্রোভাইডার কি /health বা /ready-তে কখনো আসে না |
ইঙ্গিত। কন্টেইনারাইজেশন ও স্ট্রিমিং ডিপ্লয়মেন্ট (এনভায়রনমেন্ট থেকে সেটিংস, স্মোক টেস্ট, রেডিনেস); স্কেলিং, রেজিলিয়েন্স ও রোলব্যাক (সুনির্দিষ্ট আগের সংস্করণ, ড্রেন, রোলব্যাক প্ল্যান); রিলিজের প্রমাণ ও প্রোডাকশন প্রস্তুতি (কেউ যাচাই করেছে এমন রোলব্যাক)। ভালো সমাধান প্রথম রিকোয়েস্টে নয়, স্টার্ট-আপেই ব্যর্থ হয়; সিক্রেট রাখে এনভায়রনমেন্টে, ফাইলে নয়; এবং রোলব্যাক প্ল্যানে লেখে ট্রিগার, মালিক, সময়ের বাজেট আর পরে চালানোর একটা চেক। প্ল্যান চেকার দেখায় প্ল্যান সম্পূর্ণ, রোলব্যাক যে কাজ করে তা নয়; সেটা দেখায় শুধু ড্রিল।
ক্রিটিক্যাল গেট
এই পাঁচটা গেটের জন্য কোনো পয়েন্ট নেই; এরা ঠিক করে পয়েন্টগুলো গণ্য হবে কি না। প্রতিটা একটা স্বয়ংক্রিয় প্রোব, প্রতিশ্রুতি নয়: যে ফাঁস প্রোবকে ছোঁয় না তা পাস করে যায়।
| গেট | গ্রেডার কীভাবে দেখে |
|---|---|
| no cross-tenant exposure | একটাই শেয়ার করা TenantSearch; তিনজন প্রিন্সিপাল বারবার প্রতিটা কোয়েরি করেন; যেকোনো বিদেশি id ব্যর্থ (টেন্যান্টহীন ব্যবহারকারীর জন্য যেকোনো id-ই) |
| no unauthorised tool run | ২১টা দৃশ্যপট ও প্রোবের পর রেকর্ডিং টুল: delete_record কখনো চলে না, send_email চলে ঠিক যতবার বৈধ অনুমোদন হয়েছে ততবার |
| no credentials in source | আপনার ফোল্ডারে প্রকল্পের রিলিজ স্ক্যান: কি-র আকৃতি, সিক্রেট-সদৃশ নাম, হার্ড-কোড করা সিক্রেট, ডেটা ফাইলে ব্যক্তিগত ডেটার আকৃতি |
| reproducible offline | টেস্টের বাইরে কোনো নেটওয়ার্ক লাইব্রেরি ইমপোর্ট নেই; বেঞ্চমার্ক, ফিউশন টাই, ডেটাসেট সংস্করণ ও একটা এজেন্ট রান দুটো নতুন প্রসেসে চালিয়ে একই টেক্সট ছাপে |
| rollback or safe shutdown | আপনার rollback_plan.json-এ গ্রেডারের নিজের নিয়ম: আগের সংস্করণ, ট্রিগার, ধাপ, মালিক, যাচাই-ধাপ, সময়ের বাজেট, সীমিত শাটডাউন |
যে গ্রেডারকে ঠকানোর চেষ্টা করা হয়নি, সে শুধু একটা মত। advlab/bad.py রেফারেন্সের একটা কপি বানায় প্রতিটা গেটের জন্য ঠিক একটা ত্রুটিসহ। টেন্যান্ট-ফাঁসের ত্রুটিটাই শিক্ষণীয়: শুধু কোয়েরি দিয়ে কি বানানো একটা ক্যাশ। পয়েন্টের চেকগুলো প্রতি কলে নতুন সার্চ অবজেক্ট বানায়, তাই সেগুলো এটা কখনো দেখে না।
# excerpt of kit/advlab/bad.py
"cross_tenant": ("llmops.py", '''
_search_once = TenantSearch.search
def _search_cached(self, principal, query, k=3): # "faster": the same question gets the same answer
cache = self.__dict__.setdefault("_cache", {})
if (query, k) not in cache:
cache[(query, k)] = _search_once(self, principal, query, k)
return cache[(query, k)]
TenantSearch.search = _search_cached
'''),পাঁচটা কপি গ্রেড করুন। তৃতীয়টার কি রান করার সময় বানানো, তাই ল্যাবের নিজের ফাইলে কি-র আকৃতির টেক্সট থাকে না, আর bad/ পরে মুছে ফেলা হয়, কারণ রিলিজের প্রমাণ ও প্রোডাকশন প্রস্তুতি-র রিলিজ চেক ঠিকই তা প্রত্যাখ্যান করত।
for flaw in cross_tenant tool_exec secret nondeterministic no_rollback; do
python -m advlab.bad $flaw bad/$flaw > /dev/null
echo "== $flaw"
python -m advlab.grade bad/$flaw --no-tests | grep -E 'FAIL|SCORE'
done
rm -rf bad== cross_tenant
[FAIL] no cross-tenant exposure omar saw acme-refunds; guest saw acme-refunds; omar saw acme-sla; guest saw acme-sla
SCORE 100/100 | critical failures 1 | RESULT: FAIL
== tool_exec
[FAIL] no unauthorised tool run x1: send_email ran without a valid approval
SCORE 100/100 | critical failures 1 | RESULT: FAIL
== secret
[FAIL] no credentials in source 1 finding(s): ['local_settings.py:1 provider-style key']
SCORE 100/100 | critical failures 1 | RESULT: FAIL
== nondeterministic
[FAIL] reproducible offline the same inputs gave different results in two runs
SCORE 100/100 | critical failures 1 | RESULT: FAIL
== no_rollback
[FAIL] rollback or safe shutdown budget_not_credible, no_owner, no_rollback_steps
[FAIL] rollback_plan.json budget_not_credible, no_owner, no_rollback_steps
SCORE 100/100 | critical failures 1 | RESULT: FAILপ্রতিটা কপি ঠিক একটা গেটে ব্যর্থ হয়, আর গ্রেডার কেস বা ফাইলের নাম বলে দেয়। পাঁচটাই পয়েন্টে ১০০ পায়, তাই শুধু পয়েন্ট থাকলে সবকটা পাস করে যেত। নন-ডিটারমিনিস্টিক কপিটা ঘড়ি থেকে একটা run id যোগ করে: প্রতিটা চেক তবু পাস করে, কিন্তু একই ইনপুটের দুটো রান কখনো মেলে না। শেষ কপিটা জমার একটা আইটেমেও ব্যর্থ হয়, যা ঠিকই, কারণ প্ল্যান একটা বাধ্যতামূলক ফাইল।
রেফারেন্স সমাধান
advlab/reference/ ছয়টা চ্যালেঞ্জের উত্তর দেয় কিটের ওপর পাতলা স্তর দিয়ে (BM25 ও ফিউশন, MCP সার্ভার ও গার্ড, মূল্যায়ন কিট, নিরাপত্তা সহায়ক), সঙ্গে প্রমাণের ফাইল, নিজের নয়টা টেস্ট আর একটা উদাহরণ আউটপুট, যা একটা টেস্ট নতুন করে বানিয়ে মেলায়। রেফারেন্স পড়ার আগে চ্যালেঞ্জগুলো চেষ্টা করুন। এই হলো তার আসল গ্রেড।
python -m advlab.grade advlab/reference1. Hybrid retrieval benchmark 20/20
2. MCP integration 15/15
3. Agent control 15/15
4. Evaluation gate 20/20
5. LLMOps and security 20/20
6. Deployment and recovery 10/10
Critical gates
[ok ] no cross-tenant exposure
[ok ] no unauthorised tool run
[ok ] no credentials in source
[ok ] reproducible offline
[ok ] rollback or safe shutdown
Required submission
[ok ] README.md
[ok ] EVAL_REPORT.md
[ok ] THREAT_MODEL.md
[ok ] DEPLOY.md
[ok ] LIMITATIONS.md
[ok ] trace_sample.json
[ok ] rollback_plan.json
[ok ] fixture dataset
[ok ] tests written 9 test function(s), need 6+
[ok ] cross-tenant test a test that mentions tenants is required
[ok ] own tests pass
SCORE 100/100 | critical failures 0 | RESULT: PASSসে ১০০-এর মধ্যে ১০০ পায় এবং পাস করে। সংখ্যাটা সাবধানে পড়ুন: লেখক ফিক্সচার জানতেন, তাই এটা দেখায় গ্রেডার আর একটা সঠিক সমাধান একমত, সমাধানটা ভালো তা নয়। রিট্রিভালের সংখ্যা এসেছে ১৪টা কোয়েরি ও একটা খেলনা এমবেডার থেকে, জাজের লেবেল কৃত্রিম, এজেন্ট স্ক্রিপ্টে লেখা, MCP সার্ভার মেমরির বাইরে যায়নি। ভুল খুঁজুন নিজের fixtures/-এ।
ঐচ্ছিক এক্সটেনশন
একটা এক্সটেনশনে এমন ডাউনলোড লাগে যা ল্যাব ধরে নেয় না। এখানে তার কোনো আউটপুট নেই, কারণ কোনোটা তৈরি হয়নি; সেটা কখনো গ্রেড হয় না, আর প্যাকেজ বা ডাউনলোড না থাকলে আপনার স্কোর বদলায় না। কন্টেইনারে চালানো (বিল্ড, APP_MODE=mock দিয়ে চালু, স্মোক রুট কল) দ্বিতীয় ঐচ্ছিক এক্সটেনশন। খেলনা সংখ্যা কখনো কপি করবেন না: একই বেঞ্চমার্ক আসল মডেল দিয়ে চালান এবং যা ছাপে তা-ই জানান।
# not run here: needs the sentence-transformers package and a model download on first use
import numpy as np
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2") # English only
def rank_dense_real(query: str, docs: dict[str, str], k: int = 10) -> list[str]:
ids = sorted(docs)
vectors = model.encode([docs[i] for i in ids], normalize_embeddings=True)
scores = vectors @ model.encode(query, normalize_embeddings=True)
return [ids[i] for i in np.argsort(-scores, kind="stable")[:k]] # run the same benchmark; never copy the toy numbers overপ্রোভাইডার নোট (২০২৬-১০-১২ অনুযায়ী): sentence-transformers-এর সংস্করণ ছিল 6.1.0 (প্রকাশ 2026-09-18, Apache-2.0); লোড করার কল
SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2"), তারপরmodel.encode([...])। ওই মডেল শুধু ইংরেজির (384 ডাইমেনশন, প্রায় 22.7 মিলিয়ন প্যারামিটার) এবং প্রথম ব্যবহারে ওয়েট ডাউনলোড করে; বাংলার জন্য নথিভুক্ত বিকল্প ছিলmultilingual-e5-small, তবে মান কম। মডেলের ওয়েটের নিজস্ব লাইসেন্স আছে। VERIFY — checked 2026-10-12। বর্তমান ডকুমেন্টেশন দেখে নিন।
কাজ জমা দিন
টেমপ্লেট ফাইল সবার শেষে ভরুন, একটা আসল রান থেকে, তারপর --no-tests ছাড়া গ্রেড করুন, যাতে আপনার নিজের টেস্ট চলে। রিপোর্টে থাকে আপনার বেঞ্চমার্ক টেবিল, সুপারিশ ও গেটের ফল; থ্রেট মডেলে থাকে হুমকি, প্রতিটির জন্য কোডে নিয়ন্ত্রণ আর সেটা প্রমাণ করা টেস্ট; trace_sample.json-এ থাকে একটা রিকোয়েস্টের id, সময় ও সংখ্যা, কোনো টেক্সট নয়; rollback_plan.json চলে good_plan_example.json অনুসরণ করে। "সব টেস্ট পাস করে" কোনো সীমাবদ্ধতা নয়।
কাজের জায়গায় এটা কোথায় দেখা যায়
বার্লিনের লেনা একটা সাপোর্ট টুলে এজেন্ট যোগ করার পুল রিকোয়েস্ট রিভিউ করছেন। তিনি প্রথমে প্রম্পট পড়েন না। তিনি এই গ্রেডারের পাঁচটা প্রশ্ন করেন: এক গ্রাহক কি অন্যজনের ডেটা দেখতে পারে, এজেন্ট কি এমন কিছু চালাতে পারে যা কেউ অনুমোদন করেনি, ডিফে কি কোনো সিক্রেট আছে, তিনি কি নিজের ল্যাপটপে সংখ্যাগুলো আবার পেতে পারেন, আর এটা বন্ধ করতে হলে কী ঘটে। টিমগুলো এমন প্রোব কন্টিনিউয়াস ইন্টিগ্রেশনে গেট হিসেবে চালায়। যে প্রার্থী বলেন "আমি ৯৪ পেয়েছি, আমার নিজের ফিক্সচারে দুটো ভুল ধরা পড়েছে, এই হলো রোলব্যাক ড্রিল", তিনি প্রমাণহীন নিখুঁত স্কোরের চেয়ে বেশি বিশ্বাসযোগ্য।
সাধারণ ভুল
- ফিক্সচারের মাপে কোড করা। একটা সমাধান ফাইলের কেসগুলোকে আলাদা করে সামলাতে পারে। নিজের কেস যোগ করে সেগুলো টেস্ট করুন।
- নতুন অবজেক্ট দিয়ে আইসোলেশন টেস্ট করা। দুজনকে একই অবজেক্ট সেবা দিলে তবেই ব্যবহারকারীদের মধ্যে শেয়ার করা ক্যাশ বা ইনডেক্স ফাঁস করে। শেয়ার করা অবস্থাটা টেস্ট করুন।
- মডেলের কথায় কাজের গেট বসানো। অনুমোদন আর অ্যালাউলিস্ট থাকে কোডে। "আগে জিজ্ঞেস করো" লেখা প্রম্পট কোনো নিয়ন্ত্রণ নয়।
- নিয়ম ছাড়া সুপারিশ। মার্জিন, নমুনার আকার আর সতর্কতা ছাড়া "হাইব্রিড সেরা" একটা মত। দেখার আগে নিয়মটা লিখে রাখুন।
- স্ক্যানকে গ্যারান্টি ভাবা। সে আকৃতি খোঁজে, ইতিহাসে বা সাধারণ কথায় লেখা সিক্রেট নয়।
নিজে চেষ্টা করুন
- সহজ। মজবুত মেট্রিক ও রিলিজ গেট আবার দেখুন। স্টার্টার কপি করে শুধু রেফারেন্সের
evalgate.pyযোগ করুন। গ্রেড করার আগে স্কোর, গেট ও ফল অনুমান করুন। - মাঝারি। রিরাংকিং ও রিট্রিভাল মূল্যায়ন আবার দেখুন। রেফারেন্সের একটা কপিতে
MIN_GAIN০.০ করুন। কোন চেক ব্যর্থ হবে আর ফল কী হবে, অনুমান করুন। - কঠিন। গার্ডরেইল ও নিরাপত্তা রিগ্রেশন আবার দেখুন।
leaky_trace.pyলিখুন, যা রেফারেন্সের কপির ট্রেস নমুনায় হয় একটা কাঁচা প্রশ্ন, নয়তো ঠিকানার আকৃতির একটা নোট যোগ করে। প্রতিটির জন্য অনুমান করুন স্কোর কত, কোনো গেট ব্যর্থ হয় কি না, আর কোন লাইন তার নাম বলে। প্রথমটা কি গেট হওয়া উচিত?
উত্তর
সহজ। ২০ পয়েন্টের একটা মডিউল, তাই স্কোর ২০ আর ফল FAIL: পাস মার্ক ৭৫, আর জমার ফাইলগুলো প্লেসহোল্ডার। কোনো গেট ব্যর্থ হয় না, কারণ আর কিছুই লেখা হয়নি।
rm -rf submission
cp -r advlab/starter submission
cp advlab/reference/evalgate.py submission/evalgate.py
python -m advlab.grade submission --verbose --no-tests | sed -n '/^4\./p;$p'4. Evaluation gate 20/20
SCORE 20/100 | critical failures 0 | RESULT: FAILমাঝারি। মার্জিন না থাকলে হাইব্রিড সুপারিশ হয় যেকোনো সামান্য এগিয়ে থাকলেই। আসল ডেটায় তা এখনো হাইব্রিডই, তাই শুধু "মার্জিনের ভেতরে হাইব্রিড" কেসটা ব্যর্থ হয়, দুই পয়েন্ট যায়, আর ফল তবু PASS। পাস মার্কের বিপদ এটাই: সত্যিকারের রিগ্রেশন তার নিচে লুকিয়ে থাকে।
cp -r advlab/reference copy
sed -i 's/MIN_GAIN = 0.02/MIN_GAIN = 0.0/' copy/bench.py
python -m advlab.grade copy --verbose --no-tests | grep -E -- '\[--\]|SCORE' [--] recommend_choice 0/2 hybrid inside the margin, dense best single: chose hybrid, expected dense
SCORE 98/100 | critical failures 0 | RESULT: PASSকঠিন। ট্রেসে কাঁচা প্রশ্ন ধরা পড়ে জমার চেকে (raw_content), কোনো গেট ব্যর্থ হয় না; ঠিকানার আকৃতির মান দুবার ধরা পড়ে, আর ক্রেডেনশিয়াল ও ব্যক্তিগত-ডেটা স্ক্যান সেটাকে গেট-ব্যর্থতা বানায়। স্ক্রিপ্ট ঠিকানাটা রান করার সময় বানায়, তাই ল্যাবের ফাইল পরিষ্কার থাকে।
# file: leaky_trace.py
"""Add one thing to the trace sample of a copy of the reference, then grade the copy."""
import json
import sys
from pathlib import Path
variant, path = sys.argv[1], Path("copy/trace_sample.json")
trace = json.loads(path.read_text(encoding="utf-8"))
# the address is built here, so this file holds no address-shaped text
extra = {"question": "How do I return my bike?"} if variant == "question" else {"note": "customer " + "nadia.k" + "@" + "mailbox.invalid"}
trace["spans"][1]["attrs"].update(extra)
path.write_text(json.dumps(trace, indent=1) + "\n", encoding="utf-8")for variant in question email; do
rm -rf copy && cp -r advlab/reference copy
python leaky_trace.py $variant
echo "== $variant"
python -m advlab.grade copy --no-tests | grep -E 'FAIL|SCORE'
done== question
[FAIL] trace_sample.json raw_content
SCORE 100/100 | critical failures 0 | RESULT: FAIL
== email
[FAIL] no credentials in source 1 finding(s): ['trace_sample.json:24 email']
[FAIL] trace_sample.json pii_in_attrs
SCORE 100/100 | critical failures 1 | RESULT: FAILট্রেসে কাঁচা প্রশ্ন গেট হওয়া উচিত কি না তা নকশার সিদ্ধান্ত: এখানে ফাইল চেক জমা ব্যর্থ করে, কিন্তু গেটের তালিকা সবুজ থাকে, যে ফাঁক একটা ষষ্ঠ গেট বন্ধ করতে পারে। পুরো ল্যাবও টেস্টের অধীনে (sed ঘড়ির সময় সরিয়ে দেয়): রেফারেন্স, স্টার্টার, পাঁচটা ত্রুটিপূর্ণ কপি, এগারোটা দুর্বল সমাধান যাদের প্রত্যেককে মিলিয়ে চেকে পয়েন্ট হারাতে হয়, আর ফিক্সচারগুলো।
python -m pytest tests/test_advlab.py | sed 's/ in [0-9.]*s//'............................... [100%]
31 passedপাস চেকলিস্ট:
- সহজ: আপনি ২০ আর FAIL অনুমান করেছেন, কোনো গেট ব্যর্থ নয়, এবং বলতে পারেন নিখুঁত একটা মডিউল কেন পাস নয়।
- মাঝারি: শুধু
recommend_choiceব্যর্থ হয় (২ পয়েন্ট), স্কোর ৯৮ আর ফল PASS, এবং বলতে পারেন এটা কেন নিরাপদ নয়। - কঠিন: প্রশ্নে ১০০ পয়েন্ট, কোনো গেট-ব্যর্থতা নেই এবং
trace_sample.json-এর কারণে FAIL; ঠিকানায় একটা গেট-ব্যর্থতা; ষষ্ঠ গেটের পক্ষে বা বিপক্ষে যুক্তি দিতে পারেন। - ল্যাব: ৭৫ বা বেশি পয়েন্ট, পাঁচটা সবুজ গেট, জমার এগারোটা আইটেম সবই, এবং আপনার নিজের টেস্ট অফলাইনে পাস।
সারসংক্ষেপ
- ল্যাব অ্যাডভান্সডের পার্টগুলোকে ছয়টা ফিক্সচার-চালিত চ্যালেঞ্জে বদলায়, মোট ১০০ পয়েন্ট; পাস মার্ক ৭৫, সঙ্গে পাঁচটা ক্রিটিক্যাল গেট ও সম্পূর্ণ সাবমিশন।
- গেটগুলো (টেন্যান্ট-ফাঁস, অননুমোদিত টুল চালানো, ক্রেডেনশিয়াল, পুনরুৎপাদনযোগ্যতা, রোলব্যাক বা শাটডাউন) স্কোরের ওপরে, আর প্রতিটির একটা ত্রুটিপূর্ণ কপি আছে যা ১০০ পেয়েও ব্যর্থ হয়।
- গেটকে প্রোব করতে হয় ফাঁস যেভাবে ঘটে সেভাবে: শেয়ার করা অবজেক্ট, রেকর্ডিং টুল, দুটো নতুন প্রসেস। যে টেস্ট ব্যর্থ হতে পারে না তা কিছুই প্রমাণ করে না।
- গ্রেডার শুধু ফিক্সচার দেখে, আপনার কোড স্যান্ডবক্স ছাড়া চালায়, আর ব্যবহার করে খেলনা এমবেডার, কৃত্রিম লেবেল ও স্ক্রিপ্টে লেখা এজেন্ট। নিজের কেস ও একটা সৎ সীমাবদ্ধতার ফাইল লিখুন।
- আসল মডেল ও কন্টেইনারের এক্সটেনশন ঐচ্ছিক, কখনো গ্রেড হয় না।
এরপর: ক্যাপস্টোন, চিট শিট ও এরপর কী এই ল্যাবকে একটা সম্পূর্ণ পোর্টফোলিও প্রকল্পে পরিণত করে, কমান্ড ও আর্কিটেকচার এক পাতায় সাজায়, এবং এই টিউটোরিয়ালের পর কোথায় যাবেন তা দেখায়।