رفتن به محتوا

راهنماها

اتصال به سیستم تیکت

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

بخش‌های این سناریو چطور به هم وصل‌اند

  1. 01بررسی پیام
  2. 02دسته‌بندی
  3. 03پیش‌نویس پاسخ
  4. 04بازبینی کارشناس

روند کار

مراحل ۱ تا ۴ را یک بار در اپلیکیشن مهوش انجام می‌دهید. مراحل ۵ تا ۸ برای هر پیام مشتری، در یک کار پس‌زمینه روی سرور سیستم تیکت شما اجرا می‌شوند. تیکت‌ها، مشتریان و ارسال پاسخ در سیستم خود شما می‌مانند و مهوش هیچ‌وقت مستقیم با مشتری شما تماس نمی‌گیرد.

مرحلهچه اتفاقی می‌افتدچه وقت تیکت بدون پیش‌نویس به کارشناس می‌رسد
۵. بررسی پیاممهوش پیام مشتری را از نظر محتوای آسیب‌زا مثل آزار، تهدید یا آسیب به خود بررسی می‌کند.پیام علامت خورده باشد.
۶. دسته‌بندیمهوش تیکت را برچسب می‌زند: موضوع، اینکه اسناد شما جوابش را دارند یا نه، ریسک‌ها، اولویت و اینکه پیام را انسان نوشته یا نه. تصمیم با کد شماست.تیکت ریسک دارد، به اطلاعات حساب یا تأیید یک انسان نیاز دارد، یا خارج از حوزهٔ کار شماست. پیام‌های خودکار نادیده گرفته می‌شوند.
۷. پیش‌نویسمهوش در اسناد راهنمای شما جست‌وجو می‌کند و پاسخی همراه با فایل‌هایی که استفاده کرده می‌نویسد.اسناد جواب پرسش را ندارند یا پاسخ به هیچ فایلی ارجاع نمی‌دهد.
۸. بازبینیکارشناس پیش‌نویس را می‌خواند، ویرایش می‌کند و می‌فرستد یا رد می‌کند.هیچ چیزی بدون کارشناس به مشتری نمی‌رسد.

همهٔ requestها و responseهای این صفحه روی یک پروژهٔ واقعی مهوش اجرا شده‌اند. responseها کوتاه شده‌اند و شناسه‌ها با جانگهدار جایگزین شده‌اند.

۱. ساخت پروژه

مراحل ۱ تا ۴ در اپلیکیشن مهوش انجام می‌شوند؛ همان جایی که با مهوش گفت‌وگو می‌کنید. به پنل مدیریت نیازی ندارید.

  1. ۱وارد اپلیکیشن مهوش شوید. در نوار کناری، کنار پروژه‌ها روی پروژه جدید بزنید، یک نام بگذارید (مثلاً پشتیبانی تیکت‌ها) و پروژه را بسازید.
  2. ۲پروژه را باز کنید، به زبانهٔ دستورالعمل‌ها بروید، متن زیر را وارد کنید، به‌جای [نام شرکت شما] نام شرکتتان را بنویسید و روی ذخیره دستورالعمل‌ها بزنید.
  3. ۳شناسهٔ پروژه را کپی کنید. وقتی پروژه باز است، این شناسه بخش آخر نشانی صفحه در مرورگر است: .../chat/projects/<شناسهٔ پروژه>. از API هم می‌توانید آن را بگیرید: GET /api/v1/tenancy/projects پروژه‌های شما را همراه با id فهرست می‌کند.
تو دستیار پشتیبانی [نام شرکت شما] هستی و به کارشناس‌های پشتیبانی در پاسخ به تیکت مشتری‌ها کمک می‌کنی.
- فقط بر اساس اسناد متصل به این پروژه پاسخ بده. قیمت، تاریخ، مهلت یا قانونی از خودت نساز.
- هرگز بازگشت وجه، جبران خسارت، استثنا یا نتیجهٔ حقوقی را قول نده. این تصمیم‌ها با انسان است.
- هرگز رمز عبور، شمارهٔ کامل کارت یا کد تأیید را از مشتری نخواه.
- به زبان خود مشتری، مؤدبانه، روشن و کوتاه پاسخ بده.

دستورالعمل پروژه روی همهٔ requestهایی که با کلید این پروژه فرستاده می‌شوند اعمال می‌شود؛ پس فقط قانون‌هایی را در آن بنویسید که همیشه برقرارند. متن مخصوص هر کار در پرامپت‌های مرحلهٔ ۳ می‌آید.

