ข้อกำหนดที่ไม่ใช่หน้าที่หลัก (Non-functional Requirements) ของ AI Coding คืออะไร? เหตุใด LLM จึงไม่เก่งเท่ากับข้อกำหนดด้านหน้าที่หลัก (Functional Requirements) และเกณฑ์ที่มนุษย์ควรเป็นผู้ตัดสินใจ

ข้อกำหนดที่ไม่ใช่หน้าที่การทำงาน (Non-functional requirements) คือข้อกำหนดที่ไม่ได้กำหนดว่าระบบจะ "ทำอะไร" แต่กำหนดว่าระบบจะ "ทำงานได้อย่างปลอดภัย รวดเร็ว ประหยัด และดูแลรักษาได้ง่ายเพียงใด" ในปัจจุบัน เอเจนต์สำหรับการเขียนโค้ดอย่าง Claude Code เริ่มได้รับความไว้วางใจให้รับผิดชอบการนำข้อกำหนดด้านหน้าที่การทำงาน (Functional requirements) ไปใช้งานจริงมากขึ้น เช่น การสร้างหน้าจอหรือ API ให้เป็นไปตามสเปก ในขณะเดียวกัน คุณ mizutani (@m_mizutani) ซึ่งเป็นวิศวกรด้านความปลอดภัยและซอฟต์แวร์ ได้ระบุไว้ใน โพสต์บน X ว่าสิ่งที่เขาชี้แนะให้กับ Claude นั้น "ร้อยละ 90 เกี่ยวข้องกับข้อกำหนดที่ไม่ใช่หน้าที่การทำงาน เช่น ความปลอดภัย ประสิทธิภาพ ต้นทุน และความสามารถในการบำรุงรักษา"
บทความนี้จัดทำขึ้นสำหรับ Tech Lead และผู้รับผิดชอบด้านการพัฒนาที่เริ่มมอบหมายงานการเขียนโค้ดให้กับ AI โดยจะสรุปเหตุผลตามผลการวิจัยที่เผยแพร่ว่าเหตุใด LLM จึงสามารถจัดการกับข้อกำหนดด้านหน้าที่การทำงานได้ค่อนข้างดี และเหตุใดงานด้านข้อกำหนดที่ไม่ใช่หน้าที่การทำงานจึงยังคงต้องอาศัยมือมนุษย์ นอกจากนี้ ยังจะแสดงให้เห็นว่ามนุษย์ควรตัดสินใจเรื่องใดและต้องส่งมอบงานในรูปแบบใดเพื่อให้ LLM สามารถทำงานได้ตามมาตรฐานที่กำหนด
ความแตกต่างระหว่าง Functional Requirements และ Non-functional Requirements คืออะไร?

ฟังก์ชันนัลรีไควร์เมนต์ (Functional Requirements) คือการกำหนดว่า "จะตอบสนองต่ออินพุตอย่างไร" ในขณะที่นอนฟังก์ชันนัลรีไควร์เมนต์ (Non-functional Requirements) คือการกำหนดว่า "กระบวนการนั้นจะทำงานภายใต้เงื่อนไขใดและในระดับใด"
การทำความเข้าใจการจำแนกประเภทตามมาตรฐาน จะช่วยให้ทีมมีภาษากลางในการหารือกันว่าควรให้ AI รับผิดชอบส่วนใด และส่วนใดที่มนุษย์ควรเป็นผู้ตรวจสอบ
นิยามและการจำแนกประเภทที่สำคัญ (ISO/IEC 25010 และ Non-functional Requirements Grade)
ตัวอย่างเช่น "ผู้ใช้ที่ล็อกอินสามารถดูรายการใบแจ้งหนี้ของตนเองได้" คือความต้องการเชิงฟังก์ชัน (Functional Requirements) ส่วนการกำหนดว่า "รายการต้องแสดงผลภายใน 1 วินาที" "แม้จะเปลี่ยน URL ก็ไม่สามารถดูใบแจ้งหนี้ของบริษัทอื่นได้" หรือ "ค่าใช้จ่ายในการดำเนินงานรายเดือนต้องอยู่ในงบที่กำหนด" สำหรับหน้าจอเดียวกันนั้น คือความต้องการที่ไม่ใช่เชิงฟังก์ชัน (Non-functional Requirements) อย่างแรกสามารถตรวจสอบได้ว่าบรรลุผลหรือไม่เพียงแค่ลองใช้งานหน้าจอ แต่อย่างหลังต้องมีการจัดเตรียมเงื่อนไขและวัดผลจึงจะทราบได้
มาตรฐานสากล ISO/IEC 25010 ซึ่งกำหนดคุณลักษณะด้านคุณภาพของซอฟต์แวร์ ได้แบ่งคุณภาพของผลิตภัณฑ์ออกเป็น 9 คุณลักษณะในฉบับปี 2023 (คำอธิบายเกี่ยวกับ arc42 Quality Model) โดย 8 คุณลักษณะจากทั้งหมด (ยกเว้นความเหมาะสมด้านฟังก์ชัน) ถือเป็นมุมมองของความต้องการที่ไม่ใช่เชิงฟังก์ชันโดยรวม ในประเทศญี่ปุ่น Non-functional Requirements Grade ของ IPA (Information-technology Promotion Agency) ถูกนำมาใช้เป็นรายการตรวจสอบเพื่อป้องกันความเข้าใจที่ไม่ตรงกันระหว่างผู้ว่าจ้างและนักพัฒนา
แม้ว่าการจำแนกทั้ง 2 ประเภทจะมีมุมมองที่แตกต่างกัน แต่ทั้งคู่สามารถใช้เป็นรายการตรวจสอบเพื่อค้นหา "คุณสมบัติที่ไม่ใช่ฟังก์ชัน" ได้อย่างครบถ้วน
| การจำแนก | มุมมอง | ตัวอย่างค่าที่ต้องกำหนด |
|---|---|---|
| ISO/IEC 25010 (คุณภาพผลิตภัณฑ์) | ประสิทธิภาพ, ความเข้ากันได้, ความสามารถในการโต้ตอบ, ความน่าเชื่อถือ, ความปลอดภัย, ความสามารถในการบำรุงรักษา, ความยืดหยุ่น, ความปลอดภัยทางกายภาพ | เวลาตอบสนอง, จำนวนผู้ใช้ที่รองรับพร้อมกัน, การกู้คืนจากความเสียหาย, ความง่ายในการแก้ไข |
| IPA Non-functional Requirements Grade | ความพร้อมใช้งาน, ประสิทธิภาพ/ความสามารถในการขยายตัว, การดำเนินงาน/การบำรุงรักษา, การย้ายระบบ, ความปลอดภัย, สภาพแวดล้อมระบบ/นิเวศวิทยา | อัตราการใช้งาน (Availability), ระยะเวลาเป้าหมายในการกู้คืน (RTO), จำนวนรุ่นของข้อมูลสำรอง, ระยะเวลาในการย้ายระบบ |
Non-functional Requirements Grade เป็นสิ่งที่ใช้สำหรับตกลงความต้องการด้านโครงสร้างพื้นฐานของระบบ โดยไม่ได้กำหนดไปถึงวิธีการเขียนโค้ดของแอปพลิเคชัน เมื่อต้องสร้างเกณฑ์เพื่อส่งให้ AI การใช้รายการเหล่านี้เพื่อตรวจสอบความครบถ้วนและนำเฉพาะหัวข้อที่มีความหมายต่อระบบของตนเองมาแปลงเป็นตัวเลขถือเป็นวิธีที่ใช้งานได้จริงที่สุด
ลักษณะของ Non-functional Requirements: "ครอบคลุมทุกส่วน", "การแลกเปลี่ยน (Trade-off)", และ "ปรากฏขึ้นภายหลัง"
ข้อกำหนดที่ไม่ใช่หน้าที่หลัก (Non-functional requirements) มีคุณสมบัติ 3 ประการที่ข้อกำหนดด้านหน้าที่หลักไม่มี
ประการแรก คือความเป็นองค์รวม (Cross-cutting) การรั่วไหลของสิทธิ์การเข้าถึงไม่ได้เกิดขึ้นแค่หน้าจอเดียว แต่ครอบคลุมไปถึง API ทั้งหมดที่จัดการ ID ของผู้เช่า (Tenant) เช่นเดียวกับประสิทธิภาพการทำงานที่คิวรีเพียงหนึ่งรายการที่ทำงานช้าจะฉุดให้การตอบสนองของหน้าจออื่นช้าลงไปด้วย ไม่ว่าคุณจะเปิดไฟล์ไหนขึ้นมา ก็ไม่มีจุดใดที่เขียนโค้ดแล้วถือว่า "เสร็จสิ้น"
ประการที่สอง คือการแลกเปลี่ยนผลประโยชน์ (Trade-off) หากเพิ่มความพร้อมใช้งาน (Availability) ค่าใช้จ่ายก็จะเพิ่มขึ้น หากใช้แคชเพื่อเพิ่มความเร็ว ก็จะเกิดช่วงเวลาที่ผู้ใช้เห็นข้อมูลเก่า การตัดสินใจว่าจะประนีประนอมที่จุดใดนั้น ขึ้นอยู่กับความเสียหายเมื่อระบบหยุดทำงาน งบประมาณที่มี และระยะเวลาที่ผู้ใช้สามารถรอได้ คำตอบที่ถูกต้องไม่ได้อยู่ในโค้ด
ประการที่สาม คือการปรากฏขึ้นในภายหลัง ข้อมูลทดสอบเพียงไม่กี่สิบรายการไม่สามารถเผยให้เห็นความช้าในการประมวลผลหรือขีดจำกัดของจำนวนข้อมูลได้ อินพุตในรูปแบบที่ผู้โจมตีส่งมานั้นแทบจะไม่เกิดขึ้นในการตรวจสอบการทำงานตามปกติ ข้อบกพร่องของข้อกำหนดที่ไม่ใช่หน้าที่หลักจำนวนมากไม่มีรูปร่างให้เห็นในขั้นตอนการออกแบบหรือการตรวจสอบ แต่จะปรากฏตัวออกมาเป็นครั้งแรกในรูปแบบของการละเมิดเมื่อใช้งานจริง
คุณสมบัติทั้ง 3 ประการนี้ ตรงกันข้ามกับ "สิ่งที่ LLM ถนัด" ซึ่งจะกล่าวถึงในหัวข้อถัดไปพอดี
ทำไม LLM ถึงสามารถจัดการ Functional Requirements ได้ค่อนข้างดี?

