กลับไปที่บล็อก

API และ SDKคู่มือ

ติดตามค่าใช้จ่ายโทเคนของเอเจนต์ AI ใน Python: usage, งบประมาณ, การหยุด

บันทึกฟิลด์ usage ของทุกคำขอ รวมต่องาน และหยุดเอเจนต์ที่งบประมาณเป็นดอลลาร์ ตัวอย่าง Python ที่ใช้งานได้สำหรับ API ที่เข้ากันได้กับ OpenAI

โดย CheapTokens Teamเผยแพร่เมื่อ ใช้เวลาอ่าน 7 นาที

การ์ดโค้ดสไตล์เทอร์มินัล: บันทึก usage ต่อขั้นตอนและการตรวจสอบงบประมาณที่หยุดเอเจนต์ AI
ในหน้านี้
  1. ตัวเลขอยู่ตรงไหน: ออบเจ็กต์ usage
  2. มิเตอร์ที่หยุดเอเจนต์
  3. การรัน 40 ขั้นตอนรวมเป็นเท่าไร
  4. เมื่อโมเดลกำลังคิดวิเคราะห์
  5. การสตรีม: usage มาทีหลังสุด
  6. หากตัวเลขดูผิด

เอเจนต์ของคุณรันไปสิบนาทีแล้ว แต่ค่าใช้จ่ายกลับมากกว่างานที่ทำเสียอีก หากต้องการรู้ว่าทำไม ให้อ่านออบเจ็กต์ usage ในทุกการตอบกลับของ API นำมารวมกันต่องาน แล้วคูณด้วยราคาของโมเดลต่อ 1M โทเคน หากต้องการจำกัดวงเงิน ให้นำยอดรวมที่สะสมได้นั้นมาเทียบกับงบประมาณหลังจากแต่ละขั้นตอน และหยุดลูปเมื่อเกินงบ ด้านล่างนี้คือคลาส Python ขนาดเล็กที่ทำหน้าที่นี้โดยตรง

ตัวอย่างนี้ใช้เอนด์พอยต์ที่เข้ากันได้กับ OpenAI https://api.cheaptokens.dev/v1 และรหัสโมเดล deepseek-ai/DeepSeek-V4-Flash-0731 (บริบท 380K เอาต์พุตสูงสุด 32,768 โทเคนต่อคำตอบ) หากคุณต้องการประเมินการรัน ก่อน เริ่ม นั่นเป็นอีกงานหนึ่ง และ How to estimate the cost of an AI agent ครอบคลุมเรื่องนั้น บทความนี้ว่าด้วยการวัดและจำกัดวงเงินระหว่างที่การรันดำเนินอยู่

ตัวเลขอยู่ตรงไหน: ออบเจ็กต์ usage#

การตอบกลับแบบแชทที่ไม่สตรีมทุกครั้งจะมาพร้อมออบเจ็กต์ usage เอกสารอ้างอิง API ของ DeepSeek (ตรวจสอบเมื่อ 26 ตุลาคม 2026) ระบุฟิลด์เหล่านี้:

  • prompt_tokens — ทุกอย่างที่คุณส่งไปในครั้งนี้: system prompt, ประวัติ, ผลลัพธ์จากเครื่องมือ
  • completion_tokens — สิ่งที่โมเดลเขียนกลับมา
  • total_tokens — สองอย่างรวมกัน

DeepSeek ยังระบุฟิลด์เสริมที่ไม่บังคับ: prompt_cache_hit_tokens และ prompt_cache_miss_tokens (รวมกันได้ prompt_tokens) และ completion_tokens_details.reasoning_tokens สำหรับโมเดลที่คิดวิเคราะห์ หน้าเว็บนั้นไม่แสดงวันที่เผยแพร่ และฟิลด์เสริมเหล่านี้เป็นส่วนขยายของรูปแบบ OpenAI ดังนั้นโค้ดด้านล่างจึงถือว่าเป็นฟิลด์ที่ไม่บังคับ และพึ่งพาเฉพาะสองฟิลด์แรกเท่านั้น

