پرش به محتوا

امبدینگ (Embeddings)

تبدیل متن فارسی و انگلیسی به بردار برای جست‌وجوی معنایی و RAG: مدل‌ها، ابعاد بردار، ارسال دسته‌ای و یک نمونهٔ کامل جست‌وجوی مشابه‌ترین متن.

بازبینی: ۸ مهر ۱۴۰۵ ۵ دقیقه مطالعه

امبدینگ (Embedding) متن را به یک بردار عددی تبدیل می‌کند؛ متن‌هایی که معنای نزدیک دارند، بردارهای نزدیک می‌گیرند، حتی اگر واژه‌هایشان فرق کند. با آن جست‌وجوی معنایی می‌سازید («چند روزه می‌رسه؟» متن «ارسال یک تا دو روز کاری طول می‌کشد» را پیدا می‌کند)، پرسش‌های تکراری را دسته‌بندی می‌کنید و پایهٔ RAG را می‌گذارید: مدل از روی اسناد خودتان جواب بدهد.

POSThttps://gisoo.pro/api/v1/embeddings

درخواست و پاسخ#

cURL POST /embeddings
curl https://gisoo.pro/api/v1/embeddings \
  -H "Authorization: Bearer $GISOO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "text-embedding-3-small",
    "input": ["How long does shipping take?", "What is your return policy?"]
  }'
JSON پاسخ
{
  "object": "list",
  "data": [
    { "object": "embedding", "index": 0, "embedding": [0.0182, -0.0041, 0.0333, "…"] },
    { "object": "embedding", "index": 1, "embedding": [-0.0107, 0.0219, 0.0045, "…"] }
  ],
  "model": "text-embedding-3-small",
  "usage": { "prompt_tokens": 14, "total_tokens": 14 }
}
model string الزامی
مدل امبدینگ؛ از GET /models?type=embedding.
input string | string[] الزامی
یک متن یا فهرستی از متن‌ها. فرستادن دسته‌ای (مثلاً ۱۰۰ متن در یک درخواست) از درخواست‌های تکی سریع‌تر است.
dimensions integer
کوتاه کردن طول بردار در مدل‌هایی که پشتیبانی می‌کنند (text-embedding-3 و Gemini Embedding).
encoding_format string
float (پیش‌فرض) یا base64 برای پاسخ کم‌حجم‌تر.

مدل‌ها#

  • text-embedding-3-small: ارزان و سریع؛ برای بیشتر جست‌وجوهای معنایی کافی است.
  • text-embedding-3-large: دقیق‌تر، با بردار بزرگ‌تر.
  • مدل‌های gemini-embedding هم در فهرست هستند.
یک مدل برای همه

بردارهای دو مدل مختلف با هم مقایسه‌پذیر نیستند. سندها و پرسش‌ها را با یک مدل امبدینگ کنید؛ اگر مدل را عوض کردید، همهٔ سندها را دوباره امبدینگ کنید.

سندها را یک بار امبدینگ و ذخیره کنید؛ برای هر پرسش فقط خود پرسش امبدینگ می‌شود و نزدیک‌ترین سندها با شباهت کسینوسی پیدا می‌شوند:

# pip install openai numpy
import numpy as np
from openai import OpenAI

client = OpenAI(base_url="https://gisoo.pro/api/v1", api_key="sk-gisoo-v1-...")
MODEL = "text-embedding-3-small"

docs = [
    "ارسال سفارش به تهران یک تا دو روز کاری طول می‌کشد.",
    "کالای سالم را تا هفت روز پس از تحویل می‌توانید مرجوع کنید.",
    "پرداخت با همهٔ کارت‌های عضو شتاب انجام می‌شود.",
]

def embed(texts):
    res = client.embeddings.create(model=MODEL, input=texts)
    vectors = np.array([d.embedding for d in res.data])
    return vectors / np.linalg.norm(vectors, axis=1, keepdims=True)   # normalise once

doc_vectors = embed(docs)                        # do this once and store it

def search(question: str, k: int = 2):
    q = embed([question])[0]
    scores = doc_vectors @ q                      # cosine similarity (vectors are normalised)
    best = np.argsort(-scores)[:k]
    return [(docs[i], float(scores[i])) for i in best]

for text, score in search("چند روزه می‌رسه؟"):
    print(round(score, 3), text)

از جست‌وجو تا پاسخ (RAG)#

نزدیک‌ترین سندها را به‌عنوان زمینه به یک مدل گفت‌وگو بدهید تا فقط از روی آن‌ها جواب بدهد:

Python RAG ساده
def answer(question: str) -> str:
    context = "\n".join(text for text, _ in search(question, k=3))
    reply = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": "Answer ONLY from the context below, in Persian. If the answer is not there, say you don't know.\n\nContext:\n" + context},
            {"role": "user", "content": question},
        ],
        max_tokens=300,
    )
    return reply.choices[0].message.content

برای چند هزار سند، به‌جای آرایهٔ ساده از یک پایگاه برداری مثل pgvector، Qdrant یا Chroma استفاده کنید. برای وصل کردن LangChain و LlamaIndex، یکپارچه‌سازی‌ها را ببینید.

کوتاه کردن بردار#

Python dimensions
res = client.embeddings.create(model="text-embedding-3-large", input="...", dimensions=768)
print(len(res.data[0].embedding))   # 768 instead of the full size: smaller index, a little less precise

هزینه و نکته‌ها#

  • امبدینگ فقط توکن ورودی دارد و هزینهٔ خروجی ندارد. قیمت هر مدل در GET /models آمده است.
  • متن‌های بلند را پیش از امبدینگ به تکه‌های چندصد کلمه‌ای بشکنید؛ هر مدل سقف ورودی دارد (context_length) و تکه‌های کوتاه‌تر نتیجهٔ جست‌وجو را دقیق‌تر می‌کنند.
  • امبدینگ هر سند را یک بار حساب و ذخیره کنید؛ دوباره‌کاری فقط هزینه است.

پاسخ پرسشتان را پیدا نکردید؟

شناسهٔ درخواست (هدر X-Request-Id) را با پرسشتان در تیکت بفرستید تا دقیق بررسی کنیم.

تیکت پشتیبانی