سازگاری با OpenAI و مهاجرت از OpenAI، Azure و دیگران

مهاجرت کد موجود به یوتاپن فقط با تغییر base_url؛ شکل شناسهٔ مدل‌ها، مسیرهای پشتیبانی‌شده، فیلدهایی که عبور می‌کنند و جدول اشتباه‌های رایج.

به‌روزرسانی: ۱۶ شهریور ۱۴۰۵

یوتاپن همان قرارداد chat/completions را پیاده کرده که SDK رسمی OpenAI با آن حرف می‌زند. اگر کدت الان با OpenAI، Azure OpenAI یا هر سرویس سازگار دیگری کار می‌کند، مهاجرت یعنی دو تغییر: آدرس پایه و کلید. شناسهٔ مدل هم شکل provider/model می‌گیرد. باقی صفحه دربارهٔ همین جزئیات و چند تفاوت کوچک است.

تغییر base_url

# قبل
client = OpenAI(api_key="sk-...")

# بعد
client = OpenAI(
    base_url="https://api.uttapen.ir/v1",
    api_key="sk-up-...",
)

در Node نام فیلد baseURL است؛ در PHP withBaseUri()؛ در Go option.WithBaseURL(). اگر SDK از متغیر محیطی می‌خواند، OPENAI_BASE_URL=https://api.uttapen.ir/v1 و OPENAI_API_KEY=sk-up-... را ست کن و کد را دست نزن. مسیر /v1 جزء آدرس است؛ بدون آن 404 می‌گیری.

شناسهٔ مدل

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

قبل (OpenAI)بعد (یوتاپن)
gpt-5openai/gpt-5
gpt-5-miniopenai/gpt-5-mini
o3openai/o3
—anthropic/claude-sonnet-4.5
—google/gemini-2.5-flash
—deepseek/deepseek-chat

فهرست کامل با قیمت تومانی در صفحهٔ مدل‌ها یا GET /v1/models (بدون کلید هم کار می‌کند). پسوندهای :free، :batch و :online هم پشتیبانی می‌شوند. شناسهٔ بدون نام سازنده (gpt-5) پذیرفته نمی‌شود و 404 model_not_found برمی‌گرداند.

چه چیزهایی پشتیبانی می‌شود

مسیروضعیت
POST /v1/chat/completionsکامل؛ استریم و غیراستریم، tools، vision، فایل، response_format، reasoning
POST /v1/embeddingsکامل
POST /v1/completionslegacy؛ برای مدل‌هایی که پشتیبانی می‌کنند
GET /v1/models، GET /v1/models/{id}کامل، با بلوک uttapen_pricing
POST /v1/responsesفعلاً 404 با پیام راهنما؛ از chat/completions استفاده کن
/v1/files، /v1/fine_tuning، /v1/assistants، /v1/batches، /v1/audio، /v1/imagesندارد؛ 404 not_found

Responses API بعد از تثبیت شکل رویدادهایش برای متر کردن هزینه اضافه می‌شود. تا آن روز، هر چیزی که در Responses می‌خواهی (tools، تصویر، JSON، reasoning) در chat/completions هم هست؛ فقط شکل بدنه فرق دارد.

فیلدهایی که عبور می‌کنند

بدنهٔ درخواست تو تقریباً دست‌نخورده به مدل می‌رسد. چند فیلد اضافه فراتر از قرارداد OpenAI هم پشتیبانی می‌شود:

  • provider — ترجیح یا اجبار یک ارائه‌دهندهٔ خاص برای یک مدل (مثلاً {"order": ["Anthropic"], "allow_fallbacks": false} در بدنه). برای کاربر حرفه‌ای که به latency یا region حساس است.
  • models — فهرست مدل‌های جایگزین. اگر مدل اول جواب نداد، بعدی امتحان می‌شود. رزرو هزینه با گران‌ترین مدل فهرست محاسبه می‌شود، ولی شارژ نهایی با مدلی است که واقعاً پاسخ داده.
  • reasoning، plugins، web_search_options، transforms — عبور می‌کنند و در برآورد هزینه لحاظ می‌شوند.

دو فیلد را خودمان اضافه می‌کنیم: usage: {include: true} تا مصرف واقعی برگردد، و stream: true به سمت مدل حتی وقتی تو استریم نخواسته‌ای. در حالت دوم یوتاپن تکه‌های استریم را جمع می‌کند و یک JSON استاندارد تحویلت می‌دهد، پس از بیرون فرقی نمی‌بینی.

تفاوت‌های رفتاری

  • فیلدهای عددی باید عدد صحیح JSON باشند. max_tokens، max_completion_tokens، max_output_tokens، n و best_of به‌صورت "100" (رشته)، 100.0 یا 1e2 رد می‌شوند و 400 invalid_request می‌گیری. دلیلش این است که برآورد هزینه نباید با نمایشی که مدل می‌پذیرد ولی ما نمی‌خوانیم دور زده شود.
  • 402 قبل از ارسال. اگر موجودی قابل‌استفاده از برآورد هزینهٔ درخواست کمتر باشد، درخواست اصلاً به مدل نمی‌رود. max_tokens کوچک‌تر یعنی رزرو کوچک‌تر (قیمت‌گذاری).
  • حداکثر بدنه ۲۰ مگابایت است؛ بیشتر از آن 413.
  • پیام‌های خطای مدل عیناً با همان status برمی‌گردند، فقط رشته‌های داخلی زیرساخت از متن پاک شده‌اند.
  • بدون ذخیرهٔ محتوا. پرامپت و پاسخ در مسیر API جایی ثبت نمی‌شوند (حریم خصوصی).
  • تأخیر اضافه نسبت به فراخوانی مستقیم مدل حدود ۱۰۰ میلی‌ثانیه است.

اشتباه‌های رایج

نشانهعلتراه‌حل
404 not_found روی هر درخواستbase_url بدون /v1 یا با /v1/chat/completions کاملفقط https://api.uttapen.ir/v1
404 model_not_found با مدل معتبرشناسه بدون نام سازنده یا با حروف بزرگopenai/gpt-5-mini، همه حروف کوچک
401 بعد از کار درست چند روزهکلید منقضی یا لغو شده؛ یا کلید OpenAI قدیمی در env ماندهUTTAPEN_API_KEY را چک کن؛ OPENAI_API_KEY اگر ست است اولویت ندارد ولی گیج‌کننده است
400 invalid_request روی max_tokensمقدار رشته یا اعشاریعدد صحیح بفرست
402 روی درخواست کوچکmax_tokens ست نشده و سقف پیش‌فرض ۳۲٬۷۶۸ توکن خروجی برای مدل گران رزرو شدهmax_tokens واقعی بده؛ وگرنه سقف خودش تا جایی که موجودی می‌کشد پایین می‌آید (هدر X-Uttapen-Max-Tokens)
کلاینت استریم قطع می‌شودproxy میانی (nginx، Cloudflare) بافر می‌کندproxy_buffering off یا هدر X-Accel-Buffering: no روی proxy خودت
client.responses.create خطا می‌دهدResponses API هنوز فعال نیستchat.completions.create
خروجی SDK PHP در استریم می‌شکندهدر X-Uttapen-Include-Meta با createStreamedاین هدر را فقط با کلاینت HTTP خام بفرست (PHP)

مهاجرت از یک سرویس سازگار دیگر

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

مهاجرت از Azure OpenAI

کلاینت AzureOpenAI را با OpenAI معمولی جایگزین کن؛ api_version و azure_endpoint معنایی ندارند و نام deployment جای خودش را به شناسهٔ provider/model می‌دهد.

هنوز کلید API نداری؟

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