ทำไมต้องบันทึกทุกขั้นตอน ไม่ใช่แค่ขั้นตอนสุดท้าย? เพราะเอเจนต์ส่งบริบทที่Growingขึ้นใหม่ทุกครั้ง ขั้นตอนที่ 1 อาจส่ง 2,000 อินพุตโทเคน ขั้นตอนที่ 30 อาจส่ง 9,000 และค่าใช้จ่ายคือผลรวมของทั้งหมด เหตุผลอธิบายไว้ใน why a long chat costs more และการแยกอินพุต/เอาต์พุตอยู่ใน input vs output tokens

มิเตอร์ที่หยุดเอเจนต์#

นี่คือทั้งหมด: มิเตอร์ที่รวมโทเคน พิมพ์หนึ่งบรรทัดต่อขั้นตอน และโยนข้อผิดพลาดเมื่อเกินงบประมาณ พร้อมลูปเอเจนต์แบบเรียบง่ายที่ห่อหุ้มไว้ ติดตั้ง SDK ด้วย pip install openai และใส่คีย์ของคุณใน 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 เป็นตัวเลขตัวอย่าง คัดลอกค่าปัจจุบันสำหรับโมเดลของคุณจาก pricing page ตอนนี้ DeepSeek-V4-Flash อยู่ที่ $0.015 ต่อ 1M อินพุตโทเคน และ $0.10 ต่อ 1M เอาต์พุตโทเคน

การรัน 40 ขั้นตอนรวมเป็นเท่าไร#

สมมติว่าเอเจนต์ของคุณใช้ 40 ขั้นตอน และเนื่องจากบริบทGrowingขึ้น โดยเฉลี่ยแต่ละขั้นตอนส่ง 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

240,000 โทเค็นอินพุตและ 16,000 โทเค็นเอาต์พุตรวมทั้งหมด ราคาต่อ 1M โทเค็นเป็นราคาปัจจุบันและเปลี่ยนแปลงไปพร้อมกับอัตราค่าบริการของเรา คอลัมน์ OpenRouter แสดงราคาอ้างอิงสำหรับปริมาณงานเดียวกัน

โดยรวม เมื่อนับอินพุตและเอาต์พุตรวมกัน DeepSeek-V4-Flash ถูกกว่า OpenRouter สำหรับงานนี้ สังเกตด้วยว่าโทเคนอยู่ตรงไหน: 240,000 จาก 256,000 เป็นอินพุต บริบทที่เอเจนต์ของคุณลากไปด้วยคือค่าใช้จ่าย ซึ่งเป็นเหตุผลว่าทำไมตัวเลข in= ต่อขั้นตอนในบันทึกของคุณจึงเป็นสิ่งที่ต้องจับตา งบประมาณ $0.50 ต่องานในตัวอย่างข้างต้นเป็นเพดานสำหรับการหลุดควบคุม ไม่ใช่เป้าหมาย

การเปลี่ยนโมเดลหมายถึงเพียงเปลี่ยน MODEL เลือกรหัสจาก CheapTokens docs: ชื่อแตกต่างกันระหว่างผู้ให้บริการ และรหัสสั้นจากป้ายราคาจะใช้ใน API ไม่ได้ สำหรับลูปเอเจนต์ที่ยาว DeepSeek-V4-Flash มีราคาเดียวทุกชั่วโมงของวัน งานหนึ่งจึงมีค่าใช้จ่ายเท่ากันทั้งตอนเที่ยงและตอนตี 3 ดู DeepSeek page สำหรับข้อจำกัดของมัน

เมื่อโมเดลกำลังคิดวิเคราะห์#

