Jika tim Anda ingin menjalankan banyak tugas AI atau coding secara paralel, masalah utamanya bukan sekadar bagaimana menambah worker, tetapi bagaimana menjaga sistem tetap terkendali: hasil mudah ditelusuri, biaya tidak meledak, secret aman, dan output tiap job bisa direview manusia. Konteks seperti tren “20 akun Codex berjalan paralel” menarik sebagai inspirasi, tetapi pelajaran yang lebih berguna untuk engineering adalah bagaimana membangun pipeline paralel yang disiplin, bukan sekadar memperbanyak eksekusi.

Artikel ini membahas rancangan praktis untuk pipeline paralel untuk evaluasi banyak tugas AI di CI/CD atau tooling internal. Kita akan fokus pada pola yang bisa diterapkan tim software: job queue, concurrency limit, isolasi environment, rate limit, cache artefak, logging per job, retry idempoten, agregasi hasil, review manusia, serta guardrail biaya dan secret.

Mengapa pipeline paralel untuk evaluasi banyak tugas AI perlu desain khusus

Tugas AI berbeda dari job build biasa. Ia sering melibatkan API eksternal, input besar, hasil yang tidak sepenuhnya deterministik, dan biaya per panggilan. Jika Anda memparalelkan tanpa kontrol, beberapa masalah umum muncul:

  • Rate limit dari provider model atau layanan pendukung cepat terlampaui.
  • Biaya sulit diprediksi karena banyak job aktif bersamaan.
  • Output sulit diaudit bila semua log bercampur.
  • Retry berbahaya jika job tidak idempoten dan menghasilkan duplikasi efek samping.
  • Secret bocor jika environment antar job tidak terisolasi.
  • Noise meningkat ketika banyak eksperimen paralel menghasilkan variasi, bukan keputusan.

Karena itu, desain yang baik harus memisahkan tiga lapisan: orchestration, execution, dan review.

Arsitektur referensi: orchestrator, queue, worker, dan agregator

Komponen inti

Arsitektur sederhana yang cukup kuat biasanya terdiri dari:

  • Producer/Orchestrator: membaca daftar tugas, membuat manifest, dan mendorong job ke queue.
  • Job Queue: menyimpan unit kerja dan mengatur distribusi ke worker.
  • Worker: menjalankan satu job dalam environment terisolasi.
  • Artifact Store: menyimpan output, patch, log, dan metadata tiap job.
  • Result Aggregator: mengumpulkan hasil, menghitung status akhir, dan membuat ringkasan review.
  • Human Review Gate: tahap manual sebelum merge, deploy, atau promosi hasil.

Skemanya kurang lebih seperti ini:

Task Manifest -> Orchestrator -> Queue -> Worker Pool -> Artifact Store
                                 |             |
                                 |             +-> Per-job logs
                                 |
                                 +-> Result Aggregator -> Review Dashboard / PR Comment

Kenapa queue lebih baik daripada langsung membuat banyak job sekaligus

Menjalankan semua job sekaligus di CI terlihat mudah, tetapi queue memberi kontrol yang jauh lebih baik:

  • Backpressure: Anda bisa menahan laju eksekusi saat provider API lambat.
  • Fairness: tugas penting bisa diprioritaskan.
  • Retry terkontrol: job gagal dapat dijadwalkan ulang tanpa mengulang semua pipeline.
  • Observabilitas: status antre, berjalan, gagal, sukses, dan dibatalkan lebih jelas.
  • Cost control: jumlah job aktif dapat dibatasi secara global.

Untuk tim kecil, queue bisa berupa tabel database atau Redis. Untuk skala lebih besar, bisa memakai message broker atau platform job orchestration yang sudah ada di internal.

Unit kerja yang benar: kecil, idempoten, dan dapat diulang

Struktur job yang disarankan

Satu job sebaiknya mewakili satu tugas evaluasi yang cukup kecil. Contohnya:

  • Satu prompt terhadap satu dataset subset
  • Satu file coding task terhadap satu model
  • Satu skenario uji terhadap satu konfigurasi toolchain

