Mô hình & so sánhHướng dẫn
So sánh hai LLM một cách công bằng trên tác vụ của bạn: đổi bên và log chi phí
Chạy đối đầu hai model trên ticket của chính bạn: cài đặt bằng nhau, mọi cặp được đánh giá theo cả hai thứ tự, và một log calls.jsonl cho biết chi phí của lần chạy.

Trên trang này
Bạn đã chạy ba prompt qua hai model, và model thứ hai thắng. Trước khi tin vào điều đó, hãy kiểm tra xem model nào được liệt kê thứ hai. Một so sánh công bằng cần ba thứ: cài đặt giống hệt cho cả hai model, mọi cặp được đánh giá theo cả hai thứ tự, và một log ghi token mỗi lần gọi, để bạn biết toàn bộ lần chạy tốn bao nhiêu. Dưới đây là một script Python nhỏ thực hiện cả ba điều trên chính tác vụ của bạn.
Một giải đấu công khai làm gì mà bạn có thể mượn#
Clocktower Bench của Dwarkesh Patel là một dự án nghiên cứu không chính thức, nơi các mô hình ngôn ngữ chơi trò suy luận xã hội Blood on the Clocktower với nhau. Trò chơi không phải là điểm chính ở đây; bộ khung kiểm thử mới là. Theo trang Giới thiệu của dự án (truy cập ngày 8 tháng 11 năm 2026), nó làm một vài việc mà bất kỳ so sánh đối đầu nào cũng nên làm:
- một model chơi tất cả các ghế phe thiện và model kia chơi tất cả các ghế phe ác, và mỗi ván chia bài được chơi hai lần với hai bên đổi chỗ, để một ghế may mắn không quyết định kết quả;
- tất cả các model nhận cùng cài đặt: cùng mức độ suy luận, giới hạn 8.000 token mỗi lượt và giới hạn 150 từ cho lời nói;
- Storyteller được lập trình sẵn, nên không có model nào làm trọng tài cho ván chơi;
- mọi lần gọi API được ghi vào
calls.jsonlkèm token và chi phí. Trang này nói một ván chơi tốn từ khoảng $2 đến $50, tùy thuộc vào các model (trên API của OpenAI và Anthropic).
Bộ khung được xây dựng cho các model của OpenAI và Anthropic, và tác vụ của bạn có lẽ không phải là một trò chơi bàn cờ. Nhưng ba thói quen có thể chuyển giao: cài đặt bằng nhau, đổi bên, và log chi phí. Phần còn lại của hướng dẫn này áp dụng chúng vào một việc bình thường.