หากคำตอบมีจำนวนโทเคนยาวกว่าข้อความที่คุณเห็นมาก ให้ดูที่ reasoning_tokens โทเคนการคิดวิเคราะห์นับเป็นเอาต์พุต ดังนั้นขั้นตอนที่ใช้การให้เหตุผลหนักๆ อาจสร้างเอาต์พุตโทเคนได้มากกว่าที่ข้อความที่มองเห็นบ่งชี้ และถูกคิดเงินเป็นเอาต์พุต มิเตอร์ด้านบนเก็บพวกมันไว้ใน meter.reasoning เมื่อ API ส่งฟิลด์นั้นกลับมา และปล่อยเป็น 0 เมื่อไม่ส่ง ดังนั้นมันจึงไม่พังเมื่อคีย์หายไป พิมพ์มันข้างๆ out= หากคุณต้องการเห็นว่าเอาต์พุตส่วนไหนเป็นการคิดวิเคราะห์ Reasoning effort and thinking tokens อธิบายว่าทำไม

การสตรีม: usage มาทีหลังสุด#

หากเอเจนต์ของคุณสตรีม จะไม่มี usage ในชังก์ปกติ ในรูปแบบ OpenAI คุณขอมันด้วย stream_options={'include_usage': True} เอกสารอ้างอิงของ DeepSeek (ตรวจสอบเมื่อ 26 ตุลาคม 2026) กล่าวว่าตัวเลือกนี้ใช้ได้เฉพาะร่วมกับ stream=True (ไม่เช่นนั้น API จะตอบ 400) ว่า usage เป็น null ในทุกชังก์ยกเว้นชังก์เดียว และว่าชังก์สุดท้ายก่อน data: [DONE] มีผลรวมสำหรับคำขอทั้งหมด ดังนั้นในลูปสตรีม ให้เรียก meter.add ครั้งเดียว บนชังก์ที่ usage ไม่ว่าง ลูปแบบไม่สตรีมด้านบนเป็นจุดเริ่มต้นที่ง่ายที่สุด streaming in Python มีตัวลูปเอง

หากตัวเลขดูผิด#

  • usage เป็น None คุณกำลังสตรีมโดยไม่มี include_usage เพิ่มมัน หรือเปลี่ยนไปใช้การเรียกแบบไม่สตรีม
  • ยอดรวมต่ำกว่ายอดคงเหลือที่ลดลง ตรวจสอบว่าทุกการเรียกผ่านมิเตอร์: การลองใหม่ การเรียกเพื่อสรุป หรือการเรียกเพื่อเลือกเครื่องมือที่ทำนอก run_task นั้นพลาดได้ง่าย ห่อ client.chat.completions.create ไว้ในฟังก์ชันเดียวและให้ทุกอย่างผ่านมัน
  • ค่าใช้จ่ายต่อขั้นตอนเพิ่มขึ้นเรื่อยๆ นั่นเป็นเรื่องปกติสำหรับลูปที่ต่อท้ายทุกอย่างลงใน messages ตัดเอาต์พุตเก่าของเครื่องมือออกหรือสรุปประวัติ tool output out of context แสดงแนวคิดนี้
  • BudgetExceeded ทำงานที่ขั้นตอนที่ 2 งบประมาณของคุณเล็กกว่าหนึ่งขั้นตอน ตรวจสอบว่า PRICE_IN เป็นต่อ 1M โทเคน ไม่ใช่ต่อ 1K

หากต้องการเก็บตัวเลข ให้เขียน meter.steps, meter.tokens_in, meter.tokens_out และ meter.cost เป็นบรรทัด JSON หนึ่งบรรทัดต่องาน หนึ่งสัปดาห์ของบรรทัดเหล่านั้นจะบอกจำนวนโทเคนจริงต่อขั้นตอนสำหรับเอเจนต์ของคุณ ซึ่งเป็นตัวเลขที่ต้องใส่ในการประเมินทุกครั้งหลังจากนั้น โมเดล ราคา และคำขอแรกอยู่ใน docs; การเรียกเครื่องมือครอบคลุมใน function calling in Python