نکته:پروژه‌ای که در اپلیکیشن ساخته می‌شود به‌طور خودکار در منابعش جست‌وجو می‌کند؛ پس request پیش‌نویس، بدون نام بردن از اسناد، آن‌ها را پیدا می‌کند.

نکته:همهٔ requestهای مراحل ۵ تا ۷ این شناسه را در هدر X-Mahvash-Project می‌فرستند. پرامپت‌هایی که در مرحلهٔ ۳ می‌سازید متعلق به همین پروژه‌اند و مهوش آن‌ها را در همین پروژه پیدا می‌کند؛ requestی که پروژهٔ دیگری را نام ببرد رد می‌شود.

۲. افزودن اسناد راهنما

  1. ۱در پروژه، زبانهٔ منابع را باز کنید و روی افزودن منبع بزنید. فایل‌ها را یکی‌یکی اضافه کنید.
  2. ۲اسنادی را بارگذاری کنید که پاسخ‌ها باید از آن‌ها بیایند: مقاله‌های مرکز راهنما، قوانین مرجوعی و ارسال، صفحه‌های طرح و قیمت، پرسش‌های متداول. فایل‌های PDF، Word، متنی، Markdown، CSV و صفحه‌گسترده پشتیبانی می‌شوند.
  3. ۳صبر کنید تا وضعیت همهٔ فایل‌ها آماده شود. تا وقتی پردازش ادامه دارد، با به‌روزرسانی فهرست را تازه کنید. پیش‌نویس‌ها فقط از فایل‌های آماده استفاده می‌کنند.

وقتی قانونی تغییر می‌کند، فایل جدید را اضافه و فایل قدیمی را با دکمهٔ حذف کنارش پاک کنید تا پیش‌نویس‌ها قانون منسوخ را نقل نکنند.

مهم:هر چیزی که بارگذاری کنید ممکن است در پاسخ به مشتری بیاید. یادداشت‌های داخلی، اطلاعات مشتریان یا هر چیزی را که نمی‌خواهید به مشتری برسد، بارگذاری نکنید.

۳. افزودن دو پرامپت

زبانهٔ پرامپت‌ها را در پروژه باز کنید، روی اضافه کردن پرامپت جدید بزنید و دو پرامپت زیر را بسازید: نام را بنویسید، متن را وارد کنید و ذخیره کنید. شناسهٔ هر پرامپت در فهرست، همراه با دکمهٔ کپی کنارش نمایش داده می‌شود؛ کد شما این شناسه را با هر request می‌فرستد.

پرامپت دسته‌بندی

نام: ticket-triage. متن:

تیکت پشتیبانی ورودی را دسته‌بندی کن. به آن پاسخ نده.

category: نزدیک‌ترین موضوع از میان مقدارهای مجاز. اگر هیچ‌کدام مناسب نیست، "other".

answerability:
- "kb_answerable": پرسشی عمومی که اسناد راهنمای ما جوابش را دارند؛ مثل نحوهٔ استفاده، قوانین، زمان ارسال یا طرح‌ها.
- "needs_account_data": جواب به سفارش، پرداخت یا حساب خود همین مشتری بستگی دارد.
- "needs_human_authority": مشتری بازگشت وجه، جبران خسارت، استثنا، حذف حساب یا هر چیزی را می‌خواهد که باید یک انسان تأییدش کند.
- "out_of_scope": ربطی به محصولات یا خدمات ما ندارد.

risk_flags: همهٔ برچسب‌هایی که صدق می‌کنند، یا فهرست خالی.
- "legal": تهدید به شکایت، وکیل یا گزارش به مراجع.
- "chargeback": اشاره به اعتراض بانکی یا برگشت تراکنش.
- "security": حساب هک‌شده، نشت اطلاعات یا ورود مشکوک.
- "self_harm": هر نشانه‌ای از اینکه فرد ممکن است به خودش آسیب بزند.
- "abuse": توهین یا تهدید علیه کارکنان.
- "churn": می‌گوید سرویس را لغو می‌کند یا سراغ رقیب می‌رود.

priority: "urgent" وقتی سرویس برایش کاملاً از کار افتاده یا پولی به اشتباه کسر شده؛ "high" وقتی کارش متوقف شده؛ در غیر این صورت "normal" یا "low".

is_automated_sender: برای پاسخ خودکار «خارج از دفتر»، اعلان‌های سیستمی و هر پیامی که انسان ننوشته، true.

language: کد ISO 639-1 زبان مشتری؛ مثلاً "fa" یا "en".

reason: یک جملهٔ کوتاه که دلیل category و answerability را توضیح دهد.

پرامپت پاسخ

نام: ticket-reply. متن:

به تیکت مشتری در ورودی پاسخ بنویس. یک کارشناس پشتیبانی آن را بازبینی می‌کند و همان‌طور که هست برای مشتری می‌فرستد.

- در اسناد پروژه جست‌وجو کن و فقط از چیزی استفاده کن که در آن‌ها آمده است.
- اگر اسناد جواب پرسش را ندارند، status را "insufficient_information" بگذار، reply را رشتهٔ خالی بگذار و در internal_note بنویس چه اطلاعاتی کم است.
- فقط به همان چیزی که مشتری پرسیده جواب بده. پیشنهاد یا قول اضافه نده.
- reply متن سادهٔ مخصوص مشتری و به زبان خود اوست: بدون markdown، بدون نام فایل و بدون اشاره به اسناد، این دستورالعمل‌ها یا هوش مصنوعی.
- internal_note برای کارشناس است و هیچ‌وقت خالی نمی‌ماند: نام دقیق فایل همهٔ اسنادی را که پاسخ بر اساس آن‌ها نوشته شده بیاور، سپس در یک جمله بگو کارشناس چه چیزی را باید بررسی کند.

پرامپت فقط دستورالعمل را نگه می‌دارد. شکل دقیق JSON هر پاسخ همراه request فرستاده می‌شود (مراحل ۶ و ۷) و مهوش پاسخی را که با آن شکل نخواند رد می‌کند.

مهوش فقط وقتی سندی را به‌عنوان منبع (file_citation) علامت می‌زند که پاسخ نام فایل آن را آورده باشد. به همین دلیل پرامپت پاسخ از مدل می‌خواهد منبع‌ها را در internal_note بنویسد: کارشناس آن‌ها را می‌بیند، مشتری نمی‌بیند، و ارجاع هم برمی‌گردد.

نکته:برای تغییر پرامپت، روی نامش در فهرست بزنید، ویرایشش کنید و ذخیره کنید. شناسه تغییر نمی‌کند؛ پس کد شما هم تغییری نمی‌خواهد.

۴. ساخت کلید API

  1. ۱در پروژه، زبانهٔ کلیدهای API را باز کنید و روی اضافه کردن کلید جدید بزنید. نام کلید را از روی سیستم تیکتتان بگذارید؛ مثلاً helpdesk-worker. این زبانه فقط برای مالک و مدیران سازمان نمایش داده می‌شود.
  2. ۲کلید را همان لحظه کپی کنید. فقط یک بار نمایش داده می‌شود.
  3. ۳کلید، شناسهٔ پروژه و دو شناسهٔ پرامپت را در متغیرهای محیطی سرور سیستم تیکت قرار دهید:
# Your ticketing server's environment. Never commit this file.
MAHVASH_API_URL=https://api.mahvashai.ir
MAHVASH_API_KEY=<the key from step 4>
MAHVASH_PROJECT_ID=<the project ID from step 1>
MAHVASH_TRIAGE_PROMPT_ID=<Prompt ID of ticket-triage>
MAHVASH_REPLY_PROMPT_ID=<Prompt ID of ticket-reply>

هر requestی که با این کلید فرستاده شود از دستورالعمل، منابع و سقف‌های همین پروژه استفاده می‌کند و هزینه‌اش از حساب سازمان شما کسر می‌شود.

مهم:کلید را فقط روی سرور نگه دارید. هرگز آن را در frontend سیستم تیکت نگذارید یا به مرورگر نفرستید. اگر لو رفت، در همان زبانه لغوش کنید و کلید جدید بسازید.

۵. بررسی پیام مشتری

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

curl "$MAHVASH_API_URL/v1/moderations"   -H "Authorization: Bearer $MAHVASH_API_KEY"   -H "X-Mahvash-Project: $MAHVASH_PROJECT_ID"   -H "Content-Type: application/json"   -d @- <<EOF
{
  "model": "omni-moderation-latest",
  "input": [
    "سلام، لباسشویی دیروز با در شکسته به دستم رسید. می‌توانم مرجوعش کنم یا باید از گارانتی استفاده کنم؟"
  ]
}
EOF

اگر results[0].flagged برابر true بود، همین‌جا متوقف شوید و تیکت را بدون پیش‌نویس به کارشناس بسپارید.

۶. دسته‌بندی: هوش مصنوعی جواب بدهد یا نه؟

در این مرحله از مدل می‌خواهید تیکت را برچسب بزند، نه اینکه جوابش را بدهد. برچسب‌ها به‌صورت JSON با شکل ثابت برمی‌گردند؛ پس کد شما به‌جای تجزیهٔ جمله‌ها، فیلدها را می‌خواند.

