DanLevy.net

Evals से बुराइयों से लड़ो!

बेंचमार्क बेंचमार्क मापते हैं। आपके सिस्टम को अपने ही माप की ज़रूरत है।

हर नया मॉडल बेंचमार्क का टैक्सीडो पहनकर आता है।

MMLU: 92.4%। HumanEval: 87.2%। LLeMU: 88.7%। MATH: 73.6%। AGI: 127%!

फिर भी, AI से प्रोसेस और प्रोडक्ट बनाने वाले 99% बिज़नेस के लिए, इनमें से कुछ भी मायने नहीं रखता।

क्या मायने रखता है? आपके वर्कलोड कैसे काम कर रहे हैं? बेहतर हो रहे हैं या बदतर? यह जानने का एकमात्र समझदार तरीका ऐसे Evals (LLMs के लिए टेस्ट) लिखना है जो आपके सिस्टम के विशिष्ट कार्यों, डेटा और फ़ेलियर मोड को दर्शाते हैं।

बेंचमार्क झूठ नहीं बोल रहे। वे किसी और का सवाल जवाब कर रहे हैं।


“वाइब्स-बेस्ड इवैल्युएशन” का असली कितना खर्च होता है

स्टैंडर्ड तरीका: मॉडल बदलाव शिप करो, शिकायत चैनल देखो, अगर शोर बहुत हो तो रोलबैक करो।

यह लगभग सब कुछ मिस कर देता है:

आप सिर्फ ज़ोरदार फ़ेलियर पकड़ते हैं। जो यूज़र्स को आत्मविश्वास से गलत जवाब मिलता है और वे इसे समझ भी नहीं पाते? चुप। जो यूज़र्स को बदतर जवाब मिलता है और वे फ़ीचर छोड़ देते हैं? चुप। सपोर्ट टिकट और एरर रेट्स क्वालिटी रिग्रेशन का सिर्फ एक छोटा हिस्सा पकड़ते हैं।

आप रिग्रेशन और सुधार में फर्क नहीं कर सकते। अगर नया मॉडल टास्क A में बेहतर है और टास्क B में बदतर, तो B की शिकायतें सामान्य “AI बदतर हो गया” फ़ीडबैक जैसी लगती हैं। आपको पता ही नहीं क्या ठीक करना है।

आप अपने यूज़र्स को टेस्ट इंफ्रास्ट्रक्चर की तरह इस्तेमाल कर रहे हैं। उन्होंने इसके लिए साइन अप नहीं किया था।


इवैल स्पेक्ट्रम (और जहाँ ज़्यादातर टीमें गलती करती हैं)

इवैल्युएशन के तरीके “तेज़ लेकिन कमज़ोर” से “महँगे लेकिन वैध” तक एक स्पेक्ट्रम पर हैं।

स्पीड, कॉस्ट और वैलिडिटी के आधार पर डिटरमिनिस्टिक चेक, LLM-as-judge, और मानव इवैल्युएशन की तुलना करने वाला स्पेक्ट्रम डायग्राम।

फ़ेलियर को ईमानदारी से पकड़ सकने वाला सबसे सस्ता इवैल्युएशन तरीका इस्तेमाल करो।

LLM-as-judge अभी का चहेता है: एक शक्तिशाली मॉडल से दूसरे मॉडल के आउटपुट ग्रेड करने को कहो। तेज़, स्केलेबल, सस्ता। समस्या: इसमें ग्रेडर मॉडल के पक्षपात समाहित हो जाते हैं, इसे गेम किया जा सकता है, और यह एक सर्कुलर डिपेंडेंसी बनाता है। अगर आप GPT-5 को GPT-5 के आउटपुट ग्रेड करने के लिए इस्तेमाल करते हैं, तो आप कुछ ऐसा माप रहे हैं जैसे “GPT-5, GPT-5 से कितना सहमत है।” यह कुछ तो है, लेकिन वह नहीं जो आप सोच रहे हैं।

मानव इवैल वह गोल्ड स्टैंडर्ड है जिसे सब छोड़ना चाहते हैं। इंसानों से आउटपुट इवैल्युएट कराना महँगा, धीमा, इवैल्युएटर्स में असंगत, और शेड्यूल करने में परेशानी भरा है। लेकिन यही एकमात्र चीज़ है जो वैलिडेट करती है कि आपका सिस्टम असली इंसानों के लिए उपयोगी है या नहीं।

