API at SDKGabay
Mag-classify ng libu-libong teksto gamit ang AsyncOpenAI sa Python
Isang gumaganang async script: N request na sabay-sabay, isang JSON label bawat teksto, retries para sa mga nabigong item at token total mula sa usage.

Sa pahinang ito
Para mag-classify ng libu-libong teksto, gamitin ang AsyncOpenAI, maglagay ng asyncio. sa paligid ng bawat tawag para N request lang ang sabay-sabay, humingi ng one-line JSON label, at i-rerun lang ang mga item na nabigo. Ginagawa ito ng script sa ibaba laban sa https:/ at ipinapakita ang kabuuang token mula sa usage field sa dulo.
Noong 31 Oktubre 2026, inilarawan ni Andrej Karpathy (OpenAI co-founder, dating Tesla AI director) ang HackerTube: ginawa niya ito sa loob ng mga dalawang oras at ginamit ang Sonnet para bawasan ang mga komento sa Hacker News hanggang sa mga 40K na nagrerekomenda ng YouTube video. Hindi ibinigay ng kanyang post ang prompt, batch size o concurrency, kaya ang sumusunod ay ang karaniwang pattern para sa ganitong trabaho, hindi ang kanyang recipe.
Ang script#
Sabihin nating mayroon kang 5,000 support ticket at gusto mong lagyan ng tag ang bawat isa bilang bug, question o praise. Narito ang buong bagay. I-install ang SDK gamit ang pip install openai (Python 3.10+; ipinapakita ng python - kung ano ang mayroon ka) at ilagay muna ang iyong key sa isang environment variable.
import asyncio
import json
import os
from openai import AsyncOpenAI
client = AsyncOpenAI(
base_url='https://api.cheaptokens.dev/v1',
api_key=os.environ['CHEAPTOKENS_API_KEY'],
max_retries=2,
timeout=60,
)
MODEL = 'deepseek-ai/DeepSeek-V4-Flash-0731'
LABELS = {'bug', 'question', 'praise'}
SYSTEM = (
'Classify the text as bug, question or praise. '
'Reply with JSON only: {"label": "<bug|question|praise>"}'
)
async def classify(text, sem, usage):
async with sem:
r = await client.chat.completions.create(
model=MODEL,
temperature=0,
max_tokens=100,
messages=[
{'role': 'system', 'content': SYSTEM},
{'role': 'user', 'content': text},
],
)
usage['in'] += r.usage.prompt_tokens
usage['out'] += r.usage.completion_tokens
raw = r.choices[0].message.content
label = json.loads(raw[raw.find('{'):raw.rfind('}') + 1])['label']
if label not in LABELS:
raise ValueError(f'unexpected label: {label!r}')
return label
async def run(texts, concurrency=5, rounds=3):
sem = asyncio.Semaphore(concurrency)
usage = {'in': 0, 'out': 0}
labels, pending = {}, list(range(len(texts)))
for _ in range(rounds):
if not pending:
break
results = await asyncio.gather(
*(classify(texts[i], sem, usage) for i in pending),
return_exceptions=True,
)
failed = []
for i, res in zip(pending, results):
if isinstance(res, Exception):
failed.append(i)
else:
labels[i] = res
pending = failed
return labels, pending, usage
texts = [
'The export button crashes the app on Android 15.',
'Does the Pro plan include API access?',
'Love the new dark theme, thank you!',
]
labels, failed, usage = asyncio.run(run(texts))
print(labels)
print('failed:', failed)
print('tokens in:', usage['in'], 'out:', usage['out'])Makukuha mo pabalik ang labels (text index → label), failed (mga index na hindi kailanman gumawa ng valid na label, isang empty list kapag dumaan ang lahat) at ang mga token total. Ang model id ay ang buong deepseek-; kunin ang mga id para sa ibang modelo mula sa CheapTokens docs, dahil nagkakaiba ang mga short name sa pagitan ng mga provider.
Ilagay ang pipeline sa tamang pagkakasunod-sunod para masuri mong tama ang nasa isip mo:
Ilagay sa tamang pagkakasunod-sunod
Ilagay ang batch pipeline sa tamang pagkakasunod-sunod
I-drag ang mga item o gamitin ang mga arrow
- Buuin ang listahan ng mga teksto at bilangin ang mga ito
- Gumawa ng semaphore na may concurrency cap
- Ipadala ang bawat teksto sa classify()
- Kolektahin ang mga index na nag-raise ng error
- Patakbuhin muli ang mga index na iyon lang
- I-print ang token total mula sa usage
Bakit semaphore at hindi 5,000 request nang sabay-sabay#
Masayang sinisimulan ng asyncio.gather ang lahat ng ibibigay mo. Bigyan mo ito ng libu-libong coroutine na walang limit at magsisimula silang lahat nang sabay-sabay, isang pagsabog ng mga request na mabilis na paraan para makakuha ng 429 error. Ang semaphore ay isang turnstile: ang concurrency=5 ay nangangahulugang hindi hihigit sa limang tawag ang nasa loob ng async with sem sa anumang sandali, at ang iba ay naghihintay ng kanilang pagkakataon. Gumagawa pa rin ang Python ng lahat ng task, ngunit lima lang ang nakikipag-usap sa API.