เนื่องจากข้อกำหนดเชิงฟังก์ชันมักจะสามารถตรวจสอบความถูกต้องได้ด้วยการดูอินพุตและเอาต์พุต และบ่อยครั้งก็สามารถแก้ไขได้ด้วยรูปแบบการใช้งาน (Implementation Pattern) ที่เป็นที่รู้จักกันดี ซึ่งทั้งสองประการนี้มีความสอดคล้องกับจุดแข็งของ LLM ครับ
สามารถตรวจสอบคำตอบที่ถูกต้องได้จาก Input และ Output
ข้อกำหนดที่สามารถเขียนได้ว่า "ถ้าใส่ค่านี้ ต้องได้ผลลัพธ์นี้" สามารถนำมาเปลี่ยนเป็นแบบทดสอบ (Test) ได้ หากมีแบบทดสอบ LLM จะสามารถวนลูปการทำงานด้วยตัวเองได้ ทั้งการเขียนโค้ด การรัน และการอ่านผลลัพธ์เพื่อแก้ไขหากเกิดข้อผิดพลาด แนวทางปฏิบัติที่ดีที่สุดของ Claude Code จาก Anthropic ก็แนะนำให้ส่งตัวตรวจสอบที่ให้ผลลัพธ์เป็นผ่านหรือไม่ผ่านเข้าไปด้วย โดยอธิบายว่าหากไม่มีวิธีตรวจสอบ Claude จะมีเกณฑ์ตัดสินเพียงแค่ว่า "ดูเหมือนจะเสร็จสมบูรณ์แล้ว" ซึ่งส่งผลให้มนุษย์ต้องทำหน้าที่เป็นตัวทดสอบแทน
ข้อกำหนดเชิงฟังก์ชัน (Functional Requirements) มีคุณสมบัติที่เอื้อต่อการวนลูปนี้ได้ง่าย เพราะสามารถเขียนค่าที่คาดหวังไว้ล่วงหน้าได้ ไม่ว่าจะเป็นการทำงานบนหน้าจอ การตอบสนองของ API หรือผลลัพธ์จากการคำนวณ แม้ว่าข้อความในสเปกจะมีความคลุมเครืออยู่บ้าง แต่หากระบุตัวอย่างอินพุตและเอาต์พุตสัก 2-3 ตัวอย่าง LLM ก็มักจะเข้าใจเจตนาได้ ในฝั่งของมนุษย์เอง เมื่อลองรันดูแล้วเห็นว่าถูกต้องหรือไม่ ก็จะสามารถให้คำแนะนำที่เฉพาะเจาะจงได้ว่า "ต้องการให้ผลลัพธ์ออกมาเป็นแบบนี้เมื่อใส่ค่านี้เข้าไป"
ในทางกลับกัน หลายสถานการณ์ที่เรารู้สึกว่าความสามารถในการเขียนโปรแกรมของ LLM พัฒนาขึ้น ก็คือสถานการณ์ที่มีการวนลูปการตรวจสอบเกิดขึ้นนั่นเอง แม้จะเป็นโมเดลเดียวกัน แต่หากเป็นข้อกำหนดที่ไม่สามารถเขียนแบบทดสอบได้หรือไม่มีตัวอย่างให้ ผลลัพธ์ที่ได้ก็จะด้อยลง และข้อกำหนดที่ไม่ใช่เชิงฟังก์ชัน (Non-functional Requirements) ส่วนใหญ่ก็จัดอยู่ในกลุ่มที่เขียนแบบทดสอบได้ยากในรูปแบบเดิม
สามารถแก้ไขได้ด้วยรูปแบบที่คุ้นเคย
อีกเหตุผลหนึ่งคือ ข้อกำหนดเชิงฟังก์ชันจำนวนมากประกอบขึ้นจากการรวมกันของปัญหาที่มีตัวอย่างการใช้งานจริงอยู่มากมายแล้ว ไม่ว่าจะเป็นการตรวจสอบข้อมูลในฟอร์ม (Form validation), การแบ่งหน้าแสดงรายการ (Pagination) หรือการส่งออกไฟล์ CSV ล้วนมีรูปแบบการเขียนที่เป็นมาตรฐานในแต่ละภาษาและเฟรมเวิร์ก ซึ่ง LLM มีความเชี่ยวชาญในการเลือกรูปแบบที่เหมาะสมกับสถานการณ์จากโค้ดจำนวนมหาศาลที่ได้เรียนรู้มา
แนวโน้มนี้ยังปรากฏให้เห็นในการสำรวจด้านความปลอดภัยอีกด้วย Veracode บริษัทด้านความปลอดภัยของแอปพลิเคชันได้ทำการสำรวจอย่างต่อเนื่องโดยให้ LLM กว่า 100 รุ่นแก้โจทย์เดียวกันและนำโค้ดที่สร้างขึ้นมาตรวจสอบด้วยการวิเคราะห์แบบสถิต (Static analysis) ผลปรากฏว่าในเงื่อนไขที่ไม่ได้ระบุคำสั่งเกี่ยวกับความปลอดภัยใดๆ อัตราการป้องกัน SQL Injection ได้สำเร็จอยู่ที่เฉลี่ย 83% และการเลือกวิธีการเข้ารหัสลับอยู่ที่ 87% (Veracode「2026 GenAI Code Security Report」) ซึ่งมาตรการที่มีรูปแบบตายตัว เช่น การใช้ Placeholder สำหรับ SQL หรือการหลีกเลี่ยงวิธีการเข้ารหัสแบบเก่า LLM สามารถเลือกใช้ได้เองในหลายกรณีแม้จะไม่ได้รับคำสั่งก็ตาม
อย่างไรก็ตาม รายงานฉบับเดียวกันระบุว่า แม้ความสามารถของโมเดลในการเขียนโค้ดที่ถูกต้องตามหลักไวยากรณ์จะเพิ่มขึ้น แต่อัตราการผ่านเกณฑ์ด้านความปลอดภัยโดยรวมกลับยังคงที่ โดยอัตราการผ่านเฉลี่ยอยู่ที่ 56% ซึ่งแทบไม่เปลี่ยนแปลงจากรายงานฉบับแรกที่ 55% ส่วนที่แก้ได้ด้วยรูปแบบมาตรฐานนั้นพัฒนาขึ้น แต่ส่วนที่ไม่สามารถแก้ด้วยวิธีนั้นกลับไม่มีการพัฒนา ซึ่ง "ส่วนที่ไม่สามารถแก้ด้วยวิธีนั้น" คือหัวข้อที่จะกล่าวถึงในส่วนถัดไป
ทำไม Non-functional Requirements ถึงยังต้องอาศัยมือมนุษย์?