curl "$MAHVASH_API_URL/v1/responses"   -H "Authorization: Bearer $MAHVASH_API_KEY"   -H "X-Mahvash-Project: $MAHVASH_PROJECT_ID"   -H "Content-Type: application/json"   -d @- <<EOF
{
  "model": "gpt-6-luna",
  "prompt_id": "$MAHVASH_TRIAGE_PROMPT_ID",
  "input": "سلام، لباسشویی دیروز با در شکسته به دستم رسید. می‌توانم مرجوعش کنم یا باید از گارانتی استفاده کنم؟",
  "text": {
    "format": {
      "type": "json_schema",
      "name": "ticket_triage",
      "strict": true,
      "schema": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "category",
          "answerability",
          "risk_flags",
          "priority",
          "is_automated_sender",
          "language",
          "reason"
        ],
        "properties": {
          "category": {
            "type": "string",
            "enum": [
              "order_delivery",
              "returns_refunds",
              "billing",
              "account_access",
              "how_to",
              "technical_issue",
              "other"
            ]
          },
          "answerability": {
            "type": "string",
            "enum": [
              "kb_answerable",
              "needs_account_data",
              "needs_human_authority",
              "out_of_scope"
            ]
          },
          "risk_flags": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "legal",
                "chargeback",
                "security",
                "self_harm",
                "abuse",
                "churn"
              ]
            }
          },
          "priority": {
            "type": "string",
            "enum": [
              "low",
              "normal",
              "high",
              "urgent"
            ]
          },
          "is_automated_sender": {
            "type": "boolean"
          },
          "language": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          }
        }
      }
    }
  }
}
EOF

text آیتم message در output را بردارید و به‌صورت JSON بخوانید؛ زبانهٔ Result همین را نشان می‌دهد. جدول زیر همهٔ فیلدهایی را که برمی‌گردد و کاری را که کد شما با هر کدام می‌کند نشان می‌دهد. به فیلدها تکیه کنید، نه به متن: reason متن آزاد برای انسان است و language ممکن است به‌جای کد، نام زبان باشد؛ مثلاً Persian.

فیلدمقدارهاکاری که کد شما می‌کند
categoryدسته‌های خودتان در schema؛ مثلاً returns_refundsتیکت را به صف مناسب می‌فرستد. پیش‌نویس را فقط برای دسته‌هایی فعال کنید که آزموده‌اید.
answerabilitykb_answerable، needs_account_data، needs_human_authority، out_of_scopeفقط kb_answerable به مرحلهٔ پیش‌نویس می‌رود. هر مقدار دیگری به کارشناس سپرده می‌شود.
risk_flagsفهرستی از legal، chargeback، security، self_harm، abuse، churn یا خالیهر برچسبی تیکت را فوراً و بدون پیش‌نویس به کارشناس می‌سپارد.
prioritylow، normal، high، urgentاولویت تیکت را در سیستم شما تعیین می‌کند؛ دربارهٔ نوشتن پیش‌نویس تصمیم نمی‌گیرد.
is_automated_sendertrue یا falsetrue یعنی پاسخ خودکار یا پیام سیستمی: نادیده بگیرید و هرگز جوابش را ندهید.
languageکد یا نام زبانتیم کارشناس یا زبان قالب‌های پاسخ را انتخاب می‌کند.
reasonمتن آزادبه کارشناس نشان دهید. هیچ تصمیمی را بر اساس آن نگیرید.

تصمیم با کد شماست

def decide(triage: dict) -> str:
    """Return "ignore", "agent" or "draft". These are your rules, not the model's."""
    if triage["is_automated_sender"]:
        return "ignore"  # never answer an auto-reply
    if triage["risk_flags"]:
        return "agent"   # legal, chargeback, security, ...: always a person
    if triage["answerability"] != "kb_answerable":
        return "agent"   # needs account data or someone's approval
    return "draft"

APIهای این مرحله

۷. نوشتن پیش‌نویس پاسخ

برای تیکتی که از دسته‌بندی رد شده، گفت‌وگو را برای پرامپت پاسخ بفرستید. چون پروژه به‌طور خودکار در منابعش جست‌وجو می‌کند، مهوش پیش از نوشتن در اسناد شما جست‌وجو می‌کند. input گفت‌وگوی عمومی تیکت است، از قدیمی به جدید: پیام‌های مشتری با نقش user و پاسخ‌های کارشناس‌های شما با نقش assistant.

