گردشکارهای Stateful با Responses API
Responses API زمانی کاربردی است که بخواهید API وضعیت گفتگو، ابزارهای میزبانیشده و ورودیهای چندوجهی را بدون بازسازی کامل تاریخچه پیامها در هر نوبت مدیریت کند. این مثال الگوهای عملی ادامه دادن گفتگو، شاخهسازی از پاسخ قبلی و بررسی پاسخها را از طریق AvalAI نشان میدهد.
این راهنما با اقتباس از OpenAI Cookbook رسمی و دفترچه نمونه Responses API، همراه با تغییرات لازم برای endpoint و کلید API در AvalAI تهیه شده است.
چه زمانی از این الگو استفاده کنیم
- میخواهید بدون ارسال دوباره کل تاریخچه، گفتگو را ادامه دهید.
- لازم است از یک پاسخ قبلی شاخه جدیدی بسازید و مسیر دیگری را امتحان کنید.
- یک سطح API واحد برای تولید متن و ابزارهایی مانند جستجوی وب میخواهید.
- در حال مهاجرت از Chat Completions هستید و مدل سادهتری برای مدیریت state میخواهید.
آمادهسازی
SDK رسمی OpenAI را نصب و کلید AvalAI را تنظیم کنید:
pip install openai
export AVALAI_API_KEY="your-avalai-api-key"برای Node.js:
npm install openai
export AVALAI_API_KEY="your-avalai-api-key"گفتگوی Stateful پایه
ابتدا یک response بسازید و سپس با previous_response_id آن را ادامه دهید.
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["AVALAI_API_KEY"],
base_url="https://api.avalai.ir/v1",
)
first = client.responses.create(
model="gpt-5.5",
input="Give me a concise deployment checklist for a small API service.",
)
print(first.output_text)
follow_up = client.responses.create(
model="gpt-5.5",
input="Now turn that checklist into five acceptance criteria.",
previous_response_id=first.id,
)
print(follow_up.output_text)import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.AVALAI_API_KEY,
baseURL: "https://api.avalai.ir/v1",
});
const first = await client.responses.create({
model: "gpt-5.5",
input: "Give me a concise deployment checklist for a small API service.",
});
console.log(first.output_text);
const followUp = await client.responses.create({
model: "gpt-5.5",
input: "Now turn that checklist into five acceptance criteria.",
previous_response_id: first.id,
});
console.log(followUp.output_text);FIRST_RESPONSE=$(curl https://api.avalai.ir/v1/responses \
-H "Authorization: Bearer $AVALAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.5",
"input": "Give me a concise deployment checklist for a small API service."
}')
FIRST_ID=$(printf "%s" "$FIRST_RESPONSE" | jq -r ".id")
curl https://api.avalai.ir/v1/responses \
-H "Authorization: Bearer $AVALAI_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"model\": \"gpt-5.5\",
\"input\": \"Now turn that checklist into five acceptance criteria.\",
\"previous_response_id\": \"$FIRST_ID\"
}"تصمیمهای State، نگهداری و هزینه
previous_response_id سادهترین راه برای ادامه دادن یک thread است، اما همچنان به state سمت سرویس تکیه دارد. انتخاب state را صریح کنید:
- وقتی میخواهید AvalAI از یک response ذخیرهشده سمت سرور ادامه دهد، از
previous_response_idاستفاده کنید. - وقتی کنترل دقیق retention، replay قطعی یا fallback برای مسیرهایی لازم است که response قبلی را resolve نمیکنند، تاریخچه را دستی نگه دارید.
- برای CI، eval یا دیباگ حساس، مگر اینکه retrieval بعدی لازم دارید،
store=falseبگذارید. - اگر continuation به دلیل resolve نشدن response قبلی شکست خورد، درخواست را با context کامل و بدون
previous_response_idدوباره ارسال کنید. - برای کل زنجیره بودجه بگذارید: input قبلی در thread همچنان میتواند بهعنوان input token حساب شود و مدلهای reasoning نیز reasoning token را داخل context window مصرف میکنند.
history = [{"role": "user", "content": "Draft a rollback checklist for a payment API."}]
first = client.responses.create(
model="gpt-5.5",
input=history,
store=False,
)
# فقط output_text را نگه ندارید؛ آیتمهای ساختاریافته خروجی را حفظ کنید.
history.extend(first.output)
history.append(
{"role": "user", "content": "Now make it safe for a junior on-call engineer."}
)
second = client.responses.create(
model="gpt-5.5",
input=history,
store=False,
)
print(second.output_text)const history = [
{ role: "user", content: "Draft a rollback checklist for a payment API." },
];
const first = await client.responses.create({
model: "gpt-5.5",
input: history,
store: false,
});
// فقط output_text را نگه ندارید؛ آیتمهای ساختاریافته خروجی را حفظ کنید.
history.push(...first.output);
history.push({
role: "user",
content: "Now make it safe for a junior on-call engineer.",
});
const second = await client.responses.create({
model: "gpt-5.5",
input: history,
store: false,
});
console.log(second.output_text);شاخهسازی از یک پاسخ قبلی
شاخهسازی به شما اجازه میدهد از یک پاسخ قبلی مسیر جدیدی بسازید، بدون اینکه مسیر اصلی را تغییر دهید. این کار برای A/B تست پرامپت، تولید لحنهای متفاوت یا تلاش دوباره با محدودیت جدید مفید است.
forked = client.responses.create(
model="gpt-5.5",
input=(
"Use the same original checklist, but rewrite it for a solo developer "
"who deploys manually once per week."
),
previous_response_id=first.id,
)
print(forked.output_text)const forked = await client.responses.create({
model: "gpt-5.5",
input:
"Use the same original checklist, but rewrite it for a solo developer who deploys manually once per week.",
previous_response_id: first.id,
});
console.log(forked.output_text);curl https://api.avalai.ir/v1/responses \
-H "Authorization: Bearer $AVALAI_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"model\": \"gpt-5.5\",
\"input\": \"Use the same original checklist, but rewrite it for a solo developer who deploys manually once per week.\",
\"previous_response_id\": \"$FIRST_ID\"
}"دریافت دوباره یک Response ذخیرهشده
برای لاگگیری، دیباگ یا پردازش با تاخیر بعد از یک گردشکار پسزمینه، میتوانید response را دوباره دریافت کنید. اگر retrieval بعدی لازم دارید، response را با store=true بسازید؛ در غیر این صورت store=false را ترجیح دهید و فقط فیلدهای مورد نیاز برنامه را نگه دارید.
stored = client.responses.retrieve(first.id)
print(stored.id)
print(stored.output_text)const stored = await client.responses.retrieve(first.id);
console.log(stored.id);
console.log(stored.output_text);curl "https://api.avalai.ir/v1/responses/$FIRST_ID" \
-H "Authorization: Bearer $AVALAI_API_KEY"افزودن جستجوی وب
وقتی پاسخ به اطلاعات تازه نیاز دارد، ابزار web_search را اضافه کنید. اگر رابط کاربری شما به لینک منبع نیاز دارد، در پرامپت صریحا درخواست citation کنید.
response = client.responses.create(
model="gpt-5.5",
input="Find the latest AvalAI documentation updates and summarize them with sources.",
tools=[{"type": "web_search"}],
)
print(response.output_text)
for item in response.output:
print(item.type)const response = await client.responses.create({
model: "gpt-5.5",
input:
"Find the latest AvalAI documentation updates and summarize them with sources.",
tools: [{ type: "web_search" }],
});
console.log(response.output_text);
for (const item of response.output) {
console.log(item.type);
}curl https://api.avalai.ir/v1/responses \
-H "Authorization: Bearer $AVALAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.5",
"input": "Find the latest AvalAI documentation updates and summarize them with sources.",
"tools": [{"type": "web_search"}]
}'نکات Production
- فقط وقتی response ID را ذخیره کنید که واقعا به ادامه دادن یا audit گفتگو نیاز دارید.
- اگر کنترل دقیق retention، deletion یا compliance لازم دارید، تاریخچه گفتگو را در سیستم خودتان نگه دارید.
- هنگام replay دستی state، آیتمهای ساختاریافته
response.outputرا append کنید تا tool callها و reasoning itemها حفظ شوند. - برای گردشکارهای قابل پیشبینی، instructionهای ثابت را پایدار نگه دارید و جزئیات متغیر کاربر را در آخرین input قرار دهید.
- هنگام استفاده از ابزارها،
response.outputرا بررسی کنید؛output_textبرای متن نهایی ساده است، اما tool callها و annotationها در آیتمهای ساختاریافته خروجی قرار دارند. response.id، مدل، latency وusageرا لاگ کنید تا بررسی هزینه و پشتیبانی سادهتر شود.