ข้อกำหนดที่ไม่ใช่หน้าที่การทำงาน (Non-functional requirements) มีลักษณะคือคำตอบไม่ได้อยู่ในโค้ด ข้อบกพร่องจะปรากฏให้เห็นข้ามกระแสข้อมูล และไม่สามารถมองเห็นได้ในข้อมูลขนาดเล็ก เนื่องจาก LLM ไม่สามารถตรวจสอบด้วยตนเองผ่านการทำงานแบบไปกลับ (round-trip) ได้ง่ายนัก จึงยังคงจำเป็นต้องอาศัยมือของผู้กำหนดเกณฑ์มาตรฐานในการตัดสินใจ
คำตอบที่ถูกต้องไม่ได้อยู่แค่ในโค้ด
คำถามที่ว่า "API นี้ควรตอบสนองภายในกี่วินาที" นั้น ต่อให้คุณอ่านโค้ดมากแค่ไหนก็ไม่มีทางทราบได้ เพราะคำตอบขึ้นอยู่กับระยะเวลาที่ผู้ใช้งานรอได้ จำนวนการเข้าถึงในช่วงเวลาที่มีการใช้งานสูงสุด ความเสียหายหากระบบหยุดทำงาน และค่าใช้จ่ายในการดำเนินงานที่สามารถจ่ายได้ในแต่ละเดือน หากคุณสั่งให้ LLM "ทำให้เร็วขึ้น" มันจะทำการเพิ่มแคช สร้างดัชนี และประมวลผลแบบขนานให้ แต่ LLM ไม่สามารถตัดสินได้ว่าทำแค่ไหนถึงจะเพียงพอ และจุดไหนคือการสิ้นเปลืองงบประมาณโดยเปล่าประโยชน์ เพราะข้อมูลที่ใช้ในการตัดสินใจนั้นอยู่นอกเหนือจากตัว Repository
คุณ mizutani ได้เขียนไว้ใน โพสต์ถัดมา ว่า Claude ยังคงไม่ถนัดในการกำหนดจุดที่เหมาะสมสำหรับความต้องการที่ไม่ใช่เชิงฟังก์ชัน (Non-functional requirements) และยังไม่เก่งในการเสนอไอเดียว่าจะทำให้สำเร็จได้อย่างไร หากมนุษย์เป็นผู้กำหนดทิศทาง วางแนวทาง และตั้งเกณฑ์มาตรฐานไว้ให้ มันก็จะสามารถทำตามได้ในระดับหนึ่ง แต่ปัญหาคือการเตรียมข้อมูลไปถึงจุดนั้นยังคงเป็นเรื่องยาก ซึ่ง "จุดที่เหมาะสม" ในที่นี้ก็คือจุดตัดสินใจของ Trade-off นั่นเอง
ในด้านความปลอดภัยก็มีโครงสร้างเดียวกัน การจะบังคับใช้การยืนยันตัวตนแบบหลายปัจจัย (MFA) สำหรับหน้าจอจัดการภายในองค์กร การเก็บรักษาบันทึกการใช้งานไว้นานกี่ปี หรือการเลือกวางเซิร์ฟเวอร์เก็บข้อมูลส่วนบุคคลไว้ในประเทศใดนั้น ล้วนขึ้นอยู่กับกฎระเบียบของอุตสาหกรรม สัญญาที่มีกับคู่ค้า และความรับผิดชอบในการชี้แจงหากเกิดเหตุการณ์ไม่คาดฝันขึ้น นี่ไม่ใช่ปัญหาเรื่องวิธีการเขียนโค้ด แต่เป็นปัญหาเรื่องการตัดสินใจว่าองค์กรจะยอมรับความเสี่ยงได้มากน้อยเพียงใด ซึ่งอำนาจในการตัดสินใจและความรับผิดชอบนั้นยังคงอยู่ที่ตัวบุคคล
ข้อบกพร่องที่ข้ามผ่านกระแสข้อมูลและบริบทมักถูกมองข้ามได้ง่าย
การสำรวจของ Veracode ที่กล่าวถึงในหัวข้อก่อนหน้านี้ยังมีข้อมูลต่อเนื่อง โดยอัตราการผ่านเกณฑ์ที่เคยสูงกว่า 80% ในด้าน SQL Injection และการเข้ารหัสลับ (Encryption) นั้น กลับลดลงเหลือเพียง 15% สำหรับ Cross-Site Scripting (XSS) และ 12% สำหรับ Log Injection รายงานระบุว่าสาเหตุที่ทั้งสองหัวข้อนี้มีอัตราการผ่านต่ำ เป็นเพราะการป้องกันขึ้นอยู่กับความเข้าใจในกระแสข้อมูล (Data Flow), บริบทของแอปพลิเคชัน และวิธีการที่ข้อมูลจากผู้ใช้เคลื่อนที่ผ่านระบบ แม้ว่าในการอัปเดตข้อมูลในเวลาต่อมา อัตราการผ่านเฉลี่ยจะเพิ่มขึ้นเป็น 62% แต่ผลลัพธ์ของ Log Injection ยังคงอยู่ในระดับเดิมแทบไม่เปลี่ยนแปลง (รายงานจาก CybrSec Media)
การป้องกัน XSS จำเป็นต้องติดตามว่าสตริงที่ได้รับจากฟังก์ชันหนึ่งถูกจัดเก็บไว้ที่ใด แสดงผลบนหน้าจอไหน และในรูปแบบใด เช่นเดียวกับ Log Injection ที่ไม่สามารถตรวจพบได้หากไม่ติดตามว่าข้อมูลอินพุตผ่านกี่ฟังก์ชันก่อนที่จะถูกบันทึกลงใน Log ทั้งสองกรณีนี้เป็นช่องโหว่ที่ไม่สามารถป้องกันได้เพียงแค่การเขียนโค้ดในไฟล์ที่กำลังทำอยู่ให้ถูกต้องเท่านั้น
การแยกส่วนผู้เช่า (Tenant Isolation) และการอนุญาตสิทธิ์ (Authorization) ก็มีลักษณะเดียวกัน การเขียน API หนึ่งตัวให้ถูกต้อง กับการทำให้ API ทั้งหมดตัดสินใจเลือก Tenant จากเซสชันนั้นเป็นคนละประเด็นกัน LLM สามารถเขียนโค้ดที่สมเหตุสมผลได้ภายในขอบเขตของไฟล์ที่ได้รับมา แต่หากไม่ได้รับคำสั่งให้ตรวจสอบ มันจะไม่ยืนยันว่าข้อตกลงเดียวกันนั้นถูกรักษาไว้ทั่วทั้ง Repository หรือไม่ กรณีศึกษาที่เคยกล่าวถึงใน ตัวอย่างความล้มเหลวของ Vibe Coding ซึ่งเป็นการเปิดเผยข้อมูลโดยไม่ได้ตั้งค่าการควบคุมการเข้าถึงระดับแถว (Row-level Access Control) ในฐานข้อมูล ก็เกิดขึ้นในแอปพลิเคชันที่ฟังก์ชันการทำงานต่างๆ สามารถใช้งานได้ตามปกติ
ไม่สามารถมองเห็นปัญหาได้จากข้อมูลขนาดเล็ก
ข้อบกพร่องด้านประสิทธิภาพและต้นทุนมักไม่ปรากฏให้เห็นในปริมาณข้อมูลที่ใช้ระหว่างการพัฒนา งานวิจัยที่ชื่อว่า EffiBench ได้เปรียบเทียบเวลาในการประมวลผลของโค้ดที่เขียนโดย LLM จำนวน 42 รุ่น กับคำตอบที่เขียนโดยมนุษย์ซึ่งมีประสิทธิภาพสูงสุดในโจทย์ของ LeetCode ผลปรากฏว่า แม้แต่โมเดลเชิงพาณิชย์ชั้นนำในขณะนั้น ก็ยังมีเวลาประมวลผลเฉลี่ยช้ากว่าถึง 3.12 เท่า และในโจทย์ที่ห่างกันมากที่สุดนั้นช้ากว่าถึง 13.89 เท่า ทั้งหมดที่นำมาเปรียบเทียบล้วนเป็นคำตอบที่ผ่านการทดสอบแล้ว โค้ดที่ถูกต้องแต่ทำงานช้าจะสามารถผ่านการทดสอบฟังก์ชันไปได้
ในการพัฒนาที่ทำอยู่ก็เกิดเหตุการณ์คล้ายกัน API ของ Supabase (PostgREST) จะจำกัดจำนวนแถวที่ส่งคืนในการเรียกหนึ่งครั้งไว้ที่ 1,000 แถวโดยค่าเริ่มต้น และจะตัดส่วนที่เกินออกโดยไม่มีการแจ้งเตือนข้อผิดพลาด กระบวนการดึงรายการมาสรุปผลนั้นทำงานได้อย่างถูกต้องในขณะที่จำนวนข้อมูลยังมีน้อย แต่เมื่อนำไปใช้จริงและจำนวนแถวเกิน 1,000 แถว ระบบก็เริ่มตัดข้อมูลบางส่วนออกไปอย่างเงียบๆ สิ่งที่ทำให้รู้ตัวคือรายงานจากผู้ใช้งานว่ายอดเงินรวมไม่ถูกต้อง ไม่ว่าโค้ดจะเขียนโดยมนุษย์หรือ AI หากไม่มีใครกำหนดสมมติฐานเรื่องจำนวนข้อมูลที่เพิ่มขึ้น การทดสอบก็จะยังคงแสดงผลเป็นสีเขียวเสมอ
เมื่อมองในระดับทีมหรือองค์กร แนวโน้มก็เป็นไปในทิศทางเดียวกัน ผลสำรวจ DORA ของ Google รายงานว่า ในขณะที่การนำ AI มาใช้มีความสัมพันธ์เชิงบวกกับปริมาณงานที่พัฒนาได้ (Development Throughput) แต่กลับยังคงมีความสัมพันธ์เชิงลบกับเสถียรภาพในการนำไปใช้งานจริง (Deployment Stability) ซึ่งอธิบายได้ว่า หากปริมาณการเปลี่ยนแปลงเพิ่มขึ้นโดยไม่มีการทดสอบอัตโนมัติ การจัดการเวอร์ชันที่ครบถ้วน และกลไกการรับข้อมูลป้อนกลับที่รวดเร็ว ระบบก็จะขาดเสถียรภาพ (ประกาศจาก Google Cloud)
มนุษย์ควรตัดสินใจอย่างไรเพื่อให้ LLM ปฏิบัติตาม Non-functional Requirements?

