داشبورد توسعه‌دهنده
پرسش از هوش مصنوعی
پرسش از هوش مصنوعی

مرجع API بومی System One ​

API بومی System One قالب TYPESAFE AI را از طریق AvalAI در اختیار شما قرار می‌دهد. داده‌ای را که Jev باید بررسی کند در state قرار دهید، قضاوت‌های مشخص را در questions تعریف کنید و نتیجه‌های نوع‌دار را از answers بخوانید. اعتبارسنجی، بررسی مجوزها و اجرای اقدام پس از قضاوت بر عهده برنامه شماست.

از https://api.avalai.ir/v1/systemone همراه با کلید AvalAI استفاده کنید. این قالب با API تصمیم‌گیری تفاوت دارد: System One بومی از شیئی با کلیدهای شناسه پرسش و فیلد state استفاده می‌کند، در حالی که نقطه پایانی Decisions قالب درخواست و پاسخ خودش را دارد.

نقطه پایانی و احراز هویت ​

text
POST https://api.avalai.ir/v1/systemone
Authorization: Bearer $AVALAI_API_KEY
Content-Type: application/json

AVALAI_API_KEY را در سرور نگه دارید. برای ارسال این درخواست‌ها از طریق AvalAI به کلید TYPESAFE AI نیاز ندارید. JSON با کدگذاری UTF-8 بفرستید و هم وضعیت HTTP و هم بدنه پاسخ را بررسی کنید.

مدل‌ها و قیمت ​

نگاشت‌های زیر برای AvalAI در تاریخ ۱۴۰۵-۰۸-۰۱ / (2026-10-23) اعلام شده‌اند:

مقدار model در درخواستنسخه زیربنایی Jevورودی / 1M توکنورودی از حافظه نهان / 1M توکنخروجی / 1M توکن
jev-previewjev-1.13.0$0.042$0.00$0.00
jev-latestjev-1.14.0$0.042$0.00$0.00

این نگاشت‌ها به نام‌های مستعار AvalAI تعلق دارند؛ نام‌های مستعار در سرویس اصلی ممکن است به نسخه دیگری اشاره کنند. از همین نام‌های مستندشده استفاده کنید و فرض نکنید رشته نسخه زیربنایی، شناسه مستقیم قابل‌قبول در درخواست AvalAI است. نام مستعار می‌تواند تغییر کند؛ هنگام مقایسه رفتار، نام و تاریخ ارزیابی را ثبت کنید.

رایگان بودن خروجی به معنای رایگان بودن ورودی یا صفر بودن تعداد توکن‌های خروجی نیست. قیمت ورودی از حافظه نهان، استفاده از حافظه نهان یا پشتیبانی از پارامتر کنترل آن را تضمین نمی‌کند. برای تفسیر قیمت و نکات نسخه‌ها، صفحه ارائه‌دهنده TYPESAFE AI را ببینید.

بدنه درخواست ​

فیلدنوعالزامیمعنا
modelstringبلهنام مستعار فعال در AvalAI؛ در حال حاضر jev-latest یا jev-preview.
statestring، object یا arrayبلهداده‌ای که همه پرسش‌ها بررسی می‌کنند. عدد یا مقدار بولی در سطح بالای state جزو شکل‌های مستندشده نیست.
questionsobjectبلهنگاشتی غیرخالی از شناسه‌های انتخابی شما به اشیای پرسش.

همه پرسش‌های یک درخواست، state یکسانی را می‌بینند و مستقل از یکدیگر ارزیابی می‌شوند. پاسخ یک پرسش به‌صورت زمینه پنهان در اختیار پرسش دیگری قرار نمی‌گیرد. اگر پاسخ تعیین می‌کند چه داده تازه‌ای دریافت شود یا گزینه‌های پرسش بعدی چه باشند، این وابستگی را با یک درخواست بعدی صریح پیاده‌سازی کنید.

شناسه‌هایی مانند route پاسخ‌ها را برای کد شما مشخص می‌کنند. طبق مستندات اصلی، خود شناسه‌ها به مدل فرستاده نمی‌شوند؛ بنابراین نام گویا جایگزین instructions نیست.

داده ورودی در state ​

برای یک پیام از رشته استفاده کنید. وقتی مرز فیلدها یا شناسه رکوردها به فهم داده کمک می‌کند، از شیء یا آرایه استفاده کنید:

json
{
  "ticket": {
    "id": "ticket-1042",
    "message": "I was charged twice. Please help."
  }
}

در داده ساختاریافته، مسیر فیلد مرتبط را در دستورالعمل مشخص کنید؛ برای مثال، Which team should handle `ticket.message`?. شناسه‌هایی را که نیاز به محاسبه ندارند، به‌صورت رشته نگه دارید. یک رکورد کوتاه و مرتبط از تاریخچه بزرگ و نامرتبط مناسب‌تر است.

