پردازش پسزمینه
استدلال طولانی، deep research، تحلیل کد و تولید گزارش ممکن است از timeout مرورگر، proxy یا کلاینت موبایل عبور کند. الگوی background mode در OpenAI یک task از Responses را بهصورت async شروع میکند، به کلاینت اجازه میدهد شی Response را poll کند، و در صورت پشتیبانی میتواند از یک اجرای durable پسزمینه stream کند. در AvalAI، background Responses میزبانیشده را وابسته به route، مدل و حساب بدانید؛ وقتی background: true یا cancellation پاسخ در دسترس نیست، از fallback مدیریتشده در برنامه استفاده کنید.
هشدار
ویژگی پیادهسازی نشده!
این قابلیت در حال حاضر در حال توسعه است و هنوز در AvalAI در دسترس نیست. ما انتشار آن را از طریق کانالهای رسمی خود اعلام خواهیم کرد. منتظر بهروزرسانیهای ما باشید!
چه زمانی استفاده کنیم
پردازش پسزمینه برای این موارد مناسب است:
- پاسخهایی که ممکن است چند دقیقه طول بکشند، بهخصوص reasoning با effort بالا یا deep research؛
- workflowهایی که بسته شدن تب نباید job را از بین ببرد؛
- taskهای قابل queue که progress UI، retry یا cancellation میخواهند؛
- عملیاتهایی که کلاینت میتواند بهجای باز نگه داشتن اتصال HTTP با ID وضعیت را poll کند.
برای turnهای کوتاه چت که latency فوری مهم است، از Responses عادی synchronous یا streaming استفاده کنید.
Background Responses میزبانیشده
وقتی route انتخابی شما در AvalAI از background mode به سبک OpenAI پشتیبانی کند، Response را با background: true بسازید و store: true را نگه دارید. Background mode برای retrieve بعدی به state ذخیرهشده پاسخ وابسته است.
قبل از استفاده در production، برای همان مدل و route یک تست سازگاری کوچک اجرا کنید. رفتار مرجع OpenAI فقط برای Responseهای ذخیرهشده background: true را میپذیرد، retrieve یا cancellation را با Response ID انجام میدهد، و queued / in_progress را وضعیت غیرنهایی میداند. AvalAI این الگو را جایی ارائه میکند که route بالادستی پشتیبانی کند؛ در غیر این صورت از fallback مدیریتشده در برنامه استفاده کنید.
import os
import time
from openai import OpenAI
client = OpenAI(
api_key=os.environ["AVALAI_API_KEY"],
base_url="https://api.avalai.ir/v1",
)
response = client.responses.create(
model="gpt-5.5",
input="Produce a detailed migration plan for this monorepo.",
background=True,
store=True,
)
while response.status in {"queued", "in_progress"}:
print(f"Current status: {response.status}")
time.sleep(2)
response = client.responses.retrieve(response.id)
print(response.status)
print(response.output_text)import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.AVALAI_API_KEY,
baseURL: "https://api.avalai.ir/v1",
});
let response = await client.responses.create({
model: "gpt-5.5",
input: "Produce a detailed migration plan for this monorepo.",
background: true,
store: true,
});
while (response.status === "queued" || response.status === "in_progress") {
console.log(`Current status: ${response.status}`);
await new Promise((resolve) => setTimeout(resolve, 2000));
response = await client.responses.retrieve(response.id);
}
console.log(response.status);
console.log(response.output_text);curl https://api.avalai.ir/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AVALAI_API_KEY" \
-d '{
"model": "gpt-5.5",
"input": "Produce a detailed migration plan for this monorepo.",
"background": true,
"store": true
}'اگر route پارامتر background را reject کرد، آن را حذف کنید و از queue worker خودتان استفاده کنید. یک درخواست چنددقیقهای را بیصدا به حالت synchronous retry نکنید، مگر اینکه تجربه کاربر ریسک timeout را تحمل کند.
چکلیست تست سازگاری
پیش از وعده دادن رفتار background میزبانیشده به کاربران، route، مدل، نسخه SDK و tier حساب دقیق در AvalAI را بررسی کنید:
| تست | نتیجه مورد انتظار |
|---|---|
ساخت با background: true و store: true | یک Response ID و status مثل queued یا in_progress برگرداند. |
| retrieve با Response ID | همان Response را تا رسیدن به وضعیت نهایی برگرداند. |
| poll تا تکمیل | از queued / in_progress خارج شود و به completed، failed، cancelled، incomplete یا expired برسد. |
| cancel هنگام in progress | وضعیت نهایی cancelled یا Response از قبل نهاییشده را برگرداند؛ cancelهای تکراری امن باشند. |
stream با background: true و stream: true | eventهای تایپشده Responses با مقدارهای sequence_number قابل ذخیره emit کند. |
resume stream با starting_after | وقتی route از stream resume پشتیبانی میکند از آخرین cursor ادامه دهد؛ در غیر این صورت به job stream محلی خودتان برگردید. |
نتیجه probeها را در یادداشتهای deployment ذخیره کنید. اگر یک probe شکست خورد، بهجای القای پشتیبانی میزبانیشده، fallback مدیریتشده در برنامه را برای همان قابلیت مستند کنید.
Polling امن
وقتی یک background Response میزبانیشده را poll میکنید، poller را ساده و محدود نگه دارید:
- با Response ID poll کنید، نه با تکرار prompt اصلی؛
- برای ترافیک بالا از exponential backoff همراه jitter استفاده کنید، نه حلقه ثابت و تنگ؛
- روی همه وضعیتهای نهایی polling را متوقف کنید، نه فقط
completed؛ - Response ID نهایی، status،
x-request-id، مدل و usage را در رکورد job خودتان ذخیره کنید؛ - خروجی نهایی را پیش از پایان پنجره نگهداری میزبانیشده کپی کنید؛
- اگر polling از SLA محصول شما عبور کرد، در UI وضعیت timeout را نمایش دهید.
اگر route شما در AvalAI برای این workflow از webhook پشتیبانی میکند، webhook را برای terminal کردن job ترجیح دهید و polling را بهعنوان fallback کاربرمحور نگه دارید.
مدیریت وضعیتهای نهایی
خروجی مدل را فقط بعد از خروج Response از queued و in_progress parse کنید. هر وضعیت نهایی را صریح مدیریت کنید تا UI، منطق retry و رکوردهای billing سازگار بمانند:
| وضعیت | اقدام پیشنهادی |
|---|---|
completed | output_text، usage، citationها و tool outputها را بخوانید؛ سپس job محلی را کامل علامت بزنید. |
failed | پیام خطای امن، request ID و قابلیت retry را ذخیره کنید؛ کارهای non-idempotent را خودکار retry نکنید. |
cancelled | نشان دهید کاربر یا سیستم job را متوقف کرده است؛ خروجی دیررس worker را در fallback in-flight نادیده بگیرید. |
incomplete یا expired | آن را خروجی نهایی ندانید؛ با task کوچکتر، دستور دقیقتر یا queue مدیریتشده در برنامه retry کنید. |
برای background mode میزبانیشده، store: true را نگه دارید؛ OpenAI upstream نمونهگیری background بدون state را رد میکند. اگر AvalAI یا provider انتخابی state ذخیرهشده background را برای آن route ارائه نمیکند، به job table خودتان برگردید و Responses را با store: false فراخوانی کنید.
Fallback مدیریتشده در برنامه
الگوی portable در AvalAI این است که یک رکورد job محلی ذخیره کنید، فراخوانی مدل را در worker اجرا کنید، و endpoint polling را از برنامه خودتان ارائه دهید.
import os
import uuid
from dataclasses import dataclass
from openai import OpenAI
client = OpenAI(
api_key=os.environ["AVALAI_API_KEY"],
base_url="https://api.avalai.ir/v1",
)
@dataclass
class Job:
id: str
status: str = "queued"
output_text: str | None = None
error: str | None = None
request_id: str | None = None
jobs: dict[str, Job] = {}
def create_job(prompt: str) -> Job:
job = Job(id=f"job_{uuid.uuid4().hex}")
jobs[job.id] = job
try:
job.status = "in_progress"
response = client.responses.create(
model="gpt-5.5",
input=prompt,
store=False,
)
job.request_id = response.id
job.output_text = response.output_text
job.status = "completed"
except Exception as exc:
job.error = str(exc)
job.status = "failed"
return job
job = create_job("Draft a security review checklist for this API.")
print(job.id, job.status)import OpenAI from "openai";
import crypto from "node:crypto";
const client = new OpenAI({
apiKey: process.env.AVALAI_API_KEY,
baseURL: "https://api.avalai.ir/v1",
});
const jobs = new Map();
async function createJob(prompt) {
const job = {
id: `job_${crypto.randomUUID().replaceAll("-", "")}`,
status: "queued",
outputText: null,
error: null,
requestId: null,
};
jobs.set(job.id, job);
try {
job.status = "in_progress";
const response = await client.responses.create({
model: "gpt-5.5",
input: prompt,
store: false,
});
job.requestId = response.id;
job.outputText = response.output_text;
job.status = "completed";
} catch (error) {
job.error = String(error);
job.status = "failed";
}
return job;
}
const job = await createJob("Draft a security review checklist for this API.");
console.log(job.id, job.status);در production، create_job را به worker queue واقعی مثل Celery، BullMQ، Sidekiq، SQS یا سیستم job داخلی خودتان منتقل کنید. درخواست API فقط باید job را بسازد و ID آن را برگرداند.
Streaming و اتصال دوباره
اگر background streaming میزبانیشده در دسترس است، response را با هر دو مقدار background: true و stream: true بسازید، سپس sequence_number هر event را ذخیره کنید تا کلاینت بتواند از آخرین cursor دوباره وصل شود. اگر این قابلیت در دسترس نیست، progress را از job table خودتان stream کنید:
queued: درخواست پذیرفته شده و منتظر worker است؛in_progress: فراخوانی مدل شروع شده است؛completed: پاسخ نهایی ذخیره شده و آماده دریافت است؛failed: کلاس خطا و پیام امن ذخیره شده است؛cancelled: کاربر پیش از تکمیل job را لغو کرده است.
اگر upstream خروجی جزئی مدل را برنگردانده، partial output اختراع نکنید. پیامهای progress باید وضعیت job را توضیح دهند، نه محتوای ساختگی پاسخ.
background streaming میزبانیشده از رویدادهای تایپشده Responses استفاده میکند. آخرین sequence_number هر رویداد را ذخیره کنید؛ اگر اتصال قطع شد و route از resume پشتیبانی میکند، با starting_after دوباره وصل شوید تا UI از آخرین رویداد دیدهشده ادامه دهد.
stream = client.responses.create(
model="gpt-5.5",
input="یک گزارش پژوهش بازار طولانی همراه citation بنویس.",
background=True,
stream=True,
store=True,
)
last_sequence_number = None
for event in stream:
print(event.type)
last_sequence_number = getattr(event, "sequence_number", last_sequence_number)
# اگر stream قطع شد، last_sequence_number را همراه job محلی ذخیره کنید.
# پشتیبانی resume به route/SDK وابسته است؛ اگر در دسترس نبود از job stream برنامه خودتان استفاده کنید.const stream = await client.responses.create({
model: "gpt-5.5",
input: "یک گزارش پژوهش بازار طولانی همراه citation بنویس.",
background: true,
stream: true,
store: true,
});
let lastSequenceNumber = null;
for await (const event of stream) {
console.log(event.type);
lastSequenceNumber = event.sequence_number ?? lastSequenceNumber;
}
// اگر stream قطع شد، lastSequenceNumber را همراه job محلی ذخیره کنید.
// پشتیبانی resume به route/SDK وابسته است؛ اگر در دسترس نبود از job stream برنامه خودتان استفاده کنید.# یک background stream بسازید.
curl https://api.avalai.ir/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AVALAI_API_KEY" \
-d '{
"model": "gpt-5.5",
"input": "یک گزارش پژوهش بازار طولانی همراه citation بنویس.",
"background": true,
"stream": true,
"store": true
}'
# اگر route از resume پشتیبانی میکند، از آخرین cursor دوباره وصل شوید.
curl "https://api.avalai.ir/v1/responses/resp_123?stream=true&starting_after=42" \
-H "Authorization: Bearer $AVALAI_API_KEY"Cancellation و Idempotency
Cancellation میزبانیشده، وقتی پشتیبانی شود، یک background Response در حال اجرا را با ID لغو میکند. برای fallback مدیریتشده در برنامه، cancellation باید وضعیت job محلی را cancelled کند، کار queueشده را پیش از شروع متوقف کند، و اگر فراخوانی مدل از قبل in-flight بود خروجی دیررس worker را نادیده بگیرد.
cancelled = client.responses.cancel("resp_123")
print(cancelled.status)const cancelled = await client.responses.cancel("resp_123");
console.log(cancelled.status);curl -X POST https://api.avalai.ir/v1/responses/resp_123/cancel \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AVALAI_API_KEY"Cancellation باید idempotent باشد: اگر route میزبانیشده از قبل به وضعیت نهایی رسیده باشد، درخواست cancel تکراری باید همان Response نهایی یا رکورد نهایی معادل را برگرداند. برای لغو فراخوانی synchronous غیر background، اتصال کلاینت را ببندید و action را طوری طراحی کنید که retry بعدی امن باشد.
برای actionهایی که ممکن است retry شوند از idempotency key یا کلید job قطعی استفاده کنید. مدل، نسخه prompt، user ID و زمان ایجاد را ذخیره کنید تا کلیکهای تکراری jobهای پرهزینه تکراری نسازند.
محدودیتهای عملیاتی
راهنمای مرجع OpenAI چند محدودیت مهم دارد که هنگام تطبیق الگو با AvalAI مفید است:
- background sampling به state ذخیرهشده Response نیاز دارد؛ درخواست background بدون state در upstream رد میشود.
- stream پسزمینه فقط وقتی قابل resume است که Response از ابتدا با
stream: trueساخته شده باشد. - زمان رسیدن به اولین token در background stream میتواند از streamهای synchronous بیشتر باشد.
- داده polling فقط مدت کوتاهی نگهداری میشود، بنابراین نتیجه نهایی را پیش از پایان پنجره نگهداری میزبانیشده در رکورد job خودتان کپی کنید.
نکات نگهداری داده
background mode مرجع OpenAI برای امکان polling، داده Response را حدود ۱۰ دقیقه ذخیره میکند، بنابراین با انتظارات سختگیرانه zero-data-retention سازگار نیست. OpenAI اشاره میکند که background=true ممکن است برای پروژههای ZDR قدیمی همچنان پذیرفته شود، اما استفاده از آن تضمینهای ZDR را میشکند؛ پروژههای Modified Abuse Monitoring (MAM) وقتی حساب و route پشتیبانی کنند میتوانند به background mode تکیه کنند. در AvalAI این موضوع را وابسته به provider، حساب و route بدانید و پیش از اعلام وضعیت compliance به مشتری، مسیر انتخابی را تأیید کنید.
برای پروژههای AvalAI با محدودیت نگهداری داده:
- fallback مدیریتشده در برنامه را با
store: falseترجیح دهید؛ - فقط metadata و پاسخ نهایی مجاز طبق policy خودتان را ذخیره کنید؛
- jobهای failed یا expired را طبق زمانبندی حذف کنید؛
- فقط چون کار async است، secretها را داخل prompt قرار ندهید.