AI Engineering Academy · درس

إنشاء Embeddings باستخدام OpenAI

استخدموا النموذجين text-embedding-3-small وtext-embedding-3-large لتحويل الجمل والفقرات والمستندات إلى embeddings، وقارنوا المفاضلات بينهما من حيث الجودة والتكلفة.

الدرس 2 من 413 خطوة

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

نظرة عامة على نماذج تضمين OpenAI

تقدم OpenAI نموذجَي تضمين للاستخدام في الإنتاج: text-embedding-3-small وtext-embedding-3-large. ينتج النموذج الصغير متجهات ذات 1536 بُعدًا، وتبلغ تكلفته لكل رمز خُمس تكلفة النموذج الكبير، بينما ينتج النموذج الكبير متجهات ذات 3072 بُعدًا مع دقة أعلى في الاختبارات المعيارية. وبالنسبة إلى معظم تطبيقات RAG، يُعد النموذج الصغير نقطة بداية مناسبة.

إجراء أول استدعاء للتضمين

تأخذ الطريقة client.embeddings.create() اسم model وسلسلة input أو قائمة بها. وتعيد كائن استجابة يحتوي على قائمة data، حيث يضم كل عنصر سمة embedding التي تحتوي على المتجه في صورة قائمة Python من قيم الفاصلة العائمة.

احفظوا مفتاح API دائمًا في متغير بيئي، ولا تضعوه مطلقًا بشكل ثابت في الملفات المصدرية.

import os
from openai import OpenAI

client = OpenAI(api_key=os.environ['OPENAI_API_KEY'])

response = client.embeddings.create(
    model='text-embedding-3-small',
    input='What is retrieval-augmented generation?'
)

vector = response.data[0].embedding
print(f'Vector length: {len(vector)}')      # 1536
print(f'Type: {type(vector[0])}')           # float
print(f'Sample values: {vector[:3]}')       # [-0.02, 0.01, ...]

تضمين الدفعات بكفاءة

يؤدي تمرير قائمة من السلاسل إلى input إلى تضمينها جميعًا في جولة واحدة مع واجهة API. وهذا هو الأسلوب الموصى به عند فهرسة مجموعة مستندات. وتحافظ قائمة data في الاستجابة على الترتيب الأصلي، مما يسهّل إنشاء قاموس بحث.

تقتصر الدفعات على 2048 عنصرًا لكل طلب، كما يجب أن يظل إجمالي الرموز في جميع المدخلات ضمن حد الرموز الخاص بالنموذج.

from openai import OpenAI

client = OpenAI()

documents = [
    'RAG stands for Retrieval-Augmented Generation.',
    'Embeddings convert text to numerical vectors.',
    'Pinecone is a managed vector database service.'
]

response = client.embeddings.create(
    model='text-embedding-3-small',
    input=documents
)

embeddings = [item.embedding for item in response.data]
print(f'Got {len(embeddings)} embeddings')
print(f'Each has {len(embeddings[0])} dimensions')

تقليل أبعاد التضمين

يدعم كلا نموذجي text-embedding-3 المعامل dimensions الذي يقتطع متجه الإخراج. فعلى سبيل المثال، يؤدي ضبط dimensions=256 إلى إعادة متجه مكوّن من 256 عنصرًا بدلًا من 1536. وتستهلك المتجهات الأقصر مساحة تخزين وقدرة حسابية أقل، مع تنازل محدود عن الدقة.

يفيد ذلك عندما تريدون إجراء تجارب سريعة، أو عندما تكون تكلفة التخزين أهم من بلوغ أعلى جودة للاسترجاع.

from openai import OpenAI

client = OpenAI()

response = client.embeddings.create(
    model='text-embedding-3-small',
    input='Shorter vectors save storage and query time.',
    dimensions=256   # truncate from 1536 to 256
)

print(len(response.data[0].embedding))  # 256

تنسيق الترميز: Base64 مقابل قائمة القيم العائمة

تعيد واجهة API التضمينات افتراضيًا في صورة مصفوفة JSON من قيم الفاصلة العائمة (encoding_format='float'). ويمكنكم طلب encoding_format='base64' لتلقي كتلة ثنائية مضغوطة بترميز base64، ما يتيح نقلها بسرعة أكبر عبر الشبكة عند التعامل مع دفعات كبيرة.