Metadata minimum per job:

  • job_id
  • task_type
  • input_ref atau checksum input
  • model_ref atau strategi eksekusi
  • attempt
  • created_at
  • trace_id
  • artifact_prefix

Jika hasil perlu bisa direproduksi, simpan juga:

  • hash commit repository
  • hash dataset
  • template prompt atau instruksi
  • parameter runtime yang relevan

Idempoten lebih penting daripada retry cepat

Retry aman hanya mungkin jika job idempoten. Artinya, menjalankan ulang job yang sama tidak menimbulkan kerusakan atau duplikasi efek samping. Praktiknya:

  • Gunakan artifact path deterministik berdasarkan job_id atau checksum.
  • Hindari menulis langsung ke branch utama atau state bersama tanpa locking.
  • Simpan status transisi yang jelas: queued, running, succeeded, failed, cancelled.
  • Bedakan hasil final dari attempt log.

Kesalahan umum: retry job AI yang sebenarnya sudah berhasil menghasilkan artefak, lalu retry menimpa atau menggandakan hasil sehingga agregasi menjadi ambigu.

Concurrency limit dan rate limit: inti dari paralelisme yang sehat

Dua limit yang harus dipisahkan

Banyak tim mencampur dua konsep ini:

  • Concurrency limit: berapa banyak job aktif bersamaan.
  • Rate limit: berapa banyak request ke layanan tertentu per periode waktu.

Anda bisa saja hanya menjalankan 5 worker, tetapi masing-masing worker membuat banyak request, sehingga rate limit tetap terlampaui. Karena itu, kontrol harus ada di dua lapisan.

Pola praktis untuk pembatasan

  • Global worker cap: misalnya maksimal N job AI aktif di semua pipeline.
  • Per-provider token bucket: batasi request ke model/API tertentu.
  • Per-repository atau per-team quota: mencegah satu proyek menghabiskan semua kapasitas.
  • Deadline dan timeout: job yang macet harus dihentikan.
  • Adaptive throttling: kurangi laju jika error rate naik.

Prinsipnya sederhana: lebih baik antre dengan stabil daripada berjalan cepat lalu gagal massal.

Contoh pseudo-code worker dengan semaphore dan retry

const globalSemaphore = createSemaphore(process.env.MAX_CONCURRENT_JOBS || 8);
const providerLimiter = createRateLimiter({
  maxRequests: 60,
  perSeconds: 60
});

async function runJob(job) {
  await globalSemaphore.acquire();
  try {
    return await executeWithRetry(job, async () => {
      await providerLimiter.consume(1);
      return await executeIsolatedJob(job);
    });
  } finally {
    globalSemaphore.release();
  }
}

async function executeWithRetry(job, fn) {
  const retryableErrors = ["RATE_LIMIT", "TIMEOUT", "TRANSIENT_NETWORK"];
  let attempt = 0;
  while (attempt <= 3) {
    try {
      return await fn();
    } catch (err) {
      if (!retryableErrors.includes(err.code) || attempt === 3) throw err;
      await sleep(backoffWithJitter(attempt));
      attempt++;
    }
  }
}

Poin penting dari contoh di atas bukan sintaks spesifiknya, melainkan pemisahan peran:

  • Semaphore membatasi job aktif.
  • Rate limiter membatasi panggilan keluar.
  • Retry hanya untuk error sementara.
  • Backoff + jitter mencegah lonjakan retry serempak.

Isolasi environment: wajib jika job menghasilkan kode atau menjalankan tool

Tingkat isolasi yang umum

Untuk tugas AI/coding, environment harus diperlakukan sebagai area berisiko. Pilihan isolasi, dari paling ringan ke lebih kuat:

  1. Proses terpisah: cocok untuk tugas sederhana tanpa eksekusi kode berbahaya.
  2. Container per job: opsi praktis untuk kebanyakan pipeline internal.
  3. VM/microVM per job: untuk isolasi lebih ketat jika job menjalankan kode tidak tepercaya.

Jika job melibatkan patch kode, test command, atau agen yang boleh memanggil shell, container per job biasanya baseline yang masuk akal.

