راهنمای پیگیری هزینه نمایندگان
به عنوان نماینده فروش سرویسهای AvalAI API، پیگیری دقیق هزینه هر فراخوانی API برای صورتحساب صحیح و مدیریت حاشیه سود ضروری است. این راهنما یک گردش کار کامل و گام به گام برای پیادهسازی پیگیری دقیق هزینه با استفاده از User API ارائه میدهد.
فهرست مطالب
- چرا پیگیری دقیق هزینه مهم است
- چالش با estimated_cost
- راهحل: User API
- گردش کار پیادهسازی کامل
- توصیههای معماری
- مثالهای کد
- بهترین شیوهها
- رفع مشکلات
چرا پیگیری دقیق هزینه مهم است
به عنوان نماینده فروش، شما نیاز دارید:
- صورتحساب دقیق مشتریان: هزینه دقیق بر اساس استفاده واقعی
- حفظ حاشیه سود: محاسبه مارکآپ بر اساس هزینههای دقیق، نه تخمینی
- ارائه شفافیت: گزارشهای استفاده تفصیلی به مشتریان
- مدیریت جریان نقدی: درک هزینههای دقیق برای برنامهریزی مالی
- رسیدگی به اختلافات: داشتن سوابق دقیق برای حل مسائل صورتحساب
چالش با estimated_cost
بسیاری از پاسخهای API شامل فیلد estimated_cost هستند:
{
"usage": {
"prompt_tokens": 10,
"completion_tokens": 20,
"total_tokens": 30
},
"estimated_cost": {
"unit": "0.0000066000",
"irt": 0.76,
"exchange_rate": 115250
}
}مشکلات estimated_cost:
- ❌ تضمین وجود ندارد در تمام پاسخها
- ❌ ممکن است صورتحساب واقعی را منعکس نکند (به خصوص با بستههای اعتباری، گرنتها یا قیمتگذاری ویژه)
- ❌ متغیرهای دیگر را در نظر نمیگیرد مانند توکنهای کش شده، هزینه استریمینگ
- ❌ نرخ ارز ممکن است با نرخهای صورتحساب نهایی مطابقت نداشته باشد
نتیجه: نمیتوانید به طور قابل اعتماد بر اساس estimated_cost به مشتریان خود صورتحساب ارسال کنید.
راهحل: User API
نقطه پایانی /user/v1/transactions/lookup دادههای هزینه ۱۰۰٪ دقیق برای هر فراخوانی API ارائه میدهد.
مزایای کلیدی:
✅ ۱۰۰٪ دقیق: دقیقا با صورتحساب واقعی شما مطابقت دارد
✅ همیشه در دسترس: ظرف ۳۰ ثانیه پس از اتمام درخواست
✅ جزئیات کامل: شامل گرنتها، بستهها و هزینههای واقعی
✅ مسیر حسابرسی: تاریخچه کامل تراکنش برای انطباق
✅ ارزهای مختلف: هزینهها در UNIT (USD) و IRT (تومان)
نحوه کار:
- هر پاسخ API شامل هدر
x-request-id(UUID v7) است - این شناسه را با درخواست مشتری خود ذخیره کنید
- تا ۳۰ ثانیه برای پردازش هزینه صبر کنید
- با شناسه درخواست از
/user/v1/transactions/lookupپرسوجو کنید - دادههای هزینه دقیق برای صورتحساب دریافت کنید
گردش کار پیادهسازی کامل
مرحله ۱: ضبط شناسه درخواست
هر پاسخ AvalAI API شامل هدر x-request-id است. شما باید این را ضبط کنید:
# انجام فراخوانی API
response = requests.post(
"https://api.avalai.ir/v1/chat/completions",
headers={
"Authorization": f"Bearer {AVALAI_API_KEY}",
"Content-Type": "application/json",
},
json={"model": "gpt-5.4-mini", "messages": [{"role": "user", "content": "سلام!"}]},
)
# مهم: ضبط x-request-id از هدرها
request_id = response.headers.get("x-request-id")
# فورا با context مشتری ذخیره کنید
db.insert_pending_transaction(
{
"request_id": request_id,
"customer_id": customer.id,
"timestamp": datetime.now(),
"model": "gpt-5.4-mini",
"response_data": response.json(),
}
)نسخه معادل Responses API
وقتی مدل انتخابی از /v1/responses پشتیبانی میکند، این نسخه را کنار مثال Chat Completions استفاده کنید. messages به input منتقل میشود و متن نهایی از response.output_text خوانده میشود.
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["AVALAI_API_KEY"],
base_url="https://api.avalai.ir/v1",
)
response = client.responses.create(
model="gpt-5.4-mini",
instructions="You are a helpful assistant.",
input="سلام!",
)
print(response.output_text)messages→input- پیام سیستمی →
instructionsیا آیتمdeveloper choices[0].message.content→response.output_text- برای ابزارها و خروجیهای چندوجهی،
response.outputرا بر اساسtypeبررسی کنید.
مرحله ۲: صبر برای پردازش هزینه
هزینهها به صورت ناهمزمان پردازش میشوند. تا ۳۰ ثانیه صبر کنید (معمولا خیلی سریعتر):
import time
# گزینه الف: همزمان - فورا صبر کنید
time.sleep(5) # معمولا در ۳-۵ ثانیه در دسترس است
# گزینه ب: ناهمزمان - بعدا پردازش کنید (توصیه میشود)
# request_id را برای پردازش پسزمینه در صف قرار دهید
cost_tracking_queue.add(
{
"request_id": request_id,
"customer_id": customer.id,
"retry_after": datetime.now() + timedelta(seconds=5),
}
)مرحله ۳: جستجوی هزینه دقیق
از User API برای دریافت جزئیات دقیق هزینه پرسوجو کنید:
# جستجوی هزینه تراکنش
lookup_response = requests.post(
"https://api.avalai.ir/user/v1/transactions/lookup",
headers={
"Authorization": f"Bearer {AVALAI_API_KEY}",
"Content-Type": "application/json",
},
json={"transaction_ids": [request_id]},
)
cost_data = lookup_response.json()
if cost_data["summary"]["found"] > 0:
transaction = cost_data["transactions"][0]
# استخراج هزینههای دقیق
actual_cost_usd = float(transaction["cost"]["unit"])
actual_cost_irt = float(transaction["cost"]["paid_irt"]) + float(
transaction["cost"]["paid_grant_irt"]
)
# بهروزرسانی پایگاه داده
db.update_transaction_cost(
request_id=request_id,
cost_usd=actual_cost_usd,
cost_irt=actual_cost_irt,
cost_details=transaction["cost"],
)مرحله ۴: صورتحساب به مشتری
حالا هزینههای دقیق دارید و میتوانید صورتحساب دقیق ارسال کنید:
# محاسبه قیمتگذاری (مثال: ۲۰٪ مارکآپ)
customer_cost_usd = actual_cost_usd * 1.20
customer_cost_irt = actual_cost_irt * 1.20
# ثبت هزینه
db.insert_customer_charge(
{
"customer_id": customer.id,
"request_id": request_id,
"avalai_cost_usd": actual_cost_usd,
"customer_cost_usd": customer_cost_usd,
"markup_percent": 20,
"timestamp": datetime.now(),
}
)
# بهروزرسانی موجودی مشتری
customer.deduct_balance(customer_cost_usd)توصیههای معماری
گزینه ۱: همزمان (ساده، تاخیر بیشتر)
[مشتری] → [API شما] → [AvalAI API]
↓
ضبط x-request-id
↓
صبر ۵ ثانیه
↓
جستجوی هزینه دقیق
↓
بازگشت به مشتریمزایا: پیادهسازی ساده، داده فوری هزینه
معایب: ۵+ ثانیه به زمان پاسخ اضافه میکند
گزینه ۲: ناهمزمان (توصیه میشود)
[مشتری] → [API شما] → [AvalAI API]
↓ ↓
ذخیره request_id |
↓ |
بازگشت فوری |
↓
[Worker پسزمینه]
↓
جستجوی هزینه (۵ث بعد)
↓
بهروزرسانی پایگاه دادهمزایا: پاسخ سریع به مشتری، مقیاسپذیر
معایب: کمی پیچیدهتر
گزینه ۳: پردازش دستهای (حجم بالا)
[جمعآوری request_ids در طول روز]
↓
[کار دستهای ساعتی]
↓
جستجوی هزینهها در دسته (تا ۱۰۰۰ شناسه)
↓
بهروزرسانی همه هزینهها به یکباره
↓
تولید فاکتورهای مشتریمزایا: کارآمد برای حجم بالا، کاهش فراخوانیهای API
معایب: داده تاخیری هزینه
مثالهای کد
پیادهسازی کامل پایتون
import requests
import time
from datetime import datetime, timedelta
from typing import Dict, List
import logging
class AvalAIReseller:
def __init__(self, avalai_api_key: str):
self.api_key = avalai_api_key
self.base_url = "https://api.avalai.ir"
def make_customer_request(
self, customer_id: str, model: str, messages: List[Dict], **kwargs
) -> Dict:
"""
درخواست API از طرف مشتری و پیگیری هزینهها
"""
# مرحله ۱: انجام فراخوانی API
response = requests.post(
f"{self.base_url}/v1/chat/completions",
headers={
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json",
},
json={"model": model, "messages": messages, **kwargs},
)
# مرحله ۲: ضبط x-request-id
request_id = response.headers.get("x-request-id")
if not request_id:
logging.error("هیچ x-request-id در هدرهای پاسخ وجود ندارد!")
raise ValueError("هدر x-request-id وجود ندارد")
# مرحله ۳: ذخیره برای جستجوی هزینه
self.store_pending_transaction(
request_id=request_id,
customer_id=customer_id,
model=model,
response_data=response.json(),
)
# مرحله ۴: صف برای پردازش هزینه (async)
self.queue_cost_lookup(request_id, customer_id)
return {"request_id": request_id, "response": response.json()}
def lookup_transaction_cost(
self, request_ids: List[str], max_retries: int = 3
) -> Dict:
"""
جستجوی هزینههای دقیق برای یک یا چند تراکنش
تلاش مجدد اگر هزینه هنوز در دسترس نباشد
"""
for attempt in range(max_retries):
response = requests.post(
f"{self.base_url}/user/v1/transactions/lookup",
headers={
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json",
},
json={"transaction_ids": request_ids},
)
data = response.json()
# بررسی اینکه همه تراکنشها یافت شدهاند
if data["summary"]["found"] == len(request_ids):
return data
# اگر یافت نشد، صبر کنید و دوباره تلاش کنید
if attempt < max_retries - 1:
wait_time = 5 * (attempt + 1) # عقبنشینی نمایی
logging.info(f"تراکنشها آماده نیستند، {wait_time}ث صبر میکنیم...")
time.sleep(wait_time)
return data
def process_transaction_cost(self, request_id: str, customer_id: str):
"""
پردازش هزینه برای یک تراکنش و صورتحساب به مشتری
"""
# جستجوی هزینه
cost_data = self.lookup_transaction_cost([request_id])
if cost_data["summary"]["found"] == 0:
logging.error(f"تراکنش {request_id} یافت نشد!")
return
transaction = cost_data["transactions"][0]
# استخراج هزینهها
avalai_cost_usd = float(transaction["cost"]["unit"])
avalai_cost_irt = float(transaction["cost"]["paid_irt"]) + float(
transaction["cost"]["paid_grant_irt"]
)
# اعمال مارکآپ (مثلا ۲۰٪)
markup = 1.20
customer_cost_usd = avalai_cost_usd * markup
customer_cost_irt = avalai_cost_irt * markup
# ذخیره در پایگاه داده
self.record_customer_charge(
customer_id=customer_id,
request_id=request_id,
avalai_cost_usd=avalai_cost_usd,
customer_cost_usd=customer_cost_usd,
avalai_cost_irt=avalai_cost_irt,
customer_cost_irt=customer_cost_irt,
transaction_details=transaction,
)
logging.info(
f"مشتری {customer_id} صورتحساب شد: "
f"${customer_cost_usd:.6f} "
f"(AvalAI: ${avalai_cost_usd:.6f}, مارکآپ: ۲۰٪)"
)
def store_pending_transaction(self, request_id, customer_id, model, response_data):
"""منطق ذخیرهسازی پایگاه داده خود را پیادهسازی کنید"""
pass
def queue_cost_lookup(self, request_id, customer_id):
"""منطق صف خود را پیادهسازی کنید (Redis، Celery و غیره)"""
pass
def record_customer_charge(self, **kwargs):
"""منطق صورتحساب خود را پیادهسازی کنید"""
pass
# استفاده
reseller = AvalAIReseller(avalai_api_key="your-key")
# درخواست برای مشتری
result = reseller.make_customer_request(
customer_id="cust_123",
model="gpt-5.4-mini",
messages=[{"role": "user", "content": "سلام!"}],
)
# هزینه به صورت ناهمزمان در پسزمینه پردازش خواهد شدنسخه معادل Responses API
وقتی مدل انتخابی از /v1/responses پشتیبانی میکند، این نسخه را کنار مثال Chat Completions استفاده کنید. messages به input منتقل میشود و متن نهایی از response.output_text خوانده میشود.
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["AVALAI_API_KEY"],
base_url="https://api.avalai.ir/v1",
)
response = client.responses.create(
model="gpt-5.4-mini",
instructions="You are a helpful assistant.",
input="سلام!",
)
print(response.output_text)messages→input- پیام سیستمی →
instructionsیا آیتمdeveloper choices[0].message.content→response.output_text- برای ابزارها و خروجیهای چندوجهی،
response.outputرا بر اساسtypeبررسی کنید.
بهترین شیوهها
1. همیشه x-request-id را ضبط کنید
هنگام استفاده از کتابخانه requests یا سایر HTTP clients:
# ✅ خوب
request_id = response.headers.get("x-request-id")
if not request_id:
raise ValueError("x-request-id وجود ندارد - نمیتوان هزینه را پیگیری کرد!")
# ❌ بد
# عدم ضبط x-request-id یعنی نمیتوانید هزینهها را پیگیری کنیدهنگام استفاده از OpenAI SDK (توصیه میشود):
from openai import OpenAI
client = OpenAI(
api_key="your-avalai-api-key",
base_url="https://api.avalai.ir/v1",
)
response = client.chat.completions.create(
model="gpt-5.4-mini",
messages=[{"role": "user", "content": "سلام!"}],
)
# ✅ خوب - OpenAI SDK ویژگی _request_id را فراهم میکند
request_id = response._request_id
if not request_id:
raise ValueError("request_id وجود ندارد - نمیتوان هزینه را پیگیری کرد!")
print(f"شناسه درخواست: {request_id}")
# خروجی: شناسه درخواست: 019ac4a0-a8f4-7041-845f-3ea8f15dcf1aنسخه معادل Responses API
وقتی مدل انتخابی از /v1/responses پشتیبانی میکند، این نسخه را کنار مثال Chat Completions استفاده کنید. messages به input منتقل میشود و متن نهایی از response.output_text خوانده میشود.
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["AVALAI_API_KEY"],
base_url="https://api.avalai.ir/v1",
)
response = client.responses.create(
model="gpt-5.4-mini",
instructions="You are a helpful assistant.",
input="سلام!",
)
print(response.output_text)messages→input- پیام سیستمی →
instructionsیا آیتمdeveloper choices[0].message.content→response.output_text- برای ابزارها و خروجیهای چندوجهی،
response.outputرا بر اساسtypeبررسی کنید.
توجه
ویژگی _request_id به طور خودکار توسط OpenAI SDK هنگام استفاده از نقطه پایانی API AvalAI پر میشود. این روش توصیه شده است زیرا تجزیه هدر را به طور خودکار انجام میدهد.
هنگام استفاده از LangChain (که به طور مستقیم هدرهای HTTP را نمایش نمیدهد):
import httpx
from langchain_openai import ChatOpenAI
from langchain_core.callbacks import BaseCallbackHandler
from contextvars import ContextVar
import os
# ذخیره هدرها در متغیر context برای امنیت نخ
request_headers: ContextVar[dict] = ContextVar("request_headers", default={})
class HeaderCapturingClient(httpx.Client):
def send(self, request, **kwargs):
response = super().send(request, **kwargs)
request_headers.set(dict(response.headers))
return response
class HeaderAccessCallback(BaseCallbackHandler):
def __init__(self):
self.request_id = None
def on_llm_end(self, response, **kwargs):
headers = request_headers.get()
self.request_id = headers.get("x-request-id")
# راهاندازی
http_client = HeaderCapturingClient()
chat_generator = ChatOpenAI(
base_url="https://api.avalai.ir/v1",
api_key=os.getenv("AVALAI_API_KEY"),
model="gpt-5.4-mini",
http_client=http_client,
)
callback = HeaderAccessCallback()
response = chat_generator.invoke("سلام!", config={"callbacks": [callback]})
# ✅ خوب - دسترسی به request_id از callback
request_id = callback.request_id
if not request_id:
raise ValueError("request_id وجود ندارد - نمیتوان هزینه را پیگیری کرد!")
print(f"شناسه درخواست: {request_id}")توجه
برای استفاده غیرهمزمان از LangChain، از httpx.AsyncClient و AsyncCallbackHandler استفاده کنید. برای مثالهای کامل غیرهمزمان به راهنمای هدرهای پاسخ مراجعه کنید.
2. منطق تلاش مجدد پیادهسازی کنید
هزینهها ممکن است فورا در دسترس نباشند. عقبنشینی نمایی پیادهسازی کنید:
def lookup_with_retry(request_id, max_attempts=3):
for attempt in range(max_attempts):
data = lookup_cost(request_id)
if data["summary"]["found"] > 0:
return data
time.sleep(5 * (attempt + 1)) # ۵ث، ۱۰ث، ۱۵ث
raise Exception("هزینه پس از تلاشهای مجدد در دسترس نیست")3. پردازش دستهای برای کارایی
اگر حجم بالایی دارید، درخواستهای جستجو را دستهبندی کنید:
# پردازش ۱۰۰۰ تراکنش به یکباره
request_ids = get_pending_request_ids(limit=1000)
cost_data = lookup_transaction_cost(request_ids)
for transaction in cost_data["transactions"]:
process_cost(transaction)4. جزئیات کامل تراکنش را ذخیره کنید
فقط هزینه را ذخیره نکنید - همه چیز را برای حسابرسی ذخیره کنید:
db.store_transaction({
"request_id": request_id,
"customer_id": customer_id,
"timestamp": transaction["requested_at"],
"model": transaction["model"],
"tokens": transaction["tokens"],
"avalai_cost_unit": transaction["cost"]["unit"],
"avalai_cost_irt": transaction["cost"]["paid_irt"],
markup_percent": 20
})رفع مشکلات
مشکل: x-request-id در هدرهای پاسخ نیست
علت: استفاده از SDK قدیمی یا بررسی نادرست هدرها
راهحل:
# مطمئن شوید که به هدرهای پاسخ دسترسی دارید، نه بدنه
request_id = response.headers.get("x-request-id") # ✅ صحیح
request_id = response.json().get("x-request-id") # ❌ اشتباه - در بدنه نیستمشکل: تراکنش پس از ۳۰ ثانیه یافت نمیشود
علت: بسیار نادر، اما ممکن است در بار بالا اتفاق بیفتد
راهحل:
# تلاش مجدد طولانیتر پیادهسازی کنید
max_wait = 60 # تا ۶۰ ثانیه صبر کنید
interval = 10
for i in range(max_wait // interval):
data = lookup_cost(request_id)
if data["summary"]["found"] > 0:
return data
time.sleep(interval)
# اگر هنوز یافت نشد، با شناسه درخواست با پشتیبانی تماس بگیریدمشکل: هزینهها با estimated_cost مطابقت ندارند
علت: این انتظار میرود! estimated_cost تخمینی است؛ /transactions/lookup هزینه واقعی است
راهحل:
- همیشه از
/transactions/lookupبرای صورتحساب استفاده کنید estimated_costرا برای تصمیمات مالی نادیده بگیرید- فقط برای تخمینهای تقریبی UX از
estimated_costاستفاده کنید
منابع مرتبط
- مرجع User API - مستندات کامل API
- راهنمای هدرهای پاسخ - درک x-request-id و محدودیتهای نرخ
- راهنمای سازمانی - الگوهای استفاده پیشرفته برای عملیات در مقیاس بزرگ
- محدودیتهای نرخ - درک محدودیتهای نرخ API
پشتیبانی
برای پشتیبانی ویژه نمایندگان فروش یا سوالات درباره پیگیری هزینه، با تیم پشتیبانی ما با جزئیات حساب نمایندگی خود تماس بگیرید.
ایمیل: support@avalai.ir
شامل: شناسه نمایندگی شما و شناسههای درخواست خاص برای هر مشکلی