عند استخدام base64، تحتاجون إلى فك ترميزه باستخدام NumPy: np.frombuffer(base64.b64decode(b64_str), dtype='float32').

import base64
import numpy as np
from openai import OpenAI

client = OpenAI()

response = client.embeddings.create(
    model='text-embedding-3-small',
    input='Base64 encoding transfers faster.',
    encoding_format='base64'
)

b64 = response.data[0].embedding
vector = np.frombuffer(base64.b64decode(b64), dtype='float32')
print(f'Decoded {len(vector)} floats')

تتبع استخدام الرموز والتكلفة

تتضمن كل استجابة تضمين كائن usage مع قيمة prompt_tokens. وتدفعون حسب عدد الرموز: تبلغ تكلفة text-embedding-3-small‏ 0.02 دولار لكل مليون رمز، بينما تبلغ تكلفة text-embedding-3-large‏ 0.13 دولار لكل مليون رمز (اعتبارًا من منتصف عام 2024).

يتيح لكم تتبع الاستخدام تقدير تكلفة فهرسة مجموعة المستندات كاملة قبل الالتزام بتشغيلها في الإنتاج.

from openai import OpenAI

client = OpenAI()

texts = ['Document one content here.', 'Document two content here.']

response = client.embeddings.create(
    model='text-embedding-3-small',
    input=texts
)

tokens_used = response.usage.prompt_tokens
cost_usd = tokens_used * 0.00000002  # $0.02 per 1M tokens
print(f'Tokens: {tokens_used}, Cost: ${cost_usd:.6f}')

مقارنة text-embedding-3-small وlarge

يعتمد الاختيار بين النموذجين الصغير والكبير على متطلبات الدقة والميزانية لديكم:

  • text-embedding-3-small: ‏1536D، أسرع، وتكلفته أقل بخمس مرات، ومناسب لمعظم أعباء عمل RAG
  • text-embedding-3-large: ‏3072D، ودرجات أعلى في معيار MTEB، وأنسب للمحتوى متعدد اللغات والمهام الدلالية المعقدة

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

تطبيع التضمينات للبحث بالضرب النقطي

تعيد OpenAI تضمينات مُطبَّعة وفق معيار L2، أي إن مقدار كل متجه يساوي 1. وهذا يعني أنه يمكنكم استخدام الضرب النقطي كتقريب سريع للتشابه الكوني من دون خطوة تطبيع إضافية، وهو أمر مهم عند البحث في ملايين المتجهات، حيث تتراكم التحسينات الصغيرة.

import numpy as np
from openai import OpenAI

client = OpenAI()

response = client.embeddings.create(
    model='text-embedding-3-small',
    input='Are OpenAI embeddings normalized?'
)

vec = np.array(response.data[0].embedding)
magnitude = np.linalg.norm(vec)
print(f'Vector magnitude: {magnitude:.6f}')  # very close to 1.0

التعامل مع المستندات الكبيرة

يقبل نموذج text-embedding-3-small ما يصل إلى 8191 رمزًا لكل مُدخل. إذا تجاوز المستند هذا الحد، فستُرجع واجهة API خطأً. والحل المعتاد هو تقسيم المستند أولًا إلى أجزاء (عادةً ما يتراوح حجم الجزء بين 200 و500 رمز)، ثم إنشاء embedding لكل جزء على حدة.

ولا يُعد هذا التقسيم مجرد متطلب تقني، بل يؤدي أيضًا إلى تحسين الاسترجاع؛ إذ إن إنشاء embeddings لأجزاء أصغر وأكثر تركيزًا يعطي نتائج أدق من إنشاء embedding لصفحات كاملة.

import tiktoken

enc = tiktoken.encoding_for_model('text-embedding-3-small')

def count_tokens(text):
    return len(enc.encode(text))

max_tokens = 8191
text = 'Very long document content...'  # pretend this is huge

if count_tokens(text) > max_tokens:
    print('Document too long — chunk before embedding')
else:
    print(f'Safe to embed: {count_tokens(text)} tokens')

