0Pricing
AI Prompt Engineering · درس

بنية سجل المطالبات

تخزين المطالبات كعناصر مُدارة بالإصدارات مع البيانات الوصفية والوسوم

بنية سجل المطالبات درس مجاني في AI Prompt Engineering على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في AI Prompt Engineering، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة AI Prompt Engineering 4 دروس في المجموع.

لماذا نحتاج إلى سجل للمطالبات؟

من دون سجل مركزي، تكون المطالبات مبعثرة بين التعليمات البرمجية وملفات الإعداد وذاكرة المطوّرين. سجل المطالبات هو مخزن مركزي يتعامل مع كل مطالبة بوصفها أثرًا ذا إصدار وقابلًا للتتبع — تمامًا مثل التعليمات البرمجية.

تشمل الفوائد قابلية إعادة الإنتاج، وقابلية التدقيق، وإمكانية التراجع، والتعاون بين أعضاء الفريق.

الحقول الأساسية لأثر المطالبة

ينبغي أن يتضمن كل أثر مطالبة الحقول التالية:

  • prompt_id — معرّف فريد وثابت (مثل summarize-article)
  • version — سلسلة إصدار دلالي (مثل 2.1.0)
  • template — نص المطالبة الفعلي مع العناصر النائبة {variable}
  • metadata — المؤلف، والوسوم، والنموذج المستهدف، وcreated_at، والوصف

تصميم مخطط قاعدة البيانات

يخزّن المخطط العلائقي لسجل المطالبات المطالبات وسجل إصداراتها في جدولين منفصلين، مما يتيح عمليات بحث وعمليات تدقيق فعّالة.

-- prompts table: one row per unique prompt identity
CREATE TABLE prompts (
  prompt_id   VARCHAR(100) PRIMARY KEY,
  description TEXT,
  created_at  TIMESTAMP DEFAULT NOW()
);

-- prompt_versions table: one row per versioned artifact
CREATE TABLE prompt_versions (
  id          SERIAL PRIMARY KEY,
  prompt_id   VARCHAR(100) REFERENCES prompts(prompt_id),
  version     VARCHAR(20)  NOT NULL,
  template    TEXT         NOT NULL,
  author      VARCHAR(100),
  tags        TEXT[],
  model       VARCHAR(50),
  is_active   BOOLEAN DEFAULT FALSE,
  created_at  TIMESTAMP DEFAULT NOW(),
  UNIQUE(prompt_id, version)
);

تصميم السجل المستند إلى الملفات

بالنسبة إلى الفرق الصغيرة، يستخدم السجل المستند إلى الملفات بنية مجلدات منظّمة. تحصل كل مطالبة على مجلد، ويكون كل إصدار ملف YAML أو JSON داخله.

# Directory structure
prompts/
  summarize-article/
    1.0.0.yaml
    1.1.0.yaml
    latest -> 1.1.0.yaml  # symlink
  classify-sentiment/
    1.0.0.yaml

# Example: summarize-article/1.1.0.yaml
prompt_id: summarize-article
version: '1.1.0'
model: gpt-4o-mini
author: alice@company.com
tags: [summarization, articles, english]
created_at: '2024-06-01T10:00:00Z'
template: |
  Summarize the following article in {num_sentences} sentences.
  Focus on: {focus_area}.

  Article:
  {article_text}

فئة Python PromptRegistry

تغلّف فئة Python بسيطة الوصول إلى قاعدة البيانات وتوفّر أساليب واضحة: register() وget_active() وlist_versions().

import psycopg2
import json
from datetime import datetime

class PromptRegistry:
    def __init__(self, dsn):
        self.conn = psycopg2.connect(dsn)

    def register(self, prompt_id, version, template, author, tags, model):
        with self.conn.cursor() as cur:
            # Ensure prompt identity exists
            cur.execute(
                'INSERT INTO prompts (prompt_id) VALUES (%s) ON CONFLICT DO NOTHING',
                (prompt_id,)
            )
            cur.execute(
                '''INSERT INTO prompt_versions
                   (prompt_id, version, template, author, tags, model)
                   VALUES (%s, %s, %s, %s, %s, %s)''',
                (prompt_id, version, template, author, tags, model)
            )
        self.conn.commit()
        print(f'Registered {prompt_id}@{version}')

    def get_active(self, prompt_id):
        with self.conn.cursor() as cur:
            cur.execute(
                'SELECT template, version FROM prompt_versions '
                'WHERE prompt_id=%s AND is_active=TRUE LIMIT 1',
                (prompt_id,)
            )
            row = cur.fetchone()
        if not row:
            raise ValueError(f'No active version for {prompt_id}')
        return {'template': row[0], 'version': row[1]}