สิ่งที่มนุษย์ต้องตัดสินใจมี 3 ประการ ได้แก่ ค่าตัวเลขที่เป็นจุดลงตัว ข้อห้ามต่างๆ วิธีการตรวจสอบ และผู้ที่จะเป็นคนบังคับใช้การตัดสินใจนั้น เมื่อกำหนดสิ่งเหล่านี้ได้แล้ว งานส่วนใหญ่ในการนำไปใช้งานจริงก็สามารถปล่อยให้เป็นหน้าที่ของ LLM ได้เลย
กำหนดจุดที่ยอมรับได้ด้วยตัวเลขและข้อห้าม
คำสั่งอย่าง "คำนึงถึงความปลอดภัยด้วย" หรือ "ให้ความสำคัญกับประสิทธิภาพด้วย" แทบจะไม่มีข้อมูลที่เป็นประโยชน์สำหรับ LLM เลย เพราะไม่ได้ระบุว่ามาตรฐานระดับไหนถึงจะถือว่าผ่าน สิ่งที่คุณควรให้คือตัวเลขที่เป็นผลลัพธ์จากการตัดสินใจของมนุษย์ และข้อห้ามที่ไม่อนุญาตให้มีข้อยกเว้น
ตัวอย่างเช่น ให้เขียนดังนี้:
- API รายการต้องตอบสนองภายใน 500 มิลลิวินาทีที่ p95 โดยจำกัดจำนวนรายการต่อครั้งไว้ที่ 100 รายการ และให้ใช้การแบ่งหน้า (Pagination)
- Tenant ต้องมาจาก Session เท่านั้น ห้ามใช้ Tenant ID ที่รับมาจากเนื้อหาของ Request หรือ Query
- การลองใหม่ (Retry) สำหรับ External API ให้ทำได้สูงสุด 3 ครั้งต่อ 1 Request ส่วน API ของ LLM ให้กำหนดขีดจำกัดของ Token ที่ใช้ใน 1 กระบวนการ
- หากไฟล์ใดมีเกิน 500 บรรทัด ให้เสนอการแบ่งไฟล์ก่อนที่จะเพิ่มฟังก์ชันใหม่เข้าไป
ตัวเลขเหล่านี้ไม่จำเป็นต้องถูกต้องตั้งแต่แรก สิ่งสำคัญคือการที่สิ่งที่มนุษย์ได้ตัดสินใจโดยยอมรับการแลกเปลี่ยน (Trade-off) แล้วนั้น ถูกบันทึกไว้เป็นลายลักษณ์อักษร การเพิ่มเหตุผลที่ตัดสินใจไว้สัก 1 บรรทัด จะช่วยเป็นเบาะแสให้ LLM ตัดสินใจในสถานการณ์ที่ไม่คาดคิด และยังมีประโยชน์เมื่อต้องทบทวนตัวเลขเหล่านั้นในอีกครึ่งปีข้างหน้า เพื่อป้องกันไม่ให้ตกหล่นหัวข้อสำคัญ คุณควรใช้ ISO/IEC 25010 หรือรายการระดับความต้องการที่ไม่ใช่ฟังก์ชัน (Non-functional Requirements Grade) มาใช้เป็นตารางสำหรับตรวจสอบ
ทำให้เกณฑ์การตัดสินอยู่ในรูปแบบที่ตรวจสอบได้
เกณฑ์ที่กำหนดไว้หากเป็นเพียงข้อความเฉยๆ LLM ก็จะรายงานผลด้วยตัวเองเพียงว่า "น่าจะทำตามได้แล้ว" แล้วจบไป แต่หากเปลี่ยนให้อยู่ในรูปแบบที่ส่งผลลัพธ์ผ่าน/ไม่ผ่านออกมาโดยอัตโนมัติ LLM ก็จะสามารถแก้ไขข้อกำหนดที่ไม่ใช่หน้าที่การทำงาน (Non-functional requirements) ได้ในการโต้ตอบรอบเดียวกับที่แก้ไขข้อกำหนดหน้าที่การทำงาน (Functional requirements)
แนวคิดนี้มีชื่อเรียก ผู้เขียนหนังสือ 『Evolutionary Architecture』 (สถาปัตยกรรมเชิงวิวัฒนาการ) ได้เรียกกลไกที่ใช้ประเมินคุณลักษณะของสถาปัตยกรรมอย่างเป็นกลางว่า "Architectural Fitness Function" (Thoughtworks Technology Radar) ซึ่งเป็นแนวคิดที่กว้างขวาง ครอบคลุมไปถึงเมทริกซ์และการตรวจสอบติดตาม ไม่ใช่แค่เพียงการทดสอบหน่วย (Unit test) เท่านั้น
ขอยกตัวอย่างแยกตามข้อกำหนดที่ไม่ใช่หน้าที่การทำงาน ดังนี้: หากเป็นด้านประสิทธิภาพ ให้ทำการทดสอบโดยเรียก API ที่เป็นตัวแทนด้วยปริมาณข้อมูลที่ใกล้เคียงกับสถานการณ์จริง และให้ผลลัพธ์เป็น "ไม่ผ่าน" หากค่า p95 เกินเกณฑ์ที่กำหนด หากเป็นด้านการอนุญาตสิทธิ์ ให้ทำการทดสอบโดยใช้ผู้ใช้จากอีกเทนเนนต์หนึ่งเรียก API ทั้งหมด และให้ผลลัพธ์เป็น "ไม่ผ่าน" หากมีข้อมูลส่งกลับมาแม้แต่รายการเดียว หากเป็นด้านความสามารถในการบำรุงรักษา ให้ใช้สคริปต์ตรวจสอบจำนวนบรรทัดของไฟล์หรือทิศทางการอ้างอิง หากเป็นด้านต้นทุน ให้ทำการทดสอบโดยนับจำนวนครั้งที่เรียก API ภายนอกในการประมวลผลหนึ่งครั้ง และหากเป็นด้านความปลอดภัย ให้รวมการวิเคราะห์แบบคงที่ (SAST) และการตรวจสอบช่องโหว่ของไลบรารีที่ใช้งานอยู่เข้าไว้ใน CI
ทั้งหมดนี้ หากสร้างไว้ตั้งแต่แรก LLM ก็จะสามารถสั่งรันและอ่านผลลัพธ์ได้ด้วยตัวเอง หากมีหัวข้อใดที่คุณต้องคอยชี้แนะซ้ำๆ ในการรีวิว หัวข้อนั้นคือตัวเลือกแรกที่ควรเปลี่ยนให้เป็นกลไกการตัดสินผลลัพธ์ครับ
แยก "คำสั่งให้อ่าน" ออกจาก "กลไกบังคับใช้"
แม้จะสร้างกลไกการตัดสินใจขึ้นมา แต่หากปล่อยให้ LLM เป็นผู้ตัดสินใจว่าจะรันกลไกนั้นหรือไม่ ก็จะมีบางครั้งที่มันไม่ยอมรัน Best Practices ของ Claude Code ได้แบ่งคำสั่งออกเป็น 2 ประเภท ได้แก่ คำสั่งที่โมเดลจะอ่านและตัดสินใจว่าจะปฏิบัติตามหรือไม่ เช่น Prompt, CLAUDE.md และ Skill กับกลไกที่ทำงานทุกครั้งโดยไม่ขึ้นอยู่กับการตัดสินใจของโมเดล เช่น hook, deny rule และ CI โดยแนะนำว่าคำสั่งประเภทแรกนั้น "มักจะปฏิบัติตาม" แต่ไม่มีการรับประกัน ดังนั้นกฎที่ไม่อนุญาตให้มีข้อยกเว้นควรย้ายไปไว้ในประเภทหลัง
เกณฑ์ที่ไม่อนุญาตให้มีข้อยกเว้นควรวางไว้ในกลไกที่บังคับใช้ ส่วนแนวทางที่การตัดสินใจอาจเปลี่ยนไปตามสถานการณ์ควรวางไว้ในคำสั่งที่ให้อ่าน
| ตำแหน่งที่วาง | ตัวอย่างเกณฑ์ที่เหมาะสม |
|---|---|
| CLAUDE.md・Skill (คำสั่งที่ให้อ่าน) | นโยบายการตั้งชื่อและการแบ่งส่วน, วิธีการเขียน Log, สถานการณ์ที่อนุญาตให้ใช้ Cache |
| hook・deny rule (บังคับใช้) | ห้ามอ่านไฟล์ข้อมูลลับ, ห้ามแก้ไขไดเรกทอรีของผลลัพธ์ที่สร้างขึ้น, ให้รันการจัดรูปแบบทุกครั้งที่มีการแก้ไข |
| CI・Branch Protection (บังคับใช้) | การตรวจสอบ Type, การทดสอบการอนุญาต (Authorization), การทดสอบประสิทธิภาพ, การตรวจสอบช่องโหว่ของ Dependency, ไม่สามารถ Merge ได้หากไม่มีการอนุมัติจากคน |
ในสภาพแวดล้อมการพัฒนาบนเครื่องส่วนตัว การอ่านไฟล์ env, การเริ่มเซิร์ฟเวอร์สำหรับพัฒนา, และการสลับ Repository ที่แก้ไข ก็ไม่ได้เพียงแค่เขียนไว้ใน CLAUDE.md เท่านั้น แต่ยังใช้ hook ในการหยุดการทำงานด้วย ทั้งหมดนี้เป็นกฎที่หากเกิดความผิดพลาดเพียงครั้งเดียวจะส่งผลกระทบสูง และการที่ "ส่วนใหญ่ปฏิบัติตาม" นั้นไม่เพียงพอ ในทางกลับกัน หากเพิ่มกฎที่บังคับใช้มากเกินไป ก็จะเกิดปัญหาการตรวจจับที่ผิดพลาด (False Positive) และภาระในการบำรุงรักษาที่เพิ่มขึ้น เอกสารอย่างเป็นทางการยังระบุด้วยว่าควรเก็บกฎที่บังคับใช้ไว้ให้น้อย และปล่อยให้เป็นหน้าที่การตัดสินใจของ LLM ในเรื่องที่เป็นความชอบส่วนบุคคล สำหรับวิธีการตั้งค่า hook สามารถดูได้ที่ คู่มือการนำ Claude Code ไปใช้ในทีม
พิจารณาตามมุมมอง: ขอบเขตที่มอบหมายให้ LLM และขอบเขตที่มนุษย์ต้องรับผิดชอบ

