ব্লগে ফিরে যান

API ও SDKগাইড

Python-এ AI এজেন্ট টোকেন খরচ ট্র্যাক করুন: usage, বাজেট, স্টপ

প্রতিটি রিকোয়েস্টের usage ফিল্ড লগ করুন, প্রতি টাস্কে যোগ করুন এবং একটি ডলার বাজেটে এজেন্ট থামান। OpenAI-সামঞ্জস্যপূর্ণ API-এর জন্য কার্যকর Python উদাহরণ।

CheapTokens Team দ্বারাপ্রকাশিত হয়েছে 11 মিনিট পড়ার সময়

টার্মিনাল-স্টাইল কোড কার্ড: একটি প্রতি-ধাপ usage লগ এবং একটি বাজেট চেক যা একটি AI এজেন্ট থামায়
এই পৃষ্ঠায়
  1. সংখ্যাগুলো কোথায়: usage অবজেক্ট
  2. একটি মিটার যা এজেন্টকে থামায়
  3. একটি 40-ধাপের রান যোগ করলে কত হয়
  4. যখন মডেল চিন্তা করছে
  5. স্ট্রিমিং: usage শেষে আসে
  6. যদি সংখ্যাগুলো ভুল মনে হয়

আপনার এজেন্ট দশ মিনিট ধরে চলেছে আর বিলটা কাজের চেয়ে বড় হয়ে গেছে। কারণটা দেখতে, প্রতিটি API রেসপন্সে usage অবজেক্টটি পড়ুন, প্রতি টাস্কে সেটি যোগ করুন এবং মডেলের প্রতি 1M টোকেনের দাম দিয়ে গুণ করুন। এটিকে সীমাবদ্ধ করতে, প্রতিটি ধাপের পরে সেই চলমান যোগফলকে একটি বাজেটের সাথে তুলনা করুন এবং সীমা ছাড়িয়ে গেলে লুপটি থামিয়ে দিন। নিচে একটি ছোট Python ক্লাস আছে যা ঠিক এটাই করে।

উদাহরণটি OpenAI-সামঞ্জস্যপূর্ণ এন্ডপয়েন্ট https://api.cheaptokens.dev/v1 এবং মডেল আইডি deepseek-ai/DeepSeek-V4-Flash-0731 ব্যবহার করে (380K কনটেক্সট, প্রতি উত্তরে সর্বোচ্চ 32,768 আউটপুট টোকেন)। আপনি যদি একটি রান শুরু করার আগে অনুমান করতে চান, সেটি ভিন্ন কাজ, এবং কীভাবে একটি AI এজেন্টের খরচ অনুমান করবেন সেটি কভার করে। এই নিবন্ধটি রান চলাকালীন পরিমাপ এবং সীমাবদ্ধতা সম্পর্কে।

সংখ্যাগুলো কোথায়: usage অবজেক্ট#

প্রতিটি নন-স্ট্রিমিং চ্যাট কমপ্লিশন একটি usage অবজেক্ট নিয়ে ফিরে আসে। DeepSeek-এর API রেফারেন্স (26 অক্টোবর 2026-এ যাচাই করা) এই ফিল্ডগুলো তালিকাভুক্ত করে:

  • prompt_tokens — এবার আপনি যা পাঠিয়েছেন সবকিছু: সিস্টেম প্রম্পট, ইতিহাস, টুল ফলাফল।
  • completion_tokens — মডেল যা লিখে ফেরত দিয়েছে।
  • total_tokens — দুটো একসাথে যোগ করা।

DeepSeek ঐচ্ছিক অতিরিক্তও ডকুমেন্ট করে: prompt_cache_hit_tokens এবং prompt_cache_miss_tokens (এগুলো যোগ করলে prompt_tokens হয়), এবং থিংকিং মডেলের জন্য completion_tokens_details.reasoning_tokens। পৃষ্ঠাটি কোনো প্রকাশের তারিখ দেখায় না, এবং এই অতিরিক্তগুলো OpenAI ফরম্যাটের এক্সটেনশন, তাই নিচের কোডটি সেগুলোকে ঐচ্ছিক হিসেবে বিবেচনা করে এবং শুধুমাত্র প্রথম দুটি ফিল্ডের উপর নির্ভর করে।

