บันทึกทั้งหมด

เครื่อง⁠มือ · เอ⁠เจน⁠ต์ AI · วิธีทำงาน

ทำไมเราถึงสร้างเครื่องมือใช้เอง

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

อ่านบทความนี้เป็นภาษา⁠อังกฤษ
โต๊ะทำงานยามค่ำคืน มีเครื่องมือชิ้นเล็กไม่กี่ชิ้นและแสงสีอำพันจากหน้าจอ

ทุกวันนี้ งานวิศวกรรมซอฟต์แวร์ส่วน⁠ใหญ่ของเรามีเอ⁠เจน⁠ต์ AI ช่วยเขียนโค้ด และมักใช้หลายตัวพร้อมกัน ตัวหนึ่งเขียน migration ฐาน⁠ข้อมูล อีกตัวเขียนเทสต์สำหรับตรวจ migration นั้น อีกตัวอ่านเอกสารของ vendor ขณะที่ข้างๆ ก็มี dev server เปิดค้างไว้

ช่วงแรก เราทำทั้งหมดนี้ผ่าน terminal หลายแท็บ งานเดินได้ แต่พอเปิดหลายงานพร้อมกันก็เริ่มตามไม่ทันว่าใครกำลังทำอะไร คล้ายครัวร้านอาหารที่ไม่มีที่เรียงใบออเดอร์ ทุกคนทำงานอยู่ อาหารทยอยออก แต่ตอบยากว่าโต๊ะไหนยังรอ

เราเลยสร้าง Helm เป็นแอปเดสก์ท็อปที่รวมงานเหล่านี้ไว้ในหน้าต่างเดียว เอ⁠เจน⁠ต์แต่ละตัวอยู่ใน pane หรือช่องทำงานของตัวเอง และเรียงให้มองเห็นพร้อมกันได้ ตอนนี้เป็นเครื่อง⁠มือที่เราใช้เขียนโค้ดทุกวัน

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

ปัญหาที่อยู่รอบเอ⁠เจน⁠ต์

เอ⁠เจน⁠ต์อย่าง Claude Code, Codex และเครื่อง⁠มืออื่นๆ ช่วยงานได้มาก ถ้าอธิบายโจทย์และให้ข้อมูลพอ งานอย่างการเขียน migration ก็ทำออกมาได้ดี แต่พอใช้หลายตัวพร้อมกัน เราพบว่าปัญหาหลายอย่างเกิดขึ้นระหว่างทาง

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

ถ้าเป็นงานที่จะส่งให้ลูกค้า เราต้องรู้รายละเอียดมากกว่านั้น

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

ภาพจำลองหนึ่ง workspace ใน Helm แต่ละ pane มีชื่อสั้นๆ ที่เรียกได้ มีตัวเลขค่า⁠ใช้⁠จ่ายของตัวเอง และออกแบบให้สถานะสีเขียวผูกกับ receipt ของงานที่ตรวจแล้ว

มองทีเดียว เห็นทั้งทีม

Helm วาง pane ทั้งหมดไว้บน rack เดียวกัน เราออกแบบให้แต่ละ pane มีบริบทการทำงานแยกกัน และให้การส่งงานข้าม pane เป็นขั้นตอนที่มองเห็นและติดตามได้

รายละเอียดเล็กๆ บางอย่างมีผลกับการใช้⁠งานมากกว่าที่คิด ช่วงแรก pane ใหม่ใช้ชื่อ engine เป็นชื่อของตัวเอง หัว pane จึงขึ้นประมาณ “Claude Code, Opus, high” อ่านแล้วรู้ว่าใช้โมเดลอะไร แต่พอจะเรียกกลับลำบาก โดยเฉพาะเวลามีหลายตัวเหมือนกัน

ลองสั่งงานว่า “Claude ตัวที่สอง ไม่ใช่ อีกตัวหนึ่ง” ดูครับ

เราเลยให้แต่ละ pane มี call-sign ตั้งแต่สร้าง เป็นคำสั้นๆ ที่พูดออก⁠เสียงได้ และพิมพ์ต่อ⁠ท้าย @ เพื่อเรียกมันได้ เช่น Atlas ดูแลงาน migration ส่วน Vega เขียนเทสต์ เวลาส่งงานต่อจึงระบุชื่อได้ตรงๆ โดยไม่ต้องอธิบายตำแหน่งบนหน้า⁠จอ

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

วิธีนี้ลดโอกาสที่ตัวนับกับสถานะงานจะไม่ตรงกัน แต่ยังต้องอาศัยข้อมูลสถานะของแต่ละ pane ที่ถูกต้องด้วย ความหมายที่เราอยากให้ชัดคือ ถ้า badge ขึ้นเลขสอง ผู้ใช้ควรหาเจอว่าเอ⁠เจน⁠ต์สองตัวไหนกำลังรออยู่

ส่ง⁠ต่องานแบบสืบย้อนได้

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