เมื่อแบ่งความต้องการเชิงคุณภาพ (Non-functional Requirements) ออกเป็น 5 ด้าน สิ่งที่ LLM สามารถรับหน้าที่ไปทำได้ง่ายคือ "การเขียนโปรแกรมให้เป็นไปตามเกณฑ์ที่กำหนด" ส่วนสิ่งที่มนุษย์ต้องเป็นผู้กำหนดคือ "การตั้งเกณฑ์" และ "การตัดสินใจในกรณีข้อยกเว้นที่อยู่นอกเหนือเกณฑ์"
| ด้าน | งานที่ LLM รับหน้าที่ได้ง่าย | สิ่งที่มนุษย์ต้องกำหนด | ตัวอย่างกลไกการตรวจสอบ |
|---|---|---|---|
| ความปลอดภัย (Security) | การเขียนโค้ดตรวจสอบอินพุตหรือการทำ Escape, การใช้ไลบรารีเข้ารหัสมาตรฐาน | การจำแนกประเภทข้อมูลที่ต้องปกป้อง, รูปแบบการอนุญาต (Authorization Model), ความเสี่ยงที่ยอมรับได้ | การทดสอบการอนุญาตใน Tenant อื่น, SAST, การตรวจสอบช่องโหว่ของ Dependency |
| ประสิทธิภาพ (Performance) | การเพิ่ม Index, การแก้ไขปัญหา N+1 Query, การเขียนโค้ดทำ Pagination | เป้าหมายเวลาในการตอบสนอง, ปริมาณข้อมูลและจำนวนการเข้าถึงที่คาดการณ์ | การทดสอบโหลดด้วยปริมาณข้อมูลใกล้เคียงกับระบบจริง, การตรวจสอบค่า p95 |
| ต้นทุน (Cost) | การเขียนโค้ดเพื่อทำ Cache หรือการรวมกลุ่มการประมวลผล | งบประมาณรายเดือน, ขีดจำกัดต่อหนึ่งคำขอ (Request) | การทดสอบจำนวนครั้งในการเรียกใช้ External API, การแจ้งเตือนเมื่อยอดใช้งานเกินกำหนด |
| ความสามารถในการบำรุงรักษา (Maintainability) | การแยกส่วนประกอบ (Refactoring), การทำให้ชื่อเรียกเป็นมาตรฐาน, การเพิ่ม Test | วิธีการแบ่ง Layer, ทิศทางของ Dependency ที่อนุญาต, ความซับซ้อนที่ยอมรับได้ | การตรวจสอบจำนวนบรรทัดและทิศทางของ Dependency, การตรวจสอบ Type |
| ความพร้อมใช้งานและการดำเนินงาน (Availability/Operations) | การเขียนโค้ดจัดการ Retry หรือ Timeout, การส่ง Log | ระยะเวลาที่ระบบหยุดทำงานได้, เป้าหมายในการกู้คืนระบบ, ผู้รับผิดชอบเมื่อเกิดเหตุขัดข้อง | การทดสอบโดยจำลองเหตุการณ์ขัดข้อง, การเฝ้าระวังและการแจ้งเตือน |
หากคอลัมน์ขวาสุดสองคอลัมน์ในตารางถูกกำหนดไว้ชัดเจน งานในคอลัมน์ซ้ายมือก็สามารถให้ LLM รับหน้าที่ไปทำได้เป็นอย่างดี ในทางกลับกัน หากคอลัมน์ตรงกลางยังว่างอยู่ LLM จะกำหนดค่าที่ดูสมเหตุสมผลขึ้นมาเองเพื่อดำเนินการเขียนโค้ดต่อ ตัวอย่างเช่น หากสั่งให้ทำหน้าจอแสดงรายการโดยไม่กำหนดปริมาณข้อมูลที่คาดการณ์ไว้ ก็ไม่น่าแปลกใจหาก LLM จะเขียนโค้ดที่ดึงข้อมูลทั้งหมดมาแล้วค่อยมาคัดกรองที่ฝั่งหน้าจอ เพราะโค้ดนั้นจะทำงานได้ไม่มีปัญหาเมื่อข้อมูลมีขนาดเล็ก
คำถามที่มนุษย์ใช้ตรวจสอบในการรีวิวก็สามารถสร้างขึ้นจากตารางนี้ได้เช่นกัน เริ่มจากคำถามว่าการเปลี่ยนแปลงนี้เกี่ยวข้องกับเกณฑ์ข้อใดที่กำหนดไว้ ต่อมาคือการตรวจสอบว่าการเปลี่ยนแปลงครั้งนี้ผ่านกลไกการตัดสินเกณฑ์ดังกล่าวหรือไม่ และสุดท้ายคือ LLM ได้ตัดสินใจในสิ่งที่ไม่ได้ระบุไว้ในเกณฑ์โดยพลการหรือไม่ ซึ่งคำถามข้อสุดท้ายนี้เป็นส่วนที่ยากจะแทนที่ด้วยเครื่องจักรและเป็นสิ่งที่มนุษย์ต้องรับผิดชอบต่อไป
ความผิดพลาดที่พบบ่อยและวิธีหลีกเลี่ยง

