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

โมเดลและการเปรียบเทียบคู่มือ

เปรียบเทียบ LLM สองตัวอย่างยุติธรรมบนงานของคุณ: สลับฝ่ายและบันทึกค่าใช้จ่าย

รันการเปรียบเทียบแบบตัวต่อตัวของสองโมเดลบนตั๋วของคุณเอง: การตั้งค่าเท่ากัน ทุกคู่ถูกตัดสินในทั้งสองลำดับ และบันทึก calls.jsonl ที่ให้ค่าใช้จ่ายของการรัน

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

หน้าปก: เปรียบเทียบสองโมเดลอย่างยุติธรรม ด้วยโฟลว์สามขั้นตอน: พรอมต์เดียวกัน สลับฝ่าย บันทึกทุกการเรียก
ในหน้านี้
  1. สิ่งที่การแข่งขันสาธารณะทำที่คุณสามารถนำมาใช้ได้
  2. งาน: ร่างคำตอบสำหรับตั๋วสนับสนุน 30 ใบ
  3. สลับฝ่าย: ตัดสินทุกคู่สองครั้ง
  4. บันทึกทุกการเรียก แล้วคิดราคาการรัน
  5. ก่อนเปิดการรันเต็มรูปแบบ
  6. อ่านผลลัพธ์โดยไม่หลอกตัวเอง

คุณรันพรอมต์สามรายการผ่านสองโมเดล และโมเดลที่สองชนะ ก่อนที่คุณจะเชื่อผลนั้น ให้ตรวจสอบว่าโมเดลใดถูกรายการไว้เป็นอันดับสอง การเปรียบเทียบที่ยุติธรรมต้องมีสามสิ่ง: การตั้งค่าที่เหมือนกันสำหรับทั้งสองโมเดล, ทุกคู่ถูกตัดสินในทั้งสองลำดับ, และบันทึกโทเค็นต่อการเรียก เพื่อให้คุณรู้ว่าการรันทั้งหมดมีค่าใช้จ่ายเท่าไร ด้านล่างนี้คือสคริปต์ Python ขนาดเล็กที่ทำทั้งสามอย่างบนงานของคุณเอง

สิ่งที่การแข่งขันสาธารณะทำที่คุณสามารถนำมาใช้ได้#

Clocktower Bench ของ Dwarkesh Patel เป็นโครงการวิจัยที่ไม่เป็นทางการซึ่งโมเดลภาษาต่างเล่นเกมสังคมนิยมความจริง Blood on the Clocktower แข่งขันกัน เกมไม่ใช่ประเด็นที่นี่ แต่ตัว harness คือประเด็น ตามหน้า About ของโครงการ (ตรวจสอบเมื่อ 8 พฤศจิกายน 2026) มันทำบางสิ่งที่การเปรียบเทียบแบบตัวต่อตัวใดๆ ควรทำ:

  • โมเดลหนึ่งเล่นที่นั่งฝ่ายดีทั้งหมดและอีกโมเดลหนึ่งเล่นที่นั่งฝ่ายชั่วทั้งหมด และ แต่ละการแจกไพ่จะเล่นสองครั้งโดยสลับฝ่าย ดังนั้นที่นั่งที่โชคดีไม่ใช่ตัวตัดสินผล;
  • โมเดลทั้งหมดได้รับการตั้งค่าเดียวกัน: ความพยายามในการให้เหตุผลเท่ากัน, เพดาน 8,000 โทเค็นต่อเทิร์น และจำกัดคำพูด 150 คำ;
  • Storyteller ถูกเขียนสคริปต์ไว้ ดังนั้นไม่มีโมเดลใดเป็นผู้ตัดสินเกม;
  • ทุกการเรียก API ถูกเขียนลงใน calls.jsonl พร้อมโทเค็นและค่าใช้จ่าย หน้าดังกล่าวระบุว่าเกมหนึ่งเกมมีค่าใช้จ่ายตั้งแต่ประมาณ $2 ถึง $50 ขึ้นอยู่กับโมเดล (บน API ของ OpenAI และ Anthropic)

