API embedding در ایران: امبدینگ چیست و کدام مدل را انتخاب کنی

امبدینگ چیست و API آن چطور کار می‌کند: text-embedding-3-small، Qwen3 Embedding و bge-m3 با کلید یوتاپن، پرداخت تومانی و کد Python و curl آماده.

۱۹ مهر ۱۴۰۵ · ۱۱ دقیقه مطالعه · تیم یوتاپن
API embedding در ایران: امبدینگ چیست و کدام مدل را انتخاب کنی

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

API embedding یوتاپن، یعنی مسیر POST /v1/embeddings، همان قرارداد OpenAI را دارد. با SDK رسمی OpenAI و فقط با عوض کردن base_url، تابع client.embeddings.create را صدا می‌زنی و با همان کلید sk-up- به بیش از ۳۰ مدل embedding دسترسی داری، از openai/text-embedding-3-small تا Qwen3 Embedding و Gemini Embedding. پرداخت از کیف پول تومانی است و آدرس API داخل ایران است.

embedding به چه دردی می‌خورد

هر جا که بخواهی «معنا» را مقایسه کنی، نه کلمه‌ها را، embedding به کار می‌آید. کاربردهای رایج:

  • جستجوی معنایی. کاربر می‌نویسد «چطور پولم را پس بگیرم» و صفحهٔ «شرایط مرجوعی کالا» پیدا می‌شود، با اینکه هیچ کلمهٔ مشترکی ندارند. جستجوی LIKE یا full-text این را پیدا نمی‌کند.
  • RAG. تکه‌های اسنادت را embed می‌کنی، نزدیک‌ترین تکه‌ها به سؤال را پیدا می‌کنی و همراه سؤال به یک مدل زبانی می‌دهی تا با استناد به همان اسناد جواب بدهد.
  • پیدا کردن تکراری‌ها. تیکت‌های پشتیبانی، نظرهای کاربران یا آگهی‌هایی که با کلمه‌های متفاوت یک چیز را می‌گویند، بردار نزدیک می‌گیرند. با یک آستانهٔ شباهت می‌توانی آن‌ها را ادغام یا علامت‌گذاری کنی.
  • خوشه‌بندی. هزاران نظر کاربر را embed می‌کنی و با k-means یا الگوریتم مشابه گروهشان می‌کنی تا ببینی کاربران بیشتر از چه چیزی حرف می‌زنند.
  • پیشنهاد محتوا. «مقاله‌های مرتبط» یا «محصولات مشابه» را با نزدیکی بردار توضیح محصول یا متن مقاله انتخاب می‌کنی.
  • دسته‌بندی ساده. برای هر دسته چند نمونه embed می‌کنی و متن تازه را به دسته‌ای می‌دهی که نزدیک‌ترین نمونه‌ها را دارد. برای خیلی از کارها لازم نیست مدلی آموزش بدهی.

نکتهٔ مهم: embedding خودش جستجو نمی‌کند. بردارها را باید جایی نگه داری، از یک آرایهٔ numpy برای چند هزار تکه تا pgvector یا Qdrant برای حجم بیشتر، و مقایسه را خودت انجام بدهی.

صدا زدن API embedding با Python و curl

اگر قبلاً با API خود OpenAI کار کرده‌ای، چیز تازه‌ای وجود ندارد. فقط base_url و کلید عوض می‌شوند و شناسهٔ مدل باید با پیشوند سازنده نوشته شود. جزئیات جابه‌جایی کد موجود در راهنمای عوض کردن base_url در SDK OpenAI آمده.

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.uttapen.ir/v1",
    api_key=os.environ["UTTAPEN_API_KEY"],   # sk-up-...
)

emb = client.embeddings.create(
    model="openai/text-embedding-3-small",
    input=["قرارداد اجاره", "اجاره‌نامهٔ ملک مسکونی", "دستور پخت قورمه‌سبزی"],
)
vectors = [d.embedding for d in emb.data]
print(len(vectors), len(vectors[0]), emb.usage.prompt_tokens)

input می‌تواند یک رشته یا فهرستی از رشته‌ها باشد. برای حجم بالا فهرست بفرست، چون کل فهرست یک درخواست حساب می‌شود. هر درخواست حداکثر ۲۰۴۸ ورودی می‌گیرد و دستهٔ بزرگ‌تر را باید تکه کنی. emb.usage.prompt_tokens تعداد توکن ورودی را می‌گوید که مبنای هزینه است.