ความผิดพลาดในการส่งมอบ "ข้อกำหนดที่ไม่ใช่หน้าที่การทำงาน" (Non-functional Requirements) ให้กับ LLM มักเกิดจากการส่งมอบโดยที่เกณฑ์ยังมีความคลุมเครือ และการเข้าใจผิดว่าการที่ผ่านการทดสอบ (Test) แล้วหมายถึงการผ่านเกณฑ์ในส่วนที่ไม่ใช่หน้าที่การทำงานนั้น
การเขียนเพียงว่า "ให้ระวังเรื่องความปลอดภัย" แล้วจบไป
การเขียนกำกับไว้ใน CLAUDE.md ว่า "ให้ระมัดระวังเรื่องความปลอดภัยให้ดี" หรือ "ให้คำนึงถึงประสิทธิภาพด้วย" แล้วคิดว่านั่นคือการสื่อสารความต้องการเชิงหน้าที่ (Non-functional requirements) ครบถ้วนแล้ว ถือเป็นความผิดพลาดที่พบบ่อยที่สุด LLM จะไม่เข้าใจว่าต้องทำถึงระดับไหนจึงจะถือว่าผ่านเกณฑ์ ผลที่ตามมาคือมาตรการที่มองเห็นได้ชัดเจน (เช่น การทำ Input Escaping หรือการจัดการ Exception) อาจเพิ่มขึ้น แต่ส่วนที่มองเห็นได้ยากอย่างความสอดคล้องของการอนุญาต (Authorization consistency) หรือการเตรียมพร้อมรับมือกับปริมาณข้อมูลจะยังคงเป็นปัญหาอยู่
ตัวเลขจาก Veracode ที่กล่าวถึงก่อนหน้านี้ ก็เป็นการวัดผลภายใต้เงื่อนไขที่ไม่ได้มีการระบุคำสั่งเรื่องความปลอดภัยใดๆ ไว้เลย หากไม่ระบุอะไรเลย เราต้องเผื่อใจไว้ว่าจะมีช่องโหว่ที่ทราบกันดีอยู่แล้วปะปนมาด้วยประมาณ 40% การเพิ่มประโยคที่เป็นนามธรรมเข้าไปเพียงประโยคเดียว ไม่ได้การันตีว่าจะป้องกันข้อบกพร่องประเภทที่ต้องติดตามการไหลของข้อมูลจึงจะพบได้
วิธีหลีกเลี่ยงคือการเปลี่ยนจาก "คำเตือน" ให้เป็น "เกณฑ์มาตรฐาน" โดยเขียนให้เป็นประโยคที่มนุษย์สามารถอ่านและตัดสินได้ว่าทำตามหรือไม่ เช่น "ให้กำหนด Tenant จาก Session" หรือ "ค่าที่จะแสดงบนหน้าจอต้องผ่านการทำ Template Escaping เสมอ" จากนั้นให้เตรียมการทดสอบหรือการตรวจสอบเพื่อประเมินประโยคเหล่านั้นไว้ 1 รายการ หากการเพิ่มความเข้มงวดด้วยคำว่า "สำคัญ" หรือ "ต้องทำ" ลงในบรรทัดหนึ่งของ CLAUDE.md แล้วยังไม่สามารถทำให้ปฏิบัติตามได้ เอกสารอย่างเป็นทางการก็ได้ระบุไว้ว่า นั่นคือสัญญาณที่บอกว่าควรเปลี่ยนไปใช้กลไกบังคับแทน
การถือว่าการผ่านการทดสอบคือการผ่านเกณฑ์ Non-functional
เมื่อ LLM รายงานว่า "ผ่านการทดสอบทั้งหมดแล้ว" เรามักจะรู้สึกว่าการเปลี่ยนแปลงทั้งหมดนั้นถูกต้อง แต่การทดสอบเหล่านั้นส่วนใหญ่เป็นเพียงการทดสอบความต้องการเชิงฟังก์ชัน (functional requirements) เท่านั้น โค้ดที่ทำงานได้ถูกต้องแต่ช้า หรือโค้ดที่ทำงานได้ถูกต้องแต่กลับดึงข้อมูลของเทนแนนท์อื่นออกมาได้ ก็สามารถผ่านการทดสอบฟังก์ชันได้เช่นกัน
ความเชื่อมั่นที่ผิดพลาดนี้ยังส่งผลให้มนุษย์มีความมั่นใจในตัวเองสูงเกินไปอีกด้วย งานวิจัยจากมหาวิทยาลัยสแตนฟอร์ดพบว่า ผู้เข้าร่วมที่ใช้ AI ช่วยแก้โจทย์มีแนวโน้มที่จะเขียนโค้ดที่ไม่ปลอดภัยมากกว่าผู้ที่ไม่ได้ใช้ และยังมีความมั่นใจสูงว่าโค้ดของตนนั้นปลอดภัย (Perry และคณะ "Do Users Write More Insecure Code with AI Assistants?") โค้ดที่ AI เขียนขึ้นมักจะดู "น่าเชื่อถือ" ในสายตาของผู้อ่าน
วิธีหลีกเลี่ยงปัญหานี้มี 2 ประการ ประการแรกคือ การให้ AI ระบุ "เกณฑ์การตัดสินที่ใช้ทดสอบ" มาในรายงานความสำเร็จด้วย หากให้ AI แนบคำสั่งที่ใช้รันและผลลัพธ์ที่ได้มาด้วย เราจะสังเกตเห็นได้ทันทีว่าการทดสอบแบบไม่ใช่เชิงฟังก์ชัน (non-functional tests) ยังไม่ได้ถูกดำเนินการ ประการที่สองคือ การนำการทดสอบแบบไม่ใช่เชิงฟังก์ชันไปรวมไว้ใน CI เพื่อให้แน่ใจว่าหากไม่ผ่านเกณฑ์จะไม่สามารถรวมโค้ด (merge) ได้ วิธีนี้จะช่วยให้มนุษย์ไม่ต้องคอยตัดสินใจทุกครั้งว่าควรเชื่อรายงานของ AI หรือไม่ สำหรับภาพรวมที่ครอบคลุมถึงการออกแบบสิทธิ์ การรีวิว และการหยุดการทำงาน สามารถดูได้ที่ รายการตรวจสอบการดำเนินงานการ์ดเรลของ AI Agent
คำถามที่พบบ่อยเกี่ยวกับ Non-functional Requirements ในการเขียนโค้ดด้วย AI