Praktik isolasi yang sebaiknya diterapkan

  • Workspace unik per job, jangan berbagi direktori tulis.
  • Filesystem sebisa mungkin read-only untuk bagian yang tidak perlu diubah.
  • Batasi akses jaringan jika tidak diperlukan.
  • Gunakan identity atau token berbeda sesuai kebutuhan minimum.
  • Hindari menaruh secret jangka panjang di environment variable umum.
  • Hapus environment setelah job selesai.

Kesalahan umum: memakai satu workspace bersama untuk banyak job demi menghemat checkout. Hasilnya sering berupa cache korup, file saling timpa, atau test yang tidak deterministik.

Cache artefak tanpa mengorbankan keandalan

Apa yang layak di-cache

Cache berguna, tetapi hanya untuk data yang benar-benar aman dibagikan. Yang umumnya layak di-cache:

  • dependency build
  • model prompt template statis
  • hasil preprocessing dataset yang immutable
  • toolchain yang jarang berubah

Yang sebaiknya tidak dibagikan sembarangan:

  • workspace aktif job
  • log sementara
  • file keluaran yang masih dalam proses
  • cache yang tidak memiliki key deterministik

Gunakan kunci cache yang stabil

Key cache sebaiknya mengandung kombinasi faktor yang benar-benar memengaruhi hasil, misalnya:

  • OS atau image runner
  • hash lockfile dependency
  • hash dataset versi tertentu
  • hash konfigurasi evaluator

Jika key terlalu umum, Anda mendapat cache salah. Jika terlalu spesifik, hit rate rendah. Di sini trade-off antara akurasi dan efisiensi harus disesuaikan dengan karakter job.

Logging per job dan traceability hasil

Dalam pipeline paralel untuk evaluasi banyak tugas AI, observabilitas tidak boleh hanya berupa “step gagal”. Anda perlu bisa menjawab pertanyaan berikut:

  • Job mana yang gagal?
  • Input dan commit apa yang digunakan?
  • Pada attempt ke berapa?
  • Provider atau command mana yang error?
  • Artefak hasil ada di mana?
  • Apakah ini gagal permanen atau layak retry?

Data minimum yang harus dicatat per job

  • job_id dan trace_id
  • commit SHA atau versi source
  • waktu antre, mulai, selesai
  • durasi total dan durasi per langkah
  • exit status
  • jumlah retry
  • lokasi artefak
  • ringkasan error terstruktur

Format log terstruktur seperti JSON akan sangat membantu untuk pencarian dan agregasi, terutama jika Anda mengirimkannya ke sistem log terpusat.

Artefak yang berguna untuk review

  • stdout/stderr lengkap
  • patch atau diff hasil coding
  • ringkasan evaluasi dalam format mesin dan manusia
  • metadata runtime
  • snapshot konfigurasi

Jangan hanya menyimpan skor akhir. Dalam banyak kasus, reviewer manusia perlu melihat bagaimana hasil diperoleh.

Agregasi hasil dan review manusia

Jangan merge langsung dari banyak job AI

Meski semua job sukses, itu tidak berarti semua output layak diterapkan otomatis. Pipeline yang sehat biasanya memiliki satu tahap agregasi yang:

  • mengumpulkan semua status job
  • menandai mana yang sukses, gagal, dan dibatalkan
  • menghitung ringkasan metrik yang relevan
  • menyusun tautan ke artefak per job
  • membuat komentar PR atau laporan internal

Di titik ini, review manusia menjadi guardrail penting, terutama untuk:

  • patch kode
  • perubahan konfigurasi
  • hasil evaluasi yang bertentangan
  • job yang lolos teknis tetapi tampak tidak masuk akal

Contoh format ringkasan agregasi

Run Summary
- total_jobs: 24
- succeeded: 18
- failed: 4
- cancelled: 2
- retry_count_total: 7
- artifacts_index: s3://internal-ai-runs/run-2026-08-27/index.json

Top failures
1. task=refactor-auth flow=timeout during integration tests
2. task=doc-gen provider rate limited after 3 retries
3. task=sql-fix patch failed lint step
4. task=api-test invalid secret scope

Ringkasan seperti ini lebih berguna daripada output panjang tanpa struktur.