تعمّق في مخطط البيانات الوصفية

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

  • author — تحديد المسؤول ونقطة الاتصال
  • tags — وسوم قابلة للبحث مثل ['production', 'summarization', 'v2']
  • model — النموذج المستهدف (قد لا تكون المطالبة مستقلة عن النموذج)
  • changelog — وصف مقروء للبشر لما تغيّر
  • test_suite — رابط إلى مجموعة بيانات التقييم الخاصة بهذه المطالبة
# Extended metadata example
prompt_metadata = {
    'prompt_id': 'extract-key-dates',
    'version': '2.0.0',
    'author': 'bob@company.com',
    'tags': ['extraction', 'dates', 'contracts', 'production'],
    'model': 'gpt-4o',
    'changelog': 'Added support for relative dates (next quarter, end of year)',
    'test_suite': 's3://company-evals/extract-key-dates/v2-testset.jsonl',
    'created_at': '2024-07-15T09:30:00Z',
    'is_active': True
}

عرض القالب باستخدام المتغيرات

تستخدم قوالب المطالبات صيغة العناصر النائبة. ينشئ السجل المطالبة النهائية باستبدال متغيرات وقت التشغيل في القالب. ويُعد استخدام str.format_map() في Python آمنًا وبسيطًا.

class PromptRegistry:
    # ... (previous methods)

    def render(self, prompt_id, variables: dict) -> str:
        artifact = self.get_active(prompt_id)
        template = artifact['template']
        try:
            rendered = template.format_map(variables)
        except KeyError as e:
            raise ValueError(f'Missing variable {e} for prompt {prompt_id}')
        return rendered

# Usage
registry = PromptRegistry(dsn='postgresql://...')
prompt = registry.render(
    'summarize-article',
    {
        'num_sentences': 3,
        'focus_area': 'financial impact',
        'article_text': 'Apple reported record revenue of $119B...'
    }
)
print(prompt)
# Output: Summarize the following article in 3 sentences.
# Focus on: financial impact. ...

تفعيل إصدار

ينبغي أن يكون إصدار واحد فقط من المطالبة نشطًا في الإنتاج في أي وقت. ويجب أن يكون التفعيل ذريًا: إلغاء تفعيل الإصدار الحالي وتفعيل الإصدار الجديد — كل ذلك ضمن معاملة واحدة لتجنب حدوث فجوات.

def activate_version(self, prompt_id, version):
    with self.conn.cursor() as cur:
        # Deactivate all current versions
        cur.execute(
            'UPDATE prompt_versions SET is_active=FALSE '
            'WHERE prompt_id=%s AND is_active=TRUE',
            (prompt_id,)
        )
        # Activate target version
        cur.execute(
            'UPDATE prompt_versions SET is_active=TRUE '
            'WHERE prompt_id=%s AND version=%s',
            (prompt_id, version)
        )
        if cur.rowcount == 0:
            self.conn.rollback()
            raise ValueError(f'Version {version} not found for {prompt_id}')
    self.conn.commit()
    print(f'Activated {prompt_id}@{version}')

سرد المطالبات والبحث فيها

لا يكون السجل مفيدًا إلا إذا أمكنكم اكتشاف محتوياته. ادعموا البحث المستند إلى الوسوم وسرد جميع إصدارات مطالبة معينة.

def list_versions(self, prompt_id):
    with self.conn.cursor() as cur:
        cur.execute(
            'SELECT version, author, is_active, created_at '
            'FROM prompt_versions WHERE prompt_id=%s '
            'ORDER BY created_at DESC',
            (prompt_id,)
        )
        return cur.fetchall()

def search_by_tag(self, tag):
    with self.conn.cursor() as cur:
        cur.execute(
            'SELECT prompt_id, version, tags FROM prompt_versions '
            'WHERE %s = ANY(tags)',
            (tag,)
        )
        return cur.fetchall()

# Usage
for v in registry.list_versions('summarize-article'):
    print(v)  # ('1.1.0', 'alice', True, datetime(...))

for p in registry.search_by_tag('production'):
    print(p)  # ('summarize-article', '1.1.0', ['production', 'summarization'])

نقاط نهاية واجهة برمجة تطبيقات السجل

