Prompt Engineering แบบวัดผล: อะไรเปลี่ยนผลลัพธ์
60 ticket คำเดิมใน 6 ลำดับ accuracy 26.7–85.0% ต่อด้วย 4 เทคนิคจากอินเทอร์เน็ต พร้อม error bar ทุกแบบ
ในหน้านี้
นี่คือ support ticket หนึ่งใบ และคิว 4 คิวที่มันอาจถูกส่งไป
The label on the parcel has my old surname on it.
-> billing / technical / shipping / accountในการ route มัน คุณต้องมีสามอย่างใน prompt: นิยามของคิว, ticket และคำสั่งให้เลือกหนึ่งคิว สามบล็อก มีลำดับที่จัดวางได้ 6 แบบ และบล็อกเหล่านั้นมี ตัวอักษรเหมือนกันทุกประการ ในทั้ง 6 แบบ
จาก ticket 60 ใบที่มีคำตอบที่รู้แล้ว ลำดับทั้ง 6 ทำคะแนนได้ตั้งแต่ 26.7 % ถึง 55.0 % ย้ายสองบล็อกเดิมออกจาก user turn ไปไว้ใน system turn โดยไม่เปลี่ยนแม้แต่คำเดียว model เดิมทำคะแนนได้ 76.7 % ห่อ ticket ด้วย tag สไตล์ XML แล้วขึ้นไปถึง 85.0 %
ไม่มีอะไรเกี่ยวกับ model ที่เปลี่ยน ไม่มีอะไรเกี่ยวกับงานที่เปลี่ยน ไม่มีคำใดถูกเขียนใหม่ ความต่าง 58 จุดเกิดจากการจัดวางข้อความเดิม
นี่คือเหตุผลที่บทนี้มีอยู่ และเป็นเหตุผลเดียวกันที่ทำให้มันเป็นหัวข้อที่เต็มไปด้วย cargo cult ที่สุดหัวข้อหนึ่งในวงการ ผลกระทบมีจริงและใหญ่พอให้ทุกเรื่องเล่าดูเหมือนได้รับการยืนยัน และมันไม่เสถียรข้าม model กับงานต่าง ๆ ซึ่งหมายความว่าคำแนะนำส่วนใหญ่ก็เป็นได้แค่เรื่องเล่า ดังนั้นบทนี้มีกฎเดียว และทุกอย่างในบทนี้อยู่ใต้กฎนั้น:
prompt ต้องวัด ไม่ใช่เถียงกัน 4 variant ใน 20 case แยกอะไรไม่ออกเลย
prompt คือสถานะทั้งหมด
ลิงก์ไปยังส่วน: prompt คือสถานะทั้งหมดก่อนดูการวัด มีข้อเท็จจริงหนึ่งที่อธิบายครึ่งหนึ่งของสิ่งที่จะตามมาอย่างเงียบ ๆ
model ไม่มีความจำ ระหว่างการเรียกสองครั้ง มันไม่เก็บอะไรไว้เลย — ไม่ใช่คำถามล่าสุดของคุณ ไม่ใช่คำตอบล่าสุดของมันเอง ไม่ใช่ไฟล์ที่คุณแนบ ไม่ใช่ข้อเท็จจริงว่าคุณถามมันไปแล้วสองครั้ง ทุกการเรียกเริ่มจากเครื่องว่างเปล่า และสิ่งเดียวที่เครื่องนั้นรู้คือ sequence ของ token ที่คุณเพิ่งส่งให้มัน
สิ่งที่ดูเหมือนความจำในอินเทอร์เฟซแชต คือ client ของคุณส่งบทสนทนาทั้งหมดซ้ำอีกครั้ง ทุก turn ตั้งแต่ต้น model อ่านทั้งหมดใหม่ตั้งแต่ศูนย์ ทุกครั้ง บทที่ 13 วัดต้นทุนของการอ่านซ้ำนั้นใน forward pass; บทที่ 16 แปลงมันเป็นบรรทัดหนึ่งบนใบแจ้งหนี้ สิ่งสำคัญตรงนี้คือผลต่อการออกแบบ: prompt ไม่ใช่ข้อความถึงระบบที่มีสถานะ prompt คือสถานะนั้นเอง
ข้อเท็จจริงนี้ทำให้ความสับสนทั้งตระกูลหมดไป “model ลืมสิ่งที่ฉันบอกมัน” มักหมายความว่าสิ่งนั้นไม่เคยถูกส่งไป “มันไม่ทำตามคำสั่งก่อนหน้า” มักหมายความว่าคำสั่งหลุดออกจาก window เมื่อประวัติถูกตัดทอน “มันทำงานต่างไปใน production” มักหมายความว่า production ประกอบ prompt คนละแบบกับที่คุณทดสอบ สิ่งเหล่านี้ไม่มีอันไหนเป็นปัญหาของ model และไม่มีอันไหนแก้ด้วยการเขียนคำใหม่
คำกล่าวว่า “prompt นี้ดีกว่า” คือคำกล่าวเกี่ยวกับ distribution และคุณมองไม่เห็น distribution ด้วยการดู output เดียว สิ่งที่คุณต้องการนั้นน่าเบื่อ: case ที่มีคำตอบที่รู้แล้ว, variant N แบบ และ interval
harness คือ TypeScript 50 บรรทัดที่มีรูปทรงเดียวกับ client จาก บทที่ 14 — request หนึ่ง, deadline หนึ่ง, concurrency บางส่วน, tally หนึ่ง มันกลับมาอีกใน บทที่ 19 เพื่อประเมิน retriever และใน บทที่ 29 ในฐานะ golden set
export type Case = { input: string; expected: string };
export type Variant = { name: string; build: (c: Case) => ChatMessage[] };
async function pooled<T, R>(xs: T[], n: number, f: (x: T) => Promise<R>) {
const out: R[] = new Array(xs.length);
let i = 0;
await Promise.all(
Array.from({ length: n }, async () => {
while (i < xs.length) {
const k = i++;
out[k] = await f(xs[k]);
}
}),
);
return out;
}
export async function runVariant(v: Variant, cases: Case[], concurrency = 6) {
const hits = await pooled(cases, concurrency, async (c) => {
const answer = await complete(v.build(c));
return answer.trim().toLowerCase() === c.expected;
});
return { name: v.name, hits, k: hits.filter(Boolean).length, n: cases.length };
}ตัวเลขที่กลับมาไม่ใช่ผลลัพธ์ นี่ต่างหาก:
/** 95 % Wilson score interval for a proportion. Chapter 4 derives it. */
export function wilson(k: number, n: number, z = 1.96) {
const p = k / n;
const d = 1 + (z * z) / n;
const centre = (p + (z * z) / (2 * n)) / d;
const half = (z * Math.sqrt((p * (1 - p)) / n + (z * z) / (4 * n * n))) / d;
return [Math.max(0, centre - half), Math.min(1, centre + half)] as const;
}บทที่ 4 วางข้อโต้แย้งไว้ และบทนี้เก็บเงินจากมัน ถูก 17 จาก 20 คือ 85 % และ interval 95 % ของมันวิ่งจาก 64 % ถึง 95 % variant ที่ทำได้ 13 จาก 20 — 65 % ซึ่ง รู้สึก แย่กว่าอย่างชัดเจน — มี interval จาก 43 % ถึง 82 % interval สองช่วงนี้ทับซ้อนกันแทบทั้งความยาว 20 case แยก prompt ที่ดีออกจาก prompt กลาง ๆ ไม่ได้ และคำแนะนำเรื่อง prompt ที่เผยแพร่ส่วนใหญ่ถูก validate ด้วยจำนวนน้อยกว่านั้น
60 case ซึ่งเป็นสิ่งที่บทนี้ใช้ ก็ยังไม่มากนัก มันพอให้เห็นผลกระทบขนาดใหญ่ และซื่อสัตย์พอจะยอมรับเมื่อมองไม่เห็นผลกระทบเล็ก ๆ — และข้างล่างนี้มันจะยอมรับหลายครั้ง
ตำแหน่ง: คำเดิม 6 ลำดับ
ลิงก์ไปยังส่วน: ตำแหน่ง: คำเดิม 6 ลำดับสามบล็อก — rules R, ticket T, instruction I — ต่อกันเป็น user message เดียว permutation ทั้ง 6 แบบ เนื้อหา byte-identical, แบบละ 60 case
| ลำดับของสามบล็อก | ถูก | accuracy, 95 % Wilson |
|---|---|---|
| rules, instruction, ticket | 33/60 | 55.0 % [42.5, 66.9] |
| rules, ticket, instruction | 30/60 | 50.0 % [37.7, 62.3] |
| ticket, rules, instruction | 22/60 | 36.7 % [25.6, 49.3] |
| instruction, ticket, rules | 21/60 | 35.0 % [24.2, 47.6] |
| instruction, rules, ticket | 17/60 | 28.3 % [18.5, 40.8] |
| ticket, instruction, rules | 16/60 | 26.7 % [17.1, 39.0] |
ดีที่สุดถึงแย่ที่สุดต่างกัน 28.3 จุด และ interval ไม่ทับซ้อนกัน ดังนั้นนี่ไม่ใช่เรื่อง noise เนื่องจากทุก arm ถูกให้คะแนนบน item 60 ชิ้นเดียวกัน คำถามที่คมกว่าคือคำถามแบบ paired: ใน case ที่สอง arm ไม่เห็นตรงกัน split เอียงแค่ไหน การเปลี่ยนจากลำดับแย่ที่สุดไปลำดับดีที่สุดพลิก 21 case ให้ถูก และ 4 case ให้ผิด — exact paired probability 0.00093
อ่านตารางเพื่อดูรูปร่างของมัน ไม่ใช่ผู้ชนะ สองแถวที่ดีที่สุดทั้งคู่ จบด้วย ticket; สองแถวที่แย่ที่สุดทั้งคู่ฝัง instruction ไว้กลางทางหรือทิ้งท้ายไว้หลัง data นั่นคือปรากฏการณ์เดียวกับที่ Liu et al. ตั้งชื่อว่า Lost in the Middle: เนื้อหาที่ขอบของ prompt ถูกใช้ได้เชื่อถือกว่าวัสดุตรงกลาง4 บทที่ 16 ตั้งราคาของ window และบทที่ 24 วัดผลนี้อย่างเหมาะสมเมื่อยาวขึ้น ที่ซึ่งตรงกลางพังลงตามที่อธิบาย และการฟื้นตัวที่ปลายสุดไม่กลับมาอีก ที่นี่กฎเชิงปฏิบัติโผล่ออกมาเอง: task ไว้บนสุด, data ไว้ล่างสุด, อย่าวางอะไรสำคัญไว้ตรงกลาง
ตอนนี้ย้ายคำเดิมระหว่าง turn บทที่ 11 แสดงแล้วว่า chat template ไม่ใช่ของตกแต่งรอบ model แต่เป็นส่วนหนึ่งของมัน — <|im_start|>system และ <|im_start|>user คือ token จริงที่ model เห็นมาหลายล้านครั้งระหว่าง fine-tuning ในตำแหน่งเหล่านั้นพอดี ดังนั้นมันควรสำคัญว่า instruction ของคุณตกอยู่ ฝั่งไหนของ marker เหล่านั้น และมันสำคัญจริง:
| คำเดิมอยู่ตรงไหน | ถูก | accuracy, 95 % Wilson |
|---|---|---|
| rules และ instruction อยู่ใน system turn, ticket อย่างเดียวอยู่ใน user turn | 46/60 | 76.7 % [64.6, 85.6] |
| rules อยู่ใน system turn, instruction และ ticket อยู่ใน user turn | 44/60 | 73.3 % [61.0, 82.9] |
| rules และ instruction อยู่ใน system turn, instruction ถูกทำซ้ำหลัง ticket | 42/60 | 70.0 % [57.5, 80.1] |
| ทั้งสามบล็อกอยู่ใน user turn เดียว | 33/60 | 55.0 % [42.5, 66.9] |
การย้าย rules และ instruction ข้าม template boundary ซื้อมาได้ 21.7 จุด — ได้เพิ่ม 19 case, เสีย 6 case, paired probability 0.0146 — โดยไม่เปลี่ยนตัวอักษรสักตัว นี่คือคำตอบที่จับต้องได้ต่อคำถาม system prompt เทียบกับ user prompt: มันไม่ใช่สองวิธีในการพูดสิ่งเดียวกัน มันคือสองตำแหน่ง token ต่างกันในโครงสร้างที่ model ถูก train มา และตำแหน่ง system คือที่ที่ instruction ซึ่งใช้กับบทสนทนาทั้งหมดควรอยู่
สังเกตแถวที่สามด้วย การทำ instruction ซ้ำหลัง ticket — trick ที่ถูกแนะนำกันกว้างขวาง — ทำคะแนน ต่ำกว่า การระบุเพียงครั้งเดียว บน model นี้ งานนี้ การพูดสองครั้งแย่กว่าพูดครั้งเดียว
Delimiter และบทเรียนสถิติที่ซ่อนอยู่ในนั้น
ลิงก์ไปยังส่วน: Delimiter และบทเรียนสถิติที่ซ่อนอยู่ในนั้นprompt เดิม ตำแหน่งดีที่สุด 60 case สิ่งเดียวที่เปลี่ยนคืออะไรล้อมรอบข้อความ ticket
| วิธี delimit ticket | ถูก | accuracy, 95 % Wilson |
|---|---|---|
| tag สไตล์ XML | 51/60 | 85.0 % [73.9, 91.9] |
| ไม่มีอะไรเลย | 48/60 | 80.0 % [68.2, 88.2] |
| heading ของ Markdown | 47/60 | 78.3 % [66.4, 86.9] |
label, Ticket: | 46/60 | 76.7 % [64.6, 85.6] |
| hash fences | 45/60 | 75.0 % [62.8, 84.2] |
| triple backticks | 44/60 | 73.3 % [61.0, 82.9] |
| double quotes | 40/60 | 66.7 % [54.1, 77.3] |
spread 18 จุดจากเครื่องหมายวรรคตอน แต่ดู interval สุดขั้วสองอัน: [73.9, 91.9] และ [54.1, 77.3] มันทับซ้อนกัน ถ้าอ่านแบบหยาบ — เปรียบเทียบ error bar และถ้ามันแตะกันก็ไม่พูดอะไร — ตารางนี้ไม่พิสูจน์อะไรเลย
การอ่านแบบหยาบผิดในกรณีนี้ และการเข้าใจว่าทำไมมีค่ามากกว่าตาราง ทุก variant ถูกให้คะแนนบน ticket 60 ใบเดียวกัน ดังนั้นการวัดสองครั้งไม่ใช่ sample อิสระ ความกว้างส่วนใหญ่ของแต่ละ interval มาจากแหล่ง uncertainty ที่ทั้งสอง arm แชร์ร่วมกัน — ว่า ticket 60 ใบนี้เป็นตัวแทนหรือไม่ — และแหล่งนั้น cancel เมื่อคุณเปรียบเทียบมันเข้าหากัน ถามคำถามแบบ paired แทน แล้วคำตอบคมชัด: จาก double quotes ไปเป็น XML tag พลิก 12 case ให้ถูก และ 1 case ให้ผิด, paired probability 0.0034 นั่นคือความต่างจริง
แล้วการทดสอบเดียวกันก็ทำให้พาดหัวแฟบลง XML tag ชนะ label แบบ plain Ticket: 8.3 จุด ซึ่งเป็นตัวเลขที่ blog post จะเอาไปใส่ใน title แบบ paired: ได้ 6, เสีย 1, probability 0.1250 ยังพิสูจน์ไม่ได้ case 7 ใบคือฐานที่ improvement อันโด่งดังนั้นยืนอยู่
ดังนั้นมีคำถามสองข้อพร้อมเครื่องมือสองชิ้นต่างกัน และการปนมันเข้าด้วยกันคือวิธีที่คำแนะนำเรื่อง prompt ผิดพลาดพร้อมกันทั้งสองทิศทาง:
prompt นี้ดีแค่ไหน? Wilson interval บน accuracy ของมันเอง กว้าง เว้นแต่คุณมีหลายร้อย case นี่คือตัวเลขที่คุณรายงานให้คนที่กำลังตัดสินใจว่าจะ ship หรือไม่
B ดีกว่า A หรือไม่? paired test เหนือ case ที่สองแบบไม่เห็นตรงกัน ไวต่อความต่างมากกว่า เพราะความยากร่วมของ set cancel กัน นี่คือตัวเลขที่คุณใช้ตัดสินใจระหว่าง candidate สองตัว
ข้อค้นพบทั่วไป — ว่า model อ่อนไหวอย่างแรงและคาดเดาไม่ได้ต่อ formatting choice ที่ไม่มีเนื้อหาเชิงความหมาย — ไม่ใช่เรื่องใหม่ Sclar et al. เปลี่ยนแค่ separator, spacing และ casing ในงานหลายสิบงาน แล้วพบ spread ของ accuracy กว้างพอจะกลับลำดับ ranking model ที่ตีพิมพ์แล้วได้5 ผลเชิงปฏิบัติไม่ใช่ “ใช้ XML tag” แต่คือ formatting เป็น hyperparameter มันไม่มีต้นทุนในการ sweep และการเปรียบเทียบ model สองตัวที่ fix format หนึ่งไว้ กำลังเปรียบเทียบ format พอ ๆ กับเปรียบเทียบ model
ต้องมีตัวอย่างกี่ตัวถึงจะพอจริง ๆ
ลิงก์ไปยังส่วน: ต้องมีตัวอย่างกี่ตัวถึงจะพอจริง ๆIn-context learning — การให้ model ดูตัวอย่างที่ทำเสร็จแล้วใน prompt แล้วให้มัน generalise จากตัวอย่างเหล่านั้นโดยไม่มี weight update — คือ capability ที่ทำให้ GPT-3 โด่งดัง6 คำถามเชิงปฏิบัติไม่เคยใช่ว่ามันใช้ได้หรือไม่ แต่คือควรจ่ายเพื่อตัวอย่างกี่ตัว
ตัวอย่างถูกใส่เป็น prior turn จริง สลับ user และ assistant เพราะนั่นคือโครงสร้างที่ template ถูก train มา แต่ละ k ถูกรันด้วย random draw ต่างกัน 5 ชุดจาก pool แยกที่มี ticket ติด label 16 ใบ:
| examples | mean accuracy | draw แย่สุดและดีที่สุด | spread ข้าม draw |
|---|---|---|---|
| 0 | 76.7 % | — | — |
| 1 | 78.7 % | 78.3 – 80.0 % | 1.7 points |
| 2 | 83.7 % | 80.0 – 86.7 % | 6.7 points |
| 4 | 81.7 % | 78.3 – 86.7 % | 8.3 points |
| 8 | 83.7 % | 78.3 – 88.3 % | 10.0 points |
| 16 | 89.3 % | 85.0 – 93.3 % | 8.3 points |
สองตัวอย่างซื้อมาได้ 7 จุด ตัวอย่างอีก 6 ตัวถัดไปไม่ได้ซื้ออะไรที่วัดได้ — 83.7, แล้ว 81.7, แล้ว 83.7 เป็น sequence ที่เดินไปมาอยู่ใน noise ของตัวเอง 16 ตัวอย่างซื้อเพิ่มมาอีก 5 จุดครึ่ง curve ไม่ใช่การไต่ขึ้นเรียบ ๆ แต่มันเป็น step, plateau และ step
คอลัมน์ที่สำคัญที่สุดคือคอลัมน์สุดท้าย ที่ k = 8, ตัวอย่าง 8 ตัวไหนที่คุณบังเอิญเลือก ขยับ accuracy ได้ 10 จุด — ใหญ่กว่ากำไรทั้งหมดจากการไปจากสองตัวอย่างเป็นแปดตัวอย่าง และแถวล่างสุดคือเวอร์ชันที่คมที่สุด: ที่ k = 16 pool หมดแล้ว ดังนั้นการรันทั้ง 5 ครั้งมี ตัวอย่าง 16 ตัวเหมือนกันทุกประการ ต่างกันแค่ลำดับที่ปรากฏ ลำดับอย่างเดียวขยับ accuracy ได้ 8.3 จุด
นั่นคือผลที่ Lu et al. รายงาน และมันอยู่รอดทุกที่ที่มีคนไปมองหา: การเรียงตัวอย่างเป็น hyperparameter จริงที่มีผลเทียบได้กับจำนวนตัวอย่าง7 ดังนั้นคำแนะนำที่ซื่อสัตย์เกี่ยวกับ few-shot prompting ไม่ใช่ตัวเลข แต่คือ:
เริ่มที่ศูนย์ และเพิ่มตัวอย่างเฉพาะเมื่อเทียบกับการวัด
ลิงก์ไปยังส่วน: เริ่มที่ศูนย์ และเพิ่มตัวอย่างเฉพาะเมื่อเทียบกับการวัดสองตัวแรกมักคุ้มค่า หลังจากนั้นคุณกำลังเดา และการเดานั้นมีต้นทุนเป็น tokens ในทุกการเรียกเดี่ยว ๆ ตลอดชีวิตของ product
ถือว่า selection เป็นส่วนหนึ่งของ prompt
ลิงก์ไปยังส่วน: ถือว่า selection เป็นส่วนหนึ่งของ promptตัวอย่างสองตัวที่เลือกดี ชนะตัวอย่างแปดตัวที่เลือกสะเพร่า ถ้าตัวอย่างของคุณมาจากแถวบน ๆ ของ spreadsheet นั่นคือตัวแปรที่ควร sweep ก่อนเพิ่มจำนวน
sweep ลำดับหนึ่งครั้ง แล้ว freeze มัน
ลิงก์ไปยังส่วน: sweep ลำดับหนึ่งครั้ง แล้ว freeze มันฟรี เป็นผลจริง และต่างจากสิ่งส่วนใหญ่ในบทนี้ มันไม่ต้อง rewrite เพื่อทดลอง
ตรวจ class balance
ลิงก์ไปยังส่วน: ตรวจ class balanceตัวอย่างสี่ตัวที่ label เหมือนกันทั้งหมดสอน model เรื่อง label ไม่ใช่งาน การพังของ model นี้ไปหา queue ไหนก็ตามที่ถูก list ไว้ท้ายสุดคือ failure เดียวกันในชุดเสื้อผ้าอีกแบบ
สี่ประโยคจากอินเทอร์เน็ต
ลิงก์ไปยังส่วน: สี่ประโยคจากอินเทอร์เน็ตต่อไปคือ folklore แต่ละอันคือประโยคเดียวที่ prepend ไปยัง system prompt ซึ่งนอกนั้นเหมือนเดิม บน 60 case เดียวกัน
| ประโยคที่เพิ่มใน system prompt | ถูก | accuracy, 95 % Wilson | paired เทียบ baseline |
|---|---|---|---|
| ไม่เพิ่มอะไร | 46/60 | 76.7 % [64.6, 85.6] | — |
| “Take a deep breath and work on this problem carefully.” | 47/60 | 78.3 % [66.4, 86.9] | +4 / −3, p = 1.000 |
| “This is very important to my career.” | 46/60 | 76.7 % [64.6, 85.6] | +5 / −5, p = 1.000 |
| “You are a world-class customer support operations expert with twenty years of experience.” | 42/60 | 70.0 % [57.5, 80.1] | +3 / −7, p = 0.344 |
| “I will tip you $200 if you answer correctly.” | 41/60 | 68.3 % [55.8, 78.7] | +1 / −6, p = 0.125 |
| “You will be penalised for every ticket you send to the wrong queue.” | 25/60 | 41.7 % [30.1, 54.3] | +3 / −24, p < 0.001 |
สี่จากห้าไม่ทำอะไรเลย ไม่ใช่ “ทำได้นิดหน่อย”; แต่ไม่มีอะไรที่ 60 paired case มองเห็นได้ persona ผู้เชี่ยวชาญและการติดสินบนทั้งคู่ทำคะแนน ต่ำกว่า baseline ที่ไม่แตะต้อง และแม้แต่การตกลงเหล่านั้นก็ไม่ผ่าน paired test — มันคือ noise ที่ชี้ลงเขา
แถวที่สามคือแถวที่ควรนั่งคิด “This is very important to my career” ให้ accuracy เหมือนกันทุกประการ, 46 จาก 60 — และ คำตอบ 10 จาก 60 เปลี่ยนไป, ห้าไปแต่ละทิศทาง summary statistic เหมือนเดิม แต่ behaviour ไม่เหมือนเดิม ถ้า evaluation ของคุณเป็นตัวเลขเดียวบน set เล็ก การเปลี่ยนแปลงที่เขียน output ใหม่หนึ่งในหกอาจดูเหมือนการเปลี่ยนแปลงที่ไม่ทำอะไร และคุณจะ ship มันโดยเชื่อว่ามันฟรี
แล้วก็มาถึงคำขู่ ซึ่งเป็นประโยคเดียวที่ขยับเข็ม และขยับลง 35 จุด โดยพลิก 24 case จากถูกเป็นผิด นั่นไม่ใช่ rounding artefact; มันคือ behaviour ของ model อีกแบบ บทเรียนไม่ใช่ “อย่าขู่ model เด็ดขาด” แต่คือ emotional framing ไม่ได้เฉื่อย มันเลื่อน distribution บางครั้งแรงมาก ไปในทิศทางที่ไม่มีใครคาดจากการอ่านประโยคได้ — และนั่นแหละคือเหตุผลที่มันต้องถูกวัด ไม่ใช่คิดเอาเอง
ข้อ caveat ที่บทนี้ติดค้างคุณ: ประโยคทั้งห้านี้ถูกทดสอบบน model เล็กหนึ่งตัวและงานหนึ่งงาน บางประโยคมีการสนับสนุนที่ตีพิมพ์ที่อื่น — “take a deep breath” มาจาก paper ที่ search หา instruction คะแนนสูง แทนที่จะคิดขึ้นมาเอง ซึ่งเป็น claim ที่ต่างและดีกว่า claim ที่แพร่กระจายทีหลัง8 สิ่งที่ generalise ไม่ใช่ประโยคเหล่านั้น แต่คือรายการที่อยู่รอดใน blog post กับรายการที่อยู่รอดในการวัดเป็นคนละรายการกัน และวิธีเดียวที่จะรู้ว่าคุณถือรายการไหนอยู่คือรัน bench
ทำไม “do not” ถึงล้มเหลว
ลิงก์ไปยังส่วน: ทำไม “do not” ถึงล้มเหลวกฎที่ทุกคนพูดซ้ำ — พูดสิ่งที่คุณต้องการ ไม่ใช่สิ่งที่คุณไม่ต้องการ — พร้อมกับการไม่มีตัวเลขตามปกติ นี่คือตัวเลข format requirement เดียวกัน เขียนสามแบบ โดยให้ model generate อย่างอิสระเพื่อ observe compliance:
| วิธีเขียน format rule | output เป็นคำที่อนุญาตหนึ่งคำพอดี | mean output tokens |
|---|---|---|
| “Answer with one word.” | 10/60 (16.7 %) | 2.6 |
| “Do not explain yourself. Do not write a sentence. Do not add punctuation.” | 1/60 (1.7 %) | 14.0 |
| ทั้งสองอย่างรวมกัน | 41/60 (68.3 %) | 2.3 |
ข้อห้ามสามข้อทำได้แย่กว่าคำสั่งหนึ่งข้อ และทำให้ model เขียนข้อความ มากขึ้นห้าเท่า — ตรงข้ามกับทั้งสามข้อพร้อมกันอย่างสมบูรณ์ การเพิ่มประโยคเชิงบวกกลับเข้าไปช่วยกู้ขึ้นมาเป็น 68 %
กลไกนี้ไม่ลึกลับเมื่อคุณจำ บทที่ 8 ได้ model เลือก token ถัดไปจาก distribution ที่ conditioned บนทุกอย่างก่อนหน้า และข้อห้ามเอาสิ่งที่ถูกห้าม ใส่เข้าไป ใน conditioning นั้น ไม่มี operator สำหรับ negation; มี context ที่คำหนึ่งปรากฏอยู่ในนั้นแล้ว
ซึ่งวัดได้โดยตรง เอา baseline prompt แล้วเพิ่มหนึ่งบรรทัด: Do not use the shipping queue for software problems. จากนั้นดูเฉพาะ ticket 45 ใบที่ไม่ใช่ shipping tickets:
shipping ถูกเลือก | mean probability บน shipping | overall accuracy | |
|---|---|---|---|
| baseline | 11.1 % ของ 45 case | 0.131 | 76.7 % [64.6, 85.6] |
| หลังห้ามมันด้วยชื่อ | 37.8 % | 0.374 | 51.7 % [39.3, 63.8] |
การเอ่ยชื่อคิวเพื่อ rule it out ทำให้ model เลือกมัน บ่อยขึ้นสามเท่า, ทำให้ probability mass ที่ assign ให้มันเกือบสามเท่า และทำให้ overall accuracy หายไป 25 จุด — เสีย 16 case ต่อได้ 1 case, paired probability 0.0003
อย่าคิดถึงช้าง แบบวัดผลแล้ว การ rewrite เหมือนเดิมเสมอ: แทนข้อห้ามด้วยกฎเชิงบวกที่ทำให้ข้อห้ามไม่จำเป็น ไม่ใช่ “do not use shipping for software problems” แต่เป็น “use shipping only when a physical parcel is involved”
counterexample ที่ซื่อสัตย์: chain of thought ที่มีต้นทุนแต่ไม่คุ้ม
ลิงก์ไปยังส่วน: counterexample ที่ซื่อสัตย์: chain of thought ที่มีต้นทุนแต่ไม่คุ้มบทที่ 12 สร้าง chain of thought อย่างถูกต้อง — ในฐานะ prompting technique ก่อน910 แล้วค่อยเป็นสิ่งที่ถูก train เข้าไปด้วย reward ที่ตรวจสอบได้ — และจบด้วยคำเตือนที่เลื่อนมายังบทนี้: การบอกให้ model คิดทีละขั้นหยุดช่วยเมื่อ model reason เองได้แล้ว และอาจทำร้ายได้ นี่คือคำเตือนนั้นพร้อมตารางอยู่ข้างใต้ บนงานที่ง่ายจะทึกทักว่าคิดมากขึ้นต้องดีกว่า
ทั้งสอง arm ถูกอ่านด้วยเครื่องมือเดียวกันที่ตำแหน่งเดียวกัน ความต่างเดียวคือมี chain of thought ที่ model เขียนเองนั่งอยู่ใน context ก่อนหรือไม่
| arm | ถูก | accuracy, 95 % Wilson | extra output tokens ต่อ case |
|---|---|---|---|
| ไม่มี chain of thought | 37/60 | 61.7 % [49.0, 72.9] | 0 |
| chain of thought, สูงสุด 60 tokens | 34/60 | 56.7 % [44.1, 68.4] | 53.1 |
| chain of thought, สูงสุด 200 tokens | 34/60 | 56.7 % [44.1, 68.4] | 97.7 |
accuracy ลง ต้นทุนขึ้น และกฎของบทนี้เองก็ใช้กับผลของบทนี้เอง: drop คือ ได้ 7 case ต่อเสีย 10 case, paired probability 0.629 ซึ่งยังพิสูจน์ไม่ได้ สิ่งที่ พิสูจน์ได้ คือมันผลิต output tokens เพิ่ม 98 token ต่อการเรียก และไม่ได้ซื้ออะไรที่วัดได้ uncertainty อยู่ฝั่ง benefit ทั้งหมด บิลแน่นอน
chain ที่ล้มเหลวสอนมากกว่า chain ที่สำเร็จ เมื่อถูกขอให้ reason เกี่ยวกับ “Your Slack integration stopped posting messages after Tuesday”, model เขียนว่า:
1. Check if the issue persists on Monday.
2. Verify if there are any updates or changes in your Slack setup that
might affect message posting.
3. If no update has been made since Tuesday, check for any recent system
restarts or downtime affecting Slack functionality.
4. If you have recently installed new software or updated your
environment, ensure it's compatible with Slack version.
5. Contact Slack support for further assistance or troubleshooting steps.นั่นคือคำแนะนำ troubleshooting ที่มีความสามารถ และมันไม่ใช่งาน เมื่อถูกขอให้คิด model ไหลไปยัง genre ที่ “think step by step about this support ticket” คล้ายที่สุดใน training data ของมัน — แล้วตอบคำถาม classification ด้วยตัวอักษร 500 ตัวของ reasoning ที่ไม่เกี่ยวข้องใน context ของตัวเอง Chain of thought ช่วยบนปัญหาที่มี intermediate state worth computing: arithmetic, multi-hop lookups, constraint satisfaction การ route ประโยคหนึ่งไปยังหนึ่งในสี่ bucket ไม่มี intermediate state ไม่มีอะไรให้ chain ถือไว้ ดังนั้นสิ่งเดียวที่มันทำคือเพิ่มข้อความที่ดูมีเหตุผลซึ่ง decision สุดท้ายต้องเอาตัวรอดผ่านมันให้ได้
ผลตามมาเชิงปฏิบัติสองข้อ ข้อแรก สำหรับ model ที่ถูก train ให้ reason — model RLVR ของบทที่ 12 — instruction นี้แย่กว่า redundant: มันอาจแทนที่ chain ยาวที่ model จะผลิตเองด้วย chain สั้น ๆ รูปทรงเหมือน prompt และการ sample chain หลายชุดแล้ว vote ซึ่งคือสิ่งที่ self-consistency ทำ11 ก็ช่วยงานที่ไม่มีอะไรให้เห็นต่างกันไม่ได้: มันทวีคูณต้นทุนตามจำนวน sample เพื่อ break tie ที่ไม่มีอยู่ บทที่ 12 วัด trade นั้นในที่ที่มันใช้ได้ ข้อสอง สังเกตต้นทุนของ scaffold เปรียบเทียบเอง การบังคับคำตอบให้อยู่ในบรรทัด Final queue: ทำให้ arm ที่ไม่ reasoning ลดจาก 76.7 % เป็น 61.7 % สิบห้าจุด จ่ายเพื่อให้สอง arm เปรียบเทียบกันได้ Structure ที่มีอยู่เพื่อความสะดวกของคุณก็ไม่ฟรีเช่นกัน
การเรียกเดิม สองครั้ง
ลิงก์ไปยังส่วน: การเรียกเดิม สองครั้งการวัดสุดท้ายหนึ่งครั้ง เพราะนี่คือคำถามที่ทุกคนถามหลังผลที่น่าประหลาดใจครั้งแรก 60 prompt, greedy decoding, รันซ้ำ ๆ:
- การเรียกเดิมซ้ำโดยตรึงทุกอย่างไว้คืนค่า probability ที่ bit-identical Deterministic
- การเรียกเดิม batched กับ neighbour ต่างกัน — batch size 1, 4, 12, 30 และ 60 — คืนค่า probability ที่ต่างกันได้ถึง 0.0128 label ที่เลือกไม่เคยเปลี่ยน ใน 0 จาก 60 case
label รอดเพราะมันมีพื้นที่ให้รอด: ตลอด 60 case gap ที่แคบที่สุดระหว่างคิวอันดับหนึ่งและสองคือ 0.0459 ใหญ่กว่า drift สามเท่าครึ่ง stability ไม่ใช่คุณสมบัติของ algorithm มันคือ margin และ margin หมดได้ บทที่ 17 คือที่ที่เหตุผลทาง arithmetic อยู่ และที่ที่ sampling knob ที่ขยายและบีบ gap เหล่านั้นถูกแยกชิ้นส่วน เหตุผลที่นำมาปักไว้ตรงนี้คือมันจำกัดความหมายของการวัด prompt ใด ๆ: bench วัดระบบที่ reproduce ได้เฉพาะภายใน tolerance และความต่างสองจุดระหว่าง variant อยู่ใน tolerance นั้นได้ในวันที่แย่
หยุดออกความเห็น แล้วเริ่มค้นหา
ลิงก์ไปยังส่วน: หยุดออกความเห็น แล้วเริ่มค้นหาทุกอย่างข้างบนคือมนุษย์เลือก variant และเครื่องให้คะแนนมัน ขั้นถัดไปที่ชัดเจนคือปล่อยให้เครื่องเลือก variant ด้วย
APE ทำแบบนั้นพอดี: model เสนอ candidate instruction, มันถูกให้คะแนนบน held-out examples และตัวที่ดีที่สุดอยู่รอด8 instruction ที่มันพบมักเป็นสิ่งที่ไม่มีมนุษย์คนไหนจะเขียน ซึ่งนั่นแหละคือประเด็น — การ search อยู่บนสิ่งที่ทำคะแนน ไม่ใช่บนสิ่งที่ฟังดู professional
DSPy ไปไกลกว่าและเป็นไอเดียที่มีประโยชน์กว่าสำหรับ product12 คุณประกาศว่าแต่ละขั้นของ pipeline รับอะไรและคืนอะไร แล้ว framework compile สิ่งนั้นเป็น prompt, เลือก demonstration และ optimise instruction เทียบกับ metric ของคุณ เปลี่ยน model ก็ recompile แทน rewrite prompt หยุดเป็น source code ที่ใครบางคน hand-tune และกลายเป็น artefact ที่ generate เทียบกับ metric ซึ่งเป็นสิ่งที่มันควรเป็นมาตั้งแต่แรก
ทั้งสองอย่างไม่ได้เอาความจำเป็นของ bench ออกไป ทั้งคู่ทำให้ bench เป็นสิ่งเดียวที่คุณต้องการ เพราะ optimiser ที่ไม่มี metric ก็ไม่ได้ optimise อะไร
สิ่งที่เหลือคือวินัย prompt ควรอยู่ใน version control, ใน file, ถัดจาก code ที่ส่งมัน — ไม่ใช่อยู่ใน database row ที่ใครบางคนแก้เมื่อวันอังคาร มันต้องมี version identifier ที่เก็บไว้เคียงข้าง output ทุกชิ้นที่มันผลิต ไม่เช่นนั้นวันที่อะไรบางอย่าง regress คุณจะหาว่าอะไรเปลี่ยนไม่ได้ มันต้องมี bench ใน continuous integration เพราะ prompt คือส่วนหนึ่งของระบบคุณที่ vendor สามารถ invalidate ได้เงียบ ๆ ด้วยการ deploy model ใหม่ และมันต้องมี case: ไม่ใช่ร้อย case ฉลาด ๆ แค่ 20 case น่าเบื่อที่พังเมื่อไตรมาสก่อน เก็บไว้ตลอดไป bench คือ deliverable prompt เป็น by-product ของมัน
ต่อจากนี้ไปที่ไหน
ลิงก์ไปยังส่วน: ต่อจากนี้ไปที่ไหนทุกอย่างในบทนี้ถูกวัดด้วย accuracy ทุก variant เหล่านั้นก็มีราคาเช่นกัน
system prompt ที่ซื้อมาได้ 21.7 จุดถูกส่งในทุก call ตลอดไป ตัวอย่างสองตัวที่ซื้อมาได้ 7 จุดถูกส่งในทุก call ตลอดไป ตัวอย่าง 16 ตัวที่ซื้อมาได้ 12 จุดถูกส่งในทุก call ตลอดไป และมันยาวประมาณ 10 เท่าของคำถามที่ผู้ใช้ถามจริง chain of thought ที่ไม่ได้ซื้ออะไรเลยผลิต token เพิ่ม 98 token ต่อ request และ output tokens คือชนิดที่แพง
ไม่มีสิ่งใดมองเห็นในตาราง accuracy และทั้งหมดมองเห็นบนใบแจ้งหนี้
บทที่ 16 ว่าด้วยหน่วยที่ decision เหล่านั้นถูก denominate จริง ๆ token ในฐานะหน่วย billing, context window ในฐานะ budget แทนที่จะเป็น memory, ทำไมบทสนทนา 40 turn ถึงแพงกว่า 40 เท่าของ turn แรกมาก, prompt caching จ่ายให้และไม่จ่ายให้อะไร, และทำไมลำดับ prompt ของคุณตัดสินว่า cache hit หรือไม่ — ซึ่งกลายเป็นเหตุผลข้อที่สองที่เป็นเรื่องเศรษฐศาสตร์ล้วน ๆ ในการวาง material ที่เสถียรไว้ก่อน และ material ที่แปรผันไว้ท้าย
แหล่งอ้างอิงและ method
ลิงก์ไปยังส่วน: แหล่งอ้างอิงและ methodbench และทุกตารางผลิตด้วย Qwen/Qwen2.5-0.5B-Instruct ภายใต้ greedy decoding ดังนั้นมัน reproduce ได้พอดี เอกสาร Hugging Face เรื่อง chat templates คือ reference สำหรับว่า template markers ของบทที่ 11 expand เป็นอะไรจริง และสำหรับข้อเท็จจริงว่า model ที่ ship template ผิดเป็น failure จริงและเกิดซ้ำ สำหรับ position และ format effect ใน production scale แทน laboratory scale citation ข้างบนคือ primary sources; prompting guide ของ vendor มีประโยชน์เพราะตัวอย่างของมัน และควรอ่านโดยรู้ว่าไม่มีอันไหน publish interval
รายการอ้างอิง
ลิงก์ไปยังส่วน: รายการอ้างอิง-
Anthropic, Effective context engineering for AI agents (29 September 2025), สำหรับความต่าง prompt-versus-context ที่ใช้ในบทนี้และพัฒนาต่อในบทที่ 24 ↩
-
Zhao, Z., Wallace, E., Feng, S., Klein, D. and Singh, S. Calibrate Before Use: Improving Few-Shot Performance of Language Models. arXiv:2102.09690 (2021). bias แบบ majority-label, recency และ common-token และทำไม rotation ใน bench ของบทนี้ไม่ใช่สิ่ง optional ↩
-
McNemar, Q. Note on the sampling error of the difference between correlated proportions or percentages. Psychometrika 12(2), pp. 153–157 (1947). paired comparison ในบทนี้ใช้ exact binomial form แทน chi-squared approximation เพราะ discordant count มีขนาดเล็ก ↩
-
Liu, N. F. et al. Lost in the Middle: How Language Models Use Long Contexts. arXiv:2307.03172 (2023). อ้างตรงนี้สำหรับ position effect; วัดเมื่อยาวขึ้นในบทที่ 24 ↩
-
Sclar, M., Choi, Y., Tsvetkov, Y. and Suhr, A. Quantifying Language Models' Sensitivity to Spurious Features in Prompt Design. arXiv:2310.11324 (2023). แค่ separator และ spacing ก็ขยับ accuracy พอจะ reorder leaderboard ของ model ได้ ↩
-
Brown, T. B. et al. Language Models are Few-Shot Learners. arXiv:2005.14165 (2020). paper ที่แนะนำ in-context learning ในฐานะ capability ไม่ใช่ความแปลกประหลาด; section 3 คือที่มาของ vocabulary zero-shot / one-shot / few-shot ที่ทุกคนใช้ตอนนี้ ↩
-
Lu, Y., Bartolo, M., Moore, A., Riedel, S. and Stenetorp, P. Fantastically Ordered Prompts and Where to Find Them: Overcoming Few-Shot Prompt Order Sensitivity. arXiv:2104.08786 (2021). ผลที่ reproduce ในตาราง few-shot ข้างบน ↩
-
Zhou, Y. et al. Large Language Models Are Human-Level Prompt Engineers. arXiv:2211.01910 (2022). automatic prompt engineering ด้วย proposal และ scoring instruction “take a deep breath” ที่ถูก quote กันมากมาจาก Yang, C. et al., Large Language Models as Optimizers, arXiv:2309.03409 (2023), ซึ่ง พบ มันด้วยการ search บนงานหนึ่งกับ model หนึ่ง — claim ที่ไม่รอดครบถ้วนระหว่างเดินทางเข้าสู่ blog post ↩ ↩2
-
Wei, J. et al. Chain-of-Thought Prompting Elicits Reasoning in Large Language Models. arXiv:2201.11903 (2022). ↩
-
Kojima, T., Gu, S. S., Reid, M., Matsuo, Y. and Iwasawa, Y. Large Language Models are Zero-Shot Reasoners. arXiv:2205.11916 (2022). ผล “let's think step by step” และคุ้มค่าที่จะอ่านเพื่อดูว่าเงื่อนไขแคบแค่ไหน ↩
-
Wang, X. et al. Self-Consistency Improves Chain of Thought Reasoning in Language Models. arXiv:2203.11171 (2022). วัดพร้อมต้นทุนที่แนบไว้ในบทที่ 12 ↩
-
Khattab, O. et al. DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines. arXiv:2310.03714 (2023). ↩