اختبارات تقييم ذاتية الاستضافة لوكلاء الذكاء الاصطناعي
ابنِ دورة تقييم تملكها: حوّل التتبعات الفعلية إلى حالات محفوظة، ابدأ بفحوص حتمية رخيصة، ثم استخدم حكماً لغوياً وتابع معدل النجاح مع كل commit.
ما هي اختبارات التقييم المستضافة ذاتياً لوكلاء الذكاء الاصطناعي
اختبارات التقييم المستضافة ذاتياً لوكلاء الذكاء الاصطناعي هي أربعة أشياء تحتفظ بها في مستودعك: ملف للحالات المحفوظة، ونص برمجي يشغّل الوكيل عليها، ومجموعة من عمليات التحقق لتقييم كل إجابة، وجدول للنتائج يمكنك الاستعلام عنه. لا يحتاج أي عنصر في هذه القائمة إلى مزوّد خدمة. تتكوّن الدورة كاملة من بضع مئات من أسطر Python وملف SQLite واحد.
نجح الوكيل في العرض التوضيحي لأنك اخترت المدخلات الخمسة بنفسك. لكنه تعطل في الأسبوع الثاني لأن سطراً في prompt تغيّر، أو لأن النموذج تغيّر، أو لأن وصف إحدى الأدوات تغيّر، ولم يكن هناك قياس يغطي أياً من ذلك. تحوّل دورة التقييم عبارة «يبدو الآن أسوأ» إلى عبارة «انخفض معدل النجاح من 58 من 60 إلى 51 من 60 في commit 4f1c9ab».
تتكوّن الدورة من أربع خطوات، ويخصّص هذا الدليل قسماً لكل خطوة: اجمع التتبعات الفعلية، وحوّل الحالات المهمة إلى حالات اختبار، وقيّم كل حالة عند كل تغيير، وخزّن معدل النجاح بجوار commit الذي نتجت عنه النتائج. تعمل الدورة نفسها مهما كان ما تشغّل الوكيل عليه، وتختلف أطر عمل الوكلاء المستضافة ذاتياً التي تستحق التشغيل في الغالب حسب مقدار التتبّع الذي تتيحه لك تلقائياً.
لماذا يتعطل الوكيل في الأسبوع الثاني
الوكيل هو prompt ونموذج ومجموعة من تعريفات الأدوات وأي سياق يُسترجع وقت التشغيل. يمكن أن تتغير هذه العناصر الأربعة من دون تغيير شفرة التطبيق، لذلك لا يجد مراجع الشفرة المعتاد ما يعترض عليه.
السبب الأكثر شيوعاً هو تعديل prompt. تضيف جملة واحدة لمنع رد فظ. تغيّر هذه الجملة السلوك في مدخلات لم يُعَد اختبارها، وتوضح ذلك آثار التنفيذ: يحتوي أثر الأسبوع الماضي للسؤال نفسه على استدعاء أداة create_refund، بينما لا يحتوي أثر هذا الأسبوع على أي استدعاء، ويكون الرد اعتذاراً مهذباً بدلاً من ذلك. لم يُسجَّل أي خطأ، لذلك لم يُطلَق أي تنبيه.
السبب الثاني هو النموذج. سجّل سلسلة النموذج الدقيقة التي أرسلتها مع كل تشغيل، claude-haiku-4-5-20251001 بدلاً من اختصار تحتفظ به في ذاكرتك، لأن انخفاض معدل النجاح في يوم تبديل النماذج لا يمكن تشخيصه إلا عندما يظهر النموذج في السجل.
السبب الثالث هو الأدوات. تؤثر إعادة صياغة وصف الأداة في وقت قرار النموذج لاستدعائها. إذا وصلت أدواتك عبر خوادم MCP تعمل على VPS، فسيكون المخطط في عملية أخرى، ولذلك يمكن أن يتغير دون أي فرق في مستودعك. السبب الرابع هو الاسترجاع: يصل السؤال نفسه إلى فهرس أُعيد بناؤه أثناء الليل، وتتبع الإجابة المستند الجديد.
أنشئ المجموعة المرجعية من سجلات التتبّع التي تجمعها بالفعل
لا تخترع حالات للتقييم. استخرجها من حركة الشبكة. إذا كنت تشغّل بالفعل تتبّع Langfuse مستضافاً ذاتياً لوكيلك، فسيُحفظ كل طلب مع مدخلاته واستدعاءات أدواته ومخرجاته، وهذا هو بالضبط المحتوى الخام الذي تحتاج إليه الحالة.
صدّر نافذة زمنية من ملاحظات root عبر واجهة API العامة. تستخدم الواجهة المصادقة الأساسية، بحيث يكون مفتاحك العام هو اسم المستخدم ومفتاحك السري هو كلمة المرور.
export LF_HOST="https://langfuse.example.com"
curl -sS -u "$LF_PUBLIC_KEY:$LF_SECRET_KEY" \
"$LF_HOST/api/public/v2/observations?limit=50&isRootObservation=true&fromStartTime=2026-07-01T00:00:00Z" \
| jq '.data[0]'اقرأ سجلاً واحداً قبل كتابة أي منطق للتحليل. تعود الصفوف ضمن data، لكن أسماء الحقول التي تحتوي على السؤال والرد تعتمد على طريقة تسجيل وكيلك لمقاطع التتبّع، لذلك حدّد الحقول التي تراها فعلياً بدلاً من الحقول التي توقعت وجودها. ثم اكتب الحالات يدوياً، بحيث يكون كل كائن JSON في سطر مستقل، ضمن evals/cases.jsonl:
{"id": "refund-double-charge", "tags": ["smoke"], "input": "I was charged twice for order 41822.", "must_call": ["lookup_order", "create_refund"], "must_not_include": ["I cannot help"], "rubric": "The reply confirms exactly one refund for order 41822 and states the amount."}تحافظ القواعد الخمس التالية على فائدة المجموعة عند تشغيلها:
- يكفي البدء بـ40 إلى 80 حالة. عند وجود أقل من 20 حالة، تغيّر حالة متذبذبة واحدة معدل النجاح بمقدار 5 نقاط، ويُتجاهل رقم يتغير بلا سبب.
- كل خطأ تصلحه في الإنتاج يتحول إلى حالة في يوم إصلاحه. هذه العادة هي ما يجعل المجموعة تنمو في الاتجاه الصحيح.
- سلوك واحد لكل حالة. إذا تحققت الحالة من مبلغ الاسترداد والأسلوب معاً، فلن تعرف شيئاً عند فشلها.
- لا يتغير
idأبداً، لأن المعرّف هو الطريقة التي تقارن بها تشغيل اليوم بتشغيل الشهر الماضي. - احجب البيانات الحساسة قبل تنفيذ commit. سيدخل هذا الملف إلى git، لذلك أزل أسماء العملاء وأي أرقام طلبات لا تملكها.
ابدأ بالتحقق من الشروط الحتمية، لأنها مجانية
أي شيء له إجابة صحيحة يُفحص بتأكيد مباشر. لا حاجة إلى استدعاء نموذج، ولا تكلفة، ولا غموض. تلتقط الفحوص الحتمية التراجعات البنيوية، وهي التراجعات التي تعطل الأنظمة المحيطة بوكيلك: لا يمكن تحليل JSON، أو لم تُستدعَ الأداة مطلقاً، أو عادت العبارة المحظورة، أو لا تذكر الإجابة أي مصدر.
تعرف دالة واحدة فقط تفاصيل وكيلك. أما بقية مكوّنات إطار الاختبار فهي عامة.
import json, os, urllib.request
def run_agent(case):
req = urllib.request.Request(
os.environ["AGENT_URL"],
data=json.dumps({"input": case["input"]}).encode(),
headers={"content-type": "application/json"},
)
with urllib.request.urlopen(req, timeout=120) as resp:
return json.load(resp)
def deterministic(case, result):
text = result.get("output", "")
called = [c["name"] for c in result.get("tool_calls", [])]
failures = []
for tool in case.get("must_call", []):
if tool not in called:
failures.append(f"tool not called: {tool}")
for phrase in case.get("must_not_include", []):
if phrase.lower() in text.lower():
failures.append(f"forbidden phrase: {phrase}")
if len(called) > case.get("max_tool_calls", 12):
failures.append(f"too many tool calls: {len(called)}")
return failuresأبقِ ميزانية الأدوات ضمن تلك القائمة. إذا حلّ وكيل حالةً باستخدام 3 استدعاءات اليوم و11 استدعاءً غداً، فهذا تراجع حتى عندما تكون الإجابة النهائية صحيحة، لأنك تدفع مقابل كل استدعاء يجريه.
الحكم بواسطة LLM، والطرق الأربع التي يفشل بها
كل ما ينجح في اختبارات التأكيد يحتاج إلى مُقيِّم يقرأ. حكم LLM هو استدعاء ثانٍ للنموذج: يتلقى السؤال وإجابة الوكيل ومعياراً واحداً، ثم يعيد حكماً. وهذه هي الطريقة العملية الوحيدة لتقييم «هل تجيب الإجابة عما طلبه المستخدم».
تجعل أربع قواعد الحكم قابلاً للاستخدام:
- استخدم حكماً ثنائياً، وليس درجة من 1 إلى 10. يعيد المقياس 7 و8 لكل شيء تقريباً، لذلك لا يتغير الرقم ولا تتعلم منه شيئاً.
- استخدم معياراً واحداً في كل استدعاء. اسأل عن مبلغ الاسترداد أو عن النبرة، وليس عنهما معاً.
- زوّد الحكم بالإجابة المتوقعة كلما كانت الحالة تملك إجابة متوقعة. فالتقييم بمقارنة الإجابة بمرجع أسهل بكثير من التقييم في الفراغ.
- ألزِم النموذج ببنية إخراج محددة وحلّلها بدقة.
from anthropic import Anthropic
client = Anthropic() # reads ANTHROPIC_API_KEY from the environment
def judge_prompt(case, output):
return (
"You grade one answer against one criterion.\n"
"Reply with JSON only, in this exact shape:\n"
'{"verdict": "pass", "confidence": "high", "reason": "one short sentence"}\n'
f"Criterion: {case['rubric']}\n"
f"Question: {case['input']}\n"
f"Answer: {output}\n"
"Length is not a criterion. Judge only the criterion above."
)
def judge(case, output, model):
msg = client.messages.create(
model=model,
max_tokens=200,
messages=[{"role": "user", "content": judge_prompt(case, output)}],
)
return json.loads(msg.content[0].text)والآن ننتقل إلى أنماط الفشل. لكل نمط اختبار يمكنك تشغيله هذا بعد الظهر. ومن المهم تشغيل هذه الاختبارات، لأن الحكم غير المُتحقَّق منه ينتج أرقاماً تبدو دقيقة ولا تعني شيئاً.
انحياز الطول. تنجح الإجابات الأطول بوتيرة أعلى. اختبر ذلك بأخذ عشر إجابات أخفق الحكم في تقييمها، وإضافة فقرتين من الحشو الواثق إلى كل منها من دون إضافة أي حقيقة جديدة، ثم قيّمها مرة أخرى. إذا تغيّر أي حكم إلى «ناجح»، فهذا انحياز الطول، ويجب إصلاح rubric.
تفضيل المخرجات الذاتية. غالباً ما يقيّم الحكم المخرجات الصادرة عن عائلة نموذجه بلطف أكبر من المخرجات الصادرة عن عائلة أخرى. اختبر ذلك بتقييم الإجابات الثلاثين نفسها باستخدام حكمين من عائلتين مختلفتين، ثم قارن الأحكام حالة بحالة. عندما يختلف الحكمان، اقرأ الحالة بنفسك.
انحياز الموضع. إذا استخدمت الحكم لمقارنة إجابتين، A وB، فبدّل الترتيب وشغّله مرة أخرى. إذا تغيّر الحكم عند تبديل الترتيب، فهذا يعني أن المقارنة الثنائية غير آمنة لهذا rubric حتى الآن.
انحراف معيار التقييم. تنتج المعايير الغامضة أحكاماً موافقة. فالسؤال «هل الإجابة مفيدة؟» ينجح معه كل شيء تقريباً. أما السؤال «هل تذكر الإجابة مبلغ الاسترداد بالدولار؟» فلا ينجح معه إلا ما قصدته. أعد كتابة كل معيار حتى يحدد الحقيقة التي يجري التحقق منها.
يغطي إجراء وقائي واحد أنماط الفشل الأربعة كلها. احتفظ بـ30 حالة صنّفتها يدوياً، واحسب درجة الحكم مقارنة بتصنيفاتك في كل مرة تغيّر فيها نموذج الحكم أو prompt الحكم. إذا خالفك في أكثر من حالة واحدة من كل عشر حالات، فأصلح rubric قبل أن تثق بأي معدل نجاح ينتجه. الحكم جزء من الشيفرة، لذلك يجب إصداره ومراجعته مثل الشيفرة.
التقييم بنموذج رخيص والتصعيد إلى نموذج متقدم
إن استخدام النموذج الأعلى تكلفة لتقييم كل حالة عند كل commit يؤدي إلى تضخم فاتورة التقييم بحيث تتجاوز تكلفة الوكيل الذي تختبره. رتّب المقيمين حسب السعر، وتوقف بمجرد أن تصبح الإجابة واضحة.
The data behind this chart
[
{
"label": "Haiku 4.5, Batch API",
"usd_per_1000_judge_calls": "0.90"
},
{
"label": "Haiku 4.5",
"usd_per_1000_judge_calls": "1.80"
},
{
"label": "Sonnet 5",
"usd_per_1000_judge_calls": "3.60"
},
{
"label": "Opus 5",
"usd_per_1000_judge_calls": "9.00"
}
]تفترض هذه الأرقام نحو 1,200 رمز إدخال و120 رمز إخراج لكل استدعاء للمقيّم، وهو حجم واقعي لسؤال واحد وإجابة واحدة ومعيار واحد. ويكلف تقييم 1,000 حالة 1.80 دولاراً أمريكياً باستخدام Claude Haiku 4.5، و9.00 باستخدام Claude Opus 5. تبدو الفجوة ضئيلة إلى أن تضربها في عدد الحالات. فمجموعة من 60 حالة، تُقيَّم عند كل commit، مع 40 commit أسبوعياً، تعني 2,400 استدعاء للمقيّم أسبوعياً قبل تشغيل المهمة الليلية.
ينطبق خصمان بوضوح على أعمال التقييم، ويمكن جمعهما معاً. عمليات التقييم غير تفاعلية، لذلك تخفّض Batch API سعرَي الإدخال والإخراج إلى النصف مقابل التسليم غير المتزامن، وهذا هو الصف الأول في المخطط. وتبقى rubric والتعليمات متطابقة بايتاً ببايت في كل استدعاء، لذلك تناسبها ميزة التخزين المؤقت للمطالبات: تكلف قراءة التخزين المؤقت عُشر سعر الإدخال الأساسي، بينما تكلف كتابة التخزين المؤقت لمدة خمس دقائق 1.25 ضعف سعر الإدخال الأساسي، ولذلك يغطي التخزين المؤقت تكلفته بعد استخدام واحد فقط. هذه أسعار Anthropic المعلنة حتى August 2026، وتخضع Sonnet 5 لسعر تمهيدي حتى 31 August 2026، لذلك يرتفع العمود الثالث بعد ذلك التاريخ.
سُلّم التقييم بالترتيب:
- فحوصات حتمية لكل حالة. لا توجد أي تكلفة API.
- مقيّم يستخدم نموذجاً صغيراً للحالات التي اجتازت تلك الفحوصات.
- مقيّم يستخدم نموذجاً متقدماً فقط عندما يقول المقيّم الصغير إن الحالة فاشلة، أو ينجحها مع ثقة منخفضة.
- مراجعة بشرية لعينة صغيرة مرة واحدة أسبوعياً.
CHEAP = "claude-haiku-4-5-20251001"
STRICT = "claude-opus-5"
def grade(case, result):
hard = deterministic(case, result)
if hard:
return False, "deterministic", "; ".join(hard)
first = judge(case, result["output"], CHEAP)
if first["verdict"] == "pass" and first["confidence"] == "high":
return True, CHEAP, first["reason"]
second = judge(case, result["output"], STRICT)
return second["verdict"] == "pass", STRICT, second["reason"]يؤدي ذلك إلى مقايضة بعض دقة التقييم مقابل التكلفة، لذلك قِس هذه المقايضة بدلاً من افتراضها. مرة واحدة شهرياً، قيّم المجموعة كاملة باستخدام المقيّم الصارم أيضاً، ثم قارن العمودين. إذا اختلفا في أكثر من بضع حالات، فهذا يعني أن rubric رخوة أكثر من اللازم بالنسبة إلى النموذج الصغير، وعندها يكون إصلاح rubric هو الإجراء المطلوب. أما التحكم في إنفاق الوكيل نفسه فهو مهمة منفصلة، وتغطيها التحكم في تكلفة وكيل ذكاء اصطناعي على VPS.
تتبّع معدل النجاح بمرور الوقت في نظام تملكه
معدل نجاح لا يمكنك ربطه بـ commit ليس سوى انطباع. خزّن صفاً واحداً لكل حالة في كل تشغيل، مع تضمين commit والنموذج داخل الصف.
CREATE TABLE IF NOT EXISTS results (
run_id TEXT NOT NULL,
ran_at TEXT NOT NULL,
git_sha TEXT NOT NULL,
agent_model TEXT NOT NULL,
case_id TEXT NOT NULL,
passed INTEGER NOT NULL,
graded_by TEXT NOT NULL,
reason TEXT
);SELECT run_id, git_sha, agent_model,
count(*) AS cases,
round(100.0 * sum(passed) / count(*), 1) AS pass_pct
FROM results
GROUP BY run_id
ORDER BY ran_at DESC
LIMIT 10;حمّل المخطط باستخدام sqlite3 evals/results.db < evals/schema.sql، ثم اقرأ الاتجاه باستخدام sqlite3 -box evals/results.db < evals/passrate.sql. ينتج عن تشغيل يومي لمدة عام على 60 حالة نحو 22,000 صف، لذلك لا يتحول مخزن البيانات إلى مشروع مستقل. يشرح تشغيل SQLite في بيئة الإنتاج على VPS الإعدادات التي تصبح مهمة عند مشاركة هذا الملف بين عدة أجهزة.
يعرض runner المعلومات نفسها للشخص:
run 2026-08-05T09:14:22Z sha 4f1c9ab model claude-sonnet-5 58/60 pass (96.7%)
FAIL refund-double-charge deterministic: tool not called: create_refund
FAIL pto-policy-question judge(opus): reply gives no dollar amountشغّل المجموعة على التغييرات التي قد تتسبب في تعطل agent، أي تعديلات prompt وتغييرات النموذج والأدوات، بدلاً من تشغيلها مع كل commit في أي مكان داخل repository. يغطي hook من نوع pre-push المجموعة السريعة:
cat > .git/hooks/pre-push <<'EOF'
#!/bin/sh
python3 evals/run.py --set smoke || exit 1
EOF
chmod +x .git/hooks/pre-pushالتشغيل الكامل أبطأ، ولذلك يجب جدولته. يشغّل خدمة systemd ومؤقتها على VPS المجموعة كاملة كل ليلة باستخدام prompt المنشور. وهذا يكشف التغييرات القادمة من خارج repository، مثل أداة مستضافة تغيّر سلوكها.
مراجعة بشرية بأخذ عينات بدلاً من المراجعة الشاملة
تُعايَر أداة التقييم بالاستناد إلى تصنيفات بشرية، لذلك يجب أن يُنشئها شخص ما. اقرأ عينة كل أسبوع: كل حالة أخفقت فيها أداة التقييم، إضافة إلى عشر حالات نجاح تُختار عشوائياً. حالات النجاح العشوائية هي النصف المهم، لأن أداة تقييم بدأت بهدوء في تمرير إجابات سيئة ستبدو مثالية في أي لوحة معلومات مبنية على أحكامها الخاصة.
خمسة عشر حالة، بمعدل ثلاث دقائق لكل حالة، تعني 45 دقيقة أسبوعياً. وستنتج عن ذلك تصحيحات لمعيار التقييم في المواضع التي تختلف فيها أحكامك عن أحكام الأداة، إضافة إلى حالات جديدة لأنواع إخفاق لم يتوقعها أحد. اكتب الحكم البشري في الجدول نفسه مع ضبط graded_by على human، بحيث يصبح اتفاق أداة التقييم مع الإنسان استعلاماً بدلاً من أن يبقى في الذاكرة.
ما الذي يتعطل في أداة التقييم نفسها
anthropic.RateLimitError في أول تشغيل كامل. يؤدي توزيع 60 حالة في الوقت نفسه إلى تجاوز حد الطلبات أو الرموز المسموح به في فئتك. حدّد التزامن بأربعة عمال، وانقل التشغيل الليلي إلى Batch API.
json.JSONDecodeError: Expecting value: line 1 column 1 (char 0) من أداة التحكيم. أجاب النموذج بنص نثري، أو وضع JSON داخل كتلة تعليمات برمجية. أعد المحاولة مرة واحدة، ثم سجّل الحالة كخطأ. لا تسمح أبداً باحتساب فشل التحليل كحالة نجاح، لأن المجموعة التي تحوّل الأخطاء إلى حالات نجاح تقترب من 100% بينما يزداد أداء الوكيل سوءاً.
الحالات غير المستقرة. ينجح الإدخال نفسه في تشغيل ويفشل في التشغيل التالي، لأن الوكيل يأخذ عينات من مخرجاته. شغّل الحالة غير المستقرة 3 مرات، وسجّل النسبة بدلاً من حذف الحالة. الحالة التي تنجح في تشغيلين من أصل 3 تمثل خللاً حقيقياً في المتانة، وسيكتشفها أحد العملاء.
تقادم المجموعة المرجعية. يعدّل أحدهم الإجابة المتوقعة لجعل المجموعة خضراء. راجع الفروقات في evals/cases.jsonl بعناية مماثلة لمراجعة الفروقات في الوكيل، لأن هذا الملف هو التعريف المكتوب لما يُعد صحيحاً.
مجموعة لا تفشل أبداً. يعني ثبات معدل النجاح عند 100% لمدة شهر أن المجموعة توقفت عن تتبع المنتج. استخرج 10 آثار حديثة، وابحث عن الحالات التي عالجها الوكيل بشكل سيئ، ثم أضفها.
FAQ
كم عدد الحالات التي يحتاج إليها نطاق تقييم وكيل الذكاء الاصطناعي؟
ابدأ بـ40 إلى 80 حالة، ثم وسّع المجموعة انطلاقاً من حالات الفشل الفعلية. عندما يقل العدد عن 20 حالة تقريباً، تغيّر نتيجة متذبذبة واحدة معدل النجاح بمقدار 5 نقاط، ولذلك يتوقف الرقم عن تقديم معلومات مفيدة. بعد بضع مئات من الحالات، تصبح كل عملية تشغيل مكلفة من حيث المال والوقت، بينما تضيف الحالة الإضافية تغطية محدودة. المقياس المهم ليس العدد، بل نسبة أنواع فشل الإنتاج المعروفة لديك التي تظهر في المجموعة مرة واحدة على الأقل.
هل يمكنني الوثوق بحَكَم LLM لتقييم وكيلي؟
فقط بعد قياس أدائه مقابل تسمياتك الخاصة. احتفظ بـ30 حالة قيّمتها يدوياً، وقارن أداء الحَكَم بها كلما غيّرت نموذج الحَكَم أو مطالبته. يظهر لدى الحكّام تحيز للطول، إذ تجتاز الإجابات المطوّلة التقييم بوتيرة أعلى، كما يظهر لديهم تفضيل ذاتي، إذ تُقيَّم مخرجات النماذج من عائلتهم النموذجية بلطف أكبر. يمكن اختبار الأمرين: أضف حشواً إلى إجابة فاشلة وأعد تقييمها، أو قيّم الإجابات نفسها باستخدام حَكَم من عائلة أخرى. إذا خالف الحَكَم تسمياتك في أكثر من حالة واحدة من كل 10 حالات، فإن معايير التقييم غامضة أكثر من اللازم لاستخدامها.
أي نموذج ينبغي أن يقيّم الاختبارات؟
ابدأ بالتقييم الأرخص ثم صعّد عند الحاجة. لا تكلف التأكيدات الحتمية شيئاً، لذا تُشغَّل أولاً على كل حالة. يتولى نموذج صغير الحالات التي يكون اجتيازها واضحاً. تُحال حالات الفشل ونتائج التقييم منخفضة الثقة فقط إلى نموذج متقدم. وفق الأسعار المعلنة في أغسطس 2026، يكلف تقييم 1,000 حالة نحو 1.80 دولار أمريكي باستخدام Claude Haiku 4.5، ونحو 9.00 باستخدام Claude Opus 5. وبما أن عمليات التقييم غير متزامنة، فإن Batch API يخفض أيّاً من التكلفتين إلى النصف.
هل تحل الاختبارات محل مراقبة الإنتاج؟
لا، لأنها تجيب عن أسئلة مختلفة. تخبرك مجموعة الاختبارات بما إذا كان التغيير الذي توشك على إطلاقه يجعل مجموعة ثابتة من الحالات أفضل أو أسوأ. أما التتبع والمراقبة فيخبرانك بما يواجهه المستخدمون الفعليون الآن، بما في ذلك المدخلات التي لا تغطيها أي حالة. ويغذي كل منهما الآخر: توفّر آثار التتبع الحالات الجديدة، وتحدد مجموعة الاختبارات ما إذا كان الإصلاح قد نجح فعلاً.