ตอบ 3 คำถามที่พบบ่อยเมื่อมอบหมายการเขียนโค้ด (Implementation) ให้ AI
Q1: มนุษย์จำเป็นต้องตรวจสอบความปลอดภัยของโค้ดที่ AI เขียนทั้งหมดหรือไม่?
ไม่จำเป็นครับ คุณไม่จำเป็นต้องตรวจสอบทุกส่วนด้วยความละเอียดเท่ากัน ในส่วนที่สามารถป้องกันได้ด้วย Type (เช่น การประกอบคำสั่ง SQL, การใช้งานไลบรารีเข้ารหัส) ให้ปล่อยเป็นหน้าที่ของ SAST และการตรวจสอบ Dependency ส่วนตัวคุณให้โฟกัสไปที่จุดที่มีการตัดสินใจเรื่อง Tenant หรือสิทธิ์การเข้าถึง และจุดที่มีการแสดงผลข้อมูลจากผู้ใช้งานบนหน้าจอหรือใน Log เท่านั้นครับ
Q2: สามารถให้ AI เขียนนิยามของ Non-functional Requirements เองได้หรือไม่?
มันมีประโยชน์ในฐานะร่างแรก หากคุณระบุประเภทของระบบ ขนาดของผู้ใช้งาน และประเภทของข้อมูลที่จะจัดการ AI จะช่วยลิสต์มุมมองที่ควรตรวจสอบและตัวเลขสมมติให้ตามหัวข้อต่างๆ เช่น เกรดของความต้องการที่ไม่ใช่หน้าที่หลัก (Non-functional Requirements) บางครั้งมันยังช่วยชี้ให้เห็นมุมมองที่เราอาจนึกไม่ถึง เช่น ปริมาณข้อมูลที่จะย้ายหรือจำนวนรุ่นของข้อมูลสำรอง (Backup)
อย่างไรก็ตาม การตัดสินใจว่าจะใช้ตัวเลขเหล่านั้นเลยหรือไม่นั้นเป็นอีกเรื่องหนึ่ง ตัวอย่างเช่น หากกำหนดเป้าหมายระยะเวลาการกู้คืน (Recovery Time Objective) ไว้ที่ "ภายใน 1 ชั่วโมง" หรือ "ภายในวันทำการถัดไป" โครงสร้างที่จำเป็นและค่าใช้จ่ายในการดำเนินงานจะแตกต่างกันอย่างมาก การจะตัดสินว่าแบบไหนถูกต้องนั้น จำเป็นต้องเปรียบเทียบระหว่างสิ่งที่ต้องสูญเสียหากระบบหยุดทำงานกับงบประมาณที่สามารถจ่ายได้ ดังนั้น ควรใช้ข้อเสนอของ AI เพื่อตรวจสอบความครบถ้วน และให้ผู้รับผิดชอบด้านธุรกิจและการดำเนินงานซึ่งสามารถอธิบายการเปรียบเทียบดังกล่าวเป็นผู้กำหนดตัวเลขที่แน่นอนครับ
Q3: หากโมเดลมีการอัปเดตใหม่ จะสามารถมอบหมายงานด้าน Non-functional Requirements ให้ AI ทั้งหมดได้หรือไม่?
ในส่วนของการนำไปใช้งาน ขอบเขตที่สามารถมอบหมายให้ทำได้นั้นน่าจะกว้างขึ้นเรื่อยๆ แม้แต่ในการอัปเดตล่าสุดของ Veracode อัตราการผ่านโดยเฉลี่ยก็เพิ่มสูงขึ้น และมีการปรับปรุงแก้ไขข้อบกพร่องประเภทที่สามารถป้องกันได้ด้วยการกำหนด "Type" อย่างต่อเนื่อง ในทางกลับกัน จุดสมดุลว่าจะต้องรวดเร็วแค่ไหน ราคาถูกเพียงใด และต้องปกป้องถึงระดับใดนั้น ไม่ได้ถูกกำหนดโดยประสิทธิภาพของโมเดล แต่ถูกกำหนดโดยเงื่อนไขทางธุรกิจ ดังนั้นแม้จะมีการเปลี่ยนโมเดลไป แต่หน้าที่นี้ก็จะยังคงอยู่กับฝั่งคนทำงาน หากเราสามารถเก็บรักษาเกณฑ์การตัดสินไว้ในรูปแบบที่สามารถนำมาประเมินผลได้ ก็จะยังคงใช้งานได้ทันทีแม้ในวันที่เปลี่ยนไปใช้โมเดลใหม่ก็ตาม
บทสรุป