Tác vụ: soạn thảo trả lời cho 30 ticket hỗ trợ#
Giả sử bạn điều hành một bộ phận hỗ trợ nhỏ và muốn biết DeepSeek-V4-Flash hay GLM-5.3-Flash viết bản nháp đầu tiên tốt hơn. Bạn có một tệp tickets.jsonl với 30 ticket thực tế, mỗi dòng một đối tượng JSON: {"id": 1, "text": "..
API tương thích với OpenAI, nên gói openai chính thức hoạt động với CheapTokens tại https:/. Dùng id model đầy đủ từ tài liệu: deepseek- và zai-. Cả hai model cũng nhận một model thứ ba làm trọng tài, MiniMaxAI/, để không thí sinh nào tự chấm bài của mình.
Bắt đầu với phần làm cho log trở nên khả thi: một hàm mà mọi lần gọi đều đi qua.
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)Các trường trong calls.jsonl là những gì script này chọn; các con số usage đến từ đối tượng usage của phản hồi API. Cả hai model nhận cùng system prompt, cùng temperature và cùng max_tokens. Thay đổi một trong số đó cho một model và bạn đang so sánh cài đặt, không phải model.
Đổi bên: đánh giá mỗi cặp hai lần#
Giờ đến trọng tài. Một model trọng tài có thể nghiêng về câu trả lời ở một vị trí cụ thể, nên một phán quyết duy nhất trộn lẫn chất lượng với vị trí. Mẹo của Clocktower áp dụng gọn gàng: hiển thị mỗi cặp trong cả hai vai trò. Một câu trả lời thắng một ticket chỉ khi trọng tài chọn nó trong cả hai thứ tự. Nếu phán quyết đi theo vị trí thay vì câu trả lời, ticket đó là hòa.
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)Hai chi tiết dễ bị bỏ qua. Trọng tài chạy ở temperature=0 để giữ phán quyết ổn định hơn; không phải model nào cũng tuân thủ cài đặt đó, nên hãy chạy lại vài cặp và so sánh phán quyết trước khi tin chúng. Phán quyết chỉ được đọc từ một dòng Verdict: cuối cùng, và các giới hạn được đặt rộng rãi (800 cho bản nháp, 1000 cho trọng tài) để một model suy luận trước khi trả lời không bị cắt ngang giữa chừng; ước tính bên dưới dùng kích thước điển hình, không phải các giới hạn. Một câu trả lời không phân tích được sẽ cho None, rơi vào hòa thay vì làm sập lần chạy.
Tự mình thử xemThử xem: trọng tài nói "A" trong cả hai thứ tự cho ticket 7. Ai thắng ticket đó?Hiện đáp án
Không ai cả. Trong thứ tự đầu tiên A là câu trả lời của DeepSeek, trong thứ tự thứ hai A là câu trả lời của GLM, nên trọng tài thích vị trí, không phải model. Code đếm đó là hòa. Một đống hòa như vậy tự nó là một kết quả: hai model gần nhau trên tác vụ của bạn, hoặc prompt trọng tài của bạn quá mơ hồ.
Thứ tự chỉ là một cách làm lệch một bài kiểm tra. Cài đặt, prompt và logging cũng có thể làm lệch nó, nên hãy kiểm tra toàn bộ thiết lập, không chỉ ai đi trước. Đây là cùng thí nghiệm trước và sau.
So sánh
Điều gì thay đổi khi bạn ngừng so sánh tùy tiện
Tùy tiện
Một prompt cho mỗi model, để mặc định, cặp được hiển thị theo một thứ tự, và hóa đơn đọc từ dashboard vào cuối tháng. Người thắng có thể là model tình cờ được liệt kê đầu tiên.
Công bằng
Một system prompt chung và cùng temperature và max_tokens, mỗi cặp được đánh giá theo cả hai thứ tự, và một dòng trong calls.jsonl cho mỗi lần gọi. Người thắng là ai thắng từ cả hai ghế.
Ghi log mọi lần gọi, rồi tính giá lần chạy#
Log là thứ biến so sánh thành ngân sách. Sau lần chạy, cộng token theo từng model:
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")Bạn sẽ nhận được một dòng cho mỗi model với số lần gọi, token đầu vào và token đầu ra. Nhân với hai mức giá của model (đầu vào và đầu ra được tính riêng) hoặc, dễ hơn, dán tổng vào một công cụ tính chi phí trực tiếp.
Bạn cũng có thể ước tính trước khi chạy. Giả sử mỗi ticket cộng system prompt khoảng 300 token đầu vào, một bản nháp khoảng 250 token đầu ra, và trọng tài thấy khoảng 800 token đầu vào (ticket cộng cả hai câu trả lời cộng câu hỏi) và trả lời với khoảng 200 token (dòng phán quyết cộng một chút chỗ để suy nghĩ):
- bản nháp: 30 ticket × 2 model = 60 lần gọi, 30 × 300 = 9000 đầu vào và 30 × 250 = 7500 token đầu ra cho mỗi thí sinh;
- phán quyết: 30 ticket × 2 thứ tự = 60 lần gọi, 60 × 800 = 48000 đầu vào và 60 × 200 = 12000 token đầu ra trên trọng tài.
Theo giá hiện tại, 30 bản nháp của một thí sinh tốn $0.00089 trên DeepSeek-V4-Flash và $0.00048 trên GLM-5.3-Flash. 60 phán quyết trên MiniMax-M2.7 tốn $0.0042. Cộng ba lại và bạn có giá của toàn bộ so sánh trước khi gửi một yêu cầu nào. Cùng khối lượng soạn thảo đó trên cả ba model, với đầu vào và đầu ra được cộng chung:
| Mô hình | Đầu vào $/1M | Đầu ra $/1M | Chi phí | OpenRouter |
|---|---|---|---|---|
| GLM-5.3-Flash | $0.02 | $0.04 | $0.00048 | $0.00092 |
| DeepSeek-V4-Flash | $0.015 | $0.10 | $0.00089 | $0.0017 |
| MiniMax-M2.7 | $0.05 | $0.15 | $0.0016 | $0.0189 |
Tổng cộng 9.000 token đầu vào và 7.500 token đầu ra. Giá trên 1 triệu token là giá hiện hành và thay đổi cùng với biểu phí của chúng tôi; cột OpenRouter hiển thị giá tham chiếu cho cùng khối lượng công việc.
Bảng cũng hiển thị tham chiếu OpenRouter, để bạn thấy tổng so sánh thế nào. Các giả định token là của bạn để thay đổi: nếu ticket của bạn dài, đầu vào của trọng tài tăng nhanh nhất, vì nó mang cả hai câu trả lời hai lần. Nếu trọng tài của bạn suy nghĩ thành tiếng trước khi trả lời, con số đầu ra của nó cũng tăng, và log của bạn sẽ cho thấy điều đó. Về thói quen đếm token trước một yêu cầu, xem đếm token trước khi gửi yêu cầu.
Giới hạn tương tự mà Clocktower dùng cũng đáng mượn. Nó đặt 8.000 token mỗi lượt, và bạn đã có max_tokens. Đặt nó vào SETTINGS và một câu trả lời chạy loạn không thể âm thầm nhân ước tính của bạn lên.
Trước khi khởi chạy toàn bộ lần chạy#
Danh sách kiểm tra
Kiểm tra trước cho một so sánh công bằng
Mục cuối cùng quan trọng. Chạy ba ticket, mở calls.jsonl và đọc nó. Kiểm tra rằng finish ghi stop thay vì length; nếu một bản nháp bị cắt bởi max_tokens, một model có thể đang thua chỉ vì câu trả lời của nó bị cắt cụt. Tương tự với các lần gọi của trọng tài: một length ở đó biến thành một hòa âm thầm, nên hãy đếm cả các phán quyết None. Nếu tác vụ của bạn có một đáp án đúng duy nhất, bạn có thể không cần trọng tài: kiểm tra prompt của bạn trên 20 trường hợp với chấm điểm khớp chính xác.
Đọc kết quả mà không tự lừa mình#
Hãy xem ba con số trong wins. Ba mươi ticket là một mẫu nhỏ: một tỷ lệ như 12 so với 9 với 9 hòa cho bạn biết hai model gần nhau, không phải một model tốt hơn. Log giúp ở đây. Nếu một model thắng nhẹ nhưng dùng nhiều đầu ra hơn hẳn, câu hỏi thực sự là giá của tác vụ, không phải số lần thắng; giá mỗi 1M token so với chi phí mỗi tác vụ đi qua so sánh đó.
Nếu kết quả sát nhau, hãy chọn model rẻ hơn cho tác vụ, hoặc thêm ticket và chạy lại. Cả hai đều rẻ để thử vì toàn bộ bộ máy đã là một vòng lặp. Khi bạn muốn lặp lại bài tập trên một model khác, ba model trên nằm sau một API và một khóa: thiết lập trong tài liệu là như nhau cho mỗi model, và trang giá liệt kê giá hiện tại của từng model. Phát hiện của chính Dwarkesh Patel về model OpenAI so với Anthropic (phát hiện so với lừa dối) là kết quả của anh ấy cho trò chơi của anh ấy; của bạn sẽ đến từ ticket của bạn.