Guardrail biaya dan secret

Biaya harus dibatasi oleh sistem, bukan niat baik

Begitu job AI diparalelkan, biaya bisa naik tajam walau tiap job tampak kecil. Beberapa guardrail yang praktis:

  • Budget per run: hentikan eksekusi jika estimasi biaya melewati ambang.
  • Budget per tim/proyek: mencegah satu pipeline mengambil seluruh kuota.
  • Max attempts per job: batasi retry agar error sementara tidak berubah menjadi tagihan besar.
  • Fail-fast policy: batalkan batch jika pola kegagalan sistemik terdeteksi.
  • Sampling: tidak semua task harus dievaluasi penuh di setiap commit.

Jika estimasi biaya sulit dihitung tepat, tetap gunakan pendekatan konservatif berbasis jumlah task, ukuran input, dan jumlah panggilan maksimum per job.

Secret handling yang aman

  • Gunakan secret scope minimum per job atau per workflow.
  • Jangan menulis secret ke log, artefak, atau komentar PR.
  • Redaksi output yang berpotensi mengandung token.
  • Gunakan kredensial sementara jika memungkinkan.
  • Bedakan secret untuk read-only dan write access.

Kesalahan umum: satu token serbaguna diberikan ke semua worker. Jika satu job bocor, seluruh sistem ikut terdampak.

Contoh implementasi dengan GitHub Actions

GitHub Actions bisa dipakai sebagai lapisan orchestration awal, terutama jika tim belum memiliki scheduler internal penuh. Pola yang aman adalah:

  1. Workflow awal membuat manifest tugas.
  2. Job matrix menjalankan worker dengan batas max-parallel.
  3. Tiap worker menyimpan artefak dan log per job.
  4. Job agregasi berjalan di akhir, selalu dieksekusi, lalu membuat ringkasan.

Contoh workflow ringkas

name: parallel-ai-eval

on:
  workflow_dispatch:
  pull_request:

concurrency:
  group: ai-eval-${{ github.ref }}
  cancel-in-progress: false

jobs:
  plan:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.plan.outputs.matrix }}
    steps:
      - uses: actions/checkout@v4
      - id: plan
        run: |
          python scripts/build_task_manifest.py > manifest.json
          echo "matrix=$(cat manifest.json)" >> $GITHUB_OUTPUT
      - uses: actions/upload-artifact@v4
        with:
          name: task-manifest
          path: manifest.json

  worker:
    needs: plan
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      max-parallel: 4
      matrix: ${{ fromJson(needs.plan.outputs.matrix) }}
    timeout-minutes: 30
    steps:
      - uses: actions/checkout@v4
      - name: Setup isolated workspace
        run: |
          mkdir -p runs/${{ matrix.job_id }}
      - name: Execute task
        env:
          JOB_ID: ${{ matrix.job_id }}
          TASK_INPUT: ${{ matrix.input_ref }}
          MODEL_TARGET: ${{ matrix.model_ref }}
          API_TOKEN: ${{ secrets.AI_EVAL_TOKEN }}
        run: |
          python scripts/run_task.py \
            --job-id "$JOB_ID" \
            --input-ref "$TASK_INPUT" \
            --model-ref "$MODEL_TARGET" \
            --output-dir "runs/$JOB_ID"
      - name: Upload per-job artifacts
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: job-${{ matrix.job_id }}
          path: runs/${{ matrix.job_id }}

  aggregate:
    needs: [plan, worker]
    if: always()
    runs-on: ubuntu-latest
    steps:
      - uses: actions/download-artifact@v4
        with:
          path: artifacts
      - name: Aggregate results
        run: |
          python scripts/aggregate_results.py --input-dir artifacts --output summary.md
      - name: Upload summary
        uses: actions/upload-artifact@v4
        with:
          name: ai-eval-summary
          path: summary.md

Kenapa workflow ini cukup aman sebagai titik awal

  • max-parallel memberi batas konkurensi dasar.
  • fail-fast: false mencegah satu kegagalan kecil membatalkan semua eksperimen.
  • Artefak per job memudahkan debugging dan audit.
  • Job agregasi memastikan hasil batch bisa dinilai utuh.
  • Concurrency group membantu mencegah tabrakan run pada ref yang sama.

