Kembali ke blog

Model & perbandinganPanduan

Bandingkan dua LLM secara adil pada tugas Anda: tukar sisi dan log biaya

Jalankan head-to-head dua model pada tiket Anda sendiri: pengaturan sama, setiap pasangan dinilai dalam kedua urutan, dan log calls.jsonl yang memberikan biaya proses.

Oleh CheapTokens TeamDiterbitkan 7 menit baca

Sampul: Bandingkan dua model secara adil, dengan alur tiga langkah: prompt sama, tukar sisi, catat setiap panggilan
Di halaman ini
  1. Apa yang dilakukan turnamen publik yang bisa Anda tiru
  2. Tugasnya: menyusun draf balasan untuk 30 tiket dukungan
  3. Tukar sisi: nilai setiap pasangan dua kali
  4. Catat setiap panggilan, lalu hitung biaya proses
  5. Sebelum meluncurkan proses penuh
  6. Membaca hasil tanpa membodohi diri sendiri

Anda menjalankan tiga prompt melalui dua model, dan model kedua menang. Sebelum Anda mempercayainya, periksa model mana yang dicantumkan kedua. Perbandingan yang adil memerlukan tiga hal: pengaturan identik untuk kedua model, setiap pasangan dinilai dalam kedua urutan, dan log token per panggilan, sehingga Anda tahu berapa biaya seluruh proses. Di bawah ini adalah skrip Python kecil yang melakukan ketiganya pada tugas Anda sendiri.

Apa yang dilakukan turnamen publik yang bisa Anda tiru#

Clocktower Bench milik Dwarkesh Patel adalah proyek riset tidak resmi di mana model bahasa memainkan permainan deduksi sosial Blood on the Clocktower satu sama lain. Permainannya bukan intinya di sini; harness-nya yang penting. Menurut halaman About proyek tersebut (diperiksa 8 November 2026), proyek ini melakukan beberapa hal yang harus dilakukan oleh perbandingan head-to-head mana pun:

  • satu model memainkan semua kursi baik dan model lain semua kursi jahat, dan setiap pembagian dimainkan dua kali dengan sisi ditukar, sehingga kursi yang beruntung tidak menentukan hasil;
  • semua model mendapatkan pengaturan yang sama: upaya penalaran yang sama, batas 8.000 token per giliran dan batas 150 kata untuk bicara;
  • Storyteller-nya terprogram, jadi tidak ada model yang menjadi wasit permainan;
  • setiap panggilan API ditulis ke calls.jsonl dengan token dan biayanya. Halaman tersebut menyebutkan satu permainan berbiaya sekitar $2 hingga $50, tergantung modelnya (pada API OpenAI dan Anthropic).

Harness ini dibuat untuk model OpenAI dan Anthropic, dan tugas Anda mungkin bukan permainan papan. Tapi tiga kebiasaannya bisa ditransfer: pengaturan yang sama, sisi yang ditukar, dan log biaya. Sisa panduan ini menerapkannya pada sesuatu yang biasa.

Setiap tiket diberikan ke kedua model; juri melihat pasangan itu dua kali, dalam urutan berlawanan
Loop tukar sisi untuk satu tiket

Tugasnya: menyusun draf balasan untuk 30 tiket dukungan#

Katakanlah Anda menjalankan meja dukungan kecil dan ingin tahu apakah DeepSeek-V4-Flash atau GLM-5.3-Flash menulis draf pertama yang lebih baik. Anda memiliki file tickets.jsonl dengan 30 tiket nyata, satu objek JSON per baris: {"id": 1, "text": "..."}.

API-nya kompatibel dengan OpenAI, jadi paket resmi openai berfungsi dengan CheapTokens di https://api.cheaptokens.dev/v1. Gunakan id model lengkap dari dokumentasi: deepseek-ai/DeepSeek-V4-Flash-0731 dan zai-org/GLM-5.3-Flash. Kedua model juga mendapatkan model ketiga sebagai juri, MiniMaxAI/MiniMax-M2.7, sehingga tidak ada kontestan yang menilai karyanya sendiri.

Mulailah dengan bagian yang memungkinkan log: satu fungsi yang dilalui setiap panggilan.

python
import json, os, re
from openai import OpenAI

client = OpenAI(base_url="https://api.cheaptokens.dev/v1",
                api_key=os.environ["CHEAPTOKENS_API_KEY"])

CONTESTANTS = {"deepseek": "deepseek-ai/DeepSeek-V4-Flash-0731",
               "glm": "zai-org/GLM-5.3-Flash"}
JUDGE = "MiniMaxAI/MiniMax-M2.7"
SETTINGS = {"temperature": 0.2, "max_tokens": 800}   # same for both

