جاسازی برداری — Embeddings

تولید بردارهای عددی (embedding) از متن؛ نمایشی که معنای متن را برای کارهای یادگیری ماشین (بازیابی، جست‌وجوی معنایی و…) قابل استفاده می‌کند.

Embedding ها نمایش‌های عددی از متن هستند که معنای معنایی آن را در بر می‌گیرند. آنها متن را به بردار (آرایه‌ای از اعداد) تبدیل می‌کنند که برای کارهای مختلف یادگیری ماشین قابل استفاده است. آشا یک API یکپارچه برای دسترسی به مدل‌های embedding از ارائه‌دهنده‌های مختلف فراهم می‌کند.

Embedding چیست؟

Embedding متن را به بردارهایی با ابعاد زیاد تبدیل می‌کند که در آن، متن‌های دارای معنای مشابه در فضای برداری به یکدیگر نزدیک‌تر قرار می‌گیرند. برای مثال «cat» (گربه) و «kitten» (بچه‌گربه) embedding های مشابهی دارند، در حالی‌که «cat» و «airplane» (هواپیما) از هم دورند.

این نمایش‌های برداری به ماشین اجازه می‌دهند رابطهٔ بین متن‌ها را درک کند و برای بسیاری از اپلیکیشن‌های هوش مصنوعی ضروری هستند.

کاربردهای رایج

Embedding در طیف گسترده‌ای از اپلیکیشن‌ها استفاده می‌شود:

RAG (ساخت با بازیابی و افزایش — Retrieval-Augmented Generation): سیستم‌های RAG بسازید که قبل از تولید پاسخ، بافت مرتبط را از پایگاه دانش بازیابی می‌کنند. Embedding به یافتن مرتبط‌ترین اسناد برای قرار گرفتن در بافت مدل کمک می‌کند.

جست‌وجوی معنایی: اسناد و پرس‌وجوها را به embedding تبدیل کنید و سپس با مقایسهٔ شباهت برداری، مرتبط‌ترین اسناد را بیابید. این روش نسبت به تطبیق کلمه‌ای سنتی نتایج دقیق‌تری می‌دهد، چون به‌جای تطبیق‌دادن کلمات، معنا را درک می‌کند.

سیستم‌های پیشنهاددهنده: برای آیتم‌ها (محصول، مقاله، فیلم) و ترجیحات کاربر embedding تولید کنید تا آیتم‌های مشابه را پیشنهاد دهید. با مقایسهٔ بردارها، می‌توانید آیتم‌هایی را بیابید که از نظر معنایی مرتبط‌اند حتی اگر کلمات کلیدی مشترکی نداشته باشند.

خوشه‌بندی و طبقه‌بندی: با تحلیل الگوهای embedding، اسناد مشابه را گروه‌بندی یا متن را در دسته‌ها طبقه‌بندی کنید. اسنادی با embedding مشابه، به احتمال زیاد به یک موضوع یا دسته تعلق دارند.

تشخیص تکرارها: با مقایسهٔ شباهت embedding، محتوای تکراری یا نزدیک‌به-تکراری را شناسایی کنید. این کار حتی وقتی متن بازنویسی یا تغییر جمله‌بندی شده باشد هم مؤثر است.

تشخیص ناهنجاری: با شناسایی embedding ای که از الگوهای عادی مجموعه‌داده شما دور است، محتوای غیرعادی یا پرت را تشخیص دهید.

نحوهٔ استفاده از Embedding

درخواست پایه

برای تولید embedding، یک درخواست POST به /embeddings با متن ورودی و مدل انتخابی بفرستید:

import OpenAI from 'openai';

const openai = new OpenAI({
  baseURL: 'https://app.asha-ai.ir/v1',
  apiKey: '<ASHA_API_KEY>',
});

const response = await openai.embeddings.create({
  model: 'openai/text-embedding-3-small',
  input: 'The quick brown fox jumps over the lazy dog',
});

console.log(response.data[0].embedding);
import requests
import os

response = requests.post(
  "https://app.asha-ai.ir/v1/embeddings",
  headers={
    "Authorization": f"Bearer {os.environ['ASHA_API_KEY']}",
    "Content-Type": "application/json",
  },
  json={
    "model": "openai/text-embedding-3-small",
    "input": "The quick brown fox jumps over the lazy dog"
  }
)