همان درخواست با curl:

curl -s "https://api.uttapen.ir/v1/embeddings" \
  -H "Authorization: Bearer $UTTAPEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"openai/text-embedding-3-small","input":["قرارداد اجاره","اجاره‌نامهٔ ملک"]}' \
  | jq '.data | length, (.[0].embedding | length)'

چند چیز که پیش از نوشتن کد اصلی باید بدانی:

  • فقط مدل embedding. اگر شناسهٔ یک مدل chat را به /v1/embeddings بفرستی، یا برعکس مدل embedding را به chat/completions، خطای 400 invalid_request می‌گیری و هزینه‌ای کم نمی‌شود.
  • پارامتر dimensions. روی مدل‌های openai/text-embedding-3-* کار می‌کند و طول بردار را کوتاه‌تر می‌کند. بردار کوتاه‌تر جای کمتری در دیتابیس می‌گیرد و مقایسه‌اش سریع‌تر است. برای مدل‌های دیگر به این پارامتر تکیه نکن.
  • محدودیت‌ها. درخواست‌های embeddings در همان سقف «درخواست در دقیقه»ی کلید شمرده می‌شوند و در سقف درخواست هم‌زمان هر کاربر هم حساب می‌شوند. جزئیات و کد تلاش دوباره در مستندات محدودیت نرخ آمده. اگر دسته‌های خیلی بزرگ را هم‌زمان بفرستی، ممکن است 503 server_busy بگیری. در این حالت دسته را کوچک‌تر کن و Retry-After را رعایت کن.
  • LangChain. اگر از OpenAIEmbeddings استفاده می‌کنی، check_embedding_ctx_length=False بگذار. وگرنه متن با توکن‌شمار محلی OpenAI شکسته می‌شود. بقیهٔ تنظیمات در مستندات یکپارچه‌سازی‌ها است.

جزئیات SDK در مستندات Python آمده و نمونه‌های Node، Go و PHP هم در صفحه‌های کناری همان بخش هستند. نسخهٔ کامل curl هم در مستندات curl آمده.

کدام مدل embedding را انتخاب کنم

کاتالوگ یوتاپن امروز بیش از ۳۰ مدل embedding دارد و فهرست کامل با قیمت زنده در دستهٔ مدل‌های embedding است. اینجا عدد بنچمارک یا رتبهٔ کیفیت نمی‌آوریم، چون کیفیت embedding روی متن فارسی به دامنهٔ متن تو بستگی دارد و باید روی دادهٔ خودت بسنجی. ستون «توضیح سازنده» از توضیحی آمده که خود سازندهٔ مدل منتشر کرده. قیمت‌ها تومان به‌ازای هر یک میلیون توکن ورودی‌اند و از کاتالوگ زنده خوانده می‌شوند.

مدلتوضیح سازندهقیمت ورودی (تومان / ۱M توکن)
openai/text-embedding-3-smallنسخهٔ بهبودیافته و کارآمدتر ada؛ پنجرهٔ ۸۱۹۲ توکن۶٬۹۲۴
openai/text-embedding-3-largeتوانمندترین مدل embedding شرکت OpenAI برای متن انگلیسی و غیرانگلیسی۴۵٬۰۰۹
qwen/qwen3-embedding-8bمخصوص embedding و رتبه‌بندی، با توان چندزبانه و متن بلند؛ پنجرهٔ ۳۲ هزار توکن۳٬۴۶۲
baai/bge-m3بردار ۱۰۲۴ بعدی برای بازیابی چندزبانه و متن بلند۳٬۴۶۲
google/gemini-embedding-001یک مدل برای حوزه‌های علمی، حقوقی، مالی و کد۵۱٬۹۳۳
google/gemini-embedding-2اولین مدل embedding چندوجهی Google: متن و تصویر در یک فضای برداری۶۹٬۲۴۴
mistralai/codestral-embed-2505مخصوص کد و مخزن کد۵۱٬۹۳۳