def call(model, messages, role, ticket_id, **settings):
    r = client.chat.completions.create(model=model, messages=messages, **settings)
    with open("calls.jsonl", "a", encoding="utf-8") as f:
        f.write(json.dumps({
            "role": role, "ticket": ticket_id, "model": model,
            "input_tokens": r.usage.prompt_tokens,
            "output_tokens": r.usage.completion_tokens,
            "finish": r.choices[0].finish_reason}) + "\n")
    return r.choices[0].message.content or ""

def draft(model, ticket):
    msgs = [{"role": "system", "content": "You answer support tickets. "
             "Reply in under 80 words, politely, with no promises about refunds."},
            {"role": "user", "content": ticket["text"]}]
    return call(model, msgs, "draft", ticket["id"], **SETTINGS)

Field di calls.jsonl adalah yang dipilih skrip ini; angka penggunaan berasal dari objek usage pada respons API. Kedua model mendapatkan system prompt yang sama, temperature yang sama dan max_tokens yang sama. Ubah salah satunya untuk satu model dan Anda membandingkan pengaturan, bukan model.

Tukar sisi: nilai setiap pasangan dua kali#

Sekarang jurinya. Model juri bisa condong ke jawaban di slot tertentu, jadi satu putusan mencampur kualitas dengan posisi. Trik Clocktower cocok sekali: tampilkan setiap pasangan dalam kedua peran. Sebuah balasan memenangkan tiket hanya jika juri memilihnya di kedua urutan. Jika putusan mengikuti slot bukan balasan, tiket itu seri.

python
def judge(ticket, first, second):
    prompt = (f"Ticket:\n{ticket['text']}\n\nReply A:\n{first}\n\nReply B:\n{second}\n\n"
              "Which reply is better for the customer? Finish with a last line: Verdict: A or Verdict: B.")
    out = call(JUDGE, [{"role": "user", "content": prompt}], "judge",
               ticket["id"], temperature=0, max_tokens=1000)
    letters = re.findall(r"Verdict:\s*([AB])\b", out)
    return letters[-1] if letters else None

tickets = [json.loads(l) for l in open("tickets.jsonl", encoding="utf-8")]
wins = {"deepseek": 0, "glm": 0, "tie": 0}

for t in tickets:
    a = draft(CONTESTANTS["deepseek"], t)
    b = draft(CONTESTANTS["glm"], t)
    v1 = judge(t, a, b)   # DeepSeek's reply shown as A
    v2 = judge(t, b, a)   # GLM's reply shown as A
    pick1 = {"A": "deepseek", "B": "glm"}.get(v1)
    pick2 = {"A": "glm", "B": "deepseek"}.get(v2)
    wins[pick1 if pick1 and pick1 == pick2 else "tie"] += 1

print(wins)

Dua detail mudah terlewat. Juri berjalan pada temperature=0 untuk menjaga putusannya lebih stabil; tidak semua model mematuhi pengaturan itu, jadi jalankan ulang beberapa pasangan dan bandingkan putusannya sebelum Anda mempercayainya. Putusan hanya dibaca dari baris Verdict: terakhir, dan batasnya longgar (800 untuk draf, 1000 untuk juri) agar model yang bernalar sebelum menjawab tidak terpotong di tengah pemikiran; perkiraan di bawah menggunakan ukuran tipikal, bukan batasnya. Jawaban yang tidak dapat diurai menghasilkan None, yang masuk ke seri alih-alih membuat proses gagal.

Coba sendiriCoba: juri mengatakan "A" di kedua urutan untuk tiket 7. Siapa yang menang tiket itu?Tampilkan jawaban

Tidak ada. Pada urutan pertama A adalah balasan DeepSeek, pada urutan kedua A adalah balasan GLM, jadi juri lebih memilih slot, bukan model. Kode menghitungnya sebagai seri. Tumpukan seri seperti itu sendiri adalah hasil: kedua model berdekatan pada tugas Anda, atau prompt juri Anda terlalu kabur.

Urutan hanyalah salah satu cara memiringkan tes. Pengaturan, prompt dan logging juga bisa memiringkannya, jadi periksa seluruh setup, bukan hanya siapa yang lebih dulu. Berikut eksperimen yang sama sebelum dan sesudah.

Bandingkan

Apa yang berubah ketika Anda berhenti membandingkan secara santai

Santai

Satu prompt per model, default dibiarkan, pasangan ditampilkan dalam satu urutan, dan tagihan dibaca dari dasbor di akhir bulan. Pemenangnya mungkin model yang kebetulan dicantumkan lebih dulu.

Adil

Satu system prompt bersama dan temperature serta max_tokens yang sama, setiap pasangan dinilai dalam kedua urutan, dan satu baris di calls.jsonl untuk setiap panggilan. Pemenangnya adalah siapa pun yang menang dari kedua kursi.

Catat setiap panggilan, lalu hitung biaya proses#

Log adalah yang mengubah perbandingan menjadi anggaran. Setelah proses selesai, jumlahkan token per model:

python
from collections import defaultdict