data = response.json()
embedding = data["data"][0]["embedding"]
print(f"Embedding dimension: {len(embedding)}")
const response = await fetch('https://app.asha-ai.ir/v1/embeddings', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.ASHA_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'openai/text-embedding-3-small',
    input: 'The quick brown fox jumps over the lazy dog',
  }),
});

const data = await response.json();
const embedding = data.data[0].embedding;
console.log(`Embedding dimension: ${embedding.length}`);
curl https://app.asha-ai.ir/v1/embeddings 
  -H "Content-Type: application/json" 
  -H "Authorization: Bearer $ASHA_API_KEY" 
  -d '{
    "model": "openai/text-embedding-3-small",
    "input": "The quick brown fox jumps over the lazy dog"
  }'

پردازش دسته‌ای

با فرستادن یک آرایه از رشته‌ها می‌توانید برای چند متن در یک درخواست embedding تولید کنید:

import OpenAI from 'openai';

const openai = new OpenAI({
  baseURL: 'https://app.asha-ai.ir/v1',
  apiKey: '<ASHA_API_KEY>',
});

const response = await openai.embeddings.create({
  model: 'openai/text-embedding-3-small',
  input: [
    'Machine learning is a subset of artificial intelligence',
    'Deep learning uses neural networks with multiple layers',
    'Natural language processing enables computers to understand text'
  ],
});

// Process each embedding
response.data.forEach((item, index) => {
  console.log(`Embedding ${index}: ${item.embedding.length} dimensions`);
});
import requests
import os

response = requests.post(
  "https://app.asha-ai.ir/v1/embeddings",
  headers={
    "Authorization": f"Bearer {os.environ['ASHA_API_KEY']}",
    "Content-Type": "application/json",
  },
  json={
    "model": "openai/text-embedding-3-small",
    "input": [
      "Machine learning is a subset of artificial intelligence",
      "Deep learning uses neural networks with multiple layers",
      "Natural language processing enables computers to understand text"
    ]
  }
)

data = response.json()
for i, item in enumerate(data["data"]):
  print(f"Embedding {i}: {len(item['embedding'])} dimensions")
const response = await fetch('https://app.asha-ai.ir/v1/embeddings', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.ASHA_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'openai/text-embedding-3-small',
    input: [
      'Machine learning is a subset of artificial intelligence',
      'Deep learning uses neural networks with multiple layers',
      'Natural language processing enables computers to understand text'
    ],
  }),
});

const data = await response.json();
data.data.forEach((item, index) => {
  console.log(`Embedding ${index}: ${item.embedding.length} dimensions`);
});
curl https://app.asha-ai.ir/v1/embeddings 
  -H "Content-Type: application/json" 
  -H "Authorization: Bearer $ASHA_API_KEY" 
  -d '{
    "model": "openai/text-embedding-3-small",
    "input": [
      "Machine learning is a subset of artificial intelligence",
      "Deep learning uses neural networks with multiple layers",
      "Natural language processing enables computers to understand text"
    ]
  }'

مدل‌های موجود

آشا به مدل‌های embedding مختلفی از ارائه‌دهنده‌های مختلف دسترسی می‌دهد. می‌توانید همهٔ مدل‌های embedding موجود را با فیلتر بر اساس «embed» در صفحهٔ مدل‌های آشا ببینید.

برای فهرست‌کردن برنامه‌نویسی مدل‌های موجود:

import requests
import os

response = requests.get(
  "https://app.asha-ai.ir/v1/models",
  headers={
    "Authorization": f"Bearer {os.environ['ASHA_API_KEY']}",
  }
)

models = response.json()
for model in models["data"]:
  if model.get("modalities") and "embed" in model["modalities"]:
    print(f"{model['id']}: {model.get('context_length', 'N/A')} tokens")
const response = await fetch('https://app.asha-ai.ir/v1/models', {
  headers: {
    'Authorization': `Bearer ${process.env.ASHA_API_KEY}`,
  },
});

const models = await response.json();
models.data
  .filter(m => m.modalities?.includes('embed'))
  .forEach(m => console.log(`${m.id}: ${m.context_length ?? 'N/A'} tokens`));
curl https://app.asha-ai.ir/v1/models 
  -H "Authorization: Bearer $ASHA_API_KEY"

در اینجا یک مثال کامل از ساخت یک سیستم جست‌وجوی معنایی با embedding آمده است:

import OpenAI from 'openai';

const openai = new OpenAI({
  baseURL: 'https://app.asha-ai.ir/v1',
  apiKey: '<ASHA_API_KEY>',
});

// Sample documents
const documents = [
  "The cat sat on the mat",
  "Dogs are loyal companions",
  "Python is a programming language",
  "Machine learning models require training data",
  "The weather is sunny today"
];

// Function to calculate cosine similarity
function cosineSimilarity(a: number[], b: number[]): number {
  const dotProduct = a.reduce((sum, val, i) => sum + val * b[i], 0);
  const magnitudeA = Math.sqrt(a.reduce((sum, val) => sum + val * val, 0));
  const magnitudeB = Math.sqrt(b.reduce((sum, val) => sum + val * val, 0));
  return dotProduct / (magnitudeA * magnitudeB);
}

async function semanticSearch(query: string, documents: string[]) {
  // Generate embeddings for all documents and the query
  const response = await openai.embeddings.create({
    model: 'openai/text-embedding-3-small',
    input: [query, ...documents],
  });

  const queryEmbedding = response.data[0].embedding;
  const docEmbeddings = response.data.slice(1);

  // Calculate similarity scores
  const results = documents.map((doc, i) => ({
    document: doc,
    similarity: cosineSimilarity(
      queryEmbedding as number[],
      docEmbeddings[i].embedding as number[]
    ),
  }));

  // Sort by similarity (highest first)
  results.sort((a, b) => b.similarity - a.similarity);

  return results;
}

// Search for documents related to pets
const results = await semanticSearch("pets and animals", documents);
console.log("Search results:");
results.forEach((result, i) => {
  console.log(`${i + 1}. ${result.document} (similarity: ${result.similarity.toFixed(4)})`);
});
import requests
import os
import numpy as np

ASHA_API_KEY = os.environ.get("ASHA_API_KEY")

# Sample documents
documents = [
  "The cat sat on the mat",
  "Dogs are loyal companions",
  "Python is a programming language",
  "Machine learning models require training data",
  "The weather is sunny today"
]

def cosine_similarity(a, b):
  """Calculate cosine similarity between two vectors"""
  dot_product = np.dot(a, b)
  magnitude_a = np.linalg.norm(a)
  magnitude_b = np.linalg.norm(b)
  return dot_product / (magnitude_a * magnitude_b)

def semantic_search(query, documents):
  """Perform semantic search using embeddings"""
  # Generate embeddings for query and all documents
  response = requests.post(
    "https://app.asha-ai.ir/v1/embeddings",
    headers={
      "Authorization": f"Bearer {ASHA_API_KEY}",
      "Content-Type": "application/json",
    },
    json={
      "model": "openai/text-embedding-3-small",
      "input": [query] + documents
    }
  )

  data = response.json()
  query_embedding = np.array(data["data"][0]["embedding"])
  doc_embeddings = [np.array(item["embedding"]) for item in data["data"][1:]]

  # Calculate similarity scores
  results = []
  for i, doc in enumerate(documents):
    similarity = cosine_similarity(query_embedding, doc_embeddings[i])
    results.append({"document": doc, "similarity": similarity})

  # Sort by similarity (highest first)
  results.sort(key=lambda x: x["similarity"], reverse=True)

  return results

# Search for documents related to pets
results = semantic_search("pets and animals", documents)
print("Search results:")
for i, result in enumerate(results):
  print(f"{i + 1}. {result['document']} (similarity: {result['similarity']:.4f})")

خروجی مورد انتظار:

Output search results
Search results:
1. Dogs are loyal companions (similarity: 0.8234)
2. The cat sat on the mat (similarity: 0.7891)
3. The weather is sunny today (similarity: 0.3456)
4. Machine learning models require training data (similarity: 0.2987)
5. Python is a programming language (similarity: 0.2654)

بهترین روش‌ها

مدل مناسب را انتخاب کنید: مدل‌های embedding مختلف نقاط قوت متفاوتی دارند. مدل‌های کوچک‌تر (مثل openai/text-embedding-3-small) سریع‌تر و ارزان‌ترند، در حالی‌که مدل‌های بزرگ‌تر کیفیت بهتری دارند. چند مدل را برای یافتن بهترین گزینهٔ کاربری خود آزمایش کنید.

