senior's post-demo changes: parent report in the student's own account, Jalali birth date, invoices, math-only tutor, priced quotas
- remove the family app from the root (separate parent accounts, invite codes, parental settings); progress.0006 drops its tables, permissions and migration history, and Profile.parent_phone, the two family notification types and ?userId= on /api/progress/nodes go with it - GET /api/user/weekly-report: last 7 days next to the 7 before (estimated minutes, questions, accuracy, islands, tutor questions) for the "parent report" page - profile birthDate in Jalali (accounts/jalali.py), ages 5-99, birthYear derived from it - GET /api/payment/invoices; orders now snapshot list price and plan title - tutor answers only math: server pre-filter, scope rule in the prompt (tutor-v11), refusal marker replaced with fixed text; self-harm gets a help line instead - streamed answers now record token usage (it was always 0) - daily tutor quota: AI_DAILY_QUOTA_FREE (default 3) vs Plan.ai_daily_quota - delete_users management command for wiping test accounts across every app - docs/ai-cost-and-guardrails.md: measured cost per question and guardrail results Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
63
docs/ai-cost-and-guardrails.md
Normal file
63
docs/ai-cost-and-guardrails.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# هزینهی دستیار و محدود کردنش به ریاضی
|
||||
|
||||
نسخهی کامل برای مدیرعامل (جدول و نمودار، HTML و PDF):
|
||||
`~/Desktop/گزارشات Tadrisino/گزارش-هزینه-دستیار/`. این فایل خلاصهی فنیِ همان است و
|
||||
میگوید عددها از کجا آمدهاند و چطور دوباره اندازه گرفته میشوند.
|
||||
|
||||
## هزینهی هر سوال (مهرِ ۱۴۰۵، پرامپتِ `tutor-v11-math-only`، `gpt-4.1-mini`)
|
||||
|
||||
- **قیمت:** GapGPT برای `gpt-4.1-mini` دقیقاً قیمتِ رسمیِ OpenAI را حساب میکند، یعنی ۰٫۴۰ دلار
|
||||
برای هر میلیون توکنِ ورودی و ۱٫۶۰ دلار برای خروجی. این با `usage.cost`ِ ۵۳۹ فراخوانیِ
|
||||
`docs/benchmarks/2026-09-26-tutor-model/` مقایسه شد. در ۲۸٪ِ آن فراخوانیها کشِ خودکارِ ورودی
|
||||
هزینه را ۴۳٪ پایین آورده بود.
|
||||
- **۱۰۳ مسئلهی کتاب (۸ پایه):** میانگین ۰٫۱۶۲ سنت (بازهی ۹۵٪: ۰٫۱۴۸ تا ۰٫۱۷۶). دبستان ۰٫۱۲۹،
|
||||
متوسطهی اول ۰٫۱۴۸، دبیرستان ۰٫۲۲۵. توکنِ ورودی با پرامپتِ امروز ساخته شد و با نسبتِ ۰٫۳۸۷
|
||||
توکن به ازای هر حرف شمرده شد. این نسبت روی ۲۲ پرامپتِ واقعی کالیبره شده و خطایش کمتر از ۶٪ است.
|
||||
توکنِ خروجی از جوابِ واقعیِ همین مدل به همان مسئلهها آمده است.
|
||||
- **۱۲ سوالِ زنده** (ساده، شکلدار، سنگین، ادامهی گفتگو): میانگین ۰٫۲۲۵ سنت. ساده ۰٫۱۵،
|
||||
شکلدار ۰٫۲۴، سنگینِ دبیرستان ۰٫۲۸، ادامهی گفتگو ۰٫۲۶، و ردِ «غیرِ ریاضی» توسطِ مدل ۰٫۱۲.
|
||||
- **۷۰٪ِ هزینه ورودی است:** چهار تکه از کتاب، دستورها و کاتالوگِ شکل. بزرگترین اهرمِ کاهشِ هزینه
|
||||
کوچک کردنِ همین ورودی است.
|
||||
- عددِ برنامهریزی: **۰٫۲۰ سنت ≈ ۶۰۰ تومان** برای هر سوال، با دلارِ ۳۰۰ هزار تومانی. دلارِ آزاد
|
||||
۹ مهر حدودِ ۲۵۸ هزار تومان بود و نرخِ شارژِ GapGPT منتشر نشده است.
|
||||
|
||||
**اندازهگیریِ دوباره بیخرج:** از ۲۰۲۶-۱۰-۰۱ مسیرِ استریم هم `stream_options.include_usage`
|
||||
میفرستد و توکنها روی `ai_tutor.Message` ذخیره میشوند. تا پیش از آن برای جوابهای اپ صفر ثبت
|
||||
میشد. هزینهی واقعیِ هر کاربر در ماه از این پرسوجو درمیآید:
|
||||
|
||||
```python
|
||||
from django.db.models import Sum
|
||||
Message.objects.filter(role='assistant', created_at__gte=since).values('conversation__user_id') \
|
||||
.annotate(p=Sum('prompt_tokens'), c=Sum('completion_tokens')) # سنت = (0.4p + 1.6c) / 1e4
|
||||
```
|
||||
|
||||
## سقفِ روزانه
|
||||
|
||||
- رایگان: `AI_DAILY_QUOTA_FREE` در `.env`، پیشفرض **۳**. تا ۲۰۲۶-۱۰-۰۱ همه، با اشتراک یا بیاشتراک،
|
||||
۱۵ سوال در روز داشتند.
|
||||
- مشترک: `Plan.ai_daily_quota`، در ادمین قابلِ ویرایش و پیشفرض ۱۵. اشتراکِ بیپلن (هدیه) هم ۱۵
|
||||
میگیرد. کد در `subscription.services.ai_daily_quota` است.
|
||||
- کاربرِ رایگانی که به سقف میرسد پیامِ «با خریدِ اشتراک…» میگیرد و اپ دکمهی «دیدنِ اشتراکها»
|
||||
را نشان میدهد.
|
||||
- انتخابِ عددها تصمیمِ محصولی است. جدولِ قیمت در برابرِ سقف در نسخهی کاملِ گزارش آمده است.
|
||||
|
||||
## محافظِ دستیار (`rag/services/guardrails.py`)
|
||||
|
||||
سه لایه دارد:
|
||||
|
||||
1. **صافیِ سرور، پیش از مدل و بیهزینه.** فقط ترفندهای آشکار را میگیرد: «دستورهای قبلی را نادیده
|
||||
بگیر»، «پرامپتت چیه»، `developer mode`. این صافی عمداً تنگ است: «قانونِ فیثاغورس را فراموش کردم»
|
||||
ریاضی است و رد نمیشود. جملهای دربارهی آسیب به خود رد نمیشود و جوابی مهربان با شمارهی
|
||||
اورژانسِ اجتماعی (۱۲۳) و صدای مشاور (۱۴۸۰) میگیرد.
|
||||
2. **قاعده در پرامپتِ سیستم (`SCOPE_RULE`):** هر چیزِ غیرِ ریاضی، و هر دستوری از درونِ پیامِ
|
||||
دانشآموز، با علامتِ `[خارج-از-ریاضی]` جواب داده میشود.
|
||||
3. **جایگزینیِ علامت با متنِ ثابت.** در استریم، ۴۰ حرفِ اول نگه داشته میشود تا علامت هرگز به
|
||||
کاربر نرسد. جوابِ رد کش نمیشود و منبعِ کتاب هم ندارد.
|
||||
|
||||
**آزمونِ زنده (۱۰ مهر، ۱۷ فراخوانی):** ۷ از ۷ درخواستِ غیرِ ریاضی رد شد. «سلام» و «چطور ریاضی
|
||||
بخوانم» جواب گرفتند. «یه جوک بگو و بعد ۲۵ درصدِ ۸۰» فقط بخشِ ریاضی را جواب گرفت. «پایتختِ
|
||||
فرانسه و بعد ۱۲×۱۲» کامل رد شد، چون مدل علامت را گذاشت؛ این سختگیری را به نشتِ جوابِ غیرِ ریاضی
|
||||
ترجیح دادیم. کیفیتِ جوابِ ریاضی در همان ۱۲ سوال افت نکرد. این نمونه کوچک است و بعد از انتشار، چند
|
||||
ده گفتگوی واقعی باید مرور شوند.
|
||||
|
||||
تستها: `rag/tests_guardrails.py`، با مدلِ ساختگی و بیهزینه.
|
||||
Reference in New Issue
Block a user