totals = defaultdict(lambda: [0, 0, 0])
for line in open("calls.jsonl", encoding="utf-8"):
    c = json.loads(line)
    s = totals[c["model"]]
    s[0] += c["input_tokens"]; s[1] += c["output_tokens"]; s[2] += 1

for model, (tin, tout, n) in totals.items():
    print(model, n, "calls", tin, "input", tout, "output")

Anda akan mendapatkan satu baris per model dengan jumlah panggilan, token input dan token output. Kalikan dengan dua harga model (input dan output ditagih terpisah) atau, lebih mudah, tempel totalnya ke penanda biaya langsung.

Anda juga bisa memperkirakan sebelum menjalankan. Asumsikan setiap tiket plus system prompt sekitar 300 token input, draf sekitar 250 token output, dan juri melihat sekitar 800 token input (tiket plus kedua balasan plus pertanyaan) dan menjawab dengan sekitar 200 token (baris putusan plus sedikit ruang untuk berpikir):

  • draf: 30 tiket × 2 model = 60 panggilan, 30 × 300 = 9000 input dan 30 × 250 = 7500 token output per kontestan;
  • putusan: 30 tiket × 2 urutan = 60 panggilan, 60 × 800 = 48000 input dan 60 × 200 = 12000 token output pada juri.

Pada harga saat ini, 30 draf satu kontestan berbiaya $0.00089 pada DeepSeek-V4-Flash dan $0.00048 pada GLM-5.3-Flash. 60 putusan pada MiniMax-M2.7 berbiaya $0.0042. Jumlahkan ketiganya dan Anda mendapatkan harga seluruh perbandingan sebelum mengirim satu permintaan pun. Beban penyusunan draf yang sama di ketiga model, dengan input dan output dihitung bersama:

Model Biaya OpenRouter
GLM-5.3-Flash $0.00048 $0.00092
DeepSeek-V4-Flash $0.00089 $0.0017
MiniMax-M2.7 $0.0016 $0.0189

Total 9.000 token input dan 7.500 token output. Harga per 1 juta token adalah harga saat ini dan berubah seiring tarif kami; kolom OpenRouter menunjukkan harga referensi untuk beban kerja yang sama.

Tabel juga menunjukkan referensi OpenRouter, sehingga Anda bisa melihat bagaimana totalnya dibandingkan. Asumsi tokennya terserah Anda untuk diubah: jika tiket Anda panjang, input juri tumbuh paling cepat, karena membawa kedua balasan dua kali. Jika juri Anda berpikir keras sebelum menjawab, angka outputnya juga tumbuh, dan log Anda akan menunjukkannya. Untuk kebiasaan menghitung token sebelum permintaan, lihat hitung token sebelum Anda mengirim permintaan.

Batas yang sama yang digunakan Clocktower layak ditiru. Clocktower menetapkan 8.000 token per giliran, dan Anda sudah memiliki max_tokens. Letakkan di SETTINGS dan jawaban yang lepas kendali tidak bisa diam-diam melipatgandakan perkiraan Anda.

Sebelum meluncurkan proses penuh#

Daftar periksa

Pra-penerbangan untuk perbandingan yang adil

Item terakhir itu penting. Jalankan tiga tiket, buka calls.jsonl dan baca. Periksa bahwa finish mengatakan stop bukan length; jika draf terpotong oleh max_tokens, satu model mungkin kalah hanya karena jawabannya terpotong. Hal yang sama berlaku untuk panggilan juri: length di sana berubah menjadi seri diam-diam, jadi hitung juga putusan None. Jika tugas Anda memiliki satu jawaban benar, Anda mungkin tidak perlu juri sama sekali: uji prompt Anda pada 20 kasus dengan penilaian exact-match.

Membaca hasil tanpa membodohi diri sendiri#

Lihat tiga angka di wins. Tiga puluh tiket adalah sampel kecil: pembagian seperti 12 banding 9 dengan 9 seri memberi tahu Anda bahwa modelnya berdekatan, bukan bahwa salah satu lebih baik. Log membantu di sini. Jika satu model menang sedikit tetapi menggunakan output jauh lebih banyak, pertanyaan sebenarnya adalah harga tugasnya, bukan jumlah kemenangan; harga per 1M token versus biaya per tugas membahas perbandingan itu.

Jika hasilnya berdekatan, pilih model yang lebih murah untuk tugas itu, atau tambahkan lebih banyak tiket dan jalankan ulang. Keduanya murah untuk dicoba karena seluruh mesinnya sudah berupa loop. Ketika Anda ingin mengulangi latihan pada model lain, ketiga model di atas berada di balik satu API dan satu kunci: setup di dokumentasi sama untuk masing-masing, dan halaman harga mencantumkan biaya masing-masing saat ini. Temuan Dwarkesh Patel sendiri tentang model OpenAI versus Anthropic (deteksi versus penipuan) adalah hasilnya untuk permainannya; hasil Anda akan datang dari tiket Anda.