0Pricing
AI Prompt Engineering · Pelajaran

Pemrosesan Batch dan Eksekusi Asinkron

OpenAI Batch API, Python asinkron, dan eksekusi prompt secara bersamaan.

Pemrosesan Batch dan Eksekusi Asinkron adalah pelajaran AI Prompt Engineering gratis di CoddyKit. Ini adalah pelajaran 2 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar AI Prompt Engineering, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus AI Prompt Engineering mencakup 4 pelajaran total.

Mengapa Menggunakan Batch dan Async?

Memproses ribuan permintaan LLM secara berurutan berlangsung lambat dan mahal. Pemrosesan batch mengelompokkan permintaan untuk mengurangi biaya sebesar 50%. Eksekusi async memparalelkan permintaan untuk memaksimalkan throughput dalam batas laju. Jika digabungkan, keduanya secara drastis mengurangi biaya dan waktu jam dinding.

API Batch OpenAI: Pengurangan Biaya 50%

API Batch OpenAI memproses permintaan secara asinkron di latar belakang (hingga 24 jam) dengan harga 50% dari harga API normal. Ideal untuk pelaksanaan evaluasi, pemrosesan himpunan data, dan beban kerja yang tidak memerlukan hasil waktu nyata.

import openai
import json

client = openai.OpenAI(api_key='YOUR_API_KEY')

# Step 1: Create batch input file (JSONL format)
batch_requests = [
    {
        'custom_id': f'request-{i}',
        'method': 'POST',
        'url': '/v1/chat/completions',
        'body': {
            'model': 'gpt-4o-mini',
            'messages': [
                {'role': 'user', 'content': f'Summarize this document: {doc}'}
            ],
            'max_tokens': 200
        }
    }
    for i, doc in enumerate(['Doc A text...', 'Doc B text...', 'Doc C text...'])
]

# Write to JSONL file
with open('batch_input.jsonl', 'w') as f:
    for req in batch_requests:
        f.write(json.dumps(req) + '\n')

# Step 2: Upload the file
batch_file = client.files.create(
    file=open('batch_input.jsonl', 'rb'),
    purpose='batch'
)
print(f'Batch file uploaded: {batch_file.id}')

Mengirimkan dan Memantau Pekerjaan Batch

Setelah mengunggah file input, buat pekerjaan batch dan pantau hingga selesai. API Batch memproses permintaan dalam waktu 24 jam (biasanya jauh lebih cepat untuk batch kecil).

import time

# Step 3: Create batch job
batch = client.batches.create(
    input_file_id=batch_file.id,
    endpoint='/v1/chat/completions',
    completion_window='24h'
)
print(f'Batch created: {batch.id} | Status: {batch.status}')

# Step 4: Poll for completion
def wait_for_batch(batch_id, poll_interval=30, timeout=3600):
    start = time.time()
    while time.time() - start < timeout:
        batch = client.batches.retrieve(batch_id)
        print(f'Status: {batch.status} | '
              f'Completed: {batch.request_counts.completed}/ '
              f'{batch.request_counts.total}')
        if batch.status == 'completed':
            return batch
        if batch.status in ('failed', 'expired', 'cancelling', 'cancelled'):
            raise RuntimeError(f'Batch {batch_id} ended with status: {batch.status}')
        time.sleep(poll_interval)
    raise TimeoutError('Batch polling timed out')

# batch = wait_for_batch(batch.id)

Mengambil Hasil Batch

Setelah batch selesai, unduh file output dan uraikan hasil JSONL kembali ke format yang dapat digunakan.

def retrieve_batch_results(batch):
    if not batch.output_file_id:
        raise ValueError('No output file — batch may have failed')

    # Download output file
    content = client.files.content(batch.output_file_id).text

    # Parse JSONL: one result per line
    results = {}
    for line in content.strip().split('\n'):
        if not line:
            continue
        result = json.loads(line)
        custom_id = result['custom_id']
        if result.get('error'):
            results[custom_id] = {'error': result['error']}
        else:
            response_body = result['response']['body']
            text = response_body['choices'][0]['message']['content']
            results[custom_id] = {'text': text}

    # Report error rate
    errors = sum(1 for r in results.values() if 'error' in r)
    print(f'Retrieved {len(results)} results, {errors} errors')
    return results

