تصور کنید یک خط کد SQL ساده را برای گروهبندی لاگهای درخواستها بر اساس مشتری اجرا میکنید؛ این عدد برای یک گزارش داخلی شاید کافی باشد، اما برای یک فاکتور حرفهای هرگز دقیق نیست. این «دردسر حسابداری» گریبانگیر اکثر اپلیکیشنهای چندمستاجری (Multi-tenant) است که معمولاً هزینههای تامینکننده را با مبالغ دریافتی از مشتری یکی میپندارند.
برای رسیدن به عددی که برای صورتحساب قابل اعتماد باشد، توسعهدهنده به سه رکن نیاز دارد: یک سامانه تجمیع (Rollup)، یک کلید یکتایی برای جلوگیری از ثبت تکراری (Idempotency Key) و یک سیاست شفاف برای هزینههای مشترک. حذف هر یک از این سه مورد باعث میشود عدد نهایی شما فقط تا اولین لحظهای که مشتری آن را بررسی میکند، درست به نظر برسد. در این راستا، استفاده از قراردادهای اندازهگیری میتواند راهکاری موثر برای جلوگیری از محاسبهٔ دوبرابره هزینهها در سیستمهای پیچیده باشد.
ساخت یک سامانه پرداخت در سطح تولید، نیازمند یک تفکیک معماری بنیادی است. شما باید برای هر ردیف داده، دو عدد مجزا را ردیابی کنید: هزینه واقعی پرداخت شده به تامینکننده و واحدهای قابل پرداخت مصرف شده توسط مشتری. طبق راهنمای فنی منتشر شده در dev.to در ۱۲ اوت ۲۰۲۶، ترکیب این دو مقدار باعث میشود تغییر قیمتها یا مذاکره مجدد با تامینکننده، بدون تغییر در فاکتورهای قبلی مشتریان غیرممکن شود. این دو عدد به پرسشهای متفاوتی پاسخ میدهند و مستقل از هم تغییر میکنند، بنابراین باید در ستونهای جداگانه ذخیره شوند.
درک تفکیک دو ستونی
- هزینه واقعی (cost_usd): مبلغی است که شما برای انجام کار به نام مشتری به تامینکننده پرداختهاید. این عدد بر اساس پول واقعی است و با تغییر قیمتهای تامینکننده تغییر میکند. این مقدار ورودی مستقیم حاشیه سود شماست.
- واحد قابل پرداخت (billable_units): مقدار مصرفی است که در قرارداد مشتری ذکر شده است — مثلاً بر اساس اعتبار، تعداد تسک، تعداد پیام یا یک واحد توکن سفارشی. این عدد بر اساس قوانین محصول شماست و نباید به دلیل تغییر لیست قیمت تامینکننده، به صورت عطف به ماسبق تغییر کند.
تصور کنید شما با تامینکننده مدل زبانی بزرگ (LLM) خود بر سر نرخ کمتری مذاکره میکنید. اگر تنها یک ستون داشته باشید، تاریخچه مصرف مشتریان شما ناگهان تغییر میکند. اما با تفکیک cost_usd و billable_units ، هزینههای شما کاهش مییابد در حالی که درآمد ثابت میماند و این تنها راه رشد حاشیه سود است. واحدهای قابل پرداخت توسط تابعی محاسبه میشوند که شما آن را نسخهبندی (Version) میکنید تا ثبات دادهها تضمین شود.
حل چالش هزینههای مشترک
هر دلاری که صرف یک مدل میشود، لزوماً متعلق به یک مشتری خاص نیست. سه سناریوی رایج وجود دارد که منجر به ضررهای پنهان میشود و هر کدام به یک سیاست مشخص نیاز دارند، به جای اینکه به هر چه یک پرسوجوی group-by برمیگرداند تکیه کنید:
- پیشوندهای مشترک کششده: وقتی یک پرامپت سیستمی طولانی کش میشود و بین مشتریان به اشتراک میرود، مشتریای که درخواستش باعث پر شدن کش شده، قیمت کامل را میپردازد، در حالی که بقیه نرخ ارزانتر کش را دریافت میکنند. اگر این را دقیقاً صورتحساب کنید، یعنی یک مشتری هزینه بقیه را میدهد. توسعهدهندگان باید یا یک نرخ میانگین (Blended Rate) را برای همه اعمال کنند و تفاوت را جذب کنند، یا بر اساس قیمت بدون کش صورتحساب کرده و سود حاصل از کش را به عنوان حاشیه سود خالص شرکت نگه دارند.
- بردار معنایی (Embedding) مجموعه مشترک: تبدیل مجموعهای از اسناد که همه مشتریان در آن جستوجو میکنند، یک هزینه پلتفرمی است. این موارد باید با برچسب
tenant_id = nullوfeature = 'platform'ثبت شوند و کاملاً از اعداد مربوط به هر مشتری جدا بمانند. در واقع، بسیاری از مشکلات مالی در این حوزه ناشی از ناکارآمدی پلتفرم در مدیریت هزینههای GPU است تا بهینگی خود مدل. - تلاشهای مجدد و خطاها: درخواستی که شکست میخورد و دوباره ارسال میشود، برای توسعهدهنده دو بار هزینه دارد اما فقط یک جواب به مشتری میدهد. هزینه برای هر دو تلاش ثبت میشود، اما واحد قابل پرداخت فقط برای یک بار. به همین دلیل است که باید برای هر «تلاش» یک ردیف لاگ ثبت کرد، نه برای هر «فراخوانی منطقی».
مکانیزم تجمیع یکتا (Idempotent Rollup)
پرسوجو از لاگهای خام برای صورتحساب، به دلیل ورود نامتقارن دادهها، کند و متناقض است. دو اجرای یک پرسوجوی مشابه با فاصله چند دقیقه ممکن است اعداد متفاوتی برگردانند چون ردیفها همچنان در حال رسیدن هستند. راهکار، ایجاد یک جدول تجمیع روزانه مانند llm_usage_daily است که مجموع درخواستها، توکنها و هزینهها را ذخیره میکند.
این جدول باید شامل فیلدهای دقیقی باشد: tenant_id ،day ،feature ،model ،requests (از نوع bigint)، input_tokens ،output_tokens ،cached_tokens ،cost_usd (numeric 14,6)، billable_units (numeric 14,4) و برچسب زمانی computed_at. همچنین به یک فیلد source_max_id به عنوان نشانگر پیشرفت (High-water mark) و یک عدد صحیح برای revision نیاز دارد.
برای تضمین یکپارچگی دادهها، این تجمیع باید یکتا (Idempotent) باشد. استفاده از عبارت SQL INSERT INTO ... ON CONFLICT به یک کرونجاب اجازه میدهد تا دادههای موجود را بازنویسی کند، به جای اینکه در صورت اجرای دوبارهی جاب، اعداد را دو برابر کند. سه ویژگی این روش را برای تحویل «حداقل یکبار» (at-least-once delivery) ایمن میکند:
- کلیددار است: اجراهای تکراری باعث بازنویسی میشوند نه دو برابر شدن.
- محدود به یک روز است: این امر بازسازی دادههای قدیمی (Backfills) را به یک حلقه ساده تبدیل میکند.
- دارای نسخه (Revision) است: این باعث میشود اگر عددی پس از نمایش به مشتری تغییر کرد، قابل شناسایی باشد و مرموز نماند.
مدیریت ردیفهای دیررس و مرزهای زمانی
ردیفها اغلب بعد از پایان روز مربوطه میرسند. این اتفاق زمانی میافتد که یک پاسخ استریمشده در ساعت ۰۰:۰۰:۰۳ تمام شود اما برچسب زمانی شروع آن ثبت شده باشد، یا وقتی یک ورکر نامتقارن با تأخیر بافر را خالی میکند، یا زمانی که وبهوک تامینکننده مصرف را مجدداً اعلام میکند.
برای حل این مشکل، هر شب یک پنجره زمانی عقبگرد — مثلاً ۳ روز اخیر — را مجدداً محاسبه کنید. این کار هزینه بسیار کمی دارد و اکثر ردیفهای دیررس را جذب میکند. علاوه بر این، در مرزهای نیمهشب و پایان ماه دقت کنید. چون یک پاسخ استریمشده طولانی ممکن است زمان شروع و پایانش در دو روز مختلف باشد، باید یک معیار واحد را انتخاب کرده و در همه جا به کار ببرید. زمان شروع انتخاب بهتری است زیرا قبل از نوشتن ردیف مشخص است، هرگز تغییر نمیکند و با نحوه توصیف درخواست توسط کاربر مطابقت دارد. استفاده از یک برچسب زمانی یکسان در تجمیع، فاکتور و داشبورد، از گردش سه عدد متفاوت جلوگیری میکند.
حفاظهای مالی و صدور فاکتور
پس از صدور فاکتور یک دوره، دادهها باید منجمد شوند. هرگونه خطای کشفشده باید به عنوان ردیفهای تعدیلی در دوره بعدی با یک کد دلیل (Reason Code) ثبت شود، نه با ویرایش دوره بسته شده. ویرایش دورههای بسته، تنها ویژگی ضروری یک فاکتور، یعنی «قابلیت بازتولید از روی دادههای ذخیرهشده» را از بین میبرد.
برای کسانی که دادههای مصرف را به سیستمهای اندازهگیری خارجی ارسال میکنند، استفاده از request_id به عنوان کلید یکتایی در هر رویداد حیاتی است. از شناسهی هر دسته (Batch ID) استفاده نکنید. تحویلهای تکراری عادی هستند و یک سیستم اندازهگیری که یک request_id را دو بار دریافت میکند، باید آن را بدون دخالت دستی، تنها یک بار ثبت کند.
پرسوجوی اولویتدار بر اساس حاشیه سود
تیمهای مالی به ندرت به کل هزینهها اهمیت میدهند؛ آنها میخواهند بدانند کدام مشتریان باعث ضرر میشوند. موثرترین گزارش، پیوند (Join) بین جدول تجمیع مصرف و جدول اشتراک است که بر اساس «حاشیه سود ناخالص» به صورت صعودی مرتب شده باشد.
این پرسوجو gross_margin (درآمد ماهانه یا MRR منهای هزینه مدل) و margin_pct را محاسبه میکند. مرتبسازی صعودی بلافاصله ۲۵ درصد پایینترین حسابهایی را که هزینه مدلشان از درآمد ماهانه (MRR) بیشتر است، شناسایی میکند. این گزارش باید هفتگی اجرا شود و به جای میانگین، با توزیع دادهها بررسی شود. در محصولات مبتنی بر مصرف، معمولاً تعداد کمی از مشتریان سهم بزرگی از هزینهها را به خود اختصاص میدهند؛ بنابراین میانگین حاشیه سود میتواند سالم به نظر برسد در حالی که تعدادی از حسابها به شدت منفی هستند.
یک پرسوجوی مکمل برای مشتریانی که طرحهای ثابت (Flat Plans) دارند اما دیگر از محصول استفاده نمیکنند وجود دارد. این حسابها شبیه حاشیه سود خالص به نظر میرسند اما معمولاً هشدار ریزش مشتری (Churn) هستند. جفت کردن حاشیه سود با یک عدد مربوط به میزان تعامل (Engagement) در یک نما، گفتگوها را صادقانه نگه میدارد.
در نهایت، توسعهدهندگان باید از معیار «هزینه به ازای هر درخواست» به عنوان معیار اصلی دوری کنند. چون یک درخواست، واحد ارزش نیست، این معیار وسوسهکننده اما گمراهکننده است. بهتر است هزینه را به ازای «تسک تکمیلشده» — مثل یک تیکت حلشده، یک سند تولیدشده یا یک پیشنهاد پذیرفتهشده — ردیابی کنید. این عدد با بهبود پرامپتهای شما تغییر میکند، در حالی که هزینه هر درخواست معمولاً ثابت میماند. برای حفظ این دقت، به یک جدول قیمتگذاری با نرخهای فعلی هر مدل برای هر تامینکننده، شامل نرخهای ورودی کششده، نیاز دارید تا از انحراف اعداد جلوگیری شود.
گام بعدی شما
- ساختار دیتابیس خود را بررسی کنید و ستونهای
cost_usdوbillable_unitsرا از هم جدا کنید. - یک کرونجاب (Cron Job) برای تجمیع روزانه دادهها با قابلیت بازنویسی (ON CONFLICT) پیادهسازی کنید.
- گزارشی برای شناسایی مشتریانی که هزینه مدلشان از درآمد ماهانه آنها بیشتر است تهیه کنید.
اما داستان سختافزاری این تحول و تأثیر آن بر قیمتهای نهایی حتی شگفتانگیزتر است — به تحلیل ما دربارهی تراشههای Blackwell مراجعه کنید.




گفتگو