الدرس 6 من 23

هندسة تطبيقات LLM

إدارة المطالبات

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

المطالبات هي "الكود" لأنظمة الذكاء الاصطناعي. إدارتها بشكل صحيح مهم بقدر إدارة الكود المصدري. يغطي هذا الدرس إدارة المطالبات بمستوى الإنتاج.

لماذا إدارة المطالبات مهمة

المشكلة التأثير
المطالبات مشفرة في الكود صعب التحديث بدون نشر
لا يوجد سجل إصدارات لا يمكن التراجع عن التغييرات السيئة
لا يوجد اختبار A/B لا يمكن تحسين الأداء
تنسيقات غير متسقة سلوكيات مختلفة عبر الميزات

نظام قوالب المطالبات

from jinja2 import Template

class PromptTemplate:
    def __init__(self, template_str: str, version: str):
        self.template = Template(template_str)
        self.version = version
        self.variables = self._extract_variables()

    def render(self, **kwargs) -> str:
        # التحقق من توفر جميع المتغيرات المطلوبة
        missing = set(self.variables) - set(kwargs.keys())
        if missing:
            raise ValueError(f"متغيرات مفقودة: {missing}")
        return self.template.render(**kwargs)

    def _extract_variables(self) -> set:
        # استخراج أنماط {{ variable }}
        import re
        return set(re.findall(r'\{\{\s*(\w+)\s*\}\}', self.template.source))

# الاستخدام
qa_prompt = PromptTemplate(
    template_str="""
أنت مساعد مفيد. أجب على السؤال بناءً على السياق.

السياق:
{{ context }}

السؤال: {{ question }}

الإجابة:""",
    version="1.2.0"
)

rendered = qa_prompt.render(
    context="بايثون أنشأها جويدو فان روسوم.",
    question="من أنشأ بايثون؟"
)

سجل المطالبات

تخزين مركزي لجميع المطالبات:

class PromptRegistry:
    def __init__(self, storage_backend):
        self.storage = storage_backend
        self.cache = {}

    async def get(self, name: str, version: str = "latest") -> PromptTemplate:
        cache_key = f"{name}:{version}"
        if cache_key in self.cache:
            return self.cache[cache_key]

        prompt_data = await self.storage.fetch(name, version)
        template = PromptTemplate(
            template_str=prompt_data["template"],
            version=prompt_data["version"]
        )
        self.cache[cache_key] = template
        return template

    async def save(self, name: str, template: str, metadata: dict):
        version = self._generate_version()
        await self.storage.save(name, {
            "template": template,
            "version": version,
            "metadata": metadata,
            "created_at": datetime.utcnow()
        })

# التهيئة مع قاعدة البيانات
registry = PromptRegistry(PostgresStorage())

التحكم بالإصدار للمطالبات

# prompts/qa_assistant.yaml
name: qa_assistant
versions:
  - version: "1.0.0"
    date: "2024-01-15"
    template: |
      أجب على السؤال: {{ question }}
    notes: "الإصدار الأولي"

  - version: "1.1.0"
    date: "2024-02-01"
    template: |
      أنت مساعد مفيد.
      أجب على السؤال: {{ question }}
    notes: "إضافة سياق النظام"

  - version: "1.2.0"
    date: "2024-03-10"
    template: |
      أنت مساعد مفيد. أجب بناءً على السياق المقدم.
      السياق: {{ context }}
      السؤال: {{ question }}
    notes: "إضافة دعم سياق RAG"

active_version: "1.2.0"
rollback_version: "1.1.0"

اختبار A/B للمطالبات

import random

class PromptExperiment:
    def __init__(self, name: str, variants: dict):
        self.name = name
        self.variants = variants  # {"control": 50, "variant_a": 50}

    def select_variant(self, user_id: str) -> str:
        # اختيار حتمي بناءً على user_id
        hash_val = hash(f"{self.name}:{user_id}") % 100

        cumulative = 0
        for variant, percentage in self.variants.items():
            cumulative += percentage
            if hash_val < cumulative:
                return variant
        return list(self.variants.keys())[0]

# الاستخدام
experiment = PromptExperiment(
    name="system_prompt_test",
    variants={
        "control": 50,      # المطالبة الحالية
        "concise": 25,      # مطالبة أقصر
        "detailed": 25      # مطالبة أكثر تفصيلاً
    }
)

variant = experiment.select_variant(user_id="user_123")
prompt = registry.get(f"qa_assistant_{variant}")

تركيب المطالبات

بناء مطالبات معقدة من مكونات قابلة لإعادة الاستخدام:

class PromptComposer:
    def __init__(self, registry: PromptRegistry):
        self.registry = registry

    async def compose(self, components: list, variables: dict) -> str:
        """تركيب مطالبة من مكونات متعددة."""
        parts = []
        for component in components:
            template = await self.registry.get(component)
            # تضمين المتغيرات ذات الصلة بهذا المكون فقط
            relevant_vars = {
                k: v for k, v in variables.items()
                if k in template.variables
            }
            parts.append(template.render(**relevant_vars))
        return "\n\n".join(parts)

# الاستخدام
composer = PromptComposer(registry)
full_prompt = await composer.compose(
    components=["system_context", "user_history", "current_query"],
    variables={
        "role": "assistant",
        "history": previous_messages,
        "query": user_input
    }
)

أفضل الممارسات

الممارسة الفائدة
تخزين المطالبات خارجياً التحديث بدون نشر الكود
إصدار جميع التغييرات سجل تدقيق وقدرة التراجع
الاختبار قبل النشر اكتشاف التراجعات مبكراً
مراقبة مقاييس الأداء تتبع الجودة بمرور الوقت
توثيق نية المطالبة مساعدة الفريق على فهم قرارات التصميم

بعد ذلك، سنستكشف استراتيجيات التخزين المؤقت لتقليل التكاليف وزمن الاستجابة. :::

اختبار

الوحدة 2: هندسة تطبيقات LLM

خذ الاختبار