LLM ที่สามารถนำไปใช้งานตามความต้องการเชิงฟังก์ชัน (Functional Requirements) ได้ค่อนข้างดีนั้น เป็นเพราะสามารถตรวจสอบคำตอบที่ถูกต้องได้จากอินพุตและเอาต์พุต อีกทั้งยังมักจะแก้ไขได้ด้วยรูปแบบที่เป็นที่รู้จักกันดี ส่วนเหตุผลที่ความต้องการที่ไม่ใช่เชิงฟังก์ชัน (Non-functional Requirements) ยังคงต้องอาศัยมือมนุษย์อยู่นั้น เป็นเพราะคำตอบที่ถูกต้องไม่ได้อยู่ในโค้ด แต่อยู่ในเงื่อนไขทางธุรกิจและการดำเนินงาน อีกทั้งข้อบกพร่องยังอาจกระจายอยู่ข้ามกระแสข้อมูลและจะปรากฏให้เห็นก็ต่อเมื่อใช้ข้อมูลขนาดใหญ่หรือในสถานการณ์การใช้งานจริงเท่านั้น
คุณ mizutani ได้เขียนไว้ใน โพสต์ถัดมา ว่าทักษะที่จำเป็นสำหรับวิศวกรซอฟต์แวร์ในปัจจุบันนั้น "วิธีการออกแบบและนำความต้องการที่ไม่ใช่เชิงฟังก์ชันไปใช้งานให้ประสบความสำเร็จ" จะได้รับความสำคัญมากขึ้นเรื่อยๆ
สิ่งที่มนุษย์ต้องรับผิดชอบไม่ใช่การเฝ้าดูรายละเอียดการใช้งานทั้งหมด แต่คือการกำหนดจุดที่ยอมรับได้ด้วยตัวเลขและข้อห้ามต่างๆ ทำให้มันอยู่ในรูปแบบที่สามารถตัดสินได้ และบังคับใช้ส่วนที่ไม่สามารถยกเว้นได้ด้วย hook หรือ CI หากเตรียมการได้ถึงขั้นนี้ ขอบเขตที่สามารถมอบหมายให้ LLM จัดการการใช้งานความต้องการที่ไม่ใช่เชิงฟังก์ชันได้ก็จะกว้างขึ้น เช่นเดียวกับความต้องการเชิงฟังก์ชัน เริ่มต้นจากการเลือกหัวข้อที่คุณต้องชี้แนะซ้ำๆ ในการรีวิวโค้ดสัก 1 หัวข้อ แล้วเปลี่ยนให้เป็นประโยคเกณฑ์มาตรฐานและการทดสอบเพื่อตัดสิน แนวคิดในการป้องกันความล้มเหลวของ AI Agent ด้วยกลไกนั้น ได้อธิบายไว้อย่างละเอียดใน Harness Engineering คืออะไร?
บริษัทของเราให้การสนับสนุนทั้งวิธีการพัฒนาโดยใช้ Coding Agent และการสร้างเกณฑ์สำหรับความต้องการที่ไม่ใช่เชิงฟังก์ชัน หากต้องการปรึกษา สามารถติดต่อได้ที่ บริการสนับสนุน AI/DX
ผู้เขียน・ผู้ตรวจสอบ
Yusuke Ishihara
เริ่มเขียนโปรแกรมตั้งแต่อายุ 13 ปี ด้วย MSX หลังจบการศึกษาจากมหาวิทยาลัย Musashi ได้ทำงานพัฒนาระบบขนาดใหญ่ รวมถึงระบบหลักของสายการบิน และโครงสร้าง Windows Server Hosting/VPS แห่งแรกของญี่ปุ่น ร่วมก่อตั้ง Site Engine Inc. ในปี 2008 ก่อตั้ง Unimon Inc. ในปี 2010 และ Enison Inc. ในปี 2025 นำทีมพัฒนาระบบธุรกิจ การประมวลผลภาษาธรรมชาติ และแพลตฟอร์ม ปัจจุบันมุ่งเน้นการพัฒนาผลิตภัณฑ์และการส่งเสริม AI/DX โดยใช้ generative AI และ Large Language Models (LLM)