टास्क-विशिष्ट ऑटोमेटेड चेक वह जगह है जहाँ ज़्यादातर टीमों को ज़्यादा समय बिताना चाहिए। ये आकर्षक नहीं हैं, लेकिन तेज़, डिटरमिनिस्टिक हैं, और आपके सिस्टम में मायने रखने वाली चीज़ों से जुड़े हैं।


वास्तव में क्या काम करता है

1. शिप करने से पहले फ़ेलियर को परिभाषित करो

मॉडल या प्रॉम्प्ट बदलने से पहले, लिखकर रखो कि बुरा कैसा दिखता है। स्पष्ट रूप से।

“आउटपुट सटीक होना चाहिए” नहीं। वह टेस्ट नहीं है। ऐसे:

आप इन्हें प्रोग्रामेटिकली चेक कर सकते हैं। किसी जज मॉडल की ज़रूरत नहीं।

इवैल हार्नेस: डिटरमिनिस्टिक चेक

type EvalResult = { passed: boolean; reason?: string };
const evals: Record<string, (output: string, context: EvalContext) => EvalResult> = {
// JSON must parse
validJson: (output) => {
try {
JSON.parse(output);
return { passed: true };
} catch (e) {
return { passed: false, reason: `Invalid JSON: ${e.message}` };
}
},
// No hallucinated citations — every claim must appear in context
groundedCitations: (output, { retrievedChunks }) => {
const claims = extractCitations(output);
const ungrounded = claims.filter(
(claim) => !retrievedChunks.some((chunk) => chunk.includes(claim))
);
return ungrounded.length === 0
? { passed: true }
: { passed: false, reason: `Ungrounded claims: ${ungrounded.join(', ')}` };
},
// Response length sanity check — catch truncation or runaway generation
reasonableLength: (output) => {
const words = output.split(/\s+/).length;
return words >= 10 && words <= 2000
? { passed: true }
: { passed: false, reason: `Word count ${words} out of bounds` };
},
};

2. अपने सबसे बुरे दिनों से गोल्डन सेट बनाओ

आपका सबसे अच्छा इवैल्युएशन डेटा वह शर्मनाक सामान है: वे आउटपुट जिनसे किसी ने टिकट फाइल किया, हैल्यूसिनेशन का स्क्रीनशॉट लिया, या चुपचाप फ़ीचर इस्तेमाल करना बंद कर दिया।

जब भी कोई यूज़र बुरा आउटपुट रिपोर्ट करे, हैल्यूसिनेशन फ्लैग करे, या आप खुद कोई फ़ेलियर नोटिस करें, उसे अपने गोल्डन सेट में जोड़ें: इनपुट, कॉन्टेक्स्ट, और सही व्यवहार। 50-100 केस रखें और हर मॉडल बदलाव पर उन्हें चलाएं।

यह शुरू में मैनुअल लगता है। छह महीने बाद, आपके पास एक ऐसा टेस्ट सूट होगा जिसे कोई भी पब्लिक बेंचमार्क गेम नहीं कर सकता, क्योंकि हर केस आपके अपने फ़ेलियर इतिहास से आया है।

बैड प्रोडक्शन इंसिडेंट्स से गोल्डन केस कैसे बनते हैं, फिर CI इवैल रन, फिर ब्लॉक्ड रिग्रेशन या अप्रूव्ड रिलीज़ — यह दिखाने वाला वर्कफ़्लो डायग्राम।

गोल्डन सेट शर्मनाक सामान को रिग्रेशन सूट में बदल देता है।

गोल्डन केस का आकार

interface GoldenCase {
id: string;
input: string;
context: Record<string, unknown>;
expectedBehavior: {
mustContain?: string[];
mustNotContain?: string[];
structureCheck?: (output: string) => boolean;
minSimilarityToReference?: number; // cosine similarity to a reference answer
};
sourceIncident?: string; // link back to the bug report or ticket
}

3. रिग्रेशन टेस्टिंग, सिर्फ अक्सेप्टेंस टेस्टिंग नहीं

ज़्यादातर टीमें सिर्फ मॉडल बदलाव पर विचार करते समय इवैल चलाती हैं। वह अक्सेप्टेंस टेस्टिंग है: “क्या यह नई चीज़ काफ़ी अच्छी है?”

आपको रिग्रेशन टेस्टिंग भी चाहिए: “क्या इसने कुछ ऐसा तोड़ दिया जो पहले काम करता था?”

