تصور کنید دانشجویی ساعت ۱۱ شب در حال عیبیابی یک ربات است و در حالی که مولتیمتر و پیچگوشتی در دست دارد، نمیتواند برای پرسیدن سوال، متنی را در چتباکس تایپ کند. این اصطکاک واقعی و ملموس منجر به خلق ریشیکا (Rishika) شد؛ یک معلم هوش مصنوعی صوتی که بهطور اختصاصی برای دانشجویان سال اول مهندسی در هند طراحی شده است. این دانشجویان معمولاً به زبان «هینگلیش» — ترکیبی سیال و طبیعی از هندی و انگلیسی — صحبت میکنند. این پروژه یک شکست بحرانی در ارکستراسیون فعلی مدلهای زبانی بزرگ (LLM) را افشا میکند: ناتوانی پرامپتهای سیستمی (System Prompts) در اجرای قابلاعتماد و سختگیرانه حفاظها (Guardrails).
رابطهای صوتی معمولاً به عنوان افزونههای اختیاری یا لوکس دیده میشوند، اما در حوزه رباتیک، آنها یک ضرورت عملیاتی هستند. دانشجویان اغلب اگر مجبور شوند ابزارهای خود را زمین بگذارند تا متنی را تایپ کنند، وضعیت تستهای سختافزاری خود را از دست میدهند. علاوه بر این، ترجمه علائم فنی از زبان هندی به انگلیسی اغلب باعث میشود ظرافتها و جزئیات دقیق مشکل از بین برود. ریشیکا با پذیرش تغییر زبان طبیعی (Code-switching)، این مشکل را حل میکند؛ به گونهای که دانشجو میتواند بگوید: «Kp बढ़ाया तो oscillation और बढ़ गया» (با افزایش Kp، نوسان بیشتر شد) بدون اینکه نیاز به تغییر دستی تنظیمات زبان یا توقف در جریان فکر خود داشته باشد.
معماری فنی
به نقل از گزارش توسعهدهنده، این سامانه بر یک خط لوله (Pipeline) چهاربخشی متکی است که با هدف به حداقل رساندن «سکوتهای مرگبار» (Dead Air) طراحی شده است؛ همان سکوتهایی که جریان طبیعی گفتگو را میکشند و کاربر را دچار تردید میکنند:
- تبدیل گفتار به متن (STT): استفاده از Deepgram nova-3 با تنظیم
language="multi". این تنظیم اجازه میدهد سیستم نسخهی هینگلیش را بدون نیاز به جابجایی دستی بین زبانهای هندی و انگلیسی ترنسکرایب کند. - مدل زبانی (LLM): مدل Gemini 3.5 Flash Lite. این مدل بهطور خاص به دلیل سرعت بسیار بالا و هزینه کم، بر استدلالهای پیچیده ترجیح داده شد، زیرا در این محصول، تأخیر (Latency) اصلیترین معیار موفقیت است.
- تبدیل متن به گفتار (TTS): صدای 'Anisha' از Murf Falcon. این صدا دارای لهجه انگلیسی هندی است که نیاز دانشجو به ترجمه ذهنی و تطبیق لهجه را کاهش میدهد.
- انتقال داده (Transport): LiveKit که مدیریت تشخیص فعالیت صوتی (VAD)، مدیریت قطع کردن صحبت توسط کاربر (Interruptions) و استریمینگ بلادرنگ صدا را بر عهده دارد.

