نشر الإنتاج والمراقبة

المراقبة والمقاييس

3 دقيقة للقراءة

تتطلب حواجز الإنتاج مراقبة شاملة لتتبع السلامة والأداء والتأثير التجاري. يغطي هذا الدرس المقاييس الأساسية واستراتيجيات المراقبة.

مقاييس الحواجز الرئيسية

مقاييس السلامة

المقياس الوصف الهدف
معدل الحظر % من الطلبات المحظورة < 5% للإنتاج
معدل الإيجابيات الخاطئة محتوى آمن محظور بشكل خاطئ < 1%
معدل السلبيات الخاطئة محتوى غير آمن تم تمريره < 0.1%
توزيع الفئات تفصيل الانتهاكات حسب النوع يختلف
معدل التصعيد % يتطلب مراجعة بشرية < 2%

مقاييس الأداء

المقياس الوصف الهدف
تأخير P50 وقت الحاجز المتوسط < 50 مللي ثانية
تأخير P99 المئين 99 < 200 مللي ثانية
الإنتاجية الطلبات في الثانية يختلف
معدل الخطأ فشل الحواجز < 0.1%
معدل المهلة مهلات الحواجز < 0.01%

تنفيذ مقاييس Prometheus

from prometheus_client import Counter, Histogram, Gauge
import time
from functools import wraps

# تعريف المقاييس
GUARDRAIL_REQUESTS = Counter(
    'guardrail_requests_total',
    'إجمالي طلبات الحواجز',
    ['rail_type', 'result']
)

GUARDRAIL_LATENCY = Histogram(
    'guardrail_latency_seconds',
    'تأخير معالجة الحواجز',
    ['rail_type'],
    buckets=[0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0]
)

GUARDRAIL_BLOCKS = Counter(
    'guardrail_blocks_total',
    'إجمالي الطلبات المحظورة',
    ['rail_type', 'category']
)

ACTIVE_GUARDRAIL_CHECKS = Gauge(
    'guardrail_active_checks',
    'فحوصات الحواجز قيد التشغيل حالياً',
    ['rail_type']
)

class MetricsMiddleware:
    """برمجية وسيطة لتتبع مقاييس الحواجز."""

    def __init__(self, rail_type: str):
        self.rail_type = rail_type

    def __call__(self, func):
        @wraps(func)
        async def wrapper(*args, **kwargs):
            ACTIVE_GUARDRAIL_CHECKS.labels(rail_type=self.rail_type).inc()
            start_time = time.time()

            try:
                result = await func(*args, **kwargs)

                # تتبع النتيجة
                outcome = "blocked" if result.blocked else "passed"
                GUARDRAIL_REQUESTS.labels(
                    rail_type=self.rail_type,
                    result=outcome
                ).inc()

                if result.blocked:
                    for category in result.categories:
                        GUARDRAIL_BLOCKS.labels(
                            rail_type=self.rail_type,
                            category=category
                        ).inc()

                return result

            except Exception as e:
                GUARDRAIL_REQUESTS.labels(
                    rail_type=self.rail_type,
                    result="error"
                ).inc()
                raise

            finally:
                duration = time.time() - start_time
                GUARDRAIL_LATENCY.labels(
                    rail_type=self.rail_type
                ).observe(duration)
                ACTIVE_GUARDRAIL_CHECKS.labels(rail_type=self.rail_type).dec()

        return wrapper

# الاستخدام
@MetricsMiddleware(rail_type="toxicity")
async def check_toxicity(text: str):
    # منطق فحص السمية
    pass

التسجيل المنظم

import structlog
from datetime import datetime
from typing import Dict, Any
import json

# تكوين التسجيل المنظم
structlog.configure(
    processors=[
        structlog.stdlib.filter_by_level,
        structlog.stdlib.add_logger_name,
        structlog.stdlib.add_log_level,
        structlog.processors.TimeStamper(fmt="iso"),
        structlog.processors.JSONRenderer()
    ],
    wrapper_class=structlog.stdlib.BoundLogger,
    context_class=dict,
    logger_factory=structlog.stdlib.LoggerFactory(),
)

logger = structlog.get_logger()