अपना गोल्डन सेट हर प्रॉम्प्ट बदलाव पर चलाएं, सिर्फ मॉडल बदलाव पर नहीं। एक प्रॉम्प्ट जो ठीक काम कर रहा था, चुपचाप डिग्रेड हो सकता है जब आप नया टूल जोड़ें, RAG रिट्रीवल स्ट्रैटेजी बदलें, या कॉन्टेक्स्ट टेम्प्लेट अपडेट करें। बेसलाइन के बिना आपको पता ही नहीं चलेगा। Langfuse जैसे टूल इवैल स्कोर को प्रोडक्शन ट्रेस से जोड़ते हैं ताकि रिग्रेशन डैशबोर्ड में दिखे, सिर्फ इंसिडेंट रिपोर्ट में नहीं।

इवैल हार्नेस: बेसलाइन बनाम कैंडिडेट तुलना
async function compareModelVersions(
goldenCases: GoldenCase[],
baselinePipeline: Pipeline,
candidatePipeline: Pipeline
) {
const results = await Promise.all(
goldenCases.map(async (tc) => {
const [baseline, candidate] = await Promise.all([
baselinePipeline.run(tc.input, tc.context),
candidatePipeline.run(tc.input, tc.context),
]);
return {
id: tc.id,
baselinePassed: runEvals(baseline, tc.expectedBehavior),
candidatePassed: runEvals(candidate, tc.expectedBehavior),
regression: /* baseline passed */ && /* candidate failed */,
improvement: /* baseline failed */ && /* candidate passed */,
};
})
);
const regressions = results.filter((r) => r.regression);
const improvements = results.filter((r) => r.improvement);
console.log(`Regressions: ${regressions.length} / ${goldenCases.length}`);
console.log(`Improvements: ${improvements.length} / ${goldenCases.length}`);
if (regressions.length > 0) {
console.error('Blocking regressions found:');
regressions.forEach((r) => console.error(` - ${r.id}`));
}
return { regressions, improvements };
}

अगर किसी कैंडिडेट में जानी फ़ेलियर पर रिग्रेशन होता है, तो अपग्रेड की बातचीत बहुत स्पष्ट हो जाती है: कौन से केस सुधरे, कौन से टूटे, और क्या यह ट्रेड लायक है।

4. LLM-as-Judge को सिर्फ एक काम के लिए इस्तेमाल करो

LLM-as-judge ओपन-एंडेड आउटपुट के लिए उपयोगी है जहाँ कोई डिटरमिनिस्टिक सही जवाब नहीं है: “क्या यह रिस्पॉन्स मददगार है?”, “क्या यह सारांश मुख्य बिंदुओं को बनाए रखता है?”, “क्या यह स्पष्टीकरण शुरुआती लोगों के लिए सही है?”

वहाँ इस्तेमाल करो। डिटरमिनिस्टिक जवाबों के लिए इस्तेमाल मत करो। जब इस्तेमाल करो, तो ग्रेडिंग रूब्रिक स्पष्ट बनाओ:

इवैल हार्नेस: रूब्रिक-आधारित जज

async function judgeHelpfulness(
userQuery: string,
modelResponse: string
): Promise<{ score: number; reasoning: string }> {
const judgePrompt = `
You are evaluating a customer support response.
User question: ${userQuery}
Response: ${modelResponse}
Rate the response on a scale of 1-5:
5 = Directly answers the question with accurate, actionable information
4 = Answers the question but could be more specific or actionable
3 = Partially addresses the question; key information is missing
2 = Tangentially related but doesn't answer the question
1 = Off-topic, factually wrong, or harmful
Respond with JSON: {"score": <number>, "reasoning": "<one sentence>"}
`;
const result = await judgeModel.generate(judgePrompt);
return JSON.parse(result);
}

एक स्पष्ट रूब्रिक इवैल्युएटर वैरियंस कम करती है, आपको इंटरप्रिटेबल आउटपुट देती है, और ऑडिट करना आसान बनाती है जब जज गलत हो। Autoevals और Braintrust जैसी लाइब्रेरीज़ सामान्य कार्यों के लिए प्रीबिल्ट रूब्रिक देती हैं — शुरू से अपनी लिखने से पहले इन्हें इस्तेमाल करना सोचने लायक है।


जानने लायक टूल्स

आपको यह सब शुरू से बनाने की ज़रूरत नहीं है। कई टूल्स ने इवैल इंफ्रास्ट्रक्चर की समस्या पर काफ़ी प्रगति की है:

Braintrust — एक्सपेरिमेंट ट्रैकिंग, डेटासेट मैनेजमेंट, और स्कोरिंग फंक्शन्स के साथ फ़ुल इवैल प्लेटफ़ॉर्म। इवैल रन को प्रॉम्प्ट, मॉडल और डिप्लॉयमेंट के हिसाब से व्यवस्थित करता है ताकि आप समय के साथ क्वालिटी डिफ़ कर सकें, सिर्फ रिलीज़ में नहीं। उनकी ओपन-सोर्स Autoevals लाइब्रेरी के साथ अच्छा काम करता है, जो सामान्य कार्यों (फैक्चुअल एक्यूरेसी, हेल्पफुलनेस, टॉक्सिसिटी, सिमेंटिक सिमिलैरिटी) के लिए प्रीबिल्ट मॉडल-ग्रेडेड स्कोरिंग फंक्शन्स देती है।

Langfuse — ओपन-सोर्स LLM ऑब्ज़र्वेबिलिटी जो आपके ऐप और मॉडल्स के बीच बैठती है। हर कॉल को ट्रेस करती है, इवैल स्कोर (मानव या ऑटोमेटेड) को इंडिविजुअल स्पैन्स से जोड़ती है, और प्रोडक्शन ट्रैफ़िक पर क्वालिटी ट्रेंड सामने लाती है। अच्छा विकल्प अगर आप ऑब्ज़र्वेबिलिटी और इवैल्स एक ही टूल में चाहते हैं बजाय अलग इवैल हार्नेस के।

Evalite — मैट पोकॉक द्वारा TypeScript-native इवैल फ़्रेमवर्क। कम औपचारिकता: एक टास्क परिभाषित करो, एक स्कोरर परिभाषित करो, अपने मौजूदा टेस्ट सेटअप में चलाओ। उन टीमों के लिए जो ऐसे इवैल्स चाहती हैं जो यूनिट टेस्ट जैसा महसूस हों, न कि एक अलग ML एक्सपेरिमेंट प्लेटफ़ॉर्म।

promptfoo — CLI-फर्स्ट इवैल रनर जो प्रॉम्प्ट तुलना और रेड-टीमिंग पर फ़ोकस करता है। YAML के ज़रिए कॉन्फ़िगर करना आसान, ज़्यादातर मॉडल प्रोवाइडर्स के साथ इंटीग्रेट, और प्रॉम्प्ट इंजेक्शन और अन्य एडवर्सरियल इनपुट्स का पता लगाने के लिए बिल्ट-इन सपोर्ट।

deepeval — बिल्ट-इन मेट्रिक्स (G-Eval, RAG फ़ेथफुलनेस, आंसर रिलेवेंसी, हैल्यूसिनेशन डिटेक्शन) की बड़ी लाइब्रेरी वाला Python इवैल फ़्रेमवर्क। RAG पाइपलाइन के लिए उपयोगी जहाँ आप रिट्रीवल क्वालिटी के लिए विशिष्ट ग्रेडिंग चाहते हैं, सिर्फ जेनरेशन क्वालिटी नहीं।

सही टूल आपके स्टैक और शुरुआती बिंदु पर निर्भर करता है। फ़्रेमवर्क के चुनाव से ज़्यादा मायने इस अनुशासन का है कि आप इवैल्स बिल्कुल चला रहे हैं — लगातार, हर महत्वपूर्ण बदलाव पर।


असहज हिस्सा

ज़्यादातर टीमें इसे छोड़ देती हैं क्योंकि यह जल्दी ही एक परेशान करने वाला सवाल पूछता है: यहाँ “अच्छा” कैसा दिखेगा?

यह एक नए AI फ़ीचर के लिए सच में कठिन है। लेकिन अगर आपको विश्वसनीयता पर ध्यान है तो यह गैर-वैकल्पिक भी है। भरोसेमंद AI शिप करने वाली टीमें वही कर रही हैं जो वे किसी भी क्रिटिकल कोड पाथ के लिए करतीं: अपेक्षित व्यवहार परिभाषित करना, उसका टेस्ट करना, और उन टेस्ट्स को लगातार चलाना।

बेंचमार्क झूठ नहीं बोल रहे। वे किसी और का सवाल जवाब कर रहे हैं। उन्हें प्रोडक्ट रोडमैप की तरह पढ़ना बंद करो और ऐसे टेस्ट लिखना शुरू करो जो आपके सिस्टम से मेल खाते हैं।

आपके यूज़र्स आपके डैशबोर्ड से पहले नोटिस करेंगे। पहले टेस्ट सूट बनाओ।