درخواست‌ها را دسته‌بندی کنید: هنگام پردازش چند متن، به‌جای تماس‌های مجزای API، همه را در یک درخواست بفرستید. این کار تأخیر و هزینه را کاهش می‌دهد.

Embedding ها را کش کنید: Embedding متن یکسان قطعی است (تغییر نمی‌کند). برای جلوگیری از تولید دوبارهٔ مکرر، embedding ها را در پایگاه داده یا vector store ذخیره کنید.

برای مقایسه نرمال‌سازی کنید: هنگام مقایسهٔ embedding ها، به‌جای فاصلهٔ اقلیدسی از شباهت کسینوسی استفاده کنید. شباهت کسینوسی نسبت به مقیاس نامتغیر است و برای بردارهای با ابعاد زیاد بهتر عمل می‌کند.

طول بافت را در نظر بگیرید: هر مدل حداکثر طول ورودی (پنجرهٔ بافت) دارد. متن‌های طولانی‌تر ممکن است نیاز به قطعه‌بندی یا برش داشته باشند. قبل از پردازش اسناد طولانی، مشخصات مدل را بررسی کنید.

قطعه‌بندی مناسب: برای اسناد طولانی، آن‌ها را به قطعه‌های معنادار (پاراگراف، بخش) تقسیم کنید، نه برش‌های دلخواه بر اساس تعداد کاراکتر. این کار انسجام معنایی را حفظ می‌کند.

مسیریابی ارائه‌دهنده

با پارامتر provider می‌توانید کنترل کنید کدام ارائه‌دهنده‌ها درخواست‌های embedding شما را سرویس کنند. این برای موارد زیر مفید است:

  • تضمین حریم خصوصی داده‌ها با ارائه‌دهنده‌های خاص
  • بهینه‌سازی هزینه یا تأخیر
  • استفاده از ویژگی‌های خاص ارائه‌دهنده

مثال با ترجیحات ارائه‌دهنده:

JSON request body
{
  "model": "openai/text-embedding-3-small",
  "input": "Your text here",
  "provider": {
    "order": ["openai", "azure"],
    "allow_fallbacks": true,
    "data_collection": "deny"
  }
}

برای اطلاعات بیشتر، بخش «Provider Routing» را در مستندات آشا ببینید.

مدیریت خطا

خطاهای رایجی که ممکن است با آن‌ها مواجه شوید:

400 Bad Request: قالب ورودی نامعتبر یا پارامترهای الزامی از قلم افتاده است. درست بودن فرمت پارامترهای input و model را بررسی کنید.

401 Unauthorized: کلید API نامعتبر یا موجود نیست. از درست بودن کلید خود و قرار گرفتن آن در هدر Authorization مطمئن شوید.

402 Payment Required: اعتبار کافی نیست. به حساب آشا خود اعتبار اضافه کنید.

404 Not Found: مدل مشخص‌شده وجود ندارد یا برای embedding در دسترس نیست. نام مدل را بررسی کنید و مطمئن شوید یک مدل embedding است.

429 Too Many Requests: سقف rate limit رد شده است. backoff نمایی و منطق retry پیاده‌سازی کنید.

529 Provider Overloaded: ارائه‌دهنده موقتاً بیش از ظرفیت است. برای استفادهٔ خودکار از ارائه‌دهنده‌های جایگزین، allow_fallbacks: true را فعال کنید.

محدودیت‌ها

  • بدون استریمینگ: برخلاف chat completions، embedding ها به‌صورت پاسخ کامل برگردانده می‌شوند. استریمینگ پشتیبانی نمی‌شود.
  • محدودیت token: هر مدل حداکثر طول ورودی دارد. متن‌های بیش از این حد بریده یا رد می‌شوند.
  • خروجی قطعی: embedding ورودی یکسان همیشه یکسان است (بدون temperature یا تصادفی‌بودن).
  • پشتیبانی زبانی: برخی مدل‌ها برای زبان‌های خاص بهینه‌سازی شده‌اند. برای قابلیت‌های زبانی، مستندات مدل را بررسی کنید.
  • صفحهٔ مدل‌ها — همهٔ مدل‌های embedding موجود را مرور کنید
  • Streaming — استریمینگ (برای chat completions)
  • مرجع API — نمای کلی قالب درخواست و احراز هویت با کلید API