اعرضوا السجل على هيئة REST API حتى تشترك جميع الخدمات (الواجهة الخلفية، ومسارات ML، وأدوات التقييم) في مصدر الحقيقة نفسه. نقاط النهاية الأساسية:

  • POST /prompts/{id}/versions — تسجيل إصدار جديد
  • GET /prompts/{id}/active — الحصول على القالب النشط
  • PUT /prompts/{id}/activate/{version} — تفعيل إصدار
  • GET /prompts — سرد جميع المطالبات مع البيانات الوصفية
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI()
registry = PromptRegistry(dsn='postgresql://user:pass@localhost/prompts')

class VersionPayload(BaseModel):
    version: str
    template: str
    author: str
    tags: list
    model: str

@app.post('/prompts/{prompt_id}/versions')
def register_version(prompt_id: str, payload: VersionPayload):
    registry.register(
        prompt_id, payload.version, payload.template,
        payload.author, payload.tags, payload.model
    )
    return {'status': 'registered'}

@app.get('/prompts/{prompt_id}/active')
def get_active(prompt_id: str):
    try:
        return registry.get_active(prompt_id)
    except ValueError as e:
        raise HTTPException(404, str(e))

@app.put('/prompts/{prompt_id}/activate/{version}')
def activate(prompt_id: str, version: str):
    registry.activate_version(prompt_id, version)
    return {'status': 'activated'}

سجل التدقيق وتاريخ التغييرات

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

CREATE TABLE prompt_audit_log (
  id          SERIAL PRIMARY KEY,
  prompt_id   VARCHAR(100),
  version     VARCHAR(20),
  action      VARCHAR(50),  -- 'registered', 'activated', 'deactivated'
  actor       VARCHAR(100), -- user or service that performed the action
  reason      TEXT,
  created_at  TIMESTAMP DEFAULT NOW()
);

-- Trigger to auto-log activations
CREATE OR REPLACE FUNCTION log_activation()
RETURNS TRIGGER AS $func$
BEGIN
  IF NEW.is_active != OLD.is_active THEN
    INSERT INTO prompt_audit_log (prompt_id, version, action)
    VALUES (NEW.prompt_id, NEW.version,
            CASE WHEN NEW.is_active THEN 'activated' ELSE 'deactivated' END);
  END IF;
  RETURN NEW;
END;
$func$ LANGUAGE plpgsql;

CREATE TRIGGER trg_activation
AFTER UPDATE ON prompt_versions
FOR EACH ROW EXECUTE FUNCTION log_activation();

اختبار سريع

في مخطط قاعدة بيانات سجل المطالبات، ما الحقل الذي يضمن عدم تقديم سوى إصدار واحد من المطالبة في الإنتاج في أي وقت؟

ملخص بنية السجل

يوحّد سجل المطالبات إدارة المطالبات من خلال التعامل معها بوصفها آثارًا ذات إصدارات. وتشمل قرارات التصميم الرئيسية:

  • فصل جدول الهوية (prompt_id) عن جدول الإصدارات (version، وtemplate، وmetadata)
  • يمنع العلم is_active المنفرد مع عمليات التبديل الذرية أخطاء التفعيل المزدوج
  • تدعم البيانات الوصفية الغنية (المؤلف، والوسوم، والنموذج، وسجل التغييرات) الاكتشاف والتدقيق
  • تجعل طبقة REST API السجل متاحًا لجميع الخدمات
  • يوفّر سجل التدقيق دعمًا للامتثال وتصحيح الحوادث

تصلح السجلات المستندة إلى الملفات للفرق الصغيرة، بينما يُفضَّل استخدام السجلات المدعومة بقواعد البيانات في أنظمة الإنتاج متعددة الفرق وعالية التوافر.

الأسئلة الشائعة

هل درس «بنية سجل المطالبات» مجاني؟

نعم — نص درس «بنية سجل المطالبات» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة AI Prompt Engineering، انتقل إلى CoddyKit PRO. تتضمن دورة AI Prompt Engineering 4 دروس في المجموع.

ماذا ستتعلم في «بنية سجل المطالبات»؟

تخزين المطالبات كعناصر مُدارة بالإصدارات مع البيانات الوصفية والوسوم تتمرن على AI Prompt Engineering مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ AI Prompt Engineering؟

لا تُشترط خبرة سابقة. AI Prompt Engineering على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.

كم من الوقت يستغرق درس «بنية سجل المطالبات»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس AI Prompt Engineering هذا؟

نعم. كل درس في AI Prompt Engineering يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. بنية سجل المطالبات
  2. التحكم في إصدارات المطالبات
  3. استراتيجيات النشر والتراجع
  4. مراقبة أداء المطالبات في بيئة الإنتاج
← العودة إلى AI Prompt Engineering