# results = retrieve_batch_results(batch)
# for req_id, result in results.items():
#     print(req_id, result.get('text', result.get('error', ''))[:50])

Python Async dengan asyncio.gather()

Untuk paralelisme waktu nyata (non-batch), asyncio pada Python dengan asyncio.gather() menjalankan beberapa panggilan API secara bersamaan dan menunggu semuanya selesai. Hal ini secara drastis mengurangi total waktu jam dinding untuk beban kerja dengan banyak permintaan.

import asyncio
import openai

async_client = openai.AsyncOpenAI(api_key='YOUR_API_KEY')

async def async_completion(messages, model='gpt-4o-mini', max_tokens=200):
    response = await async_client.chat.completions.create(
        model=model,
        messages=messages,
        max_tokens=max_tokens
    )
    return response.choices[0].message.content

async def process_parallel(prompts):
    tasks = [
        async_completion([{'role': 'user', 'content': p}])
        for p in prompts
    ]
    results = await asyncio.gather(*tasks, return_exceptions=True)
    return results

# Usage
async def main():
    prompts = ['Explain photosynthesis.', 'Explain gravity.', 'Explain evolution.']
    results = await process_parallel(prompts)
    for prompt, result in zip(prompts, results):
        if isinstance(result, Exception):
            print(f'ERROR: {result}')
        else:
            print(f'{prompt[:30]}... -> {result[:60]}...')

# asyncio.run(main())
print('asyncio.gather: all 3 requests fire simultaneously')

Panggilan Bersamaan yang Memperhatikan Batas Laju

Menjalankan terlalu banyak permintaan secara bersamaan akan memicu kesalahan batas laju. Semaphore membatasi konkurensi agar tetap berada dalam batas laju sekaligus memaksimalkan throughput.

import asyncio

# Rate limits (example for gpt-4o-mini):
# RPM (requests per minute): 500
# TPM (tokens per minute): 200,000

MAX_CONCURRENT = 20  # stay well below rate limit

async def process_with_rate_limit(prompts, max_concurrent=MAX_CONCURRENT):
    semaphore = asyncio.Semaphore(max_concurrent)
    results = [None] * len(prompts)

    async def bounded_completion(i, prompt):
        async with semaphore:
            try:
                result = await async_completion(
                    [{'role': 'user', 'content': prompt}]
                )
                results[i] = result
            except openai.RateLimitError as e:
                print(f'Rate limited on prompt {i}: {e}')
                await asyncio.sleep(60)  # back off and retry
                result = await async_completion(
                    [{'role': 'user', 'content': prompt}]
                )
                results[i] = result

    await asyncio.gather(*[
        bounded_completion(i, p) for i, p in enumerate(prompts)
    ])
    return results

print('Semaphore limits to', MAX_CONCURRENT, 'concurrent requests')

API Batch Anthropic

Anthropic juga menawarkan API Message Batches dengan model ekonomi yang serupa dengan API Batch OpenAI. Batch diproses secara asinkron, dan hasilnya dipantau atau dialirkan.

import anthropic

client = anthropic.Anthropic(api_key='YOUR_API_KEY')

# Create a batch of messages
batch = client.messages.batches.create(
    requests=[
        {
            'custom_id': f'doc-{i}',
            'params': {
                'model': 'claude-haiku-4-5',
                'max_tokens': 200,
                'messages': [{
                    'role': 'user',
                    'content': f'Classify the sentiment of: {text}'
                }]
            }
        }
        for i, text in enumerate([
            'Amazing product, exceeded expectations!',
            'Terrible quality, broke after one use.',
            'It works as described.'
        ])
    ]
)
print(f'Batch created: {batch.id} | Status: {batch.processing_status}')

# Poll for completion
# while (batch := client.messages.batches.retrieve(batch.id)).processing_status != 'ended':
#     time.sleep(30)