কেন প্রতিটি ধাপ লগ করবেন এবং শুধু শেষটি নয়? কারণ একটি এজেন্ট প্রতিবার তার বর্ধমান কনটেক্সট পুনরায় পাঠায়। ধাপ 1 হয়তো 2,000 ইনপুট টোকেন পাঠায়, ধাপ 30 হয়তো 9,000 পাঠায়, এবং বিলটি সেগুলোর সবকিছুর যোগফল। কারণটি কেন একটি দীর্ঘ চ্যাট বেশি খরচ করে-এ ব্যাখ্যা করা হয়েছে, এবং ইনপুট/আউটপুট বিভাজন ইনপুট বনাম আউটপুট টোকেন-এ।

একটি মিটার যা এজেন্টকে থামায়#

এখানে পুরো জিনিসটি: একটি মিটার যা টোকেন যোগ করে, প্রতি ধাপে একটি লাইন প্রিন্ট করে এবং বাজেট ছাড়িয়ে গেলে একটি ত্রুটি উত্থাপন করে, সাথে এটির চারপাশে একটি সাধারণ এজেন্ট লুপ। pip install openai দিয়ে SDK ইনস্টল করুন এবং আপনার কী CHEAPTOKENS_API_KEY-এ রাখুন।

python
import os
from openai import OpenAI

client = OpenAI(
    base_url='https://api.cheaptokens.dev/v1',
    api_key=os.environ['CHEAPTOKENS_API_KEY'],
)
MODEL = 'deepseek-ai/DeepSeek-V4-Flash-0731'

# example prices, USD per 1M tokens: use the current ones from the pricing table
PRICE_IN = 0.10
PRICE_OUT = 0.40


class BudgetExceeded(Exception):
    pass


class TaskMeter:
    def __init__(self, budget_usd):
        self.budget = budget_usd
        self.steps = 0
        self.tokens_in = 0
        self.tokens_out = 0
        self.reasoning = 0

    @property
    def cost(self):
        return (self.tokens_in * PRICE_IN + self.tokens_out * PRICE_OUT) / 1_000_000

    def add(self, usage):
        self.steps += 1
        self.tokens_in += usage.prompt_tokens
        self.tokens_out += usage.completion_tokens
        details = getattr(usage, 'completion_tokens_details', None)
        self.reasoning += getattr(details, 'reasoning_tokens', 0) or 0
        print(f'step {self.steps}: in={usage.prompt_tokens} '
              f'out={usage.completion_tokens} task=${self.cost:.4f}')
        if self.cost > self.budget:
            raise BudgetExceeded(
                f'budget ${self.budget:.2f} crossed at step {self.steps}: '
                f'${self.cost:.4f}')


def run_task(goal, budget_usd=0.50, max_steps=40):
    meter = TaskMeter(budget_usd)
    messages = [
        {'role': 'system', 'content': 'Work step by step. Reply DONE when finished.'},
        {'role': 'user', 'content': goal},
    ]
    for _ in range(max_steps):
        resp = client.chat.completions.create(
            model=MODEL, messages=messages, max_tokens=1024)
        meter.add(resp.usage)  # log first, then decide
        reply = resp.choices[0].message.content or ''
        messages.append({'role': 'assistant', 'content': reply})
        if 'DONE' in reply:
            break
        messages.append({'role': 'user', 'content': 'Continue.'})
    return meter


try:
    meter = run_task('Summarise the main risks of a database migration.')
    print(f'finished: {meter.steps} steps, ${meter.cost:.4f}')
except BudgetExceeded as err:
    print('stopped:', err)

সেখানে তিনটি পছন্দ অনুকরণ করার মতো।

সিদ্ধান্ত নেওয়ার আগে লগ করুন। meter.add প্রথমে ধাপটি রেকর্ড করে এবং তারপরেই বাজেট পরীক্ষা করে, তাই একটি থামানো রানও একটি সম্পূর্ণ ট্রেস রেখে যায়। সীমা ছাড়িয়ে যাওয়া কলে যাওয়ার পরে চেকটি ঘটে, তাই আপনি সর্বোচ্চ এক ধাপ বেশি যেতে পারেন। max_tokens=1024 সেই শেষ ধাপের আউটপুট সীমাবদ্ধ করে।