class GuardrailLogger:
    """التسجيل المنظم لأحداث الحواجز."""

    def log_check(
        self,
        request_id: str,
        rail_type: str,
        input_text: str,
        result: Dict[str, Any],
        latency_ms: float
    ):
        """تسجيل نتيجة فحص الحاجز."""
        logger.info(
            "guardrail_check",
            request_id=request_id,
            rail_type=rail_type,
            input_length=len(input_text),
            result=result.get("decision"),
            categories=result.get("categories", []),
            confidence=result.get("confidence"),
            latency_ms=latency_ms,
            timestamp=datetime.utcnow().isoformat()
        )

    def log_block(
        self,
        request_id: str,
        rail_type: str,
        reason: str,
        categories: list,
        input_preview: str = None
    ):
        """تسجيل طلب محظور."""
        logger.warning(
            "guardrail_block",
            request_id=request_id,
            rail_type=rail_type,
            reason=reason,
            categories=categories,
            input_preview=input_preview[:100] if input_preview else None
        )

    def log_error(
        self,
        request_id: str,
        rail_type: str,
        error: Exception,
        fallback_action: str
    ):
        """تسجيل خطأ الحاجز."""
        logger.error(
            "guardrail_error",
            request_id=request_id,
            rail_type=rail_type,
            error_type=type(error).__name__,
            error_message=str(error),
            fallback_action=fallback_action
        )

لوحة القيادة الفورية

from dataclasses import dataclass
from datetime import datetime, timedelta
from collections import defaultdict
import asyncio

@dataclass
class MetricWindow:
    """نافذة متحركة لتجميع المقاييس."""
    window_seconds: int = 60
    buckets: dict = None

    def __post_init__(self):
        self.buckets = defaultdict(list)

    def record(self, key: str, value: float):
        now = datetime.now()
        self.buckets[key].append((now, value))
        self._cleanup(key)

    def _cleanup(self, key: str):
        cutoff = datetime.now() - timedelta(seconds=self.window_seconds)
        self.buckets[key] = [
            (ts, v) for ts, v in self.buckets[key]
            if ts > cutoff
        ]

    def get_stats(self, key: str) -> dict:
        values = [v for _, v in self.buckets[key]]
        if not values:
            return {"count": 0, "avg": 0, "p99": 0}

        values.sort()
        return {
            "count": len(values),
            "avg": sum(values) / len(values),
            "p50": values[len(values) // 2],
            "p99": values[int(len(values) * 0.99)]
        }

class RealTimeDashboard:
    """لوحة قيادة المقاييس الفورية."""

    def __init__(self):
        self.latency = MetricWindow(window_seconds=60)
        self.block_rates = MetricWindow(window_seconds=300)
        self.error_counts = defaultdict(int)

    def record_check(
        self,
        rail_type: str,
        latency_ms: float,
        blocked: bool
    ):
        self.latency.record(rail_type, latency_ms)
        self.block_rates.record(rail_type, 1 if blocked else 0)

    def record_error(self, rail_type: str):
        self.error_counts[rail_type] += 1

    def get_dashboard_data(self) -> dict:
        """الحصول على مقاييس لوحة القيادة الحالية."""
        data = {}
        for rail_type in self.latency.buckets:
            latency_stats = self.latency.get_stats(rail_type)
            block_stats = self.block_rates.get_stats(rail_type)

            data[rail_type] = {
                "latency_ms": {
                    "avg": latency_stats["avg"],
                    "p50": latency_stats["p50"],
                    "p99": latency_stats["p99"]
                },
                "requests_per_minute": latency_stats["count"],
                "block_rate": block_stats["avg"] * 100,
                "errors": self.error_counts[rail_type]
            }
        return data

قواعد التنبيه

# prometheus_alerts.yml
groups:
  - name: guardrails
    rules:
      - alert: HighGuardrailLatency
        expr: histogram_quantile(0.99, rate(guardrail_latency_seconds_bucket[5m])) > 0.2
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "تأخير P99 للحاجز أعلى من 200 مللي ثانية"

      - alert: HighBlockRate
        expr: rate(guardrail_blocks_total[5m]) / rate(guardrail_requests_total[5m]) > 0.1
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "معدل الحظر أعلى من 10%"

      - alert: GuardrailErrors
        expr: rate(guardrail_requests_total{result="error"}[5m]) > 0.01
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "معدل خطأ الحاجز أعلى من 1%"

      - alert: UnusualViolationSpike
        expr: rate(guardrail_blocks_total{category="hate_speech"}[5m]) > 2 * avg_over_time(rate(guardrail_blocks_total{category="hate_speech"}[5m])[1h:5m])
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "ارتفاع غير عادي في انتهاكات خطاب الكراهية"

نصيحة المراقبة: تتبع كل من مقاييس السلامة والأداء. الحاجز الذي يكون دقيقاً 100% لكنه يضيف 5 ثوان من التأخير غير قابل للاستخدام. وازن بين الشمولية وتجربة المستخدم.

التالي: اختبار A/B لتكوينات الحواجز. :::

اختبار

الوحدة 6: نشر الإنتاج والمراقبة

خذ الاختبار
نشرة أسبوعية مجانية

ابقَ على مسار النيرد

بريد واحد أسبوعياً — دورات، مقالات معمّقة، أدوات، وتجارب ذكاء اصطناعي.

بدون إزعاج. إلغاء الاشتراك في أي وقت.