راهنماها
چکلیست اتصال در محیط اصلی
کارهایی که یکپارچهسازی با مهوش را در عمل قابلاعتماد میکنند: نگهداری secretها، timeout، تکرار request، ثبت لاگ و پایش، اجرای پسزمینه، webhookها، تنظیم SDK و مدیریت داده؛ بههمراه یک چکلیست برای مرور پیش از انتشار.
پیش از انتشار
پیش از آنکه کاربران واقعی به یکپارچهسازی شما وابسته شوند، این موارد را بررسی کنید:
- API key پروژه فقط روی سرور شما و در سامانهٔ مدیریت secretهاست و کمترین scope لازم را دارد.
- staging و production پروژهها و کلیدهای جداگانه دارند.
- مدل از
GET /v1/modelsیا باautoانتخاب میشود و کد شما خطایprovider_unavailableرا مدیریت میکند. - هر فراخوانی هم timeout اتصال و هم timeout کلی دارد.
- طول خروجی (
max_output_tokens)، حجم فایلها و طول ورودی کاربر محدود شده است. - در تکرار request از همان
Idempotency-Keyاستفاده میشود و نتیجههای مبهم بررسی میشوند، نه اینکه دوباره فرستاده شوند. - در لاگها
X-Request-ID، وضعیت و زمان پاسخ ثبت میشود؛ هرگز prompt، فایل، کلید یا token. - یک پاسخ موفق، یک خطای اعتبارسنجی، یک خطای محدودیت نرخ و یک قطع stream را در پروژهای غیر از production آزمودهاید.
- محدودیتهای پروژه و بودجهٔ ماهانه تنظیم شدهاند تا یک باگ نتواند هزینهٔ بیحساب بسازد.
timeout و تکرار request
timeoutها را صریح تعیین کنید. یک مدل استدلالی یا یک سند طولانی ممکن است خیلی بیشتر از یک فراخوانی معمولی HTTP طول بکشد؛ پس بهجای یک عدد برای همهچیز، برای هر نوع عملیات محدودیت جداگانه بگذارید و برای کارهایی که ممکن است چند دقیقه طول بکشند، اجرای پسزمینه را ترجیح دهید.
const response = await fetch("https://api.mahvashai.ir/v1/responses", {
method: "POST",
headers: {
Authorization: "Bearer " + process.env.MAHVASH_API_KEY,
"Content-Type": "application/json",
"Idempotency-Key": job.idempotencyKey,
"X-Request-ID": job.traceId,
},
body: JSON.stringify({ model: job.model, input: job.input, max_output_tokens: 800 }),
signal: AbortSignal.timeout(90_000),
});
logger.info("mahvash call", {
status: response.status,
requestId: response.headers.get("X-Request-ID"), // log this, never the prompt or key
});- به
429وRetry-Afterاحترام بگذارید و برای429و5xxفاصلهٔ تلاشها را بهتدریج و با کمی تصادفیسازی بیشتر کنید. - timeout پس از فرستادن request مبهم است. پیش از فرستادن کار پولی تازه، response را بازیابی کنید یا با همان idempotency key دوباره بفرستید.
- تعداد کارهای همزمان را در سمت خودتان هم محدود کنید. مهوش runهای بیشتر از
max_active_runsرا نمیپذیرد؛ صف کردن کارها در worker خودتان کمهزینهتر از requestهای ردشده است.
لاگ و پایش
- شناسهٔ ردگیری خودتان را در
X-Request-IDبفرستید یا مقداری را که مهوش برمیگرداند ثبت کنید. آن را در همهٔ خطهای لاگ مربوط به آن فراخوانی بیاورید و در درخواستهای پشتیبانی هم ذکر کنید. - شناسهٔ response، مدل و
usageرا کنار رکورد کسبوکار خودتان ذخیره کنید. با این کار، نسبت دادن هزینهها و بررسیهای بعدی ساده میشود. - نرخ خطا را به تفکیک
error.typeوerror.code، زمان پاسخ و سهم responseهایincompleteزیر نظر داشته باشید. - مصرف سازمان و پروژه را پایش کنید تا هشدار بودجه اولین نشانهٔ یک مشکل نباشد.
اجرای پسزمینه و webhookها
برای responseهای پسزمینه میتوانید GET /v1/responses/{id} را هر چند وقت یک بار بخوانید، یا بگذارید مهوش خودش خبرتان کند. webhook برای هر پروژه توسط یک مدیر و با JWT کاربر ساخته میشود:
curl -X POST https://api.mahvashai.ir/api/v1/chat/projects/<project-uuid>/webhooks \
-H "Authorization: Bearer $MAHVASH_USER_JWT" \
-H "X-Mahvash-Organization: acme" \
-H "Content-Type: application/json" \
-d '{"url": "https://hooks.example.com/mahvash", "event_types": ["response.completed", "response.failed"]}'
# The response contains the signing secret (whsec_...) exactly once.رویدادها نتیجهٔ responseها را گزارش میکنند: response.completed، response.failed، response.cancelled و response.incomplete. محتوای رویداد فقط شامل شناسه، وضعیت، مدل، مصرف و کد خطاست و هیچوقت prompt یا خروجی مدل را ندارد؛ هر وقت محتوا لازم داشتید، response کامل را با شناسهاش بگیرید.
بررسی اصالت webhookها
هر ارسال سه header به نامهای webhook-id، webhook-timestamp و webhook-signature دارد که از قالب Standard Webhooks پیروی میکنند؛ همان قالبی که OpenAI هم استفاده میکند. پیش از اعتماد به هر چیزی در پیام، امضای body خام و دستنخورده را با secret whsec_... خودتان بررسی کنید:
import crypto from "node:crypto";
import express from "express";
const app = express();
const secret = Buffer.from(process.env.MAHVASH_WEBHOOK_SECRET.replace(/^whsec_/, ""), "base64");
// Verify the exact raw bytes; a re-serialized JSON body will not match.
app.post("/mahvash", express.raw({ type: "application/json" }), async (req, res) => {
const id = req.header("webhook-id");
const timestamp = req.header("webhook-timestamp");
const signatures = (req.header("webhook-signature") ?? "").split(" ");
if (!id || Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return res.sendStatus(400);
const expected = "v1," + crypto
.createHmac("sha256", secret)
.update(id + "." + timestamp + ".")
.update(req.body)
.digest("base64");
const valid = signatures.some((candidate) =>
candidate.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(candidate), Buffer.from(expected)));
if (!valid) return res.sendStatus(400);
const event = JSON.parse(req.body.toString("utf8"));
if (await db.webhookEvents.exists(event.id)) return res.sendStatus(200); // duplicate
await db.webhookEvents.record(event.id);
await jobs.enqueue("sync-response", { responseId: event.data.id }); // work outside the request
res.sendStatus(200);
});- پیامهایی را که timestamp آنها بیش از چند دقیقه قدیمی است رد کنید.
- با کمک
idرویداد، موارد تکراری را کنار بگذارید؛ یک رویداد ممکن است بیش از یک بار برسد. - ممکن است رویدادها به ترتیب نرسند؛ handler را طوری بنویسید که تکرار یا جابهجایی رویدادها مشکلی ایجاد نکند.
- سریع با
2xxپاسخ دهید و کار اصلی را در صف انجام دهید. مقصدی که پشت سر هم شکست بخورد، خودکار غیرفعال میشود. - secret را با
POST /api/v1/chat/webhooks/{id}/rotateعوض کنید. secret قبلی تا ۲۴ ساعت همچنان امضا میکند تا بتوانید بدون عجله نسخهٔ تازه را مستقر کنید.
استفاده از SDKهای OpenAI
برای عملیات پشتیبانیشدهٔ /v1، SDKهای رسمی OpenAI با مهوش کار میکنند؛ به شرطی که baseURL (در JavaScript) یا base_url (در Python) را https://api.mahvashai.ir/v1 بگذارید و API key پروژهٔ مهوش را به آن بدهید. این نکتهها را هم در نظر داشته باشید:
- فیلدهای مخصوص مهوش، مثل
asset_idsیاmanaged_tools، را با گزینهٔ extra body در SDK یا از طریق HTTP مستقیم بفرستید. - endpointهای مدیریت فضای کاری زیر
/api/v1بخشی از SDKهای OpenAI نیستند. آنها را با HTTP ساده صدا بزنید و پاسخ را از داخلdataبخوانید. - SDKها بعضی خطاها را خودکار تکرار میکنند. تکرار را آگاهانه تنظیم کنید تا با روش شما برای idempotency هماهنگ باشد.
- نسخهٔ SDK را ثابت نگه دارید و با هر بهروزرسانی، شروع سریع، یک stream و یک حالت خطا را دوباره آزمایش کنید.
مدیریت داده
- فقط دادهای را بفرستید که برای آن کار لازم است. secretها، tokenها و اطلاعات شخصی غیرضروری را از prompt و فایلها حذف کنید.
- برای requestهایی که نباید محتوایشان پس از تحویل نگه داشته شود،
store: falseبفرستید. در این حالت نمیتوانید آن response را بعداً بازیابی یا با idempotency key دوباره دریافت کنید. - responseها، فایلها و vector storeهایی را که دیگر لازم ندارید، طبق سیاست نگهداری دادههای خودتان حذف کنید.
- کنترل دسترسی خودتان را جلوی هر چیزی که به کاربر نشان میدهید قرار دهید: مهوش دادهها را به پروژه محدود میکند، اما فقط اپلیکیشن شما میداند کدام کاربر اجازهٔ دیدن کدام سند یا پاسخ را دارد.