بقیهٔ فهرست هم گزینه‌های قابل‌توجهی دارد: intfloat/multilingual-e5-large که به گفتهٔ سازنده بیش از ۹۰ زبان را پوشش می‌دهد، خانوادهٔ voyageai/voyage-4 که چندزبانه است و بردار را در طول‌های ۲۰۴۸ تا ۲۵۶ می‌دهد، voyageai/voyage-code-4 برای کد، و perplexity/pplx-embed-v1 در دو اندازه برای بازیابی در مقیاس وب. openai/text-embedding-ada-002 را سازنده‌اش مدل قدیمی (legacy) می‌داند. فقط وقتی سراغش برو که بردارهای قدیمی‌ات با همین مدل ساخته شده‌اند.

چند نکتهٔ عملی برای انتخاب:

  • برای متن فارسی، مدل چندزبانه انتخاب کن. مدل‌هایی مثل bge-base-en-v1.5، e5-base-v2 و gte-large به گفتهٔ خود سازنده برای انگلیسی ساخته شده‌اند و پنجرهٔ ۵۱۲ توکنی دارند. برای فارسی از text-embedding-3-small، qwen3-embedding-8b، bge-m3 یا multilingual-e5-large شروع کن. فقط یادت باشد پنجرهٔ multilingual-e5-large هم ۵۱۲ توکن است و برای تکه‌های کوتاه مناسب است.
  • text-embedding-3-small نقطهٔ شروع امنی است. ارزان است، با کتابخانه‌ها و ابزارها سازگار است و dimensions را پشتیبانی می‌کند. صفحه‌اش در یوتاپن قیمت زنده و جزئیات را نشان می‌دهد.
  • اگر اسنادت بلند است، به پنجرهٔ مدل نگاه کن. پنجرهٔ مدل‌های Qwen3 Embedding ۳۲ هزار توکن و پنجرهٔ مدل‌های OpenAI ۸۱۹۲ توکن است. با این حال برای جستجو معمولاً تکه‌های کوچک‌تر نتیجهٔ بهتری می‌دهند، پس پنجرهٔ بزرگ دلیلی برای embed کردن کل یک سند در یک بردار نیست.
  • برای کد، مدل‌های مخصوص کد مثل Codestral Embed یا voyage-code-4 را هم امتحان کن.
  • مدل را وسط کار عوض نکن. بردارهای دو مدل مختلف، و حتی یک مدل با dimensions متفاوت، با هم قابل مقایسه نیستند. اگر مدل را عوض کردی، باید همهٔ اسناد را دوباره embed کنی. پس شناسهٔ مدل و طول بردار را کنار هر بردار ذخیره کن.

هزینهٔ embedding چطور حساب می‌شود

مدل embedding خروجی متنی ندارد، پس هزینه فقط بابت توکن‌های ورودی است و بر اساس مصرف واقعی از کیف پول کم می‌شود. قیمت تومانی هر مدل در جدول بالا زنده است و با نرخ ارز و قیمت سازنده تغییر می‌کند، برای همین در متن عدد ثابت نمی‌نویسیم.

برای برآورد کار خودت، یک نمونهٔ کوچک از اسنادت را embed کن و usage.prompt_tokens را بخوان. بعد آن را به نسبت حجم کل اسنادت بزرگ کن. متن فارسی معمولاً توکن بیشتری از متن انگلیسی هم‌طول مصرف می‌کند و تعداد دقیقش به توکنایزر هر مدل بستگی دارد. اینکه یک درخواست فارسی چند توکن است را با عدد واقعی جداگانه بررسی کرده‌ایم.

دو چیز هزینه را واقعاً پایین نگه می‌دارد:

  1. فقط یک بار embed کن. بردار هر سند را ذخیره کن و فقط وقتی سند تغییر کرد دوباره بسازش. یک هش از متن کنار بردار نگه دار تا تغییر را تشخیص بدهی.
  2. سؤال کاربر ارزان است. در جستجو هر بار فقط متن کوتاه پرسش embed می‌شود. هزینهٔ اصلی همان ساخت اولیهٔ ایندکس است.

کیف پول برای همهٔ مدل‌ها مشترک است. با همان شارژی که مدل embedding را صدا می‌زنی، مدل chat مرحلهٔ پاسخ RAG را هم صدا می‌زنی. توضیح کلی قیمت‌گذاری در صفحهٔ قیمت‌ها است.

