Loop Engineering - ออกแบบระบบที่พรอมป์ต์เอเจนต์แทนเรา
(addyo.substack.com)- เปลี่ยนจากวิธีที่คอยพรอมป์ต์ coding agent โดยตรงในทุกเทิร์น ไปสู่รูปแบบการทำงานที่ ออกแบบระบบที่พรอมป์ต์เอเจนต์แทนเรา
- ลูป คือ เป้าหมายแบบเรียกซ้ำ ที่เมื่อกำหนดวัตถุประสงค์แล้ว AI จะวนทำซ้ำจนกว่างานจะเสร็จ โดยประกอบด้วยองค์ประกอบราวห้าส่วน
- องค์ประกอบทั้งห้าคือ Automations, Worktrees, Skills, Plugins·connectors, Sub-agents ซึ่งปัจจุบันทั้ง Claude Code และ Codex ต่างก็มีครบทั้งห้า
- องค์ประกอบที่หกคือ หน่วยความจำ ซึ่งอาจเป็นไฟล์ markdown หรือบอร์ด Linear ที่เก็บสถานะไว้นอกบทสนทนาเดียว เพื่อชดเชยข้อจำกัดของโมเดลที่ลืมทุกครั้งเมื่อเริ่มรันใหม่
- ทั้งหมดยังอยู่ในช่วงเริ่มต้น และต้องระวัง ต้นทุนโทเค็น ให้มาก การตรวจสอบและความเข้าใจยังคงเป็นหน้าที่ของมนุษย์ (build the loop, stay the engineer)
ความหมายของ Loop Engineering และที่มาของแนวคิด
- Loop engineering คือการ แทนที่คนที่พรอมป์ต์เอเจนต์ด้วยระบบที่เราสร้างขึ้นเอง โดยเราเป็นผู้ออกแบบระบบที่ทำหน้าที่นั้นแทน
- ลูปคือ เป้าหมายแบบเรียกซ้ำ (recursive goal) ที่เมื่อกำหนดวัตถุประสงค์แล้ว AI จะวนไปเรื่อย ๆ จนกว่างานจะเสร็จ
- นี่อาจเป็นรูปแบบการทำงานแห่งอนาคตกับ coding agent แต่ยังอยู่ในระยะเริ่มต้น และต้องระวัง ต้นทุนโทเค็น อย่างมาก (รูปแบบการใช้งานจะแตกต่างกันมากตามว่าเป็นคนที่ token rich หรือ token poor)
- คำพูดที่ถูกอ้างถึง
- Peter Steinberger: "เลิกพรอมป์ต์ coding agent ตรง ๆ แล้วมา ออกแบบลูป ที่พรอมป์ต์เอเจนต์แทน"
- Boris Cherny (หัวหน้าฝ่าย Claude Code ของ Anthropic): "ตอนนี้ผมไม่ได้พรอมป์ต์ Claude โดยตรงแล้ว แต่รัน ลูปที่พรอมป์ต์ Claude และกำหนดว่าจะให้ทำอะไร งานของผมคือการเขียนลูป"
- ตลอดราว 2 ปีที่ผ่านมา แนวทางคือให้พรอมป์ต์ที่ดีและคอนเท็กซ์ที่มากพอ แล้วคุยกันทีละเทิร์นในลักษณะ ที่เรายังถือเอเจนต์ไว้ในมือเหมือนเครื่องมือโดยตรง แต่วิธีนั้นกำลังจะสิ้นสุดลง
- ตอนนี้คือการสร้าง ระบบเล็ก ๆ ที่คอยค้นหางาน กระจายงาน ตรวจสอบ บันทึกสิ่งที่เสร็จแล้ว และตัดสินใจว่างานถัดไปคืออะไร จากนั้นให้ระบบนั้นไปสะกิดเอเจนต์อีกที
- แนวคิดนี้อยู่เหนือบทความก่อนหน้าเรื่อง agent harness engineering (สภาพแวดล้อมที่เอเจนต์หนึ่งตัวทำงานอยู่) และ factory model (ระบบสำหรับสร้างซอฟต์แวร์)
- เป็น harness ที่รันด้วยตัวจับเวลา สร้าง helper ขนาดเล็ก และคอยป้อนงานให้ตัวเอง
- เรื่องนี้ไม่ใช่ปัญหาของเครื่องมืออีกต่อไป — เมื่อ 1 ปีก่อน ถ้าอยากได้ลูปต้องเขียนและดูแล bash ก้อนใหญ่เอง แต่ตอนนี้องค์ประกอบต่าง ๆ ถูกฝังมาในผลิตภัณฑ์แล้ว
- รายการของ Steinberger แทบตรงกับแอป Codex แบบเป๊ะ และแทบเหมือนกับ Claude Code เช่นกัน ดังนั้นแทนที่จะเถียงกันว่าเครื่องมือไหนดีกว่า ควร ออกแบบลูปที่ทำงานได้บนทั้งสองฝั่ง
องค์ประกอบทั้งห้าของลูปและหน่วยความจำ
- ลูปต้องมีห้าอย่าง และมีที่เพิ่มมาอีกหนึ่งแห่งไว้จำสถานะ
- Automations — ทำงานตามตารางเวลาเพื่อค้นหาและคัดแยก (triage) ด้วยตัวเอง
- Worktrees — ทำให้เอเจนต์สองตัวที่ทำงานขนานกันไม่ชนกัน
- Skills — บันทึกความรู้เกี่ยวกับโปรเจกต์ที่เอเจนต์ไม่ต้องเดาเอาเอง
- Plugins·connectors — เชื่อมเอเจนต์เข้ากับเครื่องมือที่ใช้อยู่แล้ว
- Sub-agents — ให้ฝั่งหนึ่งคิดแนวทาง และอีกฝั่งหนึ่งตรวจสอบ
- อย่างที่หกคือ หน่วยความจำ เช่นไฟล์ markdown หรือบอร์ด Linear ที่อยู่นอกบทสนทนาเดียว และเก็บสิ่งที่ทำเสร็จแล้วรวมถึงสิ่งที่จะทำต่อ
- มันดูง่ายเกินไป แต่เป็นกลเม็ดเดียวกันที่เอเจนต์ระยะยาวทุกตัวพึ่งพา (บทความก่อนหน้าเรื่อง long-running agents)
- โมเดลจะลืมทุกอย่างระหว่างการรันแต่ละครั้ง ดังนั้นหน่วยความจำต้องอยู่บนดิสก์ ไม่ใช่อยู่ในคอนเท็กซ์ — เอเจนต์อาจลืม แต่ repo ไม่ลืม
- ตอนนี้ทั้งสองผลิตภัณฑ์มีครบทั้งห้าส่วนแล้ว ต่างกันแค่ชื่อ แต่ความสามารถเหมือนกัน
Automations — จังหวะการเต้นของหัวใจของลูป
- Automations คือสิ่งที่ทำให้ลูปไม่ใช่แค่การรันครั้งเดียว แต่เป็น ลูปจริง ๆ
- ในแอป Codex สามารถสร้างได้จากแท็บ Automations โดยเลือกโปรเจกต์ พรอมป์ต์ที่จะให้รัน รอบเวลา และจะใช้ local checkout หรือ background worktree
- การรันที่พบอะไรบางอย่างจะถูกส่งไปยัง Triage inbox ส่วนการรันที่ไม่พบอะไรเลยจะถูกเก็บถาวรเองโดยอัตโนมัติ
- OpenAI ใช้สิ่งนี้ภายในองค์กรกับงานน่าเบื่อ เช่น triage issue รายวัน สรุปความล้มเหลวของ CI เขียน commit briefing และไล่ล่าบั๊กที่เพิ่งถูกเพิ่มเข้ามาในสัปดาห์ก่อน
- ระบบอัตโนมัติสามารถ เรียกใช้ skill ได้ จึงไม่ต้องแปะกำแพงข้อความคำสั่งยาว ๆ แต่ใช้การเรียก
$skill-nameเพื่อทำให้งานซ้ำ ๆ ดูแลง่ายขึ้น
- Claude Code ไปถึงจุดเดียวกันด้วย scheduling และ hooks
- ใช้
/loopเพื่อรันพรอมป์ต์หรือคำสั่งเป็นช่วง ๆ ตั้งเวลาแบบ cron ได้ และยิงคำสั่งเชลล์ผ่าน hooks ในจังหวะเฉพาะของ lifecycle ของเอเจนต์ - ถ้าต้องการให้มันรันต่อแม้ปิดโน้ตบุ๊กไปแล้ว ก็สามารถย้ายทั้งหมดไปที่ GitHub Actions ได้
- ใช้
- ยังมี primitive อีกตัวภายในเซสชันที่เป็นแก่นสำคัญของบทความนี้
/loopจะรันซ้ำตามรอบเวลาที่กำหนด/goalจะทำต่อไปจนกว่าเงื่อนไขที่เราเขียนไว้จะเป็นจริง และหลังจบแต่ละเทิร์นจะมี โมเดลเล็กอีกตัวแยกต่างหากมาตรวจว่าทำเสร็จหรือยัง เพื่อไม่ให้เอเจนต์ที่เขียนโค้ดเป็นคนตรวจงานตัวเอง- ตัวอย่างเช่น กำหนดเงื่อนไขว่า "ทุกเทสต์ใน
test/authต้องผ่าน และ lint ต้อง clean" แล้วเราก็ลุกไปทำอย่างอื่นได้
- ตัวอย่างเช่น กำหนดเงื่อนไขว่า "ทุกเทสต์ใน
- Codex ก็มี
/goalแบบเดียวกัน ทำงานต่อเนื่องโดยส่งต่อทีละเทิร์นจนกว่า เงื่อนไขหยุดที่ตรวจสอบได้ จะเป็นจริง และรองรับ pause, resume, clear
Worktrees — ให้การทำงานขนานไม่กลายเป็นความโกลาหล
- ทันทีที่รันเอเจนต์มากกว่าหนึ่งตัว ไฟล์ก็เริ่มชนกัน และนี่คือจุดที่ทุกอย่างพังได้
- การที่เอเจนต์สองตัวเขียนไฟล์เดียวกันก็ปวดหัวพอ ๆ กับวิศวกรสองคน commit ลงบรรทัดเดียวกันโดยไม่คุยกัน
- git worktree แก้ปัญหานี้ได้ — มันแชร์ประวัติ repo เดียวกัน แต่แต่ละตัวมีไดเรกทอรีทำงานแยกบน branch ของตัวเอง จึงทำให้การแก้ไขของเอเจนต์ฝั่งหนึ่งไม่ไปโดน checkout ของอีกฝั่ง
- Codex รองรับ worktree ในตัว จึงให้หลายเธรดแตะ repo เดียวกันพร้อมกันได้โดยไม่ชนกัน
- Claude Code ก็ให้การแยกแบบเดียวกันผ่าน
git worktree, แฟลก--worktreeที่เปิดเซสชันด้วย checkout ของตัวเอง และการตั้งค่าisolation: worktreeสำหรับ subagent (แต่ละ helper จะได้ checkout ใหม่ที่ล้างทิ้งเองเมื่อทำงานเสร็จ) - worktree ช่วยตัดปัญหาการชนกันเชิงกลไกออกไป แต่ ตัวคุณยังเป็นคอขวดอยู่ดี — จำนวนที่รันได้จริงไม่ได้ขึ้นกับเครื่องมือ แต่ขึ้นกับแบนด์วิดท์ในการรีวิวของคุณเอง (บทความก่อนหน้าเรื่อง the orchestration tax)
Skills — เพื่อไม่ต้องอธิบายโปรเจกต์ใหม่ทุกครั้ง
- skill คือวิธีหยุดการต้องอธิบายคอนเท็กซ์ของโปรเจกต์เดิมซ้ำ ๆ ในทุกเซสชันเหมือนปลาทองความจำสั้น
- ทั้งสองเครื่องมือใช้ฟอร์แมตเดียวกัน — โฟลเดอร์ที่มี
SKILL.mdสำหรับเก็บคำสั่งและเมตะดาตา พร้อมสคริปต์ เอกสารอ้างอิง หรือแอสเซ็ตเพิ่มเติมแบบเลือกได้ - Codex เรียกใช้ได้ด้วย
$หรือ/skillsหรือจะให้มันรันเองเมื่อพบว่างานตรงกับคำอธิบายของ skill ก็ได้ ดังนั้นแทนที่จะเขียนให้อัจฉริยะ ควรเขียนแบบ สั้น ตรง และน่าเบื่อ จะดีกว่า - Claude Code ก็ทำงานแบบเดียวกัน (บทความก่อนหน้าเรื่อง agent skills)
- ทั้งสองเครื่องมือใช้ฟอร์แมตเดียวกัน — โฟลเดอร์ที่มี
- skill คือที่ที่ เจตนา (intent) ไม่กลายเป็นต้นทุนที่ต้องจ่ายซ้ำ
- เอเจนต์เริ่มทุกเซสชันจากสภาพเย็น และจะเติมช่องว่างของเจตนาด้วยการเดาอย่างมั่นใจ (บทความก่อนหน้าเรื่อง the intent debt)
- skill คือการเขียนเจตนานั้นไว้ข้างนอก — เช่น convention, ขั้นตอน build, หรือข้อจำกัดประเภท "เพราะเหตุการณ์ครั้งนั้น เราไม่ทำแบบนี้" เขียนไว้ครั้งเดียว แล้วเอเจนต์จะอ่านทุกครั้งที่รัน
- ถ้าไม่มี skill ลูปจะต้องสรุปความเข้าใจทั้งโปรเจกต์ใหม่จากศูนย์ในทุกวัฏจักร แต่ถ้ามี มันจะ สะสมและทบต้นเหมือนดอกเบี้ย
- skill คือฟอร์แมตสำหรับการเขียน ส่วน plugin คือวิธีการแจกจ่าย — ถ้าต้องการแชร์ข้ามหลาย repo หรือแพ็กเป็นชุด ก็ค่อยทำเป็น plugin (Codex และ Claude Code เหมือนกันทั้งคู่)
Plugins·connectors — ให้ลูปแตะต้องเครื่องมือจริงได้
- ลูปที่มองเห็นแค่ไฟล์ระบบอย่างเดียวคือลูปขนาดเล็ก
- connector ที่อิง MCP ทำให้เอเจนต์อ่าน issue tracker, query ฐานข้อมูล, เรียก staging API, หรือส่งข้อความใน Slack ได้
- ทั้ง Codex และ Claude Code ต่างพูดภาษา MCP ดังนั้น connector ที่ทำให้ฝั่งหนึ่งมักจะใช้กับอีกฝั่งได้เลย
- plugin จะรวม connector กับ skill ไว้ด้วยกัน เพื่อให้เพื่อนร่วมทีมติดตั้งได้ทีเดียว โดยไม่ต้องสร้างทั้งหมดขึ้นใหม่จากความจำ
- นี่คือความต่างระหว่างเอเจนต์ที่บอกว่า "มีแพตช์แก้ตรงนี้นะ" กับ ลูปที่เปิด PR เชื่อมตั๋ว Linear และส่ง ping เข้าแชนเนลเมื่อ CI เป็นสีเขียว
- connector คือเหตุผลที่ลูปไม่ใช่แค่พูดถึงความเป็นไปได้ แต่สามารถ ลงมือกระทำในสภาพแวดล้อมจริง ได้
Sub-agents — แยกคนทำออกจากคนตรวจ
- โครงสร้างที่มีประโยชน์ที่สุดในลูปอย่างไม่ต้องสงสัยคือ การแยกฝั่งที่เขียนโค้ดออกจากฝั่งที่ตรวจสอบ
- โมเดลที่เขียนโค้ดเองมักใจดีกับการให้คะแนนการบ้านตัวเองเกินไป
- เอเจนต์ตัวที่สองซึ่งมีคำสั่งต่างออกไป และบางครั้งใช้คนละโมเดล จะจับสิ่งที่ตัวแรกปล่อยผ่านเพราะมันโน้มน้าวตัวเองไปแล้วได้
- Codex จะสร้าง subagent เมื่อร้องขอเท่านั้น จากนั้นรันพร้อมกันและรวมผลลัพธ์เป็นคำตอบเดียว
- สามารถกำหนดเอเจนต์ของตัวเองด้วย ไฟล์ TOML ใน
.codex/agents/(name, description, instructions และมี model กับ reasoning effort เป็นตัวเลือก) - ตัวอย่างเช่น reviewer ด้านความปลอดภัยอาจใช้โมเดลที่แรงและตั้ง high effort ส่วน explorer อาจใช้โมเดลเร็วแบบ read-only
- สามารถกำหนดเอเจนต์ของตัวเองด้วย ไฟล์ TOML ใน
- Claude Code ก็ทำแบบเดียวกันผ่าน subagents ใน
.claude/agents/และ agent teams ที่ส่งงานถึงกัน- การแบ่งงานที่พบได้บ่อยในทั้งสองเครื่องมือคือ เอเจนต์หนึ่งสำรวจ เอเจนต์หนึ่งลงมือทำ และอีกเอเจนต์หนึ่งตรวจเทียบกับสเปก (บทความก่อนหน้าเรื่อง the code agent orchestra และ adversarial code review)
- เพราะลูปจะทำงานตอนที่เราไม่ได้มองอยู่ จึงต้องมี ผู้ตรวจสอบที่เชื่อถือได้ (verifier) เพื่อให้เรากล้าลุกออกจากที่นั่ง
- subagent แต่ละตัวใช้โมเดลและการเรียกเครื่องมือของตัวเอง จึง กินโทเค็นเพิ่มขึ้น และควรใช้ในจุดที่การมีความเห็นที่สองคุ้มค่า
- สิ่งนี้เองคือสิ่งที่
/goalของ Claude Code ทำอยู่ภายใน — ใช้โมเดลใหม่มาตัดสินความสำเร็จแทนฝั่งที่ลงมือทำ เป็นการนำการแยก maker/checker มาใช้กับเงื่อนไขหยุดด้วย
ลูปหนึ่งชุดหน้าตาเป็นอย่างไร
- เมื่อนำทั้งหมดมารวมกัน เธรดเดียวจะกลายเป็นแผงควบคุมขนาดเล็ก และนี่คือรูปแบบหนึ่งที่ใช้ซ้ำได้
- automation รันใน repo ทุกเช้า โดยพรอมป์ต์ของมันจะเรียกใช้ triage skill เพื่ออ่านความล้มเหลวของ CI เมื่อวาน issue ที่ยังเปิดอยู่ และ commit ล่าสุด แล้วบันทึกผลลงไฟล์ markdown หรือบอร์ด Linear
- สำหรับแต่ละรายการที่คุ้มค่าจะทำต่อ เธรดจะเปิด worktree ที่แยกจากกัน แล้วมอบหมายให้ sub-agent ร่างการแก้ไข จากนั้น sub-agent ตัวที่สองจะรีวิวร่างนั้นเทียบกับ project skill และเทสต์ที่มีอยู่
- connector ทำให้ลูปเปิด PR และอัปเดตตั๋วได้ ส่วนสิ่งที่ลูปจัดการไม่ไหวจะเข้าไปอยู่ใน triage inbox
- state file คือกระดูกสันหลังของทั้งหมด — มันจำได้ว่าเคยลองอะไรไปแล้ว อะไรผ่านแล้ว และอะไรยังเปิดค้างอยู่ เพื่อให้การรันในเช้าวันถัดไปต่อจากจุดที่วันนี้หยุดไว้ได้
- ประเด็นสำคัญคือ ไม่มีขั้นตอนไหนในนั้นที่ต้องพรอมป์ต์ทีละอย่าง แต่เป็นการ ออกแบบไว้ครั้งเดียว — ไม่ว่าจะเป็น Codex หรือ Claude Code องค์ประกอบก็เหมือนกัน ลูปจึงเหมือนกัน
สิ่งที่ลูปยังทำแทนไม่ได้
- ลูปเปลี่ยนลักษณะของงาน แต่ไม่ได้ลบมนุษย์ออกไป และยิ่งลูปดีขึ้น ก็ยิ่งมีปัญหาสามอย่างที่คมชัดขึ้น
- การตรวจสอบยังเป็นหน้าที่ของคุณอยู่ดี
- ลูปที่รันแบบไม่มีคนเฝ้า ก็คือลูปที่ทำพลาดแบบไม่มีคนเฝ้าได้เช่นกัน
- เหตุผลที่ต้องแยก verifier sub-agent ออกจาก maker ก็เพื่อทำให้คำว่า "เสร็จแล้ว" ของลูปมีความหมาย แต่ถึงอย่างนั้นคำว่า "done" ก็ยังเป็น คำกล่าวอ้าง ไม่ใช่ข้อพิสูจน์ (บทความก่อนหน้าเรื่อง code review in the age of AI — งานคือการส่งมอบโค้ดที่ยืนยันแล้วว่าใช้งานได้)
- ความเข้าใจจะเสื่อมหากปล่อยทิ้งไว้
- ยิ่งลูปช่วยให้ส่งมอบโค้ดที่เราไม่ได้เขียนเองได้เร็วขึ้น ช่องว่างระหว่างสิ่งที่มีอยู่กับสิ่งที่เราเข้าใจจริงก็ยิ่งกว้างขึ้น
- นี่คือ comprehension debt และลูปที่ลื่นไหลจะขยายช่องว่างนั้นให้เร็วขึ้น ถ้าเราไม่อ่านสิ่งที่ลูปสร้างขึ้นมา
- ท่าทีที่สบายเกินไปคือท่าทีที่อันตราย
- เมื่อปล่อยให้ลูปรันเอง เราอาจหยุดมีความเห็นของตัวเองและรับสิ่งที่มันส่งกลับมาแบบตรง ๆ ได้ง่าย (cognitive surrender)
- การออกแบบลูปเป็นยารักษาได้ถ้าทำด้วยวิจารณญาณ แต่เป็นตัวเร่งได้ถ้าทำเพื่อหลีกเลี่ยงการคิด — พฤติกรรมเดียวกัน แต่ผลลัพธ์ตรงข้ามกันสุดขั้ว
จงสร้างลูป แต่จงยังเป็นวิศวกร
- สิ่งนี้ดูเหมือนตัวอย่างล่วงหน้าของวิธีที่งานจะพัฒนาไป แต่ถ้าไม่รีวิวโค้ดด้วยตัวเอง หรือพึ่งลูปอัตโนมัติอย่างเดียว ก็อาจติดอยู่ใน วงจรขาลงที่คุณภาพผลิตภัณฑ์ลดลงและจมลึกลงเรื่อย ๆ
- ตั้งค่าลูปได้ แต่การ พรอมป์ต์เอเจนต์โดยตรงก็ยังมีประสิทธิภาพอยู่ หัวใจสำคัญคือการหาสมดุลที่เหมาะสม
- ลูปเดียวกันอาจให้ผลตรงข้ามกันสุดขั้วในคนละคน — ในสองคนที่สร้างลูปเดียวกัน คนหนึ่งจะใช้มันเพื่อเร่งงานที่ตนเข้าใจลึกอยู่แล้ว ส่วนอีกคนจะใช้มันเพื่อหลีกเลี่ยงการทำความเข้าใจงาน
- ลูปไม่รู้ความต่างนี้ แต่คุณรู้
- นี่คือเหตุผลที่การออกแบบลูปไม่ง่ายกว่าการทำ prompt engineering และจริง ๆ แล้วยากกว่า — ประเด็นของ Cherny ไม่ใช่ว่างานง่ายขึ้น แต่คือ จุดที่เกิด leverage ได้ย้ายที่ไปแล้ว
- สรุปคือ จงสร้างลูป แต่จงสร้างมัน ราวกับว่าคุณจะยังเป็นวิศวกร ไม่ใช่แค่คนกดปุ่มเริ่มต้น
1 ความคิดเห็น
การตรวจสอบก็ยังคงเป็นหน้าที่ของตัวเอง
ความเข้าใจถ้าปล่อยทิ้งไว้ก็เสื่อมถอย
ท่าที่สบายคือท่าที่อันตราย
=> สุดท้ายแล้วจำเป็นต้องตรวจสอบด้วยตัวเอง และต้องมีการเขียนพรอมป์ต์เพื่อทำให้งานที่ทำซ้ำๆ น้อยลง