Anong numero ang dapat na concurrency? Magsimula sa mababa, tulad ng 5 sa itaas, at itaas ito habang wala ang mga error. Ituring itong setting na ini-tune mo per job, hindi isang constant na kokopyahin.
Retries: dalawang layer, dalawang trabaho#
Ang unang layer ay built-in sa SDK. Ayon sa openai-python README (sinuri noong 1 Nobyembre 2026), ang mga connection error, 408, 409, 429 at 5xx response ay nire-retry nang dalawang beses bilang default na may maikling exponential backoff. Ang max_retries=2 sa script ay ginagawa lang itong nakikita; itaas ito gamit ang client. o gawing 0 para patayin. Ang default timeout ay 10 minuto at ang timeout ay nag-raise ng APITimeoutError, kaya nagse-set ang script ng timeout=60 para sa maiikling label. Ang mga detalye ay nasa OpenAI Python SDK timeout and retries, at ang backoff na ideya sa likod nito sa 429 Too Many Requests from an AI API.
Ang pangalawang layer ay sa iyo, at sinasaklaw nito ang hindi nakikita ng SDK: nagtagumpay ang tawag, ngunit sumagot ang modelo ng prose at walang JSON (I can't classify this) o nag-imbento ng label na tinatawag na complaint. Hindi mahalaga ang teksto sa paligid ng {...}, dahil pinuputol ng code ang JSON mula sa sagot. Pagkatapos, ang json.loads o ang LABELS check ay nag-raise, pinapanatili ng gather(. ang error bilang value sa halip na patayin ang batch, at ang item ay napupunta sa susunod na round. Pagkatapos ng rounds pagtatangka, ang natitira pa sa failed ay sa iyo para suriin nang manu-mano. Ang isang masamang sagot sa 5,000 ay nagkakahalaga ng isang karagdagang request, hindi ang buong trabaho.
Hinihingi ng script ang JSON sa prompt at vine-validate ito sa code. Kung gusto mong mas pilitin ang format gamit ang response_format, tingnan ang Get valid JSON from an LLM API.
Magkano ang trabaho#
Ang token ang tanging metro, kaya pinagsasama-sama ng script ang usage at sumusunod ang gastos. Kunin ang karaniwang kaso: maiikling teksto, maiikling label. Ipagpalagay na 10,000 teksto sa mga 300 input token bawat isa (ang teksto kasama ang instruction) at mga 20 output token para sa JSON label:
10,000 × 300 = 3,000,000 input token; 10,000 × 20 = 200,000 output token.
Sa DeepSeek-V4-Flash ang trabahong iyon ay nagkakahalaga ng $0.065, sa GLM-5.3-Flash ay $0.068, sa MiniMax-M2.7 ay $0.18. Ipinapakita ng table ang parehong trabaho para sa bawat modelo, katabi ng OpenRouter; kapag pinagsama ang input at output, mas mura ito sa kabuuan kaysa sa OpenRouter.
| Modelo | Input $/1M | Output $/1M | Bawat kahilingan | 10,000 mga kahilingan | OpenRouter, 10,000 mga kahilingan |
|---|---|---|---|---|---|
| GLM-5.3-Flash | $0.02 | $0.04 | $0.0000068 | $0.068 | $0.117 |
| DeepSeek-V4-Flash | $0.015 | $0.10 | $0.0000065 | $0.065 | $0.238 |
| MiniMax-M2.7 | $0.05 | $0.15 | $0.000018 | $0.18 | $2.16 |
300 input at 20 output na token bawat kahilingan. Ang mga presyo kada 1M token ay kasalukuyan at nagbabago kasabay ng aming mga taripa; ang column ng OpenRouter ay nagpapakita ng reference na presyo para sa parehong workload.
Ilipat ang mga slider sa calculator sa iyong sariling mga numero. Ang in at out field ay para sa isang request, at ang runs ay kung ilang request ang ipapadala mo.
Calculator ng gastos
Pag-classify ng 10,000 maiikling teksto
Mga input token bawat kahilingan: 300 · Mga output token bawat kahilingan: 20 · Mga kahilingan bawat araw: 10,000
| Modelo | Bawat araw | Bawat buwan |
|---|---|---|
| GLM-5.3-Flash$0.02$0.04 | $0.068 | $2.04 |
| DeepSeek-V4-Flash$0.015$0.10 | $0.065 | $1.95 |
| MiniMax-M2.7$0.05$0.15 | $0.18 | $5.40 |
Nangingibabaw dito ang input side: pumapasok ang teksto, isang salita ang lumalabas. Kaya naman ang isang model na may murang input at 380K context window, tulad ng DeepSeek-V4-Flash na may isang presyo sa anumang oras, ay angkop para sa bulk filtering; para sa maiikling label, ang GLM-5.3-Flash at MiniMax-M2.7 ay mga alternatibo para sa parehong script, binabago mo lang ang MODEL. Hindi sigurado kung paano lumalaki ang ganitong bill? Nasa What an AI API bills you for ang larawan.
Bago ang malaking run#
Patakbuhin muna ang 20 teksto at tingnan ang failed at ang mga token total. Kung ang 20 teksto ay gumagamit ng mga 6,000 input token, ang 5,000 ay gagamit ng mga 1,500,000, at makakapag-multiply ka bago mag-commit.
Listahan ng dapat gawin
Bago mo ipadala ang buong dataset
Kung hindi ito gumana#
KeyError: 'CHEAPTOKENS_: hindi naka-set ang variable sa terminal na ito. I-export ito at simulan muli ang Python.API_ KEY' 401o404: maling key, base URL o model id. Dinadaanan ng API 401 or 404 error ang bawat isa.json.sa maraming item: walangJSONDecodeError {...}ang sagot, madalas dahil pinutol ito ngmax_tokens=100. I-print angr.; angchoices[0]. finish_ reason lengthay nangangahulugang naabot ang limit, kaya itaas angmax_tokens.- Maraming
429at mabagal na run: babaan angconcurrency.

Ang pangkalahatang modelo at endpoint na detalye ay nasa CheapTokens docs at sa pricing page.