نکته‌های متن فارسی پیش از embed کردن

این‌ها توصیه‌های عمومی‌اند، نه قاعدهٔ یک مدل خاص، ولی روی کیفیت جستجوی فارسی اثر واضحی دارند:

  • ی و ک را یکسان کن. متنی که از منابع مختلف جمع شده گاهی «ي» و «ك» عربی دارد و گاهی «ی» و «ک» فارسی. برای ماشین این‌ها دو حرف متفاوت‌اند. پیش از embed کردن، هم اسناد و هم پرسش کاربر را با یک تابع ساده یکسان کن.
  • نیم‌فاصله را نگه دار. بعضی ابزارهای تمیزکاری نیم‌فاصله (U+200C) را حذف یا به فاصله تبدیل می‌کنند و «می‌شود» به «می شود» تبدیل می‌شود. نیم‌فاصله را نگه دار و فقط نسخه‌های اشتباهش را درست کن.
  • اعراب و کشیده را حذف کن. «ـــ» و اعراب معمولاً معنا را عوض نمی‌کنند ولی توکن اضافه می‌سازند.
  • عددها را یکسان کن. اگر کاربر ممکن است «۱۴۰۵» یا «1405» بنویسد، یک شکل را انتخاب کن و همه‌جا همان را بنویس.
  • همان پیش‌پردازش برای سند و پرسش. هر تمیزکاری‌ای که روی اسناد انجام دادی، دقیقاً همان را روی پرسش کاربر هم انجام بده.

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

قدم بعدی: ساختن RAG

حالا که می‌دانی embedding چیست و چطور صدایش بزنی، قدم بعدی معمولاً ساختن یک سیستم پرسش‌وپاسخ روی اسناد خودت است. راهنمای RAG روی اسناد فارسی کل مسیر را در یک فایل پایتون پیاده می‌کند: تکه‌کردن متن فارسی با حفظ نیم‌فاصله، embedding دسته‌ای، جستجوی کسینوسی با numpy و پاسخ مدل با شمارهٔ منبع.

سؤال‌های رایج

text-embedding-3-small API را از ایران چطور صدا بزنم؟

با SDK رسمی OpenAI و base_url="https://api.uttapen.ir/v1"، شناسهٔ openai/text-embedding-3-small را به client.embeddings.create بده. کلید sk-up- را از داشبورد یوتاپن می‌گیری و کیف پول را به تومان شارژ می‌کنی. VPN و کارت ارزی لازم نیست. کدی که برای API خود OpenAI نوشته‌ای، با عوض کردن همین دو مقدار و افزودن پیشوند openai/ به نام مدل کار می‌کند.

طول بردار text-embedding-3-small را می‌توانم کم کنم؟

بله. پارامتر dimensions روی مدل‌های openai/text-embedding-3-* کار می‌کند. فقط یادت باشد بردارهایی که با طول‌های مختلف ساخته شده‌اند با هم قابل مقایسه نیستند. اسناد و پرسش‌ها باید با یک مدل و یک طول embed شوند.

چرا خطای 400 invalid_request می‌گیرم؟

رایج‌ترین دلیل این است که شناسهٔ یک مدل chat را به /v1/embeddings فرستاده‌ای، یا مدل embedding را به chat/completions. شناسه را از دستهٔ مدل‌های embedding کپی کن. اگر شناسه را بدون نام سازنده بفرستی (مثل text-embedding-3-small بدون openai/)، خطا 404 model_not_found است، نه 400.

کدام مدل embedding برای فارسی بهتر است؟

ما عدد مقایسه‌ای برای فارسی منتشر نمی‌کنیم، چون نتیجه به نوع متن بستگی دارد. مدل‌های چندزبانه مثل text-embedding-3-small، qwen/qwen3-embedding-8b، baai/bge-m3 و intfloat/multilingual-e5-large نقطهٔ شروع خوبی‌اند. دو سه تا را روی بیست پرسش واقعی خودت امتحان کن و بهترین را نگه دار.

embedding متن را پیش شما ذخیره می‌کنید؟

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

مقاله‌های مرتبط

می‌خواهی همین کد را اجرا کنی؟

با شماره موبایل ثبت‌نام کن، کیف پول را شارژ کن و کلید بگیر. ساخت کلید API ←