harness ถูกสร้างสำหรับโมเดล OpenAI และ Anthropic และงานของคุณอาจไม่ใช่เกมกระดาน แต่สามนิสัยสามารถถ่ายโอนได้: การตั้งค่าเท่ากัน, สลับฝ่าย, และบันทึกค่าใช้จ่าย ส่วนที่เหลือของคู่มือนี้จะนำไปใช้กับสิ่งธรรมดา

แต่ละตั๋วถูกส่งไปยังทั้งสองโมเดล ผู้ตัดสินเห็นคู่สองครั้งในลำดับตรงกันข้าม
ลูปสลับฝ่ายสำหรับหนึ่งตั๋ว

งาน: ร่างคำตอบสำหรับตั๋วสนับสนุน 30 ใบ#

สมมติว่าคุณดูแลศูนย์สนับสนุนขนาดเล็กและต้องการทราบว่า DeepSeek-V4-Flash หรือ GLM-5.3-Flash เขียนร่างแรกได้ดีกว่ากัน คุณมีไฟล์ tickets.jsonl ที่มีตั๋วจริง 30 ใบ หนึ่งออบเจกต์ JSON ต่อบรรทัด: {"id": 1, "text": "..."}

API เข้ากันได้กับ OpenAI ดังนั้นแพ็กเกจ openai อย่างเป็นทางการจึงทำงานกับ CheapTokens ที่ https://api.cheaptokens.dev/v1 ใช้รหัสโมเดลเต็มจากเอกสาร: deepseek-ai/DeepSeek-V4-Flash-0731 และ zai-org/GLM-5.3-Flash ทั้งสองโมเดลยังได้โมเดลที่สามเป็นผู้ตัดสิน คือ MiniMaxAI/MiniMax-M2.7 ดังนั้นไม่มีผู้เข้าแข่งขันคนใดให้คะแนนงานของตัวเอง

เริ่มจากส่วนที่ทำให้บันทึกเป็นไปได้: ฟังก์ชันเดียวที่ทุกการเรียกผ่าน

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)

ฟิลด์ใน calls.jsonl คือฟิลด์ที่สคริปต์นี้เลือก ตัวเลขการใช้งานมาจากออบเจกต์ usage ของการตอบกลับ API ทั้งสองโมเดลได้รับ system prompt เดียวกัน, temperature เดียวกัน และ max_tokens เดียวกัน เปลี่ยนหนึ่งในนั้นสำหรับโมเดลหนึ่งและคุณกำลังเปรียบเทียบการตั้งค่า ไม่ใช่โมเดล

สลับฝ่าย: ตัดสินทุกคู่สองครั้ง#

ตอนนี้ผู้ตัดสิน โมเดลผู้ตัดสินอาจเอนเอียงไปทางคำตอบในช่องใดช่องหนึ่ง ดังนั้นคำตัดสินเดียวจึงผสมคุณภาพกับตำแหน่ง กลเม็ด Clocktower เข้ากันได้พอดี: แสดงแต่ละคู่ในทั้งสองบทบาท คำตอบจะชนะตั๋วก็ต่อเมื่อผู้ตัดสินเลือกมันในทั้งสองลำดับ หากคำตัดสินตามช่องแทนที่จะตามคำตอบ ตั๋วนั้นคือเสมอ

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)

มีสองรายละเอียดที่พลาดได้ง่าย ผู้ตัดสินรันที่ temperature=0 เพื่อให้คำตัดสินมั่นคงขึ้น ไม่ใช่ทุกโมเดลจะทำตามการตั้งค่านั้น ดังนั้นให้รันคู่สองสามคู่ซ้ำและเปรียบเทียบคำตัดสินก่อนที่คุณจะเชื่อ คำตัดสินอ่านจากบรรทัด Verdict: สุดท้ายเท่านั้น และเพดานมี generous (800 สำหรับร่าง, 1000 สำหรับผู้ตัดสิน) เพื่อไม่ให้โมเดลที่ให้เหตุผลก่อนตอบถูกตัดกลางความคิด การประมาณด้านล่างใช้ขนาดทั่วไป ไม่ใช่เพดาน คำตอบที่ไม่สามารถแยกวิเคราะห์ได้ให้ None ซึ่งกลายเป็นเสมอแทนที่จะทำให้การรันพัง

ลองด้วยตัวเองลองดู: ผู้ตัดสินพูดว่า "A" ในทั้งสองลำดับสำหรับตั๋ว 7 ใครชนะตั๋วนั้น?แสดงคำตอบ