Namun, GitHub Actions sendiri bukan pengganti penuh queue cerdas. Jika kebutuhan Anda mencakup prioritas lintas tim, quota global, adaptive throttling, atau isolasi kuat berbasis container/VM, biasanya perlu runner self-hosted atau orchestrator internal di belakangnya.

Kapan memakai runner CI murni, kapan butuh tooling internal

Runner CI murni cukup jika

  • jumlah task masih puluhan, bukan ribuan
  • durasi job relatif pendek
  • artefak masih mudah dikelola di sistem CI
  • prioritas scheduling belum rumit
  • kebutuhan audit dan biaya masih sederhana

Tooling internal lebih tepat jika

  • Anda butuh queue lintas repository atau lintas tim
  • Ada quota global per provider AI
  • Job perlu sandbox khusus atau jaringan terbatas
  • Anda perlu retry policy, cancellation, dan deduplication yang lebih canggih
  • Agregasi hasil harus masuk dashboard internal atau approval flow formal

Pilihan terbaik sering berupa kombinasi: CI memicu run, lalu scheduler internal mengelola worker sebenarnya.

Debugging dan kesalahan yang paling sering terjadi

1. Paralelisme dinaikkan sebelum bottleneck diukur

Gejalanya: job lebih banyak, tetapi throughput tidak naik. Penyebabnya bisa rate limit API, startup container lambat, atau storage artefak menjadi bottleneck. Ukur dulu sebelum menambah worker.

2. Retry semua error tanpa klasifikasi

Error validasi input, secret salah, atau bug deterministik tidak boleh di-retry berkali-kali. Bedakan error sementara dan permanen.

3. Log tidak punya korelasi

Jika tidak ada job_id dan trace_id, debugging batch paralel akan sangat lambat. Pastikan semua log dan artefak punya identitas konsisten.

4. Shared state diam-diam

File sementara, cache global, atau branch kerja bersama sering menimbulkan perilaku acak. Asumsikan setiap job harus bisa berjalan sendiri.

5. Hasil AI diperlakukan seperti hasil test deterministik

Output AI bisa bervariasi. Karena itu, agregasi dan review perlu melihat konteks, bukan hanya pass/fail biner.

Checklist: kapan paralelisme mempercepat kerja, kapan justru menambah noise

Paralelisme biasanya mempercepat jika

  • Tugas dapat dipisah jelas dan minim dependensi antar job.
  • Bottleneck utama memang waktu tunggu, bukan CPU lokal atau rate limit tunggal.
  • Tiap job punya kriteria sukses yang jelas.
  • Artefak dan log per job bisa direview tanpa kebingungan.
  • Biaya per job sudah dibatasi dan dipantau.
  • Retry dan cancellation policy sudah ada.

Paralelisme sering menambah noise jika

  • Input atau definisi tugas masih berubah-ubah.
  • Tidak ada mekanisme agregasi yang baik.
  • Semua job menulis ke state yang sama.
  • Rate limit provider adalah bottleneck utama.
  • Tim belum punya proses review manusia untuk output penting.
  • Metrik keberhasilan tidak jelas, sehingga banyak hasil hanya menambah kebisingan.

Penutup

Merancang pipeline paralel untuk evaluasi banyak tugas AI bukan soal mengejar angka worker tertinggi. Yang lebih penting adalah memastikan setiap job dapat dijalankan ulang dengan aman, dibatasi oleh concurrency dan rate limit yang masuk akal, diisolasi dengan baik, dilog secara terstruktur, dan hasilnya diagregasi untuk review manusia.

Jika Anda ingin memulai secara pragmatis, gunakan CI seperti GitHub Actions untuk orchestration dasar, tambahkan max-parallel, artefak per job, dan tahap agregasi. Setelah pola kerja terbukti, baru pindahkan scheduling, quota, dan sandboxing ke tooling internal yang lebih kuat. Dengan pendekatan ini, paralelisme benar-benar mempercepat kerja tim, bukan hanya memperbanyak output yang sulit dipercaya.