# Retrieve results
# for result in client.messages.batches.results(batch.id):
#     print(result.custom_id, result.result.message.content[0].text[:50])

Optimasi Throughput: Strategi Pembatchan

Maksimalkan throughput dengan memilih strategi pembatchan yang tepat berdasarkan kebutuhan latensi dan karakteristik beban kerja Anda.

throughput_strategies = {
    'API Batch (OpenAI/Anthropic)': {
        'cost': '50% of normal price',
        'latency': 'Minutes to hours (background processing)',
        'best_for': 'Offline workloads: eval runs, dataset labeling, report generation',
        'max_batch_size': '50,000 requests per batch'
    },
    'asyncio.gather()': {
        'cost': 'Normal price',
        'latency': 'Same as slowest individual request',
        'best_for': 'Real-time parallel enrichment, multi-step pipelines',
        'max_concurrent': '10-50 depending on rate limits'
    },
    'Streaming + Concurrent': {
        'cost': 'Normal price',
        'latency': 'First token arrives faster, total similar',
        'best_for': 'User-facing applications needing perceived speed',
        'pattern': 'asyncio with stream=True per request'
    },
    'Worker Queue (Celery, RQ)': {
        'cost': 'Normal price',
        'latency': 'Variable (depends on queue depth)',
        'best_for': 'High-volume production with auto-scaling workers',
        'backends': 'Redis, RabbitMQ'
    }
}

for strategy, details in throughput_strategies.items():
    print(f'{strategy}: {details["best_for"][:60]}')

Penanganan Kesalahan dan Logika Percobaan Ulang dalam Batch/Async

Beban kerja bersamaan dan batch memerlukan penanganan kesalahan yang tangguh. Kegagalan permintaan individual tidak boleh menghentikan seluruh batch — catat kegagalannya, coba lagi dengan jeda bertahap, dan laporkan tingkat keberhasilan secara agregat.

import asyncio
import random

async def resilient_completion(prompt, max_retries=3, base_delay=1.0):
    for attempt in range(max_retries):
        try:
            return await async_completion(
                [{'role': 'user', 'content': prompt}]
            )
        except openai.RateLimitError:
            wait = base_delay * (2 ** attempt) + random.uniform(0, 1)
            print(f'Rate limited. Waiting {wait:.1f}s (attempt {attempt+1})')
            await asyncio.sleep(wait)
        except openai.APITimeoutError:
            print(f'Timeout on attempt {attempt+1}')
            await asyncio.sleep(base_delay)
        except openai.APIError as e:
            if e.status_code >= 500:
                await asyncio.sleep(base_delay * (attempt + 1))
            else:
                raise  # Don't retry 4xx errors
    raise RuntimeError(f'Failed after {max_retries} attempts')

async def batch_with_error_reporting(prompts):
    tasks = [resilient_completion(p) for p in prompts]
    results = await asyncio.gather(*tasks, return_exceptions=True)
    successes = sum(1 for r in results if not isinstance(r, Exception))
    print(f'Batch complete: {successes}/{len(prompts)} succeeded')
    return results

Membagi Input Besar untuk Pemrosesan Batch

Dokumen yang lebih besar daripada jendela konteks model harus dibagi menjadi beberapa bagian sebelum diproses secara batch. Setiap bagian menjadi permintaan batch terpisah; hasilnya kemudian digabungkan atau diringkas.

def chunk_document(text, max_tokens=3000, overlap_tokens=200):
    '''
    Split a long document into overlapping chunks for batch processing.
    Approximate: 1 token ~ 4 characters
    '''
    max_chars = max_tokens * 4
    overlap_chars = overlap_tokens * 4
    chunks = []
    start = 0
    while start < len(text):
        end = min(start + max_chars, len(text))
        # Try to break at a sentence boundary
        if end < len(text):
            last_period = text.rfind('.', start, end)
            if last_period > start + max_chars // 2:
                end = last_period + 1
        chunks.append({'text': text[start:end], 'start': start, 'end': end})
        start = end - overlap_chars  # overlap for context continuity
    return chunks