ไม่มีใคร ในลำดับแรก A คือคำตอบของ DeepSeek ในลำดับที่สอง A คือคำตอบของ GLM ดังนั้นผู้ตัดสินชอบช่อง ไม่ใช่โมเดล โค้ดนับเป็นเสมอ กองของเสมอดังกล่าวเป็นผลลัพธ์ในตัวเอง: สองโมเดลใกล้กันในงานของคุณ หรือพรอมต์ผู้ตัดสินของคุณคลุมเครือเกินไป

ลำดับเป็นเพียงวิธีหนึ่งในการเอียงการทดสอบ การตั้งค่า พรอมต์ และการบันทึกก็เอียงได้เช่นกัน ดังนั้นตรวจสอบการตั้งค่าทั้งหมด ไม่ใช่แค่ใครมาก่อน นี่คือการทดลองเดียวกันก่อนและหลัง

เปรียบเทียบ

สิ่งที่เปลี่ยนเมื่อคุณหยุดเปรียบเทียบแบบสบายๆ

สบายๆ

หนึ่งพรอมต์ต่อโมเดล ปล่อยค่าเริ่มต้นไว้ แสดงคู่ในลำดับเดียว และอ่านบิลจากแดชบอร์ดตอนสิ้นเดือน ผู้ชนะอาจเป็นโมเดลที่บังเอิญถูกรายการไว้ก่อน

ยุติธรรม

system prompt ที่ใช้ร่วมกันหนึ่งอันและ temperature และ max_tokens เดียวกัน แต่ละคู่ถูกตัดสินในทั้งสองลำดับ และมีบรรทัดใน calls.jsonl สำหรับทุกการเรียก ผู้ชนะคือใครก็ตามที่ชนะจากทั้งสองที่นั่ง

บันทึกทุกการเรียก แล้วคิดราคาการรัน#

บันทึกคือสิ่งที่เปลี่ยนการเปรียบเทียบเป็นงบประมาณ หลังการรัน ให้รวมโทเค็นต่อโมเดล:

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")

คุณจะได้หนึ่งบรรทัดต่อโมเดลพร้อมจำนวนการเรียก โทเค็นอินพุต และโทเค็นเอาต์พุต คูณด้วยราคาสองราคาของโมเดล (อินพุตและเอาต์พุตคิดแยกกัน) หรือง่ายกว่านั้น วางยอดรวมลงในตัวบ่งชี้ค่าใช้จ่ายสด

คุณยังประมาณก่อนรันได้ด้วย สมมติว่าแต่ละตั๋วบวก system prompt ประมาณ 300 โทเค็นอินพุต ร่างประมาณ 250 โทเค็นเอาต์พุต และผู้ตัดสินเห็นประมาณ 800 โทเค็นอินพุต (ตั๋วบวกคำตอบทั้งสองบวกคำถาม) และตอบด้วยประมาณ 200 โทเค็น (บรรทัดคำตัดสินบวกพื้นที่ให้คิดเล็กน้อย):

  • ร่าง: 30 ตั๋ว × 2 โมเดล = 60 การเรียก, 30 × 300 = 9000 อินพุต และ 30 × 250 = 7500 โทเค็นเอาต์พุตต่อผู้เข้าแข่งขัน;
  • คำตัดสิน: 30 ตั๋ว × 2 ลำดับ = 60 การเรียก, 60 × 800 = 48000 อินพุต และ 60 × 200 = 12000 โทเค็นเอาต์พุตบนผู้ตัดสิน

ที่ราคาปัจจุบัน ร่าง 30 ฉบับของผู้เข้าแข่งขันหนึ่งคนมีค่าใช้จ่าย $0.00089 บน DeepSeek-V4-Flash และ $0.00048 บน GLM-5.3-Flash คำตัดสิน 60 รายการบน MiniMax-M2.7 มีค่าใช้จ่าย $0.0042 บวกสามอย่างเข้าด้วยกันและคุณได้ราคาของการเปรียบเทียบทั้งหมดก่อนที่คุณจะส่งคำขอเดียว ภาระงานร่างเดียวกันในทั้งสามโมเดล โดยนับอินพุตและเอาต์พุตรวมกัน:

โมเดล ค่าใช้จ่าย OpenRouter
GLM-5.3-Flash $0.00048 $0.00092
DeepSeek-V4-Flash $0.00089 $0.0017
MiniMax-M2.7 $0.0016 $0.0189

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

ตารางยังแสดงข้อมูลอ้างอิง OpenRouter เพื่อให้คุณเห็นว่ายอดรวมเปรียบเทียบอย่างไร สมมติฐานโทเค็นเป็นของคุณที่จะเปลี่ยน: หากตั๋วของคุณยาว อินพุตของผู้ตัดสินจะโตเร็วที่สุด เพราะมันบรรทุกคำตอบทั้งสองสองครั้ง หากผู้ตัดสินของคุณคิดออกเสียงก่อนตอบ ตัวเลขเอาต์พุตก็จะโตเช่นกัน และบันทึกของคุณจะแสดงให้เห็น สำหรับนิสัยการนับโทเค็นก่อนส่งคำขอ ดู นับโทเค็นก่อนส่งคำขอ

เพดานเดียวกับที่ Clocktower ใช้ก็คุ้มค่าที่จะขโมย มันตั้ง 8,000 โทเค็นต่อเทิร์น และคุณมี max_tokens อยู่แล้ว ใส่ไว้ใน SETTINGS และคำตอบที่หลุดการควบคุมไม่สามารถเพิ่มประมาณการของคุณอย่างเงียบๆ

ก่อนเปิดการรันเต็มรูปแบบ#

เช็กลิสต์

การตรวจสอบก่อนบินสำหรับการเปรียบเทียบที่ยุติธรรม

รายการสุดท้ายมีความสำคัญ รันสามตั๋ว เปิด calls.jsonl และอ่าน ตรวจสอบว่า finish พูดว่า stop แทนที่จะเป็น length; หากร่างถูกตัดโดย max_tokens โมเดลหนึ่งอาจแพ้เพียงเพราะคำตอบถูกตัดทอน เช่นเดียวกันกับการเรียกของผู้ตัดสิน: length ที่นั่นกลายเป็นเสมอเงียบ ดังนั้นนับคำตัดสิน None ด้วย หากงานของคุณมีคำตอบที่ถูกต้องเพียงหนึ่งเดียว คุณอาจไม่ต้องการผู้ตัดสินเลย: ทดสอบพรอมต์ของคุณกับ 20 กรณีด้วยการให้คะแนนแบบตรงกันทุกประการ

อ่านผลลัพธ์โดยไม่หลอกตัวเอง#

ดูตัวเลขสามตัวใน wins สามสิบตั๋วเป็นตัวอย่างเล็ก: การแบ่งเช่น 12 ต่อ 9 พร้อม 9 เสมอ บอกคุณว่าโมเดลใกล้กัน ไม่ใช่ว่าตัวหนึ่งดีกว่า บันทึกช่วยตรงนี้ หากโมเดลหนึ่งชนะเล็กน้อยแต่ใช้เอาต์พุตมากกว่ามาก คำถามจริงคือราคาของงาน ไม่ใช่จำนวนครั้งที่ชนะ; ราคาต่อ 1M โทเค็นเทียบกับค่าใช้จ่ายต่องาน อธิบายการเปรียบเทียบนั้น

หากผลลัพธ์ใกล้กัน ให้เลือกโมเดลที่ถูกกว่าสำหรับงาน หรือเพิ่มตั๋วและรันซ้ำ ทั้งสองอย่างลองได้ถูกเพราะเครื่องจักรทั้งหมดเป็นลูปอยู่แล้ว เมื่อคุณต้องการทำแบบฝึกหัดซ้ำบนโมเดลอื่น สามโมเดลข้างต้นอยู่หลัง API เดียวและคีย์เดียว: การตั้งค่าในเอกสาร เหมือนกันสำหรับแต่ละโมเดล และหน้าราคา แสดงค่าใช้จ่ายของแต่ละโมเดลในขณะนี้ การค้นพบของ Dwarkesh Patel เองเกี่ยวกับโมเดล OpenAI เทียบกับ Anthropic (การตรวจจับเทียบกับการหลอกลวง) เป็นผลลัพธ์ของเขาสำหรับเกมของเขา ของคุณจะมาจากตั๋วของคุณ