- โรงงานซอฟต์แวร์ คือการนำลูปที่วนซ้ำระหว่างการเก็บคอนเท็กซ์ การลงมือทำ และการตรวจสอบ มาห่อด้วยฮาร์เนสเพื่อให้รันได้ในวงกว้าง โดยแบ่งเป็นโรงงานแบบสว่างที่มนุษย์เป็นผู้ตัดสิน และโรงงานแบบมืดที่แม้แต่การรีวิวโค้ดก็ปล่อยให้เครื่องจัดการ
- การสร้างโค้ด การทดสอบ และการสแกน ขยายได้แทบไม่มีต้นทุน แต่ การรีวิวและการตัดสินใจ ของมนุษย์ขยายได้ยาก จึงเกิดคอขวดที่ความเร็วในการตรวจสอบผลลัพธ์ให้ราคาถูกและเชื่อถือได้ มากกว่าปริมาณที่สร้างออกมา
- หากไม่มีคนอ่านโค้ด จะเกิด หนี้ความเข้าใจ (comprehension debt) สะสมขึ้นระหว่างขนาดของโค้ดกับความเข้าใจของมนุษย์ และแม้การทดสอบจะยังผ่านต่อเนื่อง ปัญหาด้านการบำรุงรักษาอาจโผล่มาช้า ๆ ในระบบซับซ้อนที่ใช้งานมานาน
- ควรอนุญาตให้ทำงานแบบอัตโนมัติเต็มรูปแบบเฉพาะลูปสั้น ๆ ที่มีเกณฑ์ตัดสินทันที ไม่เบี่ยงเบนไปตามเวลา และยากต่อการบิดเบือน ส่วนงานอย่างการยืนยันตัวตน การชำระเงิน หรือ public API ที่ความเสียหายและขอบเขตผลกระทบจากการตัดสินผิดสูง ควรคงการรีวิวโดยมนุษย์ไว้
- บทบาทของวิศวกรย้ายจากการเขียนการเปลี่ยนแปลงทีละรายการด้วยตนเอง ไปเป็นการออกแบบและเฝ้าดูแล ลูปภายนอก โดยต้องตรวจสอบหลักฐานจากการวินิจฉัย การลงมือแก้ไข และการทดสอบที่เอเจนต์ทำ รวมถึงรับผิดชอบต่อการอนุมัติและผลลัพธ์
จากลูปสู่โรงงานซอฟต์แวร์
- แนวคิดที่จะทำให้ซอฟต์แวร์เป็นกระบวนการผลิตที่ทำซ้ำได้และวัดผลได้ ย้อนกลับไปได้ถึงบทความ 「The economics of program production」 ที่ Bob Bemer เผยแพร่ในปี 1968
- เพราะไอเดียไม่สามารถผลิตออกมาเป็นชิ้น ๆ แบบอะไหล่รถยนต์ได้ง่าย ความพยายามลักษณะนี้ตลอดครึ่งศตวรรษที่ผ่านมาจึงมักไม่เป็นไปตามความคาดหวัง
- การเปลี่ยนแปลงในช่วง 2 ปีหลังใหญ่พอจะทำให้แนวคิดโรงงานซอฟต์แวร์แบบเดิมกลับมาน่าทบทวนอีกครั้ง แต่กับดักจากอดีตก็อาจถูกห่อให้ดูเหมือนเป็นโอกาสใหม่ได้
- โครงสร้างทั้งหมดประกอบด้วย 3 ชั้นคือ ลูป ฮาร์เนส และโรงงาน
- ลูปคือหน่วยงานขั้นต่ำที่เอเจนต์หนึ่งตัวรวบรวมคอนเท็กซ์ ลงมือทำ ตรวจสอบผลลัพธ์ และทำซ้ำจนกว่าจะเข้าเงื่อนไขสิ้นสุด
- Loop engineering คือแนวทางออกแบบระบบเล็ก ๆ ที่คอยป้อนพรอมป์ต์ให้เอเจนต์ แทนที่จะให้คนพิมพ์พรอมป์ต์ทุกครั้ง
- ฮาร์เนสประกอบด้วย sandbox ที่ลูปรันอยู่ เครื่องมือที่ใช้ได้ หน่วยความจำที่คงอยู่ระหว่างการรัน และ gate ที่ใช้ตัดสินว่างานเสร็จหรือยัง
- โมเดลที่ไม่มีฮาร์เนสอาจวนซ้ำไม่รู้จบ ดังนั้นฮาร์เนสจึงทำให้ลูปมีประโยชน์และปลอดภัย
- โรงงานซอฟต์แวร์ คือโครงสร้างที่รับรายการจากคิวงาน รันลูปที่อิงฮาร์เนสหลายตัวพร้อมกัน และส่งต่อไป production ผ่าน review gate
- มันไม่ได้เป็นเอเจนต์เดี่ยวที่ใหญ่ขึ้น แต่ใกล้เคียงกับ แผนผังองค์กรที่ประกอบด้วยลูป มากกว่า
- หน่วยงานของวิศวกรก็ย้ายจากการเปลี่ยนโค้ดรายรายการ ไปสู่ลูป ฮาร์เนส และการไหลระหว่างลูป
เวิร์กโฟลว์และคอขวดของโรงงาน
- สัญญาณจากวิสัยทัศน์ของผู้นำวิศวกรรม เจตนาของวิศวกร เหตุขัดข้อง และคำขอจากผู้ใช้ จะไหลเข้าสู่ คิวงาน เดียวกัน
- ฮาร์เนสจะเลือกรายการมาสร้างการเปลี่ยนแปลง และ CI การทดสอบ static analysis และการสแกนรูปแบบต่าง ๆ จะตรวจสอบการเปลี่ยนแปลงนั้นพร้อมกัน
- หาก review gate อนุมัติ การเปลี่ยนแปลงก็จะถูก deploy และข้อมูลจาก production monitoring จะย้อนกลับมาเป็นสัญญาณกระตุ้นงานใหม่อีกครั้ง
- การสร้าง การทดสอบ และการสแกนขยายได้ด้วยต้นทุนที่แทบมองข้ามได้ แต่ การตัดสินของมนุษย์ที่ review gate ขยายได้ยาก
- จะเร่งความเร็วการพัฒนาและความถี่ในการ deploy ได้มากแค่ไหน ขึ้นอยู่กับว่าจะจัดการคอขวดของการตัดสินนี้อย่างไร
โรงงานมืดและหนี้ความเข้าใจ
- โรงงานมืดในภาคการผลิตคือสถานที่ที่เครื่องจักรไม่ต้องใช้แสงสว่าง จึงทำงานได้ทั้งที่ปิดไฟอยู่
- FANUC ดำเนินโรงงานลักษณะนี้มาตั้งแต่ปี 2001 และ Xiaomi ก็เปิดโรงงานมืดที่มีระบบอัตโนมัติสูงในปี 2024
- ใน โรงงานซอฟต์แวร์แบบมืด มนุษย์ไม่อ่านโค้ด และ deploy การเปลี่ยนแปลงโดยอาศัยเพียงการตรวจสอบที่เครื่องซึ่งสร้างโค้ดนั้นเป็นผู้ทำ
- ความมืดในที่นี้ไม่ได้หมายถึงบรรยากาศด้านลบ แต่หมายถึงมนุษย์หายไปจากกระบวนการเขียน diff รีวิว diff และ deploy
- เมื่อเอาการรีวิวโดยมนุษย์ออกไป สิ่งรบกวนจะหายไปจนดูเหมือนว่า throughput แนวดิ่งของทีมพุ่งขึ้นอย่างรวดเร็ว
- แต่เพราะมีต้นทุนที่ซ่อนอยู่ การคงเวิร์กโฟลว์เช่นนี้ในระยะยาวจึงยากกว่าที่เห็นภายนอก
- orchestration การทำ prototype บน sandbox และการเรียกใช้เครื่องมือจะทรงพลังขึ้นเรื่อย ๆ แต่ฮาร์เนสเพียงอย่างเดียวยังไม่พอจะรักษาคุณภาพของ codebase ระยะยาว
- หนี้ความเข้าใจ คือช่องว่างระหว่างปริมาณโค้ดที่มีอยู่ กับปริมาณโค้ดที่มนุษย์เข้าใจจริง
- โรงงานมืดสะสมหนี้ความเข้าใจได้อย่างรวดเร็ว แม้การทดสอบจะยังผ่านอยู่ก็ตาม
- ต่างจากการเปลี่ยนแปลงทันทีในโค้ดส่วนเล็ก ๆ หรือโปรเจ็กต์สุดสัปดาห์ ระบบเดิมที่ซับซ้อนและพัฒนามานานกว่า 10 ปี จำเป็นต้องได้รับการบำรุงรักษาอย่างต่อเนื่องด้วยความเร็วระดับมืออาชีพ
- หากเดินโครงการอัตโนมัติไป 3~6 เดือน คุณอาจถูกโค้ดที่ไม่เคยอ่านถาโถมใส่จนรับไม่ไหว
- เมื่อ Dex Horthy รันโรงงานอัตโนมัติเต็มรูปแบบอยู่ราว 4 เดือน โดยที่มนุษย์ไม่ดูโค้ดที่สร้างขึ้นเลย การหาสาเหตุของปัญหาต้องอาศัยการดีบักด้วยมืออย่างหนักหน่วง
- ยิ่งพยายามดันการใช้โทเค็นให้สูงสุด ระดับความเข้าใจระบบของมนุษย์ก็ยิ่งค่อย ๆ ลดลงอย่างเงียบ ๆ
- ความล้มเหลวอาจไม่ได้มาในรูปแบบที่ระบบทั้งชุดพังลงทันทีทั้งที่การทดสอบยังผ่าน แต่กลับมา ช้าและเงียบ
ทำไมการตรวจสอบจึงเป็นข้อจำกัดมากกว่าการสร้าง
- back pressure คือหลักการที่ให้ความอิสระแก่ลูปได้เท่าที่เรายังตรวจสอบได้อย่างราคาถูกและเชื่อถือได้
- ช่องว่างระหว่างความสามารถในการสร้างที่เกือบไร้ขีดจำกัด กับความสนใจของมนุษย์ที่มีจำกัด คือปัญหาแกนกลาง
- หากช่วงของการตรวจสอบไม่กว้างขึ้น การเปลี่ยนแปลงก็จะกองค้าง และถ้าเพิ่มแต่ปริมาณโดยไม่มี gate ที่เชื่อถือได้ ก็จะได้ PR คุณภาพต่ำและบั๊กที่ถูกผลิตออกมา
- ประสิทธิภาพของโมเดลที่ดีขึ้นไม่ได้ทำให้ช่องว่างระหว่างการสร้างกับการตรวจสอบแคบลงโดยอัตโนมัติ
- คุณค่าของสถาปัตยกรรมที่ดีจะปรากฏชัดในช่วงหลายเดือนและหลายปี ไม่ใช่ไม่กี่วินาทีหรือนาที
- การคำนวณ cost function ที่สะอาดหรือสัญญาณประเมินผลแบบทันทีสำหรับความยอดเยี่ยมด้านสถาปัตยกรรมทำได้ยาก จึงยากจะฝึกการตัดสินใจด้านดีไซน์ที่ซับซ้อนจากตัวอย่างที่ดี
วิธีเปิดไฟกลับมา
- แม้ใน โรงงานแบบสว่าง เอเจนต์จะรับหน้าที่ลงมือทำเป็นส่วนใหญ่ แต่ในจุดที่ต้นทุนของการตัดสินพลาดสูง ก็ควรเปิดไฟและให้มนุษย์อ่านผลลัพธ์ก่อน deploy
- การตัดสินของมนุษย์ไม่ควรถูกผูกไว้แค่กับ code review ขั้นสุดท้าย แต่ควรถูกย้ายขึ้นไปอยู่ในขั้น product, design และ architecture ก่อนที่เอเจนต์จะเริ่มลูป
- ถ้าใช้เวลา 1 ชั่วโมงรีวิวแผน 200 บรรทัดล่วงหน้า ก็อาจลดการรีวิวยาว ๆ ที่ต้องไปคุ้ยโค้ดที่สร้างขึ้น 2,000 บรรทัดเพื่อหาการตัดสินใจด้านดีไซน์หลังลงมือทำแล้วได้
- ยิ่งการตัดสินมีต้นทุนสูงและส่งผลยาวนานเท่าไร มนุษย์ยิ่งควรมีส่วนร่วมก่อนลงมือทำ และแม้จะมีการรีวิวล่วงหน้าแล้ว ก็ยังควรตรวจ diff โดยตรงเมื่อจำเป็น
- ตาข่ายนิรภัยไม่ได้ประกอบด้วยเทคนิคใหม่ แต่เป็น แนวปฏิบัติด้านสถาปัตยกรรม ที่คุ้นเคย
- ใช้ type และ method signature ที่ดีเพื่อจับข้อผิดพลาดที่ compiler แทนที่จะหลุดไปถึง production
- มี test seam เพื่อยึดพฤติกรรมไว้และสังเกตการเปลี่ยนแปลงได้
- จัดวางโค้ดให้ทั้งคนและโมเดลหาโค้ดที่ต้องการได้ง่าย
- รักษา call stack ให้สั้นและอ่านง่าย
- ทำขอบเขตของ component ให้ชัด เพื่อจำกัดวงผลกระทบของการเปลี่ยนแปลง
- ใช้ dependency injection เพื่อให้เปลี่ยนองค์ประกอบแทนกันได้
- สถาปัตยกรรมเหล่านี้ยังทำหน้าที่เป็นแนวป้องกันชั้นที่สอง คอยป้องกันความผิดพลาดของเอเจนต์เขียนโค้ดอัตโนมัติด้วยวิธีที่ต้นทุนต่ำและหลอกได้ยาก
- เอเจนต์อย่าง Claude Code และ Codex ถูกฝึกด้วยการเสริมแรงกับฮาร์เนสและการใช้เครื่องมือของตัวเองก็จริง แต่ไม่ได้มอบความสามารถในการบำรุงรักษาระยะยาวมาด้วย
- ตาข่ายนิรภัยต้องอยู่นอกโมเดล และการลงทุนด้านสถาปัตยกรรมคือวิธีเพิ่มความเป็นอิสระได้อย่างปลอดภัย
- หากจับคู่กับโครงสร้างพื้นฐานที่ปลอดภัย ลูปสั้นบางประเภทที่มีความเสี่ยงต่ำก็อาจรันแบบไร้คนดูได้
- ตัวอย่างเช่น ทุกคืน GitHub Actions cron อาจแก้ anti-pattern, lint violation หรือ prop ที่ถูกทำเป็น optional โดยไม่จำเป็นได้อย่างแม่นยำเพียงหนึ่งจุด จากนั้น commit และเปิด PR เล็ก ๆ หนึ่งรายการ
- แต่ระบบยืนยันตัวตน payment engine หรือสัญญา public API ที่มีต้นทุนความล้มเหลวสูง ยังต้องให้มนุษย์ใช้ความรู้ของระบบและวิจารณญาณในการรีวิว
ลูปแบบไหนจึงมีสิทธิ์ได้ระบบอัตโนมัติ
- ลูปที่จะอัตโนมัติเต็มรูปแบบได้ ต้องพึ่งพาการตรวจสอบที่ รันได้บ่อยและมีต้นทุนต่ำ พร้อมเกณฑ์ที่ไม่ถูกหลอกได้ง่าย
- ตัวอย่างได้แก่ตัวตัดสินที่ให้ผลจริง/เท็จชัดเจน, type gate, property-based test และ review agent ที่จับคู่กับ rubric การประเมินจริง
- การตัดสินต้องออกมาทันที และต้องไม่ drift ไปตามเวลา
- งานจึงจะอัตโนมัติได้เมื่อสถานะว่าเสร็จแล้วนั้นไม่ใช่แค่มนุษย์ แต่เครื่องก็พิสูจน์ได้เช่นกัน
- ลูปสั้นตรวจสอบได้ง่ายกว่าลูปยาว
- ตาม กฎคร่าว ๆ ของ Dex เอเจนต์ทำงานได้ดีในช่วง 3~10 ขั้นตอน แต่เมื่อเกิน 20 ขั้นตอนจะเริ่มหลุดจากเส้นทาง
- ยิ่งคอนเท็กซ์สะสมมาก เอเจนต์ก็ยิ่งมีโอกาสออกนอกทาง และลูปยาว ๆ จะซ่อนข้อผิดพลาดไว้ตามมุมต่าง ๆ
- หากต้นทุนของคำตอบที่ผิดสูง และมีแต่มนุษย์เท่านั้นที่มองออก ก็ควรเปิดไฟ
- เช่น บั๊ก production ที่ละเอียดอ่อนจนการทดสอบจับไม่ได้, ขอบเขตผลกระทบที่กว้าง, หรือการตัดสินใจที่กำหนดทิศทางงานเกิน 1 ปี
- ในกรณีเช่นนี้ ความสนใจของมนุษย์คือสินค้าจริง และเป็นทรัพยากรที่แพงแต่จำเป็น
- ถ้าตั้งทุกลูปให้อยู่ในโหมดเดียวกันทั้งหมด ทั้งสองฝั่งจะล้มเหลว
- ถ้าให้มืดทั้งหมด อีกไม่กี่เดือนอาจต้องรื้อระบบทิ้ง
- ถ้าให้สว่างทั้งหมด การรีวิวจะกลายเป็นคอขวดขนาดใหญ่
- ทักษะสำคัญคือการตัดสินว่าในแต่ละลูปควรเปิดไฟตรงจุดไหน
กราฟและ state machine ที่ห่อหุ้มลูป
- งานของเอเจนต์ ไม่ว่าจะเรียกมันว่า finite-state machine หรือ conditional service call สุดท้ายก็มีแนวโน้มจะประกอบขึ้นเป็น กราฟมีทิศทาง
- แต่ละโหนดคือขั้นตอนที่ชัดเจน และเส้นเชื่อมระหว่างโหนดคือเงื่อนไขที่ชัดเจน
- โค้ดทุกชุดแสดงเป็น control-flow graph ได้อยู่แล้ว ดังนั้นตัวโครงสร้างเองจึงไม่ใช่เรื่องใหม่
- ความเป็นอิสระของเอเจนต์ถูกจำกัดไว้ในแต่ละโหนด ไม่ใช่ทั้งกราฟ
- ความพยายามแบบใหม่เคยเป็นการลบผังงานออก แล้วให้โมเดลเลือกเส้นทางเองทุกครั้งที่เรียกใช้เครื่องมือ ก่อนจะประกาศเองว่างานเสร็จแล้ว
- แต่เมื่อชนเข้ากับ codebase เก่า การพยายามกลับมายึดครอง control flow อีกครั้ง ก็เท่ากับการฟื้นกราฟแบบเดิมกลับมาล้อมรอบลูป
- งานแก้บั๊กดำเนินไปต่างกันระหว่างลูปเพียว ๆ กับกราฟ
- ในลูปเพียว ๆ จะตัดสินใจระหว่างทางทั้งหมดเองว่าจะสืบหาปัญหาอย่างไร เปลี่ยนโค้ดตรงไหน เลือกและรันทดสอบลำดับใด จะ retry อย่างไร และจะตัดสินว่าเสร็จเมื่อไร
- ในกราฟ จะนิยามเส้นทางล่วงหน้าไว้ว่าให้ทำการ reproduce บั๊กหรือขอข้อมูลเพิ่ม หา root cause แก้ไข ทดสอบ และรีวิว
- ถ้าทดสอบไม่ผ่านก็ย้อนกลับไปขั้นแก้ไข ถ้าผ่านก็ไปขั้นรีวิว และจะถือว่าเสร็จสมบูรณ์ก็ต่อเมื่อได้รับอนุมัติ
- เอเจนต์ยังคงทำงานอย่างชาญฉลาดภายในแต่ละโหนดได้ แต่ไม่สามารถออกนอกเส้นทางที่ไม่ได้รับอนุญาต
- กราฟคือรูปแบบหนึ่งของ การทำให้ back pressure มองเห็นได้
- เรายอมสละอิสระของเอเจนต์บางส่วน เพื่อแลกกับการตรวจสอบที่จำเป็นและจุดล้มเหลวที่อ่านรู้เรื่อง
- เมื่อการรันล้มเหลว เราจะระบุได้ว่าโหนดใดเป็นตัวหยุดมัน
- เช่นเดียวกับแนวทางของ 12-factor agents ระบบเอเจนต์จำนวนมากจริง ๆ แล้วใกล้เคียงกับ “โค้ดที่มีความกำหนดแน่นอนเป็นส่วนใหญ่ แล้วคั่นด้วยขั้นตอน LLM ในจุดที่เหมาะสม”
- รูปแบบเดียวกันนี้ปรากฏใน LangGraph และ LlamaIndex Workflows, กราฟเวิร์กโฟลว์แบบไฮบริดบนเอเจนต์ของ Jerry Liu และ state machine กับ actor model ที่ David Khourshid เชื่อมโยงไว้
- กราฟในที่นี้ไม่ได้หมายถึง knowledge graph แต่หมายถึง กราฟมีทิศทาง ที่กำหนดเวิร์กโฟลว์และเส้นเชื่อมแบบมีเงื่อนไขไว้ล่วงหน้า
มนุษย์เป็นเจ้าของลูปภายนอก
- มนุษย์ไม่ได้หายไปจากโรงงาน แต่ย้ายจากสายการผลิตมาอยู่ที่ ลูปภายนอก
- เอเจนต์ทำลูปภายใน ได้แก่ การสืบหาบั๊ก เขียนการวินิจฉัย ลงมือแก้ รันทดสอบ และรายงานผล
- ส่วนวิศวกรจะตัดสินว่างานนั้นแก้ปัญหาได้ถูกทางหรือไม่ ตรวจสอบการวินิจฉัยและการลงมือทำ อนุมัติการเปลี่ยนแปลง และรับผิดชอบต่อผลลัพธ์ที่ผิดพลาด
- ที่ขอบระหว่างลูปภายในกับลูปภายนอกจะมี หลักฐาน อย่าง diff การทดสอบ log และคำอธิบายสั้น ๆ ที่เชื่อมสิ่งเหล่านี้เข้าด้วยกัน
- หากมี type, test seam และ rubric การประเมินพร้อม ก็จะกำกับดูแลการรันของเอเจนต์ได้โดยไม่ต้องทำงานมือจำนวนมากในทุกการเปลี่ยนแปลง
- ตำแหน่งของวิศวกรย้ายจากการยืนบนสายการผลิตเพื่อเขียนการเปลี่ยนแปลงด้วยตนเอง ไปสู่การออกแบบสายงานและเฝ้าประตูตรวจสอบ
- โมเดลและฮาร์เนสอาจพัฒนาได้ แต่การทำให้วิจารณญาณของมนุษย์ที่ใช้ระบุปัญหาราคาแพงในระยะยาวกลายเป็นอัตโนมัตินั้นยังยาก
- สถานการณ์ที่อันตรายที่สุดคือทำให้พื้นที่ทำงานทุกส่วนมืดไปหมด จนมนุษย์ไม่รู้ว่ากำลังเกิดอะไรขึ้น หรือแม้แต่หาสวิตช์ไฟไม่เจอ
ยังไม่มีความคิดเห็น