شکل بالا با قرارداد بومی ارائه‌دهنده مطابقت دارد. بررسی‌های زنده‌ای که در ادامه آمده‌اند از رشته و شیء JSON استفاده کرده‌اند؛ چند نمونه دستورکار عملی با داده شیء موفق بودند. شیء مشخص ticket در بالا آموزشی است و داده آرایه‌ای در این مجموعه بررسی نشده است.

اشیای پرسش ​

فیلدنوعمعنا
typestringبرای مؤلفه‌های متنی این صفحه، یکی از choice، score یا noul.
instructionsstring، object، array یا nullقضاوت و داده مورد بررسی را تعریف می‌کند. حتی اگر قرارداد اصلی حذف این فیلد یا null را بپذیرد، در نمونه‌های منتشرشده دستورالعمل روشن بنویسید.
criteriaوابسته به typeنگاشت گزینه‌ها برای Choice، آرایه مرتب برای Score، یا توضیح‌های اختیاری true و false برای Noul.

برای دستورالعمل‌ها و توضیح‌های ساده از رشته معمولی استفاده کنید. اشیای ساختاریافته می‌توانند معیار ارزیابی، نمونه‌ها یا مرز داده‌ها را جدا کنند؛ کلیدهای تو‌در‌تویی که انتخاب می‌کنید، محتوای شما هستند و فیلد ویژه تازه‌ای به API اضافه نمی‌کنند.

فیلدهای Chat Completions یا Responses مانند messages، temperature، max_tokens، stream یا tools را به این درخواست بومی اضافه نکنید. درخواست متنی مستندشده، پشتیبانی از این کنترل‌ها را اثبات نمی‌کند.

Choice: انتخاب یک گزینه بدون ترتیب ​

Choice مشخص می‌کند کدام گزینه با داده بیشترین تناسب را دارد. criteria شیئی است که هر مقدار مجاز را به توضیح آن نگاشت می‌کند:

json
{
  "type": "choice",
  "instructions": "Which team should handle this message?",
  "criteria": {
    "billing": "Payments or invoices",
    "technical": "Software or API problems",
    "other": "Anything else"
  }
}

قرارداد بومی ۱ تا ۲۵۵ گزینه را می‌پذیرد؛ برای انتخاب معنادار، دست‌کم دو گزینه داشته باشید. مدل هم نام گزینه و هم توضیح آن را می‌بیند. توضیح null یعنی نام گزینه به‌تنهایی تفسیر شود. به‌ویژه برای برچسب‌هایی مانند شناسه داخلی صف، توضیح صریح بنویسید.

برچسب‌های Choice ترتیب ذاتی ندارند. مرز دسته‌های هم‌پوشان را با توضیح مشخص جدا کنید. در یک مجموعه بسته همیشه گزینه‌ای بهتر از بقیه وجود دارد، حتی وقتی هیچ‌کدام مناسب نیست؛ برای کار خود، گزینه other مناسب یا یک پرسش Noul جداگانه برای بررسی قابل‌اعمال بودن دسته‌ها را ارزیابی کنید.

پاسخ Choice ​

فیلدنوعتفسیر
typestringمقدار "choice".
choicestringکلید معیار انتخاب‌شده. آن را با گزینه‌هایی که فرستاده‌اید اعتبارسنجی کنید.
confidencenumberنشانه‌ای بین ۰ و ۱ که در سرویس اصلی از توزیع محاسبه می‌شود؛ احتمال اندازه‌گیری‌شده درست بودن تصمیم نیست.
probabilitiesobjectکلیدهای معیار و احتمال‌های عددی. پیش از الزامی دانستن نگاشت کامل، پاسخ ثبت‌شده AvalAI را ببینید.

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

Score: ارزیابی با معیار مرتب ​

Score یک طیف مرتب را نشان می‌دهد. آرایه‌ای از توضیح‌ها را از پایین‌ترین سطح تا بالاترین سطح بفرستید:

json
{
  "type": "score",
  "instructions": "How severe is the reported issue?",
  "criteria": [
    "Cosmetic issue; functionality works",
    "Feature is degraded, but a workaround exists",
    "Blocking failure with no workaround"
  ]
}

قرارداد بومی ۱ تا ۱۰ سطح را می‌پذیرد. برای مقیاس مفید، ۲ تا ۱۰ سطح داشته باشید. جایگاه آرایه، شماره سطح را از 0 تا n - 1 تعیین می‌کند؛ این شماره‌ها برچسب عددی دلخواه نیستند. هر توضیح باید به‌تنهایی قابل‌فهم باشد: مدل شماره جایگاه آن سطح یا توضیح‌های همسایه را نمی‌بیند. از عبارت‌هایی مانند «شدیدتر از سطح قبلی» پرهیز کنید.

پاسخ Score ​

فیلدنوعتفسیر
typestringمقدار "score".
scorenumberمیانگین جایگاه سطح‌ها با وزن احتمال؛ می‌تواند اعشاری باشد و بین 0 و n - 1 قرار می‌گیرد.
legendobjectنگاشت جایگاه سطح به توضیح آن. کلیدهای JSON رشته‌هایی مانند "0"، "1" و "2" هستند.
probabilitiesobjectاحتمال‌ها با همان کلیدهای رشته‌ای جایگاه سطح.
confidencenumberنشانه‌ای بین ۰ و ۱ که فاصله سطح‌های مرتب را در توزیع در نظر می‌گیرد.