برای کاهش بیشتر تأخیر ادراکشده توسط کاربر، توسعهدهنده یک SentenceTokenizer پیاده کرد. این ابزار اجازه میدهد سیستم صدا را به صورت جمله به جمله استریم کند؛ به این معنا که دانشجو جمله اول را میشنود در حالی که مدل زبانی هنوز در حال تولید جمله سوم است. پیادهسازی دقیق این بخش در کد به صورت زیر است: tts=murf.TTS(voice="Anisha", style="Casual", tokenizer=tokenize.basic.SentenceTokenizer(min_sentence_len=2), text_pacing=True).
تأخیر (Latency) هسته تجربه کاربری در این محصول است. توسعهدهنده اشاره کرد که عملکرد Murf Falcon در اینجا حیاتی بود و تأخیر مدل ۵۵ میلیثانیه و زمان شروع پخش اولین تکه صدا (Time-to-first-audio) ۱۳۰ میلیثانیه بود. هزینه این سرویس ۰.۰۱ دلار به ازای هر ۱۰۰۰ کاراکتر است. از آنجایی که فرآیند TTS دقیقاً بعد از تصمیم مدل برای پاسخ و قبل از شنیدن آن توسط دانشجو رخ میدهد، هر میلیثانیه تأخیر اضافی به عنوان یک سکوت آزاردهنده و غیرطبیعی حس میشود.
مهندسی تجربه کاربری
رابطهای صوتی در نمایش دادههای پیچیده، مانند سوالات چندگزینهای، بهطور ذاتی شکست میخورند. برای حل این مشکل، ریشیکا بستههای TOOL_RESULT_CARD را از طریق کانال داده LiveKit ارسال میکند. این بستهها در سمت کاربر به صورت دکمههای قابل کلیک روی صفحه رندر میشوند. وقتی دانشجو روی یک گزینه کلیک میکند، این عمل یک نوبت صوتی (Voice Turn) را فعال میکند و بدین ترتیب تجربه بصری (UI) با تجربه صوتی ادغام میشود.
مدیریت حافظه از طریق سه ابزار تخصصی lookup_user ،save_user_memory و forget_user_memory انجام میشود. برای تضمین حریم خصوصی، سیستم بهصورت سختافزاری (Hard-coded) طوری طراحی شده که قبل از هرگونه ثبت داده در حافظه، حتماً رضایت شفاهی کاربر را بخواهد. این قانون بهطور صریح خارج از پرامپت مدل قرار گرفته است تا از توهم (Hallucination) مدل و ثبت ناخواسته دادهها جلوگیری شود. این رویکرد سختگیرانه برای حذف توهمات، مشابه راهکاری است که RevoplyAI با استفاده از محدودیتهای RAG برای پاکسازی خروجیهای چتباتها به کار گرفت. این قابلیت اجازه میدهد دانشجویان هنگام بازگشت به سیستم بشنوند: «पिछली बार हमने IR sensors किए थे» (دفعه پیش سنسورهای IR را بررسی کردیم) به جای اینکه مجبور شوند همه چیز را از ابتدا توضیح دهند.

قابلیتهای تفصیلی
ریشیکا فراتر از یک معلم ساده، یک متخصص در دامنهای محدود است و چندین مکانیزم یکپارچه را در خود جای داده است:
- یکپارچگی دادههای زنده: او برای تعریف اصطلاحات فنی از Free Dictionary API و برای طرح سوالات آزمون از Open Trivia DB استفاده میکند.
- امتیازدهی عملکرد: یک ابزار داخلی که پاسخهای صوتی دانشجو را از ۰ تا ۱۰۰ رتبهبندی کرده و یک خط بازخورد کوتاه و مفید ارائه میدهد.
- تمرینات برونخط (Outbound): سامانه میتواند تماسهای خروجی برقرار کند. این تماسها با اعلام هویت تماسگیرنده، بیان هدف تماس و توضیح نحوه توقف تماس آغاز میشوند.
- تکلیفات ایمنی و ارجاع: اگر دانشجو بوی سوختگی یا دود از درایور موتور گزارش دهد، عامل فوراً فرآیند عیبیابی را متوقف کرده و درخواست حضور یک منتور انسانی میکند. در این حالت، یک شناسه مرجع (Reference ID) به همراه بازه زمانی «ظرف یک روز کاری» به کاربر ارائه میشود.
- مهندسی تلفظ: برای جلوگیری از اینکه TTS کلمات هندی را با فونتیک انگلیسی تلفظ کند، پرامپت الزام میکند که تمام پاسخهای هندی حتماً با خط دیواناگری نوشته شوند و هرگز به صورت رومیسازی شده (Romanised) نباشند.
تحویل به متخصص (Handoff)
تنظیم PID — فرآیند تنظیم بهرههای تناسبی (Proportional)، انتگرالی (Integral) و مشتق (Derivative) — یک کار بسیار دقیق، تخصصی و حساس است. بهجای اجبار یک عامل عمومی به مدیریت این پیچیدگی، سیستم گفتگو را به کبیر (Kabir) تحویل میدهد؛ یک عامل متخصص با صدای مردانه (صدای 'Samar' در Murf).