إنشاء Embeddings بطريقة غير متزامنة لتحقيق إنتاجية عالية

عند فهرسة آلاف المستندات، استخدم عميل OpenAI غير المتزامن مع asyncio.gather لإرسال عدة طلبات لإنشاء embeddings بشكل متزامن. فهذا أسرع بكثير من إجراء الاستدعاءات بالتتابع، لأن عنق الزجاجة هو زمن استجابة الشبكة، وليس وحدة المعالجة المركزية.

أضف دائمًا معالجة لحدود المعدل مع التراجع الأُسّي عند تشغيل طلبات متزامنة، لتجنب تجاوز حد الرموز في الدقيقة.

import asyncio
from openai import AsyncOpenAI

async def embed_batch(texts):
    client = AsyncOpenAI()
    response = await client.embeddings.create(
        model='text-embedding-3-small',
        input=texts
    )
    return [item.embedding for item in response.data]

async def main():
    batches = [['doc1', 'doc2'], ['doc3', 'doc4']]
    results = await asyncio.gather(*[embed_batch(b) for b in batches])
    all_embeddings = [emb for batch in results for emb in batch]
    print(f'Embedded {len(all_embeddings)} documents')

asyncio.run(main())

تخزين Embeddings مؤقتًا لتوفير التكلفة

إنشاء embeddings للنص نفسه عدة مرات يهدر المال والوقت. خزّن embeddings في قاموس يكون مفتاحه سلسلة النص (أو تجزئة لها)، واحفظ هذا التخزين مؤقتًا على القرص بين الجلسات.

في أنظمة الإنتاج، خزّن embeddings في قاعدة بيانات متجهية تزيل التكرار بالاعتماد على معرّف المستند. ولا تُعد إنشاء embedding للمستند إلا عندما يتغير محتواه فعليًا، وليس عند كل تشغيل للفهرسة.

import json, hashlib, os
from openai import OpenAI

CACHE_FILE = '/tmp/embedding_cache.json'
client = OpenAI()

try:
    cache = json.load(open(CACHE_FILE))
except FileNotFoundError:
    cache = {}

def get_embedding(text):
    key = hashlib.md5(text.encode()).hexdigest()
    if key not in cache:
        r = client.embeddings.create(model='text-embedding-3-small', input=text)
        cache[key] = r.data[0].embedding
        json.dump(cache, open(CACHE_FILE, 'w'))
    return cache[key]

vec = get_embedding('Caching saves API costs.')
print(f'Retrieved {len(vec)}-dim embedding')

تحقق سريع

اختبر مدى فهمك لمفاهيم هندسة الذكاء الاصطناعي الواردة في هذا الدرس.

مراجعة الدرس

تعلمت في هذا الدرس أن: text-embedding-3-small هو الخيار الفعّال من حيث التكلفة لمعظم أعباء عمل RAG، وأن إنشاء embeddings لنصوص متعددة في استدعاء واحد لواجهة API أكثر كفاءة من الاستدعاءات المتتابعة، وأن المعامل dimensions يمكنه تقليل حجم المتجه للموازنة بين الدقة وتوفير مساحة التخزين. بعد ذلك سنبني نظام بحث دلالي باستخدام هذه embeddings وNumPy.

البدء مجانًا

تعلم Python مع معلم ذكاء اصطناعي — مجانًا

اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.

الدورات
30
الدروس
120

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

هل درس «إنشاء Embeddings باستخدام OpenAI» مجاني؟

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

ماذا ستتعلم في «إنشاء Embeddings باستخدام OpenAI»؟

استخدموا النموذجين text-embedding-3-small وtext-embedding-3-large لتحويل الجمل والفقرات والمستندات إلى embeddings، وقارنوا المفاضلات بينهما من حيث الجودة والتكلفة. تتمرن على AI Engineering Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

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

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

كم من الوقت يستغرق درس «إنشاء Embeddings باستخدام OpenAI»؟

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

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

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

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

  1. ما هي Vector Embeddings؟
  2. إنشاء Embeddings باستخدام OpenAI
  3. البحث الدلالي باستخدام NumPy
  4. تجميع Embeddings وتصويرها
← العودة إلى AI Engineering Academy