برای مثال، توزیع سه‌سطحی (0, 0.57, 0.43) امتیاز 1.43 دارد. این مثال محاسبه سرویس اصلی را توضیح می‌دهد و پاسخ ثبت‌شده Score از AvalAI نیست. امتیاز، درصد، مقدار دقیق استخراج‌شده یا احتمال درست بودن نتیجه نیست.

امتیاز میانی می‌تواند نشان‌دهنده قضاوت روشن در سطح میانی یا اختلاف میان دو انتهای طیف باشد. اگر توزیع و اطمینان کامل در دسترس هستند، آن‌ها را بررسی کنید. هنگام ترکیب معیارهایی با تعداد سطح متفاوت در کد برنامه، فقط برای n > 1 از score / (n - 1) برای نرمال‌سازی استفاده کنید و وزن‌ها را با نمونه‌های برچسب‌خورده تنظیم کنید.

بررسی مؤلفه‌های بومی از همین پرسش Score و داده Checkout is blocked and there is no workaround. Please refund the duplicate charge. استفاده کرد. برای هر دو نام مستعار AvalAI، این شیء answers.severity را برگرداند:

json
{
  "type": "score",
  "score": 2.0,
  "confidence": 1.0,
  "legend": {
    "0": "Cosmetic issue; functionality works",
    "1": "Feature is degraded, but a workaround exists",
    "2": "Blocking failure with no workaround"
  },
  "probabilities": {
    "0": 0.0,
    "1": 0.0,
    "2": 1.0
  }
}

این پاسخ ثبت‌شده، بخشی از پاسخ بزرگ‌تر است. همان درخواست، پرسش Noul زیر را نیز داشت؛ پاسخ هر دو پرسش در بررسی زنده اعتبارسنجی نوع‌دار را گذراند. امتیاز و احتمال‌ها ممکن است در پاسخ جداگانه گرد شوند؛ بنابراین برابری دقیق محاسباتی بین امتیاز گزارش‌شده و مقدار بازحساب‌شده از احتمال‌های نمایش‌داده‌شده را الزامی ندانید.

Noul: برآورد احتمال بله یا خیر ​

Noul یک گزاره مشخص را بررسی می‌کند و احتمال بله/درست را برمی‌گرداند:

json
{
  "type": "noul",
  "instructions": "Does this message explicitly request a refund?",
  "criteria": {
    "true": "Explicitly asks for money to be refunded",
    "false": "Does not explicitly ask for a refund"
  }
}

criteria اختیاری است. اگر آن را می‌فرستید، از کلیدهای true و false با توضیح‌هایی سازگار با دستورالعمل استفاده کنید. شرط‌های مرکب را به پرسش‌های مستقل تقسیم کنید و پاسخ‌ها را در کد ترکیب کنید.

پاسخ Noul ​

همان بررسی مؤلفه‌ها، این شیء ثبت‌شده answers.refund_intent را برای هر دو نام مستعار برگرداند:

json
{
  "type": "noul",
  "noul": 0.99
}

در بررسی زنده، معیارهای صریح true و false که در بالا آمده‌اند ارسال شدند. یک بررسی جداگانه دستورکار عملی نیز با دستورالعمل Noul و بدون معیار موفق بود. noul عددی متناهی بین ۰ و ۱ است. فیلد جداگانه‌ای به نام confidence ندارد. مقدار نزدیک به ۰٫۵ یعنی مدل بین بله و خیر نامطمئن است؛ مقدار متوسط یک ویژگی مانند فوریت را نشان نمی‌دهد. برای طیف از Score استفاده کنید.

با داده برچسب‌خورده، بازه‌های بله، خیر و بازبینی را متناسب با کار خود انتخاب کنید. مقدار بالای Noul، پرداخت را مجاز نمی‌کند، مجوز دسترسی نمی‌دهد و درستی یک ادعا را اثبات نمی‌کند. واقعیت‌های لازم و سیاست را در کد برنامه بررسی کنید.

نخستین درخواست: بررسی ثبت‌شده Choice در AvalAI ​

کاربر همین بدنه درخواست را با کلید AvalAI خود در تاریخ ۱۴۰۵-۰۸-۰۱ / (2026-10-23) برای هر دو نام مستعار اجرا کرد. هر دو HTTP 200 برگرداندند. پوشش پوسته زیر، بدون تغییر بدنه، تلاش مجدد محدود را اضافه می‌کند.

درخواست را روی دستگاهی اجرا کنید که AVALAI_API_KEY از قبل در آن تنظیم شده است. نمونه وضعیت، شناسه درخواست و پاسخ کامل را نمایش می‌دهد و کلید را چاپ نمی‌کند. حداکثر سه تلاش و بودجه کلی ۶۰ ثانیه دارد. تلاش مجدد می‌تواند درخواست استنتاج تازه‌ای ایجاد کند که هزینه دارد. پوشش curl برای بررسی امن JSON خطا به Python 3 نیز نیاز دارد.