দুটি কঠিন স্টপ, একটি নয়। max_steps এমন একটি এজেন্টকে ধরে যা বেশি খরচ না করেই লুপ করে; ডলার বাজেট এমন একটি এজেন্টকে ধরে যা প্রতি ধাপে অনেক খরচ করে। আপনার দুটোই দরকার।

দাম এক জায়গায় থাকে। PRICE_IN এবং PRICE_OUT প্লেসহোল্ডার সংখ্যা। আপনার মডেলের জন্য বর্তমান মানগুলো প্রাইসিং পেজ থেকে কপি করুন; এই মুহূর্তে DeepSeek-V4-Flash প্রতি 1M ইনপুট টোকেনে $0.015 এবং প্রতি 1M আউটপুট টোকেনে $0.10।

একটি 40-ধাপের রান যোগ করলে কত হয়#

ধরুন আপনার এজেন্ট 40 ধাপ নেয়, এবং কনটেক্সট বাড়ার কারণে একটি গড় ধাপ 6,000 ইনপুট টোকেন পাঠায় এবং 400 টোকেন ফেরত পায়। সেটি হলো 40 × 6,000 = 240,000 ইনপুট টোকেন এবং 40 × 400 = 16,000 আউটপুট টোকেন টাস্কের জন্য।

ধাপ 1 2,000 ইনপুট টোকেন পাঠায়, ধাপ 30 9,000 পাঠায়; টাস্কের মোট হলো সব ধাপের যোগফল
নিবন্ধের অনুমানসহ চিত্রণ, রান ফলাফল নয়

DeepSeek-V4-Flash-এ এর খরচ $0.0052। টেবিলটি একই কাজের চাপ অন্য মডেলগুলোতে চালায় এবং OpenRouter-এর রেফারেন্স মূল্য আমাদেরটির পাশে রাখে:

মডেল খরচ OpenRouter
GLM-5.3-Flash $0.0054 $0.0111
DeepSeek-V4-Flash $0.0052 $0.0139
MiniMax-M2.7 $0.0144 $0.0912

মোট ২,৪০,০০০ ইনপুট এবং ১৬,০০০ আউটপুট টোকেন। প্রতি 1M টোকেনের দাম বর্তমান এবং আমাদের ট্যারিফের সাথে পরিবর্তিত হয়; OpenRouter কলামটি একই ওয়ার্কলোডের জন্য রেফারেন্স মূল্য দেখায়।

সব মিলিয়ে, ইনপুট এবং আউটপুট একসাথে গণনা করলে, এই টাস্কের জন্য DeepSeek-V4-Flash OpenRouter-এর চেয়ে সস্তা হয়। টোকেনগুলো কোথায় আছে সেটিও লক্ষ্য করুন: 256,000-এর মধ্যে 240,000 হলো ইনপুট। আপনার এজেন্ট যে কনটেক্সট টেনে নিয়ে যায় সেটিই বিল, তাই আপনার লগে প্রতি-ধাপের in= সংখ্যাটিই নজরে রাখার মতো। উপরের উদাহরণে প্রতি টাস্কে $0.50 বাজেট হলো একটি অনিয়ন্ত্রিত খরচের সীমা, লক্ষ্য নয়।

মডেল বদলানো মানে শুধু MODEL পরিবর্তন করা। CheapTokens ডকস থেকে আইডি বেছে নিন: প্রদানকারীদের মধ্যে নামগুলো ভিন্ন, এবং একটি মূল্য লেবেল থেকে নেওয়া ছোট আইডি API-তে কাজ করবে না। দীর্ঘ এজেন্ট লুপের জন্য, DeepSeek-V4-Flash-এর দিনের যেকোনো সময়ে একই দাম, তাই একটি টাস্কের খরচ দুপুরে এবং রাত 3টায় একই। এর সীমাগুলোর জন্য DeepSeek পেজ দেখুন।

যখন মডেল চিন্তা করছে#