کبیر تمام زمینه گفتگو (chat_ctx) را به ارث میبرد، به این معنی که دانشجو هرگز مجبور نیست مشکل خود را دوباره تکرار کند. این انتقال (Handoff) با شناسایی علائم خاصی مانند «زیگزاگ» یا «اُورشوت» (Overshoot) فعال میشود. این فرآیند از طریق super().__init__ اجرا میشود که در آن کبیر زمینه گفتگو را دریافت کرده و از یک پرامپت اختصاصی به نام PID_COACH_PROMPT استفاده میکند:
super().__init__(
instructions=PID_COACH_PROMPT + _briefing(main, learner_request),
chat_ctx=main.chat_ctx,
tts=murf.TTS(voice="Samar", style="Conversation", ...),
)
در حالی که ریشیکا ۱۰ ابزار در اختیار دارد، کبیر دقیقاً یک ابزار دارد: ابزار خروج. از آنجایی که تنظیمات tts= روی خود عامل تعریف شده و نه روی جلسه (Session)، بازگشت به ریشیکا بهطور خودکار صدای او را بدون نیاز به مدیریت دستی یا دفترچه یادداشتهای سیستمی بازیابی میکند.
شکست حفاظها
مهمترین یافته فنی این پروژه این است که پرامپتها نمیتوانند به تنهایی حفاظها (Guardrails) را نگه دارند. توسعهدهنده ابتدا دستورات صریح، با حروف بزرگ و تأکیدی در پرامپت نوشت که ابزار ارجاع به منتور انسانی فقط و فقط پس از رضایت شفاهی کاربر فعال شود.
با وجود این دستورات صریح، مدل زبانی گاهی مرحله رضایت را دور میزد و مستقیماً ارجاع میداد. همچنین، مدل بهاشتباه سوالات ساده مربوط به سنسورها را به متخصص PID میفرستاد، زیرا کلمات «سنسور» و «تنظیم» در فضای برداری (Embedding Space) به هم نزدیک هستند و مدل آنها را مرتبط میپنداشت. این نوع چرخههای تکرار و خطاهای مسیریابی در مدلها، ضرورت استفاده از ساختارهایی مانند موتور شفافسازی متوالی را برجسته میکند تا از تکرارهای بیهوده در خروجیهای هوش مصنوعی جلوگیری شود.
راهکار نهایی، انتقال منطق از پرامپت به کد بود. توسعهدهنده یک بررسی Regex (عبارات منظم) سختگیرانه در تابع transfer_to_pid_specialist پیاده کرد. اگر درخواست کاربر شامل کلمات کلیدی خاصی مثل «oscillation»، «wobble»، «zig-zag»، «overshoot» یا «Kp/Ki/Kd» (چه به انگلیسی و چه به دیواناگری) نباشد، ابزار یک رشته متنی را برمیگرداند که به مدل میگوید این درخواست را خودش پاسخ دهد:
@function_tool
async def transfer_to_pid_specialist(self, context, learner_request: str) -> Agent | str:
if not specialists.needs_pid_coach(learner_request):
return ("NOT_TRANSFERRED: that request has no PID or tuning symptom in it, so it is " "yours to answer. Handle it yourself now, and only transfer if they describe " "zig-zagging, wobbling, oscillation, overshoot, or ask about Kp, Ki or Kd.")
اکنون مسیر رضایت کاربر دو بار گیت شده است: یک بار در سطح ابزار و یک بار در تابع escalations.create_or_update(). این ساختار تضمین میکند که حتی اگر مدل زبانی فراموش کند از کاربر بپرسد، سیستم نمیتواند بهطور تصادفی ردیفی در پایگاه داده ایجاد کند.
حل باگ تلفظ PID
یک باگ کوچک اما بسیار آزاردهنده رخ داد: TTS کلمه "PID" را به جای خواندن حروف (پی-آی-دی)، به صورت یک کلمه واحد («پید») تلفظ میکرد. تلاش برای اصلاح این مورد با نوشتن "P.I.D." شکست خورد، زیرا SentenceTokenizer(min_sentence_len=2) صدا را در هر نقطه (Period) قطع میکرد و باعث میشد گفتار بسیار تکهتکه و غیرطبیعی شود.
راهکار نهایی، اجبار به یک قاعده املایی خاص در پرامپت بود: نوشتن "P I D" (با فاصله) در انگلیسی و "पी आई डी" در هندی. این قاعده در اعلان انتقال، پرامپت سیستمی ریشیکا و پرامپت کبیر اعمال شد. برای جلوگیری از بازگشت این باگ در نسخههای آینده، یک تست پایتون نوشته شد تا اطمینان حاصل شود کلمه "PID" (به صورت یک کلمه چسبیده) هرگز در قصدها یا پرامپتهای استاتیک ظاهر نمیشود:
def test_pid_is_never_spoken_as_one_word():
assert "PID" not in static_intents.HANDOFF_TO_PID_FILLER
assert "पी आई डी" in static_intents.HANDOFF_TO_PID_FILLER
assert "पी आई डी" in specialists.PID_COACH_PROMPT
سیگنال ناپدید شده UI
یک باگ پیچیده در مورد نشانگر رابط کاربری (UI) برای شناسایی اینکه کدام عامل در حال صحبت است، ظاهر شد. بکاند ویژگی active_agent: "kabir" را از طریق set_attributes منتشر میکرد، اما هوک React به نام useAgent() در حال خواندن از یک کش دلتا (Delta Cache) بود. از آنجایی که فریمورک LiveKit در هر انتقال وضعیت (گوش دادن $ \rightarrow $ فکر کردن $ \rightarrow $ صحبت کردن) مقدار lk.agent.state را بهروز میکند، کلید active_agent هر ثانیه بازنویسی میشد و سیگنال گم میشد.
راهکار، دور زدن کش هوک و خواندن مستقیم و کامل نقشه ویژگیهای شرکتکننده بود: internal.agentParticipant?.attributes.active_agent.
حریم خصوصی و ایمنی
به دلیل تعامل مستقیم با دانشجویان، پاکسازی سختگیرانه اطلاعات شناسایی شخصی (PII) اجرا شد. داشبورد تحلیل تماسها هیچ ترنسکریپت، لاگ پیام یا شماره تلفنی را ذخیره نمیکند. هر تماس تنها به صورت تعداد نوبتهای گفتگو، نتیجه نهایی و مدت زمان ذخیره میشود.
نام دانشجویان قبل از رسیدن به داشبورد به تکحرف تبدیل میشود. خلاصههای ارجاع نیز از یک فیلتر PII عبور میکنند که کدهایی مثل OTPها، پینها و شماره حسابها را حذف اما اصطلاحات فنی مانند "L298N" را حفظ میکند. علاوه بر این، صفحه عملیات (Ops page) بهطور سختگیرانه فقط به 127.0.0.1 متصل شده تا از هرگونه دسترسی خارجی احتمالی جلوگیری شود.
راهنمای پیادهسازی
برای کسانی که قصد ساخت عاملهای صوتی مشابه را دارند، توسعهدهنده استفاده از Murf LiveKit starter را توصیه میکند. این استک فنی به Python 3.10+، uv، Node 18+ و pnpm نیاز دارد.
گامهای کلیدی راهاندازی:
- محیط: کلیدها باید حتماً در
.env.local(که در gitignore است) قرار گیرند و هرگز در.env.exampleنباشند. - کلیدهای مورد نیاز:
LIVEKIT_URL،LIVEKIT_API_KEY،LIVEKIT_API_SECRET،MURF_API_KEY،DEEPGRAM_API_KEYوGOOGLE_API_KEY. - ایمنی پایگاه داده: توسعهدهنده هشدار میدهد که فایل پایگاه داده SQLite را فوراً به
.gitignoreاضافه کنید تا پروفایلهای تست دانشجویان به اشتباه کامیت نشوند. در این پروژه یک اشتباه رخ داد که در آن یک فایل SQLite حاوی پروفایلهای تست به مدت یک هفته ردیابی شد، زیرا.gitignoreدر ابتدا فقط.env.*را پوشش میداد.
اجرای سیستم:
- بکاند:
cd backend && uv sync && uv run python src/agent.py download-files - فرانتاند:
cd ../frontend && pnpm install - اجرا: دستور
uv run python src/agent.py devبرای اجرای عامل وpnpm devبرای اجرای رابط کاربری.
تست حلقه (Loop Testing):
برای اعتبارسنجی کامل سیستم، توسعهدهنده توالی خاصی از عبارات را پیشنهاد میکند:
- «नमस्ते» (تست اینترسپتور Regex برای خوشآمدگویی فوری).
- «मैं रमेश हूँ» (تست یادگیری نام و دریافت رضایت).
- «मुझे एक quiz दो» (تست ارسال کارتهای کانال داده).
- «IR sensor का threshold कैसे set करूं?» (تست دانش عمومی ریشیکا).
- «मेरा robot line पर ज़िग-ज़ैग कर रहा है» (تست انتقال صحیح به کبیر).
- «L298N गरम है, जलने की smell आ रही है» (تست ارجاع به انسان).
برای تضمین قابلیت اطمینان بدون وابستگی به شبکه، پروژه شامل ۳۵ تست pytest است که اجرای رضایت، مسیریابی PID (با ده جمله واقعی دانشجویان) و تداوم انصراف (Opt-out) را پوشش میدهد.
این پروژه این فرض رایج را تغییر میدهد که «پرامپتنویسی بهتر» میتواند تمام مشکلات قابلیت اطمینان را حل کند. برای هر عامل هوش مصنوعی که ارجاعهای حساس به ایمنی یا قوانین سختگیرانه حریم خصوصی را مدیریت میکند، منطق باید در کد ابزار (Tool Code) باشد، جایی که مدل نمیتواند با آن مذاکره کند یا آن را نادیده بگیرد. اگر در حال ساخت یک عامل صوتی هستید، با یک حلقه ساده شروع کنید و گوش دهید کجا احساس «اشتباه» میکند. ارزشمندترین ویژگیهای ریشیکا — انتقال به متخصص و حفاظهای سختافزاری — در برنامه اولیه نبودند، بلکه از مشاهده شکستهای مدل در زمان واقعی ظهور کردند.
گام بعدی شما
- اگر در حال ساخت عاملهای صوتی هستید، منطقهای حیاتی (مانند پرداخت یا دسترسی به داده) را از پرامپت خارج کرده و در کد ابزار (Tool Code) پیاده کنید.
- برای کاهش تأخیر در TTS، از استراتژی Sentence Tokenization استفاده کنید تا پخش صدا همزمان با تولید متن آغاز شود.
- در محیطهای چندزبانه، برای جلوگیری از خطاهای تلفظ، از اسکریپت بومی (مانند دیواناگری) بهجای رومیسازی در پرامپتها استفاده کنید.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما دربارهی تراشههای Blackwell مراجعه کنید.




گفتگو