curl "$MAHVASH_API_URL/v1/responses"   -H "Authorization: Bearer $MAHVASH_API_KEY"   -H "X-Mahvash-Project: $MAHVASH_PROJECT_ID"   -H "Content-Type: application/json"   -d @- <<EOF
{
  "model": "gpt-6-luna",
  "prompt_id": "$MAHVASH_REPLY_PROMPT_ID",
  "input": [
    {
      "role": "user",
      "content": "سلام، لباسشویی دیروز با در شکسته به دستم رسید. می‌توانم مرجوعش کنم یا باید از گارانتی استفاده کنم؟"
    }
  ],
  "text": {
    "format": {
      "type": "json_schema",
      "name": "ticket_reply",
      "strict": true,
      "schema": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "status",
          "reply",
          "internal_note"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "answered",
              "insufficient_information"
            ]
          },
          "reply": {
            "type": "string"
          },
          "internal_note": {
            "type": "string"
          }
        }
      }
    }
  }
}
EOF

دو وضعیت تعیین می‌کنند با پیش‌نویس چه کنید: status خود response و status داخل JSONی که مدل نوشته. به همین ترتیب بررسی کنید:

چه می‌بینیدیعنی چهچه کنید
status خود response برابر failed یا incomplete است، یا کد HTTP برابر 200 نیستپیش‌نویس قابل استفاده‌ای ساخته نشده است.تیکت را بدون پیش‌نویس به کارشناس بسپارید.
status داخل JSON برابر insufficient_information استاسناد جواب پرسش را ندارند و internal_note می‌گوید چه چیزی کم است.تیکت را بدون پیش‌نویس به کارشناس بسپارید و یادداشت را به او نشان دهید. به status تکیه کنید، نه به خالی بودن reply.
status داخل JSON برابر answered است اما در annotations هیچ file_citationی نیستپاسخی بدون منبع اثبات‌شده.تیکت را بدون پیش‌نویس به کارشناس بسپارید.
status داخل JSON برابر answered است و دست‌کم یک file_citation وجود داردپیش‌نویسی متکی بر اسناد شما.آن را همراه با منبع‌ها و internal_note برای بازبینی کارشناس (مرحلهٔ ۸) ذخیره کنید.

پیش‌نویس فقط در ردیف آخر قابل استفاده است. در نمونهٔ بالا مدل نام help-center.md را آورده، پس file_citation برگشته و پیش‌نویس نگه داشته می‌شود. اگر مدل جواب درستی بنویسد اما نام فایل منبع را نیاورد، file_citation برنمی‌گردد و تیکت بدون پیش‌نویس به کارشناس می‌رسد.

۸. بازبینی کارشناس

پیش‌نویس را داخل تیکت و به‌صورت یادداشت خصوصی که فقط کارشناس‌ها می‌بینند نمایش دهید، همراه با:

  • متن پاسخ در یک کادر قابل ویرایش؛
  • فایل‌های منبع، با پیوند به صفحهٔ متناظر در مرکز راهنمای خودتان؛
  • internal_note؛
  • سه دکمه: ارسال، ویرایش و ارسال و رد کردن.

نکته:چون منبع‌ها در internal_note می‌آیند، خود پاسخ تمیز می‌ماند. اگر پاسخی باز هم نام فایلی را آورد، کارشناس پیش از ارسال آن را پاک می‌کند.

برای هر پیش‌نویس این‌ها را ذخیره کنید: شناسهٔ تیکت و پیام، شناسهٔ response مهوش، برچسب‌های دسته‌بندی، پیش‌نویس، کاری که کارشناس انجام داد و متنی که واقعاً فرستاده شد. همین سابقه نشان می‌دهد پیش‌نویس‌ها در کدام دسته‌ها خوب کار می‌کنند.

قانون‌های ایمنی

  • تا کارشناس دکمهٔ ارسال را نزند، هیچ چیزی به مشتری نمی‌رسد.
  • برای هر پیام مشتری فقط یک پیش‌نویس. هر پیام جدید مشتری یک پیش‌نویس جدید می‌گیرد.
  • اگر کارشناسی شروع به نوشتن پاسخ کرده، متن او را با پیش‌نویس جایگزین نکنید.

ارسال بدون بازبینی

در شروع، همهٔ پیش‌نویس‌ها را بازبینی کنید. بعد از چند هفته، برای هر دسته بررسی کنید کارشناس‌ها چند بار پیش‌نویس را بدون تغییر فرستاده‌اند. فقط دسته‌ای که در آن این اتفاق تقریباً همیشه می‌افتد، و فقط برای تیکت‌هایی با kb_answerable و بدون برچسب ریسک، برای ارسال بدون بازبینی مناسب است. حتی در آن حالت هم هر روز نمونه‌ای از پاسخ‌ها را بازبینی کنید.