যদি একটি উত্তর আপনি যে টেক্সট দেখেন তার চেয়ে টোকেনে অনেক বেশি লম্বা হয়, reasoning_tokens দেখুন। থিংকিং টোকেন আউটপুট হিসেবে গণনা করা হয়, তাই একটি রিজনিং-ভারী ধাপ দৃশ্যমান টেক্সটের চেয়ে অনেক বেশি আউটপুট টোকেন তৈরি করতে পারে, এবং সেগুলো আউটপুট হিসেবে বিল করা হয়। উপরের মিটারটি API ফিল্ডটি ফেরত দিলে সেগুলো meter.reasoning-এ সংগ্রহ করে এবং না দিলে 0-তে রাখে, তাই অনুপস্থিত কী-তে এটি কখনো ক্র্যাশ করে না। আউটপুটের কতটা চিন্তা ছিল তা দেখতে চাইলে out=-এর পাশে এটি প্রিন্ট করুন। রিজনিং এফোর্ট এবং থিংকিং টোকেন কেন তা ব্যাখ্যা করে।

স্ট্রিমিং: usage শেষে আসে#

যদি আপনার এজেন্ট স্ট্রিম করে, সাধারণ চাঙ্কগুলোতে usage থাকে না। OpenAI ফরম্যাটে আপনি stream_options={'include_usage': True} দিয়ে এটি চান। DeepSeek-এর রেফারেন্স (26 অক্টোবর 2026-এ যাচাই করা) বলে অপশনটি শুধু stream=True-এর সাথে কাজ করে (অন্যথায় API 400 উত্তর দেয়), usage প্রতিটি চাঙ্কে null কিন্তু একটিতে নয়, এবং data: [DONE]-এর আগের শেষ চাঙ্কটি পুরো রিকোয়েস্টের মোট বহন করে। তাই একটি স্ট্রিমিং লুপে, meter.add একবার কল করুন, সেই চাঙ্কে যেখানে usage খালি নয়। উপরের নন-স্ট্রিমিং লুপটি শুরু করার সবচেয়ে সহজ জায়গা; Python-এ স্ট্রিমিং-এ লুপটি নিজেই আছে।

যদি সংখ্যাগুলো ভুল মনে হয়#

  • usage None। আপনি include_usage ছাড়া স্ট্রিম করছেন। এটি যোগ করুন, বা একটি নন-স্ট্রিমিং কলে স্যুইচ করুন।
  • মোট ব্যালেন্স হ্রাসের চেয়ে কম। পরীক্ষা করুন প্রতিটি কল মিটারের মধ্য দিয়ে যায়: রিট্রাই, একটি সামারাইজিং কল বা run_task-এর বাইরে করা একটি টুল-পিকিং কল সহজেই মিস হয়। client.chat.completions.create একটি ফাংশনে মুড়ে দিন এবং সবকিছু তার মধ্য দিয়ে রুট করুন।
  • প্রতি ধাপে খরচ ক্রমাগত বাড়ছে। messages-এ সবকিছু অ্যাপেন্ড করা একটি লুপের জন্য এটি স্বাভাবিক। পুরনো টুল আউটপুট ছেঁটে দিন বা ইতিহাস সামারাইজ করুন; কনটেক্সটের বাইরে টুল আউটপুট ধারণাটি দেখায়।
  • BudgetExceeded ধাপ 2-এ ফায়ার করে। আপনার বাজেট এক ধাপের চেয়ে ছোট। পরীক্ষা করুন PRICE_IN প্রতি 1M টোকেনে, প্রতি 1K-তে নয়।

সংখ্যাগুলো সংরক্ষণ করতে, meter.steps, meter.tokens_in, meter.tokens_out এবং meter.cost প্রতি টাস্কে একটি JSON লাইন হিসেবে লিখুন। এক সপ্তাহের সেই লাইনগুলো আপনার এজেন্টের জন্য প্রতি ধাপে প্রকৃত টোকেন বলে দেয়, যা পরবর্তীতে প্রতিটি অনুমানে বসানোর সংখ্যা। মডেল, দাম এবং প্রথম রিকোয়েস্ট ডকস-এ আছে; টুল কল Python-এ ফাংশন কলিং-এ কভার করা হয়েছে।