تخطي إلى المحتوى
T.E.N.E.G.T.A
اللغة
المدونة والأخبار

2024-08-15

من التجربة إلى الإنتاج: كيف خفّضنا زمن استجابة نموذج الذكاء الاصطناعي بنسبة 60٪

دقة النموذج في notebook هي أقل ما يهم. المهم كم يستغرق لاتخاذ قرار بينما مستخدم حقيقي ينتظر.

من التجربة إلى الإنتاج: كيف خفّضنا زمن استجابة نموذج الذكاء الاصطناعي بنسبة 60٪

قال الـ notebook: دقة 94٪. أبهر العرض الغرفة. ثم سأل الإنتاج سؤالاً مختلفاً: هل تستطيع الإجابة تحت 200 مللي ثانية بينما المنسق ينظر للشاشة؟

لنظام ذكاء اصطناعي تشغيلي — توجيه، تسجيل مخاطر، كشف شذوذ — latency ليس رفاهية أداء. إنه SLA قرار. أخطئه، فيتجاوز البشر النموذج. تجاوزاً طويلاً يقتل المشروع بغض النظر عن F1.

أخذنا مسار استدلال PyTorch من p95 420ms → 168ms (−60٪) دون رمي عتاد أولاً. هذا التسلسل الذي حرّك الإبرة فعلاً.


خط الأساس: الإنتاج قبل التحسين

مكدس الـ pilot مألوف:

عميل → API (FastAPI) → جلب ميزات (Postgres + joins)
     → نموذج PyTorch (GPU) → JSON

تحت حمل حقيقي:

  • Cold starts على عمال GPU scaled-to-zero
  • هندسة ميزات متزامنة تعطل خيط الاستدلال
  • PyTorch دقة كاملة لكل طلب — حتى «السهلة»
  • لا cache — نفس المتجهات تُعاد كل 30 ثانية لنفس الأصل

p95 عند 200 RPS: 420ms. بدأت العمليات بجدول بيانات بجانب النموذج.


خمس روافع (بالترتيب الذي طبّقناه)

1. تخزين ميزات مؤقت بـ TTL متماشٍ مع العمل

ليست كل الميزات تحتاج حداثة لحظية. GPS: TTL 30ث. مخزون: 5 دقائق. طقس: 15 دقيقة.

def get_features(entity_id: str, tenant_id: str) -> FeatureVector:
    key = f"feat:{tenant_id}:{entity_id}"
    cached = redis.get(key)
    if cached:
        return FeatureVector.from_bytes(cached)
    vec = compute_features(entity_id, tenant_id)
    redis.setex(key, ttl_seconds_for_entity(entity_id), vec.to_bytes())
    return vec

الأثر: ~35٪ من وسيط latency — قبل لمس النموذج.

2. خط أنابيب معالجة مسبقة غير متزامن

أخرجنا عمل I/O (DB، APIs) من المسار الساخن للاستدلال. للواجهات التفاعلية: asyncio.gather — لكن لا تُوقف GPU على round-trip Postgres.

3. تصدير ONNX + تكميم

PyTorch ممتاز للتدريب. للاستدلال المستقر: ONNX Runtime مع تكميم ديناميكي:

torch.onnx.export(model, dummy, "model.onnx", opset_version=17,
                  input_names=["features"], output_names=["score"])
quantize_dynamic("model.onnx", "model.int8.onnx", weight_type=QuantType.QUInt8)
session = ort.InferenceSession("model.int8.onnx", providers=["CPUExecutionProvider"])

أبقينا مسار GPU صغيراً لـ 5٪ من الطلبات المعقّدة — أغلب الحركة INT8 CPU بتكلفة أقل 3×.

4. تجميع استدلال (micro-batches)

نافذة 10ms تجمع طلبات متزامنة حتى 32 — مقبولة عندما الأساس 420ms.

5. توسع أفقي مع مجمعات دافئة

scaled-to-zero وفّر في pilot. في الإنتاج اشترى spikes. حد أدنى نسختين دافئتين لكل منطقة، autoscale على عمق الطابور + p95.


المراقبة: تحسين قابل للتكرار

| المقياس | لماذا | |---------|-------| | inference_latency_ms | SLO للمستخدم | | feature_cache_hit_rate | يتحقق من TTL | | batch_size | استغلال GPU | | model_path | تكلفة | | prediction_drift | الجودة — السرعة لا تتبادل الدقة |

تنبيهات عند تراجع p95 > 15٪ أسبوعياً أو hit rate < 70٪.


قبل / بعد

| المرحلة | p95 | ملاحظات | |---------|-----|---------| | Pilot | 420ms | مقبول للعرض | | + cache + async | 280ms | أكبر فوز | | + ONNX INT8 | 195ms | تكلفة ↓ | | + batching + warm pool | 168ms | موسم الذروة |

انخفاض الدقة على المقياس الرئيسي: < 0.4٪. توقف الفريق عن الجدول الموازي.


لماذا التحسين المبكر يقتل المشاريع

لم نبدأ بالتكميم. بدأنا بـ الملف الشخصي — 62٪ من وقت الطلب إعادة حساب ميزات، لا ضرب مصفوفات.

الفرق الفاشلة تشتري GPU قبل القياس، أو تحسّن النموذج بينما الميزات تعمل JOINs متزامنة على سبعة جداول.

يرتبط هذا بأنماط الفشل في لماذا تتعثر مشاريع الذكاء الاصطناعي المؤسسية.


قراءة إضافية

البرنامج نفسه — طبقة بيانات موحّدة ومخرجات جاهزة للقرار — في دراسة حالة الذكاء الاصطناعي التشغيلي.

إذا كان latency العائق بين pilot والإنتاج، أخبرنا عن مسار الاستدلال — نُلفّي قبل أن نوصي بعتاد.