curl ​

bash
# با Bash و کلید AVALAI_API_KEY از پیش تنظیم‌شده اجرا کنید.
: "${AVALAI_API_KEY:?Set AVALAI_API_KEY in your environment}"
request_dir=$(mktemp -d) || exit 1
trap 'rm -rf "$request_dir"' EXIT

cat >"$request_dir/request.json" <<'JSON'
{
  "model": "jev-latest",
  "state": "I was charged twice. Please help.",
  "questions": {
    "route": {
      "type": "choice",
      "instructions": "Which team should handle this message?",
      "criteria": {
        "billing": "Payments or invoices",
        "technical": "Software or API problems",
        "other": "Anything else"
      }
    }
  }
}
JSON

deadline=$((SECONDS + 60))
for attempt in 1 2 3; do
  remaining=$((deadline - SECONDS))
  ((remaining > 0)) || break
  timeout=$((remaining < 20 ? remaining : 20))
  : >"$request_dir/headers"
  : >"$request_dir/response.json"
  status=$(curl --silent --show-error \
    --connect-timeout 10 --max-time "$timeout" \
    --dump-header "$request_dir/headers" \
    --output "$request_dir/response.json" \
    --write-out '%{http_code}' \
    https://api.avalai.ir/v1/systemone \
    -H "Authorization: Bearer $AVALAI_API_KEY" \
    -H 'Content-Type: application/json' \
    --data-binary "@$request_dir/request.json")
  curl_status=$?
  printf 'HTTP status: %s\n' "$status"
  awk 'tolower($1) == "avalai-request-id:" {print}' "$request_dir/headers"
  cat "$request_dir/response.json"
  printf '\n'
  if ((curl_status == 0)) && [[ $status == 2?? ]]; then
    exit 0
  fi
  retryable=false
  if ((curl_status == 0)); then
    quota_error=$(
      python3 - "$request_dir/response.json" <<'PY'
import json
import sys

try:
    with open(sys.argv[1], encoding="utf-8") as response:
        body = json.load(response)
except (OSError, ValueError):
    sys.exit(0)
if isinstance(body, dict):
    containers = [body, body.get("error")]
    terminal = ("quota_exceeded", "insufficient_quota")
    if any(
        isinstance(item, dict) and any(item.get(key) in terminal for key in ("code", "type", "error_type"))
        for item in containers
    ):
        print("yes")
PY
    ) || exit 1
    [[ $quota_error != yes ]] || exit 1
    case "$status" in 408 | 429 | 5??) retryable=true ;; esac
  else
    case "$curl_status" in 6 | 7 | 28 | 52 | 55 | 56) retryable=true ;; esac
  fi
  [[ $retryable == true && $attempt -lt 3 ]] || exit 1
  delay=$((1 << (attempt - 1)))
  retry_after=$(awk 'tolower($1) == "retry-after:" {
    $1=""; sub(/^[ \t]+/, ""); sub(/\r$/, ""); value=$0
  } END {print value}' "$request_dir/headers")
  if [[ $retry_after =~ ^[0-9]+$ ]]; then
    delay=$((10#$retry_after))
  elif [[ -n $retry_after ]]; then
    retry_at=$(LC_ALL=C date -u -d "$retry_after" +%s 2>/dev/null \
      || LC_ALL=C date -ju -f '%a, %d %b %Y %H:%M:%S GMT' "$retry_after" +%s 2>/dev/null)
    if [[ $retry_at =~ ^[0-9]+$ ]]; then
      delay=$((retry_at - $(date +%s)))
      ((delay >= 0)) || delay=0
    fi
  fi
  ((SECONDS + delay + 1 < deadline)) || break
  sleep "$delay.$((RANDOM % 1000))"
done
exit 1

این نمونه پوسته، Retry-After عددی یا تاریخ HTTP را با date در GNU یا macOS/BSD می‌پذیرد. شکست‌های اعتبارسنجی درخواست را دوباره ارسال نمی‌کند. برای تکرار همین بررسی با jev-preview، فقط مقدار مدل را تغییر دهید.

Python: HTTP با کتابخانه استاندارد ​

این نمونه از HTTP مستقیم استفاده می‌کند و وجود متد بومی System One در SDK شرکت OpenAI را فرض نمی‌کند. بدنه JSON آن با curl یکسان است.

python
import json
import os
import random
import time
import urllib.error
import urllib.request
from datetime import datetime, timezone
from email.utils import parsedate_to_datetime

payload = {
    "model": "jev-latest",
    "state": "I was charged twice. Please help.",
    "questions": {
        "route": {
            "type": "choice",
            "instructions": "Which team should handle this message?",
            "criteria": {
                "billing": "Payments or invoices",
                "technical": "Software or API problems",
                "other": "Anything else",
            },
        },
    },
}


def quota_failure(text):
    try:
        body = json.loads(text)
    except ValueError:
        return False
    if not isinstance(body, dict):
        return False
    terminal = ("quota_exceeded", "insufficient_quota")
    return any(
        isinstance(item, dict)
        and any(item.get(key) in terminal for key in ("code", "type", "error_type"))
        for item in (body, body.get("error"))
    )


def retry_delay(headers, attempt):
    value = headers.get("Retry-After", "").strip()
    if value.isdigit():
        return int(value) + random.uniform(0, 0.25)
    if value:
        try:
            when = parsedate_to_datetime(value)
            if when.tzinfo is None:
                when = when.replace(tzinfo=timezone.utc)
            return max(
                0, (when - datetime.now(timezone.utc)).total_seconds()
            ) + random.uniform(0, 0.25)
        except (TypeError, ValueError, OverflowError):
            pass
    return min(2 ** (attempt - 1), 5) + random.uniform(0, 0.25)


def systemone(body):
    deadline = time.monotonic() + 60
    encoded = json.dumps(body).encode("utf-8")
    for attempt in range(1, 4):
        remaining = deadline - time.monotonic()
        if remaining <= 0:
            raise TimeoutError("System One retry budget exhausted")
        request = urllib.request.Request(
            "https://api.avalai.ir/v1/systemone",
            data=encoded,
            headers={
                "Authorization": f"Bearer {os.environ['AVALAI_API_KEY']}",
                "Content-Type": "application/json",
            },
            method="POST",
        )
        try:
            with urllib.request.urlopen(
                request, timeout=min(20, remaining)
            ) as response:
                result = json.loads(response.read().decode("utf-8"))
                return result, response.headers.get("avalai-request-id")
        except urllib.error.HTTPError as error:
            error_body = error.read().decode("utf-8", errors="replace")
            request_id = error.headers.get("avalai-request-id")
            retryable = not quota_failure(error_body) and (
                error.code in (408, 429) or 500 <= error.code < 600
            )
            if not retryable or attempt == 3:
                raise RuntimeError(
                    f"HTTP {error.code}; request_id={request_id}; {error_body}"
                ) from error
            headers = error.headers
        except (urllib.error.URLError, TimeoutError) as error:
            if attempt == 3:
                raise RuntimeError(
                    "System One transport failure after three attempts"
                ) from error
            headers = {}
        delay = retry_delay(headers, attempt)
        if delay >= deadline - time.monotonic():
            raise TimeoutError("Retry-After exceeds the remaining retry budget")
        time.sleep(delay)
    raise RuntimeError("System One request did not complete")


result, request_id = systemone(payload)
print("avalai-request-id:", request_id)
print(json.dumps(result, indent=2, ensure_ascii=False))

زمان‌سنجی که به urlopen داده می‌شود، به عملیات مسدودکننده سوکت تعلق دارد و برای خواندن هر پاسخ، مهلت سخت مبتنی بر زمان واقعی تعیین نمی‌کند. بودجه کلی تلاش مجدد، تلاش‌ها و انتظارها را محدود می‌کند؛ اگر سرویس شما برای کل عملیات به مهلت سخت نیاز دارد، از کارخواه HTTP با زمان‌سنج کلی استفاده کنید. پیش از ثبت بدنه خطا در گزارش‌های عملیاتی، اطلاعات حساس را حذف کنید.

JavaScript: Fetch در Node.js ​

از Node.js نسخه ۲۰ یا جدیدتر استفاده کنید. کلید را در محیط سرور نگه دارید و کد را به‌صورت ES module اجرا کنید؛ آن را در کد مرورگر قرار ندهید.

javascript
const apiKey = process.env.AVALAI_API_KEY;
if (!apiKey) throw new Error("Set AVALAI_API_KEY in your environment");

const payload = {
  model: "jev-latest",
  state: "I was charged twice. Please help.",
  questions: {
    route: {
      type: "choice",
      instructions: "Which team should handle this message?",
      criteria: {
        billing: "Payments or invoices",
        technical: "Software or API problems",
        other: "Anything else",
      },
    },
  },
};

function quotaFailure(text) {
  let body;
  try {
    body = JSON.parse(text);
  } catch {
    return false;
  }
  if (!body || typeof body !== "object" || Array.isArray(body)) return false;
  const terminal = new Set(["quota_exceeded", "insufficient_quota"]);
  return [body, body.error].some((item) =>
    item && typeof item === "object" && !Array.isArray(item) &&
    ["code", "type", "error_type"].some((key) => terminal.has(item[key]))
  );
}

function retryDelay(headers, attempt) {
  const value = headers?.get("retry-after")?.trim();
  let delay = Math.min(1000 * 2 ** (attempt - 1), 5000);
  if (value && /^\d+$/.test(value)) {
    delay = Number(value) * 1000;
  } else if (value) {
    const when = Date.parse(value);
    if (Number.isFinite(when)) delay = Math.max(0, when - Date.now());
  }
  return delay + Math.random() * 250;
}

async function systemone(body) {
  const deadline = performance.now() + 60_000;
  for (let attempt = 1; attempt <= 3; attempt += 1) {
    const remaining = deadline - performance.now();
    if (remaining <= 0) throw new Error("System One retry budget exhausted");
    let response;
    let text;
    try {
      response = await fetch("https://api.avalai.ir/v1/systemone", {
        method: "POST",
        headers: {
          Authorization: `Bearer ${apiKey}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify(body),
        signal: AbortSignal.timeout(Math.ceil(Math.min(20_000, remaining))),
      });
      text = await response.text();
    } catch (error) {
      if (attempt === 3) throw error;
    }
    if (response && text !== undefined) {
      const requestId = response.headers.get("avalai-request-id");
      if (response.ok) return { result: JSON.parse(text), requestId };
      const retryable = !quotaFailure(text) && (
        [408, 429].includes(response.status) ||
        (response.status >= 500 && response.status < 600)
      );
      if (!retryable || attempt === 3) {
        throw new Error(`HTTP ${response.status}; request_id=${requestId}; ${text}`);
      }
    }
    const delay = retryDelay(response?.headers, attempt);
    if (delay >= deadline - performance.now()) {
      throw new Error("Retry-After exceeds the remaining retry budget");
    }
    await new Promise((resolve) => setTimeout(resolve, delay));
  }
  throw new Error("System One request did not complete");
}

const { result, requestId } = await systemone(payload);
console.log("avalai-request-id:", requestId);
console.log(JSON.stringify(result, null, 2));

نمونه‌ها پاسخ‌های موقت HTTP 408، 429 و 5xx، از جمله وضعیت ازدحام 529 در سرویس اصلی، و برخی شکست‌های ارتباطی را دوباره امتحان می‌کنند. فیلدهای code، type و error_type را در بدنه خطا و شیء error بررسی می‌کنند و برای quota_exceeded یا insufficient_quota بلافاصله متوقف می‌شوند؛ انتظار، اعتبار حساب را افزایش نمی‌دهد. بدنه اصلی خطا برای تشخیص حفظ می‌شود؛ پیش از اشتراک‌گذاری یا ثبت آن، اطلاعات حساس را حذف کنید.

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

پاسخ کامل ثبت‌شده ​

بررسی Choice برای مسیریابی پشتیبانی با jev-latest، این بدنه JSON کامل را در ۱۴۰۵-۰۸-۰۱ / (2026-10-23)، ساعت ۱۶:۱۱:۳۷ UTC برگرداند:

json
{
  "model": "jev-latest",
  "answers": {
    "route": {
      "type": "choice",
      "choice": "billing",
      "confidence": 1.0,
      "probabilities": {
        "technical": 0.0,
        "other": 0.0
      }
    }
  },
  "usage": {
    "input_tokens": 333,
    "output_tokens": 38
  },
  "estimated_cost": {
    "unit": "0.0000139860",
    "irt": 3.78,
    "exchange_rate": 270000
  }
}

مقدار هدر avalai-request-id برای این درخواست 01a16988-3487-7b81-b0e8-122228180f1c بود. بررسی jev-preview نیز HTTP 200 برگرداند، مقدار "model": "jev-preview" را در پاسخ قرار داد و در آن نمونه، پاسخ، تعداد توکن‌ها و هزینه یکسانی داشت؛ شناسه درخواست آن 01a16988-5bd1-7931-a0ff-cc06d6cc9bde بود.

در این بررسی‌ها، درگاه نام مستعار درخواست‌شده را بازگرداند. نسخه نهایی یا id در سطح بالای پاسخ وجود نداشت و نگاشت probabilities شامل billing نبود. این فیلدها را به پاسخی که به‌عنوان پاسخ ثبت‌شده ارائه می‌شود اضافه نکنید.

بدنه نمایش‌داده‌شده، یک درخواست ثبت‌شده است و دقت، تأخیر، تعداد توکن یا نرخ تبدیل قیمت را تضمین نمی‌کند. نرخ ارز و برآورد پول محلی می‌تواند تغییر کند.

دامنه بررسی زنده ​

در تاریخ ۱۴۰۵-۰۸-۰۱ / (2026-10-23)، کاربر شش حالت بومی را برای هر نام مستعار در api.avalai.ir اجرا کرد: هر ۱۲ درخواست System One، وضعیت HTTP 200 برگرداند و اعتبارسنجی پاسخ نوع‌دار را گذراند. چهار درخواست دیگر Decisions نیز موفق بودند؛ در مجموع ۱۶ بررسی موفق در دو نقطه پایانی انجام شد.

حالت بومیشکل درخواست بررسی‌شدهنام‌های مستعار بررسی‌شده
مسیریابی پشتیبانییک Choice با داده رشته‌ای؛ پاسخ کامل آن در بالا آمده است.jev-latest، jev-preview
مرجع مؤلفه‌هاScore و Noul در یک درخواست با داده رشته‌ای؛ معیارهای مرتب Score و معیارهای صریح true و false در Noul.jev-latest، jev-preview
بازیابی و استناددو Score و یک Choice با شیء JSON.jev-latest، jev-preview
نشانه محافظتییک Noul با شیء JSON، همراه دستورالعمل و بدون معیار.jev-latest، jev-preview
معیار وزن‌داردو Score مستقل با شیء JSON.jev-latest، jev-preview
پیشنهاد تابع مناسبیک Choice با شیء JSON؛ اجرا و بررسی مجوز همچنان بر عهده کد برنامه است.jev-latest، jev-preview

این درخواست‌های مصنوعی، سازگاری بدنه‌های بررسی‌شده را نشان می‌دهند. همه ورودی‌ها، داده آرایه‌ای، همه SDKها، رفتار تلاش مجدد خودکار در سرویس زنده، دقت کار عملیاتی، ظرفیت محدودیت نرخ یا قابلیت‌های اختیاری بومی را اعتبارسنجی نمی‌کنند. برای جریان‌های متناظر، دستورکار عملی Jev را ببینید.

فیلدهای پاسخ ​

فیلدمعنا
modelفراداده مدل پاسخ. در بررسی‌های ثبت‌شده، نام مستعار درخواست‌شده بود؛ برای آشکار شدن نسخه نهایی به آن تکیه نکنید.
answersنگاشت شناسه پرسش به پاسخ نوع‌دار. وجود هر شناسه موردنیاز را بررسی کنید.
usage.input_tokensمصرف توکن ورودی گزارش‌شده برای درخواست. محتوای قابل‌صورتحساب درخواست را شامل می‌شود و فقط تعداد نویسه‌های پیام نیست.
usage.output_tokensتوکن خروجی گزارش‌شده؛ رایگان بودن خروجی این شمارش را حذف نمی‌کند.
estimated_cost.unitهزینه دلاری برآوردشده AvalAI که در پاسخ ثبت‌شده به‌صورت رشته اعشاری آمده است.
estimated_cost.irtهزینه برآوردشده به تومان ایران با نرخ ارز گزارش‌شده.
estimated_cost.exchange_rateنرخ ارزی که برای برآورد پول محلی استفاده شده است.

وقتی دقت حسابداری مهم است، مقدارهای پولی اعشاری را به‌صورت نوع اعشاری یا رشته نگه دارید. هزینه را از طریق API کاربر تطبیق دهید و هزینه این نمونه را هزینه ثابت هر درخواست ندانید. برای پشتیبانی، هدر پاسخ avalai-request-id را ثبت کنید؛ مقدارهای X-Request-ID در واسطه‌ها ممکن است متفاوت باشند. هدرهای پاسخ را ببینید.

پیش از استفاده، پاسخ را اعتبارسنجی کنید ​

پاسخ را مستقل از موفقیت HTTP بررسی کنید:

  • وجود شیء JSON، شیء answers و همه شناسه‌های پرسشی را که کد به آن‌ها وابسته است الزامی بدانید.
  • type پاسخ را با مؤلفه درخواست‌شده مطابقت دهید.
  • در Choice، مقدار choice باید از گزینه‌های مجاز باشد. اگر از اطمینان استفاده می‌کنید، عددی متناهی بین ۰ و ۱ بخواهید. مقدارهای احتمال موجود را اعتبارسنجی کنید و ناقص بودن نگاشت را حفظ کنید.
  • در Score، score باید عددی متناهی بین 0 و n - 1 باشد؛ پیش از تفسیر، شکل مورد انتظار راهنمای سطح‌ها و کلیدهای احتمال را بررسی کنید. مقدار عددی غایب را صفر نگذارید.
  • در Noul، مقدار noul باید عددی متناهی بین ۰ و ۱ باشد. به دنبال فیلد اطمینان جداگانه نباشید.
  • پاسخ غایب، نوع غیرمنتظره، برچسب ناشناخته، مقدار نامعتبر و کمبود داده را به مسیر صریح خطا یا بازبینی بفرستید.

اطمینان، توزیع مدل را توصیف می‌کند و جایگزین اندازه‌گیری دقت کار نیست. آستانه‌ها را با نمونه‌های نماینده انگلیسی و فارسی تنظیم کنید، حالت‌های مبهم و خارج از دامنه را در ارزیابی بگنجانید و اقدام‌های مهم را به سیاست برنامه وابسته نگه دارید. راهنمای مدل‌های تصمیم‌گیری ارزیابی و مسیرهای بازبینی را توضیح می‌دهد.

محدودیت‌ها و قابلیت‌های اختیاری بومی ​

سرویس اصلی، محدودیت پیش‌فرض 64k توکن برای هر درخواست (state به‌علاوه همه پرسش‌ها) و 32k توکن برای هر پرسش (state به‌علاوه همان پرسش) را مستند کرده است. این‌ها دو محدودیت جداگانه‌اند و نباید با هم جمع شوند. در سرویس اصلی محدودیت جداگانه‌ای برای تعداد پرسش‌ها وجود ندارد؛ اندازه درخواست و زمینه همچنان ارسال گروهی را محدود می‌کنند.

قواعد رسمی درخواست بومی، بدنه حداکثر ۳۲ MiB، عددهای متناهی JSON، UTF-8 بدون نشان ترتیب بایت و حداکثر ۶۴ سطح تو‌در‌توی شیء یا آرایه در داده، دستورالعمل و معیارها را نیز مشخص می‌کنند. این‌ها قواعد سرویس اصلی هستند؛ محدودیت AvalAI یا واسطه‌ها می‌تواند کمتر باشد. با JSON متنی کوچک و فشرده‌نشده شروع کنید و در صورت رد درخواست، داده غیرضروری را کاهش دهید.

سرویس اصلی، قابلیت اختیاری زمینه بلند و قابلیت‌های آزمایشی تصویر و Box را منتشر کرده است. عبور هدرها، پردازش دارایی‌ها، صورتحساب و رفتار پاسخ آن‌ها از طریق AvalAI با بررسی‌های متنی این صفحه تأیید نشده است. درخواست‌های قابل‌اجرای این مرجع، این قابلیت‌ها را اثبات نمی‌کنند. پیش از وابسته شدن به آن‌ها، سازگاری را جداگانه بررسی کنید؛ نکات ارائه‌دهنده را ببینید.

خطاها و عیب‌یابی ​

بدنه خطای AvalAI می‌تواند شیء error با فیلدهای message، type، param، code و request_id داشته باشد؛ TYPESAFE AI در سرویس اصلی ممکن است جزئیات اعتبارسنجی را با ساختار دیگری برگرداند. مستند شدن HTTP 422 در سرویس اصلی، یکسان بودن وضعیت یا بدنه در AvalAI را تضمین نمی‌کند. پیش از دسته‌بندی شکست، وضعیت واقعی و JSON بدون اطلاعات حساس را ثبت کنید.

نشانه یا وضعیتنخست چه چیزی را بررسی کنید؟ارسال مجدد بدون تغییر؟
400 یا 422، درخواست نامعتبرنقطه پایانی درست، نام مستعار مدل، شکل state، نگاشت غیرخالی پرسش، type، دستورالعمل و معیار متناسب با نوع.خیر
رد زمینه یا حجم، از جمله 413داده، محتوای پرسش یا حجم بدنه را کاهش دهید؛ فقط زمانی تقسیم کنید که داده کافی برای قضاوت باقی بماند.خیر
401هدر Bearer و کلید AvalAI که برنامه بارگذاری کرده است.خیر
403مجوز حساب و دسترسی به مدل.خیر
415JSON فشرده‌نشده با Content-Type: application/json بفرستید.خیر
429 با quota_exceeded یا insufficient_quotaموجودی اعتبار، سهمیه حساب و جزئیات صورتحساب.خیر؛ وضعیت حساب را برطرف کنید
408، 429 یا 5xx موقتشناسه درخواست، تأخیر اعلام‌شده سرور، محدودیت نرخ و وضعیت موقت سرویس.با پس‌روی زمانی محدود و تأخیر تصادفی
شکست اتصال یا پایان زمان‌سنجمسیر شبکه و بودجه زمان؛ ممکن است سرور درخواست را قبلاً پردازش کرده باشد.با سیاست محدود
HTTP 200 با پاسخ غایب یا نامعتبربدنه کامل را اعتبارسنجی کنید و نمونه تشخیصی بدون اطلاعات حساس را نگه دارید.ناسازگاری قالب را بی‌صدا نپذیرید یا دوباره ارسال نکنید

یک اشتباه رایج، فرستادن criteria در Choice به‌صورت آرایه است. حذف instructions به دلیل گویا بودن شناسه پرسش نیز می‌تواند معنای قضاوت موردنظر را مبهم کند، هرچند قرارداد اصلی حذف این فیلد یا null را می‌پذیرد. در Score، توضیح‌ها باید در آرایه مرتب باشند؛ در Noul، معیارهای اختیاری از true و false استفاده می‌کنند.

نقطه پایانی، نام مستعار انتخاب‌شده، وضعیت، تأخیر، تعداد تلاش مجدد و avalai-request-id را در صورت دریافت ثبت کنید. اعتبارنامه و داده خام غیرضروری را در گزارش‌ها نگه ندارید. صرفاً برای تشخیص شکست اعتبارسنجی، درخواست زنده نامرتبط اجرا نکنید. برای سیاست عمومی AvalAI، مدیریت خطا را ببینید.

راهنماهای مرتبط و منابع رسمی ​

منابع رسمی، رفتار سرویس اصلی را توضیح می‌دهند. نگاشت‌ها و قیمت AvalAI از اعلام این انتشار آمده‌اند؛ پاسخ ثبت‌شده دقیقاً مشخص می‌کند کدام رفتار بومی از طریق AvalAI مشاهده شده است.