ميزانيات المهلة والتدهور السلس
حدّدوا ميزانيات مهلة صارمة في كل طبقة من مساركم، ونفذوا تدهورًا سلسًا يقدّم استجابات مخزنة مؤقتًا أو مبسطة عندما يتجاوز LLM ميزانيته.
ميزانيات المهلة والتدهور السلس درس مجاني في AI Engineering Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في AI Engineering Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة AI Engineering Academy 4 دروس في المجموع.
ما موازنة المهلة الزمنية؟
موازنة المهلة الزمنية هي الحد الأقصى للوقت الإجمالي المخصّص لاكتمال الطلب عبر جميع مراحل مسار المعالجة. بدلًا من ضبط مهلة زمنية عشوائية لكل استدعاء API على حدة، تحدد الموازنة الشاملة للعملية التي يراها المستخدم، ثم توزّعها على مراحل الاسترجاع وإنشاء LLM والمعالجة اللاحقة. يضمن ذلك أن تستجيب دائمًا خلال وقت مقبول، حتى إذا كانت بعض المراحل بطيئة.
توزيع الموازنة على مراحل مسار المعالجة
يتكوّن مسار محادثة RAG النموذجي من ثلاث مراحل: الاسترجاع، وإنشاء LLM، وتنسيق الاستجابة. خصّص شريحة زمنية لكل مرحلة بناءً على مدتها المعتادة ومقدار الوقت الإضافي الذي يمكن للمستخدمين تحمّله. ويُسمّى الوقت المتبقي مخزن التدهور؛ فإذا استهلكت أي مرحلة مخصصها بالكامل، تبدأ بتقليص بعض الخطوات في المراحل اللاحقة للبقاء ضمن الموازنة الإجمالية.
# Total user-facing SLA: 8000ms
BUDGET_TOTAL_MS = 8000
BUDGET_STAGES = {
'retrieval': 1500, # vector search + rerank
'llm_call': 5500, # token streaming
'formatting': 500, # post-processing
'slack': 500, # buffer for overhead
}
assert sum(BUDGET_STAGES.values()) == BUDGET_TOTAL_MSتتبّع استهلاك الموازنة
استخدم BudgetTracker لتسجيل وقت البدء والتحقق من الموازنة المتبقية عند الانتقال بين المراحل. قبل بدء أي مرحلة، تحقّق من بقاء موازنة كافية. يتيح ذلك للمراحل اللاحقة التكيّف؛ فخطوة استرجاع تستغرق 1200ms من موازنة قدرها 1500ms تترك هامشًا قدره 300ms فقط، ما ينبغي أن يؤدي إلى تشغيل مطالبة LLM أبسط أو تخطّي خطوة إعادة الترتيب.
import time
class BudgetTracker:
def __init__(self, total_ms: float):
self.start = time.perf_counter()
self.total_ms = total_ms
def elapsed_ms(self) -> float:
return (time.perf_counter() - self.start) * 1000
def remaining_ms(self) -> float:
return self.total_ms - self.elapsed_ms()
def check(self, stage: str, required_ms: float = 0) -> bool:
remaining = self.remaining_ms()
if remaining < required_ms:
print(f'Budget exhausted before {stage}: {remaining:.0f}ms left, need {required_ms}ms')
return False
return Trueتعريف التدهور السلس
يعني التدهور السلس تقديم استجابة أقل جودة لكنها تظل مفيدة عندما يتعذر إكمال مسار المعالجة الكامل ضمن الموازنة، بدلًا من إرجاع خطأ. ومن أمثلته: إرجاع استجابة مخزّنة مؤقتًا، أو تخطّي إعادة الترتيب، أو اقتطاع نافذة السياق، أو استخدام نموذج أسرع لكنه أقل دقة، أو إرجاع رسالة احتياطية مكتوبة مسبقًا. الهدف دائمًا هو تقديم شيء للمستخدم بدلًا من لا شيء.
# Degradation ladder for a RAG chat endpoint:
# Level 0 (normal): retrieve 10 chunks + rerank + GPT-4o -- 8000ms budget
# Level 1 (fast): retrieve 5 chunks + skip rerank + GPT-4o -- 5000ms budget
# Level 2 (minimal): retrieve 3 chunks + GPT-4o-mini -- 3000ms budget
# Level 3 (cached): return semantic cache hit -- 100ms
# Level 4 (sorry): return static 'Try again in a moment' -- 1msتنفيذ سُلّم التدهور
عند كل نقطة لاتخاذ قرار في مسار المعالجة، تحقّق من الموازنة المتبقية واختر مستوى الجودة المناسب. يختار الكود أدناه عمق الاسترجاع والنموذج بناءً على الموازنة المتبقية. وهذا يعني أن المستخدمين يحصلون على أفضل جودة في ظروف التحميل العادية، بينما يظلون يحصلون على استجابة مفيدة خلال فترات ارتفاع زمن الاستجابة بدلًا من ظهور خطأ انتهاء المهلة.
async def smart_rag_query(question: str, budget_ms: float = 8000) -> str:
tracker = BudgetTracker(budget_ms)
# Retrieval stage
if tracker.remaining_ms() > 5000:
chunks = await retrieve_and_rerank(question, top_k=10)
elif tracker.remaining_ms() > 3000:
chunks = await retrieve(question, top_k=5) # skip rerank
elif tracker.remaining_ms() > 1500:
chunks = await retrieve(question, top_k=3) # minimal retrieval
else:
return await get_cached_or_static(question)
# LLM stage
if tracker.remaining_ms() > 4000:
model = 'gpt-4o'
else:
model = 'gpt-4o-mini' # faster fallback
timeout = tracker.remaining_ms() / 1000 - 0.5
return await generate_answer(question, chunks, model, timeout)ضبط المهلات الزمنية على مستوى استدعاء API
اضبط دائمًا مهلات زمنية صريحة لكل استدعاء API خارجي. يقبل OpenAI Python SDK معامل timeout بالثواني. اضبطه على قيمة أقل قليلًا من الموازنة المتبقية، حتى يتوفر لديك وقت لمعالجة الاستثناء وربما تنفيذ التدهور السلس قبل الموعد النهائي للاستجابة الإجمالية. لا تعتمد مطلقًا على المهلة الزمنية الافتراضية لـ SDK، فقد تكون طويلة جدًا بالنسبة إلى الطلبات الموجّهة للمستخدمين.
async def generate_answer(question: str, chunks: list, model: str, timeout_sec: float) -> str:
context = '\n\n'.join(chunks)
prompt = f'Answer using this context:\n{context}\n\nQuestion: {question}'
try:
resp = await client.chat.completions.create(
model=model,
messages=[{'role': 'user', 'content': prompt}],
max_tokens=500,
timeout=max(timeout_sec, 1.0) # minimum 1 second
)
return resp.choices[0].message.content
except openai.APITimeoutError:
return 'I was unable to generate a response in time. Please try again.'إرجاع استجابات بث جزئية
باستخدام البث، يمكنك إرجاع استجابات جزئية أُنشئت قبل انتهاء الموازنة. عند حدوث انتهاء للمهلة أثناء البث، أوقف قراءة الرموز الجديدة، وأضف علامة حذف أو مطالبة متابعة موجزة، ثم أغلق البث. سيرى المستخدم استجابة تتوقف بصورة سليمة بدلًا من ظهور خطأ فارغ. ولا يكون ذلك ممكنًا إلا مع البث؛ أما الاستدعاءات غير المتدفقة فإما أن تكتمل بالكامل أو تفشل بالكامل.
async def stream_with_budget(question: str, budget_ms: float):
tracker = BudgetTracker(budget_ms)
collected = []
stream = await client.chat.completions.create(
model='gpt-4o-mini',
messages=[{'role': 'user', 'content': question}],
stream=True
)
async for chunk in stream:
if tracker.remaining_ms() < 200: # 200ms safety margin
collected.append(' [response truncated]')
break
delta = chunk.choices[0].delta.content or ''
collected.append(delta)
yield delta
# Ensure stream is closed even if budget exceeded
await stream.close()ذاكرة التخزين المؤقت الدلالية كطبقة للتدهور
تُعد ذاكرة التخزين المؤقت الدلالية طبقة ممتازة للتدهور لأنها تتميز بزمن استجابة شبه معدوم. قبل استدعاء LLM، استعلم من الذاكرة الدلالية المؤقتة عن أسئلة سابقة مشابهة. إذا عثرت على نتيجة مطابقة بدرجة تشابه مرتفعة (أعلى من 0.92 للتشابه الكوني)، فأرجع الإجابة المخزّنة مؤقتًا فورًا. فهذا يسرّع الاستجابات ويوفّر أيضًا بديلًا فوريًا عندما يكون LLM بطيئًا أو غير متاح.
async def query_with_cache_fallback(question: str, budget_ms: float = 8000) -> str:
# Try semantic cache first (fast)
cached = await semantic_cache.lookup(question, threshold=0.92)
if cached:
return cached.response
tracker = BudgetTracker(budget_ms)
# Try full pipeline
if tracker.remaining_ms() > 3000:
try:
return await smart_rag_query(question, tracker.remaining_ms())
except Exception:
pass # fall through to static response
# Last resort
return 'I am experiencing high load right now. Please try again in a moment.'تسجيل أحداث التدهور
في كل مرة يتدهور فيها مسار المعالجة إلى مستوى جودة أقل، سجّل ذلك كحدث منظم. ضمّن مستوى التدهور الذي تم الوصول إليه، والموازنة المتبقية في كل مرحلة، وزمن الاستجابة النهائي. يوضح تحليل هذه السجلات عدد مرات تشغيل كل مستوى من مستويات التدهور، ما يساعدك على ضبط الموازنات، وتحديد المراحل التي تتجاوز موازنتها باستمرار، وتبرير الاستثمارات في البنية التحتية.
import structlog
log = structlog.get_logger()
def log_degradation(level: int, stage: str, remaining_ms: float, total_ms: float):
log.warning(
'pipeline_degradation',
degradation_level=level,
triggered_at_stage=stage,
remaining_budget_ms=round(remaining_ms),
total_budget_ms=total_ms,
budget_consumed_pct=round((total_ms - remaining_ms) / total_ms * 100)
)ضبط توقعات المستخدم باستخدام مؤشرات الواجهة
عند تقديم استجابة متدهورة، أشر إلى أن الجودة قد تكون أقل من المعتاد. في واجهة المحادثة، اعرض مؤشرًا غير بارز مثل: "وضع الاستجابة السريعة — قد تكون بعض التفاصيل محدودة." وفي واجهة API للاستخراج، ضمّن الحقل degraded: true في استجابة JSON حتى يتمكن المستهلكون اللاحقون من معالجة النتائج المتدهورة بطريقة مختلفة. تحافظ الشفافية على ثقة المستخدم حتى أثناء حالات انقطاع الخدمة.
from pydantic import BaseModel
from typing import Optional
class ChatResponse(BaseModel):
content: str
degraded: bool = False
degradation_level: Optional[int] = None # 0=full, 1=fast, 2=minimal, 3=cached
latency_ms: int
# API response when degraded:
# {
# 'content': 'Here is a brief answer...',
# 'degraded': true,
# 'degradation_level': 2,
# 'latency_ms': 2800
# }ضبط توزيعات الموازنة بمرور الوقت
توزيعات الموازنة الأولية تقديرات فحسب. بعد التشغيل في بيئة الإنتاج لمدة أسبوع، حلّل توزيع الوقت المستغرق في كل مرحلة باستخدام بيانات التتبّع. فإذا استغرق الاسترجاع 800ms باستمرار بدلًا من 1500ms المخصصة له، فأعد توزيع هذا الهامش على مرحلة LLM، بما يتيح عددًا أكبر من رموز الإخراج أو نافذة سياق أكبر. ويُعد ضبط الموازنة نشاطًا تشغيليًا مستمرًا، وليس إعدادًا لمرة واحدة.
# Budget tuning based on production p95 data:
ACTUAL_P95 = {
'retrieval': 780, # vs budget 1500ms -> 720ms headroom
'llm_call': 4200, # vs budget 5500ms -> 1300ms headroom
'formatting': 120, # vs budget 500ms -> 380ms headroom
}
TOTAL_HEADROOM = sum(
BUDGET_STAGES[k] - ACTUAL_P95[k] for k in ACTUAL_P95
)
print(f'Total headroom: {TOTAL_HEADROOM}ms')
# Reallocate headroom to allow longer LLM responsesتحقّق سريع
اختبر مدى فهمك لموازنات المهلة الزمنية والتدهور السلس.
مراجعة الدرس
تعلّمت في هذا الدرس أن موازنات المهلة الزمنية توزّع الوقت على مراحل مسار المعالجة لكي تستجيب دائمًا ضمن موعد نهائي مقبول، وأن سلالم التدهور تقدم استجابات تتناقص جودتها تدريجيًا بدلًا من الأخطاء عند نفاد الوقت، وأن تسجيل أحداث التدهور يساعدك على تحديد الاختناقات المزمنة وإصلاحها. ننتقل بعد ذلك إلى استكشاف نمط LLM-as-judge لتقييم الجودة آليًا.
الأسئلة الشائعة
هل درس «ميزانيات المهلة والتدهور السلس» مجاني؟
نعم — نص درس «ميزانيات المهلة والتدهور السلس» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة AI Engineering Academy، انتقل إلى CoddyKit PRO. تتضمن دورة AI Engineering Academy 4 دروس في المجموع.
ماذا ستتعلم في «ميزانيات المهلة والتدهور السلس»؟
حدّدوا ميزانيات مهلة صارمة في كل طبقة من مساركم، ونفذوا تدهورًا سلسًا يقدّم استجابات مخزنة مؤقتًا أو مبسطة عندما يتجاوز LLM ميزانيته. تتمرن على AI Engineering Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ AI Engineering Academy؟
لا تُشترط خبرة سابقة. AI Engineering Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.
كم من الوقت يستغرق درس «ميزانيات المهلة والتدهور السلس»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس AI Engineering Academy هذا؟
نعم. كل درس في AI Engineering Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- قياس زمن استجابة LLM: TTFT وTPOT
- موازنة الحمل واستراتيجيات المفاتيح المتعددة
- المزودون الاحتياطيون وقواطع الدائرة
- ميزانيات المهلة والتدهور السلس