def batch_summarize_long_document(document_text, summary_prompt):
    chunks = chunk_document(document_text)
    print(f'Document split into {len(chunks)} chunks')
    # Create one batch request per chunk
    batch_inputs = [
        {'custom_id': f'chunk-{i}',
         'content': summary_prompt + '\n\n' + chunk['text']}
        for i, chunk in enumerate(chunks)
    ]
    # Submit all chunks as one batch job
    return batch_inputs

long_doc = 'Lorem ipsum ' * 5000  # ~20K character document
chunks = chunk_document(long_doc)
print(f'Chunks: {len(chunks)}, first chunk length: {len(chunks[0]["text"])} chars')

Pelacakan Kemajuan untuk Batch Besar

Untuk pekerjaan batch besar (ribuan permintaan), tampilkan kemajuan waktu nyata agar operator dapat memantau throughput dan memperkirakan waktu penyelesaian.

import asyncio
import time

async def batch_with_progress(prompts, max_concurrent=20):
    semaphore = asyncio.Semaphore(max_concurrent)
    completed = 0
    total = len(prompts)
    start_time = time.time()
    results = [None] * total

    async def process_one(i, prompt):
        nonlocal completed
        async with semaphore:
            results[i] = await resilient_completion(prompt)
            completed += 1

        elapsed = time.time() - start_time
        rate = completed / elapsed if elapsed > 0 else 0
        eta = (total - completed) / rate if rate > 0 else float('inf')

        if completed % 10 == 0 or completed == total:
            print(f'Progress: {completed}/{total} '
                  f'({completed/total:.0%}) | '
                  f'{rate:.1f} req/s | '
                  f'ETA: {eta:.0f}s')

    await asyncio.gather(*[
        process_one(i, p) for i, p in enumerate(prompts)
    ])
    return results

print('Progress tracking: reports every 10 completions with ETA.')

Pemeriksaan Singkat

Anda perlu memberi label sentimen pada 10.000 dokumen dalam semalam. Anda ingin meminimalkan biaya dan tidak memerlukan hasil waktu nyata. Pendekatan mana yang terbaik?

Ringkasan Batch dan Async

Pemrosesan batch dan eksekusi async sangat penting untuk rekayasa prompt dalam skala besar:

  • API Batch OpenAI/Anthropic: pengurangan biaya 50%, pemrosesan di latar belakang, hingga 50 ribu permintaan per batch
  • asyncio.gather(): permintaan waktu nyata secara bersamaan, semuanya dijalankan serentak dan menunggu semua hasil
  • Semaphore: kontrol konkurensi yang memperhatikan batas laju (biasanya 10–50 permintaan bersamaan)
  • Jeda bertahap eksponensial: coba lagi dengan jeda yang berlipat ganda saat terjadi kesalahan batas laju atau batas waktu
  • Pengumpulan yang tangguh: return_exceptions=True mencegah satu kegagalan menghentikan seluruh batch
  • Pelacakan kemajuan: laporkan penyelesaian beserta laju dan ETA untuk pekerjaan besar

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Pemrosesan Batch dan Eksekusi Asinkron” gratis?

Ya — teks lengkap “Pemrosesan Batch dan Eksekusi Asinkron” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus AI Prompt Engineering, upgrade ke CoddyKit PRO. Kursus AI Prompt Engineering mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Pemrosesan Batch dan Eksekusi Asinkron”?

OpenAI Batch API, Python asinkron, dan eksekusi prompt secara bersamaan. Kamu berlatih AI Prompt Engineering dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai AI Prompt Engineering?

Tidak diperlukan pengalaman sebelumnya. AI Prompt Engineering di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 4.

Berapa lama pelajaran “Pemrosesan Batch dan Eksekusi Asinkron” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran AI Prompt Engineering ini?

Ya. Setiap pelajaran AI Prompt Engineering menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Strategi Caching untuk Prompt
  2. Pemrosesan Batch dan Eksekusi Asinkron
  3. Penyeimbangan Beban di Seluruh Model
  4. Pemantauan dan Pemberitahuan untuk Pipeline Prompt
← Kembali ke AI Prompt Engineering