เราเลยวางกฎการส่งข้อความใน Helm โดยยึดหลักว่า ต้องตามกลับไปหาคำ⁠สั่งของคนที่เริ่มงานได้

  • pane ที่ทำงานตามคำ⁠สั่งของคน เรียก pane อื่นในทีมได้ด้วย call-sign
  • pane ที่กำลังตอบงานจากเพื่อน ส่งคำ⁠ตอบกลับไปยัง pane ที่เรียกมาได้เท่านั้น
  • ไม่ให้ pane คุยกับตัวเอง ส่วนการกระจายงานให้ทั้งทีมเป็นหน้าที่ของคนหรือ orchestrator

orchestrator ของเราชื่อ Vesper มีหนึ่งตัวต่อหนึ่ง workspace ทำหน้าที่ช่วยจัดและส่งงานภายในพื้นที่นั้น

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

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

เห็นต้นทุนระหว่างทำงาน

เราให้แต่ละ pane แสดงตัวเลขค่า⁠ใช้⁠จ่ายไว้บนหน้า⁠จอหลัก เพื่อให้ดูต้นทุนระหว่างทำงานได้ โดยไม่ต้องเปิดหน้าตั้งค่าหรือรอไปดูยอดรวมตอนสิ้นเดือน

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

การเห็นตัวเลขข้างงานทำให้เรากลับมาดูวิธีสั่งงานของตัวเองด้วย เช่น ถ้าเอ⁠เจน⁠ต์ที่หาข้อมูลใช้เงินมากกว่าตัวที่เขียนฟีเจอร์ เราจะถามต่อว่า brief กว้างเกินไปไหม ต้องอ่านเอกสารมากขนาดนั้นจริงหรือเปล่า หรือเราระบุแหล่งข้อมูลที่ต้องการให้ชัดกว่านี้ได้

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

receipt: สีเขียวต้องอธิบายได้

ถ้าต้องเลือกส่วนหนึ่งของ Helm ที่ผมให้ความสำคัญที่สุด ผมเลือก receipt ครับ

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

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

ผลแต่ละอย่างยืนยันได้เฉพาะสิ่งที่ตรวจ เทสต์ผ่านไม่ได้ครอบคลุมทุกพฤติกรรมของระบบ การตรวจความ⁠ปลอดภัยไม่พบปัญหาก็ยังมีขอบเขตตามเครื่อง⁠มือและวิธีตรวจที่ใช้ เราจึงต้องอ่านรายละเอียดใน receipt ด้วย ไม่หยุดอยู่แค่สีของสถานะ

ถ้ายังไม่มีหลักฐานรองรับ เราก็ควรเห็นว่างานส่วนนั้นยังต้องตรวจ แม้เอ⁠เจน⁠ต์จะสรุปด้วยน้ำเสียงมั่นใจแล้วก็ตาม

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

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

สิ่งที่เปลี่ยนไปในโปร⁠เจ⁠กต์

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

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

เครื่อง⁠มือช่วยให้ตามขั้นตอนเหล่านี้ได้ง่ายขึ้น แต่เรายังต้องตรวจว่างานแต่ละชิ้นผ่านอะไรมาแล้ว และมีอะไรค้างอยู่ก่อนรวมโค้ดหรือส่ง⁠มอบ

ข้อมูลที่ส่งให้ลูกค้าจึงมีมากกว่าไฟล์โค้ด เราสามารถแนบร่องรอยของงานได้ว่า เริ่มจากคำขออะไร ใครหรือเอ⁠เจน⁠ต์ตัวไหนทำ มีข้อมูลต้นทุนเท่าไร และตรวจการทำงานด้วยวิธีไหน ข้อมูลเหล่านี้ช่วยทั้งตอนรับมอบงานและตอนที่ต้องกลับมาแก้ต่อภายหลัง

ทำไมสร้างเอง ไม่ซื้อ

มีคนถามว่าการสร้างเครื่อง⁠มือใช้เองทำให้เสียโฟกัสไหม บางทีก็ใช่ครับ เพราะต้องใช้เวลาพัฒนา แก้บั๊ก และดูแลต่อเหมือนซอฟต์แวร์ชิ้นอื่น

เราเลยใช้เกณฑ์ค่อนข้างง่าย ถ้าเครื่อง⁠มือนั้นเกี่ยวข้องกับงานที่เราส่ง⁠มอบแทบทุกชิ้น และตัวเลือกที่มีอยู่ยังไม่เข้ากับวิธีทำงานมากพอ เราจะพิจารณาว่าคุ้มที่จะสร้างเองหรือไม่ สำหรับเรา Helm ผ่านเกณฑ์นี้ เช่นเดียวกับเครื่อง⁠มือเสียงและเครื่อง⁠มือจับภาพ⁠หน้า⁠จอที่ใช้ควบคู่กัน

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

การอยู่กับรายละเอียดเหล่านี้ทำให้เราใส่ใจจุดเล็กๆ ในซอฟต์แวร์มากขึ้น และความใส่ใจแบบเดียวกันก็ติดไปกับงานที่ทำให้ลูกค้าด้วย นี่เป็นอีกเหตุผลที่เรายังเลือกสร้างและใช้เครื่อง⁠มือของตัวเองครับ

กำลังสร้างระบบที่ต้องใช้⁠งานได้จริงอยู่หรือเปล่า

เล่าให้เราฟังว่ากำลังสร้างอะไร แล้วเราจะบอกตรงๆ ว่าช่วยได้หรือไม่

เริ่มโปรเจกต์