رفتن به محتوا

راهنماها

چک‌لیست اتصال در محیط اصلی

کارهایی که یکپارچه‌سازی با مهوش را در عمل قابل‌اعتماد می‌کنند: نگهداری 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هایی را که دیگر لازم ندارید، طبق سیاست نگهداری داده‌های خودتان حذف کنید.
  • کنترل دسترسی خودتان را جلوی هر چیزی که به کاربر نشان می‌دهید قرار دهید: مهوش داده‌ها را به پروژه محدود می‌کند، اما فقط اپلیکیشن شما می‌داند کدام کاربر اجازهٔ دیدن کدام سند یا پاسخ را دارد.