เหตุผลที่ระบบเอเจนต์หลายตัวล้มเหลวเมื่อนำใช้งานจริง และวิธีออกแบบเอเจนต์ที่เชื่อถือได้ด้วย state machine สัญญาเครื่องมือที่ชัดเจน นโยบาย retry และการมองเห็นเชิงลึก

ระบบเอเจนต์คือแอปพลิเคชันที่ LLM ไม่ได้แค่ตอบ prompt แต่ ตัดสินใจว่าจะทำอะไรต่อ: เรียกเครื่องมือไหน ดึงข้อมูลอะไร ทำขั้นตอนไหน และเมื่อไรที่ถือว่า “เสร็จ” พวกมันรวมโมเดล ชุดเครื่องมือ (API, ฐานข้อมูล, บริการ), วงจรการวางแผน/ใช้งาน และโครงสร้างพื้นฐานที่เชื่อมทุกอย่างเข้าด้วยกัน
ในงานสาธิต สิ่งนี้ดูเหมือนเวทมนตร์: เอเจนต์วางแผน เรียกเครื่องมือไม่กี่ครั้ง แล้วคืนผลลัพธ์ที่เพอร์เฟ็กต์ เส้นทางที่ราบรื่น หน่วงเวลาต่ำ และไม่มีอะไรล้มเหลวพร้อมกัน
ในโหลดงานจริง เอเจนต์เดียวกันถูกกดดันในแบบที่งานสาธิตไม่เคยเจอ:
ผลลัพธ์คือพฤติกรรมที่ไม่เสถียร ยากจะทำซ้ำ ข้อมูลเสียเงียบ และการใช้งานที่บางครั้งค้างหรือวนไม่จบ
เอเจนต์ที่ไม่เสถียรไม่ใช่แค่ทำให้ผู้ใช้ไม่พอใจ แต่ยัง:
บทความนี้เน้นที่ รูปแบบวิศวกรรม ไม่ใช่แค่ "prompt ที่ดีกว่า" เราจะดู state machines, สัญญาเครื่องมือที่ชัดเจน, กลยุทธ์ retry และการจัดการความล้มเหลว, การควบคุมหน่วยความจำและความขนาน, และรูปแบบ observability ที่ทำให้ระบบเอเจนต์ทำนายได้ภายใต้ภาระงาน — ไม่ใช่แค่สร้างความประทับใจบนเวที
ระบบเอเจนต์ส่วนใหญ่ดูดีในสาธิตเส้นทางเดียวที่สำเร็จ แต่จะล้มเมื่อมีทราฟฟิก เครื่องมือ และกรณีขอบมาพร้อมกัน
การออร์เคสตราแบบตื้นเขินสมมติว่าโมเดลจะ "ทำสิ่งที่ถูกต้อง" ในการเรียกหนึ่งหรือสองครั้ง แต่ในการใช้งานจริง คุณจะเห็นรูปแบบซ้ำ ๆ:
โดยไม่มีสถานะที่ชัดเจนและเงื่อนไขการยุติ พฤติกรรมเหล่านี้หลีกเลี่ยงไม่ได้
การสุ่มของ LLM ความแปรผันของหน่วงเวลา และเวลาในการตอบของเครื่องมือสร้าง ความไม่แน่นอนที่ซ่อนอยู่ อินพุตเดียวกันอาจพาไปยังสาขาต่างกัน เรียกเครื่องมือต่างกัน หรือแปลผลลัพธ์ของเครื่องมือต่างกัน
เมื่อสเกลขึ้น ปัญหาเครื่องมือจะกลายเป็นตัวกำหนด:
ทุกประเด็นเหล่านี้นำไปสู่ลูปซ้ำ retry ที่ไม่จำเป็น หรือคำตอบสุดท้ายที่ผิด
สิ่งที่ไม่พังที่ 10 RPS จะพังบ่อยเมื่อเป็น 1,000 RPS ความขนานเปิดเผย:
ทีมผลิตภัณฑ์มักคาดหวังเวิร์กโฟลว์เชิงกำหนดการ SLA ที่ชัดเจน และการตรวจสอบย้อนหลัง เอเจนต์ที่ปล่อยไว้อย่างไม่จำกัดจะให้พฤติกรรมแบบ ความน่าจะเป็นและพยายามดีที่สุด โดยรับประกันน้อย
เมื่อสถาปัตยกรรมมองข้ามความไม่ตรงกันนี้—มองเอเจนต์เหมือนบริการแบบเดิมแทนที่จะเป็นตัววางแผนเชิงสถิติ—ระบบจะพฤติกรรมไม่คาดคิดเมื่อความน่าเชื่อถือสำคัญที่สุด
เอเจนต์ที่พร้อมใช้งานใน production เน้นการออกแบบระบบที่มีวินัย มากกว่าการพึ่งพา "prompt ฉลาด" วิธีคิดที่มีประโยชน์คือมองพวกมันเป็นเครื่องเล็ก ๆ ที่คาดเดาได้ซึ่งบางครั้งเรียก LLM ไม่ใช่ก้อนลึกลับของ LLM ที่บางครั้งสัมผัสระบบของคุณ
คุณสมบัติสำคัญ 4 ประการ:
คุณสมบัติเหล่านี้ไม่ได้มาจาก prompt เพียงอย่างเดียว แต่อยู่ในโครงสร้าง
รูปแบบเริ่มต้นที่หลายทีมใช้คือ: "while not done, call the model, let it think, maybe call a tool, repeat" ซึ่งง่ายสำหรับการพัฒนาแต่ยากในเชิงปฏิบัติการ
รูปแบบที่ปลอดภัยกว่าคือแทนที่ด้วย เวิร์กโฟลว์แบบชัดเจน:
COLLECTING_INPUT, PLANNING, EXECUTING_STEP, WAITING_ON_HUMAN, DONE)วิธีนี้แปลงเอเจนต์เป็น state machine ที่ทุกขั้นตอนตรวจสอบได้ ทดสอบได้ และ replay ได้ ลูปแบบอิสระอาจให้ความยืดหยุ่น แต่เวิร์กโฟลว์ที่ชัดเจนคือสิ่งที่จะทำให้ incident ดีบักได้และพฤติกรรมตรวจสอบได้
เอเจนต์โมโนลิทิกที่ "ทำทุกอย่าง" แม้จะดูดึงดูดแต่สร้างการเชื่อมโยงแน่นเกินไประหว่างความรับผิดชอบที่ต่างกัน เช่น การวางแผน การดึงข้อมูล โลจิกทางธุรกิจ การออร์เคสตรา UI เป็นต้น
ให้ประกอบด้วย เอเจนต์หรือสกิลขนาดเล็กที่มีขอบเขตชัดเจน:
แต่ละสกิลสามารถมี state machine ของตัวเอง เครื่องมือ และกฎความปลอดภัย การประกอบกันของสกิลเหล่านี้จะกลายเป็นเวิร์กโฟลว์ระดับบน ไม่ใช่ prompt ที่โตขึ้นเรื่อย ๆ ในเอเจนต์เดียว
ความโมดูลาร์นี้ทำให้แต่ละเอเจนต์ง่ายพอที่จะใคร่ครวญและพัฒนาความสามารถเฉพาะโดยไม่ทำให้ส่วนอื่นล้มตาม
รูปแบบทางความคิดที่มีประโยชน์คือแยกเอเจนต์เป็นสามชั้น:
การบังคับแยกชั้นนี้ช่วยหลีกเลี่ยงการซ่อนโลจิกทางธุรกิจใน prompt หรือคำอธิบายเครื่องมือ ทำให้ LLM เป็นส่วนตัดสินใจภายในเปลือก deterministic ที่ชัดเจน ไม่ใช่เปลือกเอง
ระบบเอเจนต์ที่เชื่อถือได้ที่สุดไม่ใช่งานสาธิตที่ยิ่งใหญ่ที่สุด แต่เป็นระบบที่คุณอธิบายได้บนไวท์บอร์ด
ข้อปฏิบัติ:
การเอียงไปทางเอเจนต์ที่เล็ก ประกอบได้ และมีโครงสร้างดีช่วยให้ระบบขยายขอบเขตโดยไม่ล้มด้วยความซับซ้อนของตนเอง
การใช้งานเอเจนต์ส่วนใหญ่เริ่มจากลูป "คิด ทำ สังเกต" อยู่รอบการเรียก LLM ซึ่งใช้ได้กับงานสาธิต แต่เปลือกแบบนี้จะทึบและเปราะเร็วกว่า แนวทางที่ดีกว่าคือให้เอเจนต์เป็น state machine ที่ชัดเจน: ชุดสถานะจำกัด กับการเปลี่ยนสถานะที่กำหนดโดยอีเวนต์
แทนที่จะปล่อยให้โมเดลตัดสินใจโดยนัยว่าจะทำอะไรต่อ ให้กำหนดไดอะแกรมสถานะเล็ก ๆ:
การเปลี่ยนระหว่างสถานะเหล่านี้ถูกกระตุ้นด้วย อีเวนต์แบบมีชนิด เช่น UserRequestReceived, ToolCallSucceeded, ToolValidationFailed, TimeoutExceeded, หรือ HumanOverride ทุกอีเวนต์พร้อมสถานะปัจจุบันจะกำหนดสถานะถัดไปและการกระทำที่ตามมา
นี่ทำให้ retry และ timeout ตรงไปตรงมา: แนบ policy เฉพาะกับสถานะแต่ละตัว (เช่น CALL_TOOL อาจ retry 3 ครั้งแบบ exponential backoff, PLAN อาจไม่ retry เลย) แทนที่จะกระจาย logic ของ retry ทั่วโค้ดเบส
เก็บสถานะปัจจุบันและคอนเท็กซ์ขั้นต่ำในสตอร์ภายนอก (ฐานข้อมูล คิว หรือ workflow engine) เอเจนต์จะกลายเป็นฟังก์ชันบริสุทธิ์:
next_state, actions = transition(current_state, event, context)
สิ่งนี้ทำให้เกิดประโยชน์:
ด้วย state machine ทุกขั้นตอนของพฤติกรรมเอเจนต์ชัดเจน: อยู่สถานะใด อีเวนต์ใดเกิด การเปลี่ยนใดทำงาน ผลข้างเคียงอะไรเกิดขึ้น ความชัดเจนนี้ทำให้การดีบักเร็วขึ้น ทำให้การสืบสวน incident ง่ายขึ้น และสร้างเส้นทางการตรวจสอบ (audit trail) ตามธรรมชาติสำหรับการตรวจสอบด้านการปฏิบัติตามข้อกำหนด คุณสามารถพิสูจน์จากล็อกและประวัติสถานะได้ว่าการกระทำที่มีความเสี่ยงถูกทำเฉพาะจากสถานะที่กำหนดและภายใต้เงื่อนไขที่ชัดเจน
เอเจนต์ทำงานคาดเดาได้มากขึ้นเมื่อเครื่องมือไม่ดูเหมือน "API ที่ซ่อนในคำพูด" แต่เหมือนอินเทอร์เฟซที่ออกแบบมาอย่างดีมีการรับประกันชัดเจน
แต่ละเครื่องมือควรมีสัญญาที่ครอบคลุม:
InvalidInput, NotFound, RateLimited, TransientFailure) พร้อมความหมายชัดเจนเผยสัญญานี้ต่อโมเดลเป็นเอกสารเชิงโครงสร้าง ไม่ใช่กำแพงของข้อความ planner ของเอเจนต์ควรรู้ว่าข้อผิดพลาดใด retry ได้ ข้อผิดพลาดใดต้องขอผู้ใช้ และข้อผิดพลาดใดควรหยุดเวิร์กโฟลว์
ปฏิบัติต่อ I/O ของเครื่องมือเหมือน API ใน production:
สิ่งนี้ช่วยให้ prompt สั้นลง: แทนคำสั่งยาว ๆ ให้พึ่งพาแนวทางที่ขับเคลื่อนด้วยสกีมา ข้อจำกัดชัดเจนลดการสร้างอาร์กิวเมนต์ที่ประสาทหลอนและลำดับการเรียกเครื่องมือที่ไม่มีความหมาย
เครื่องมือมีวิวัฒนาการ เอเจนต์ไม่ควรพังเมื่อเครื่องมือเปลี่ยน:
v1, v1.1, v2) และผูกเอเจนต์กับเวอร์ชันโลจิกการวางแผนสามารถผสมเอเจนต์และเครื่องมือในระดับความโตที่ต่างกันได้อย่างปลอดภัย
ออกแบบสัญญาโดยคำนึงถึง ความล้มเหลวบางส่วน:
เอเจนต์จะปรับตัวได้: ดำเนินเวิร์กโฟลว์ด้วยฟังก์ชันการทำงานลดลง ขอการยืนยันจากผู้ใช้ หรือสลับไปใช้เครื่องมือสำรอง
สัญญาเครื่องมือเป็นที่ธรรมชาติในการเข้ารหัสข้อจำกัดด้านความปลอดภัย:
confirm: true)รวมสิ่งนี้กับการตรวจสอบฝั่งเซิร์ฟเวอร์; อย่าเชื่อว่าโมเดลจะ "ประพฤติ" เสมอไป
เมื่อเครื่องมือมีสัญญาที่ชัดเจน ตรวจสอบได้ และเวอร์ชันได้ prompt จะสั้นลง ออร์เคสตราโลจิกจะง่ายขึ้น และการดีบักง่ายขึ้นมาก คุณย้ายความซับซ้อนจากคำอธิบายภาษาธรรมชาติที่เปราะเป็นสกีมาและนโยบายที่กำหนดผล จึงลดการเรียกเครื่องมือที่ประสาทหลอนและผลข้างเคียงที่ไม่คาดคิด
ระบบเอเจนต์ที่เชื่อถือได้ถือว่าทุกอย่างจะล้มสักครั้ง: โมเดล เครื่องมือ เครือข่าย หรือแม้แต่ชั้นการประสานงานของคุณ เป้าหมายไม่ใช่หลีกเลี่ยงความล้มเหลว แต่ทำให้มันถูกจัดการได้ถูกและปลอดภัย
Idempotency หมายความว่า: การทำคำขอซ้ำมีผลภายนอกเท่ากับการทำครั้งเดียว สิ่งนี้สำคัญสำหรับเอเจนต์ LLM ที่มักเรียกเครื่องมือซ้ำหลังความล้มเหลวบางส่วนหรือคำตอบคลุมเครือ
ทำให้เครื่องมือ idempotent ด้วยการออกแบบ:
request_id คงที่ เครื่องมือเก็บและคืนผลลัพธ์เดิมเมื่อเห็น ID ซ้ำใช้ retry ที่มีโครงสร้างสำหรับความล้มเหลวชั่วคราว (timeout, rate limit, 5xx): exponential backoff, jitter เพื่อหลีกเลี่ยง thundering herd, และจำกัดจำนวนครั้งสูงสุด บันทึกทุกการพยายามพร้อม correlation IDs เพื่อให้ติดตามพฤติกรรมเอเจนต์ได้
สำหรับ ความล้มเหลวถาวร (4xx, validation errors, business rule violations) ห้าม retry ให้แสดงข้อผิดพลาดเชิงโครงสร้างต่อ policy ของเอเจนต์เพื่อให้มันสามารถปรับแผน ถามผู้ใช้ หรือเลือกเครื่องมืออื่นได้
ติดตั้ง circuit breakers ทั้งที่ชั้นเอเจนต์และชั้นเครื่องมือ: หลังความล้มเหลวบ่อยครั้ง ให้บล็อกการเรียกเครื่องมือนั้นชั่วคราวและล้มเร็ว (fail fast) จับคู่กับ fallback ที่กำหนดชัดเจน: โหมด degraded, ข้อมูลแคช หรือเครื่องมือทางเลือก
หลีกเลี่ยงการ retry แบบตาบอดจากลูปเอเจนต์ หากไม่มีเครื่องมือ idempotent และคลาสข้อผิดพลาดที่ชัดเจน คุณจะเพิ่มผลข้างเคียง หน่วงเวลา และค่าใช้จ่ายโดยไม่จำเป็น
เอเจนต์ที่เชื่อถือได้เริ่มจากการคิดที่ชัดเจนเกี่ยวกับ อะไรคือสถานะ และ เก็บไว้ที่ไหน
ปฏิบัติต่อเอเจนต์เหมือนบริการที่จัดการคำขอ:
การผสมสองอย่างนี้นำไปสู่ความสับสนและบั๊ก เช่น การใส่ผลลัพธ์เครื่องมือชั่วคราวลงใน "memory" ทำให้เอเจนต์ใช้บริบทเก่าในการสนทนาครั้งถัดไป
มีตัวเลือกหลักสามแบบ:
กฎที่ดี: LLM เป็นฟังก์ชันไร้สถานะบนอ็อบเจ็กต์สถานะที่ชัดเจน เก็บอ็อบเจ็กต์นั้นข้างนอกโมเดลและสร้าง prompt จากมัน
รูปแบบล้มเหลวจำนวนมากคือการใช้ logs, traces หรือ prompt เป็นหน่วยความจำโดยปริยาย
ปัญหา:
ให้กำหนด สกีมา memory เชิงโครงสร้าง เช่น user_profile, project, task_history เป็นต้น สกัด logs จากสถานะแทนที่จะให้ logs เป็นแหล่งความจริง
เมื่อหลายเครื่องมือหรือหลายเอเจนต์อัปเดตเอนทิตีเดียวกัน (เช่น record CRM หรืองาน) คุณต้องมีการควบคุมความสอดคล้องพื้นฐาน:
สำหรับการดำเนินการมูลค่าสูง ให้บันทึก decision log แยกจาก conversational log: อะไรเปลี่ยน ทำไม และอ้างอิงจากอินพุตใด
เพื่อรอดจากการ crash, deploys และ rate limiting เวิร์กโฟลว์ควร resume ได้:
สิ่งนี้ยังช่วยให้ดีบักแบบ time travel: คุณสามารถตรวจสอบและ replay สถานะที่นำไปสู่การตัดสินใจที่ผิดพลาดได้
ความจำเป็นทั้งเป็นทรัพย์สินและภาระ สำหรับเอเจนต์ใน production:
ปฏิบัติต่อความจำเป็นเป็นผลิตภัณฑ์: ออกแบบ มีเวอร์ชัน และกำกับดูแล ไม่ใช่แค่ dump ของข้อความที่เติบโตขึ้นเรื่อย ๆ แนบกับเอเจนต์ของคุณ
เอเจนต์ดูเป็นลำดับบนไวท์บอร์ด แต่ทำงานเหมือนระบบกระจายเมื่ออยู่ภายใต้ภาระงานจริง เมื่อมีผู้ใช้พร้อมกัน เครื่องมือ และงานพื้นหลัง คุณต้องรับมือกับ race condition งานซ้ำ และปัญหาการเรียงลำดับ
รูปแบบความล้มเหลวทั่วไป:
ลดความเสี่ยงด้วยสัญญาเครื่องมือ idempotent สถานะเวิร์กโฟลว์ที่ชัดเจน และการล็อกแบบ optimistic/pessimistic ที่ชั้นข้อมูล
โฟลว์แบบ synchronous ง่ายแต่เปราะ: ทุก dependency ต้องขึ้นและเร็วพอ เมื่อเอเจนต์กระจายเป็นหลายเครื่องมือหรือซับทาส์คู่ขนาน ให้ย้ายขั้นตอนที่รันนานหรือมีผลข้างเคียงไว้หลัง คิว
การออร์เคสตราด้วยคิวให้คุณ:
เอเจนต์มักเจอขีดจำกัดสามกลุ่ม:
คุณต้องมี ชั้น rate-limit ชัดเจนพร้อม throttle ต่อผู้ใช้ ต่อเทนแนนต์ และแบบรวม ใช้ token bucket หรือ leaky bucket เพื่อบังคับนโยบาย และส่ง error type ที่ชัดเจน (เช่น RATE_LIMIT_SOFT, RATE_LIMIT_HARD) เพื่อให้เอเจนต์ถอยได้อย่างสุภาพ
Backpressure คือวิธีที่ระบบปกป้องตนเองภายใต้ความเครียด กลยุทธ์ได้แก่:
ติดตามสัญญาณอิ่มตัว: ความลึกของคิว การใช้งาน worker อัตราข้อผิดพลาดของโมเดล/เครื่องมือ และ latency percentiles คิวที่ขึ้นพร้อมกับ latency หรืออัตรา 429/503 คือสัญญาณเตือนว่าระบบเอเจนต์กำลังโหลดเกิน
คุณไม่อาจทำให้เอเจนต์เชื่อถือได้หากตอบสองคำถามนี้ไม่ได้อย่างรวดเร็ว: มันทำอะไร? และ ทำไปทำไม? Observability สำหรับระบบเอเจนต์คือทำให้คำตอบเหล่านี้หาง่ายและแม่นยำ
ออกแบบ observability ให้ task เดียวมี trace ที่เชื่อมต่อผ่าน:
แนบ logs เชิงโครงสร้าง สำหรับการตัดสินใจสำคัญ (เช่น การเลือกเส้นทาง การปรับแผน การทริกเกอร์ guardrail) และ metrics สำหรับปริมาณและสุขภาพ
เทรซที่มีประโยชน์มักรวม:
บันทึก prompt อินพุต/เอาต์พุตของเครื่องมือในรูปแบบเชิงโครงสร้าง แต่ให้ผ่าน ชั้น redaction ก่อน:
เก็บเนื้อหาดิบไว้เบื้องหลัง feature flags ในสภาพแวดล้อมทดสอบ; production ควรมองเห็นแบบ redacted เป็นค่าปริยาย
อย่างน้อยที่สุด ให้ติดตาม:
เมื่อเกิด incident เทรซและ metrics ที่ดีจะช่วยเปลี่ยนจาก "เอเจนต์ดูล้ม" เป็นข้อความชัดเจนเช่น: “P95 งานล้มใน ToolSelection หลัง 2 retries เนื่องจากสกีมาใหม่ใน billing_service” ทำให้การวินิจฉัยลดจากชั่วโมงเป็นนาที และให้จุดปรับที่ชัดเจน
การทดสอบเอเจนต์คือการทดสอบทั้ง เครื่องมือ ที่มันเรียก และ โฟลว์ ที่เย็บทุกอย่างเข้าด้วยกัน จงปฏิบัติเหมือนการทดสอบระบบกระจาย ไม่ใช่แค่ปรับ prompt
เริ่มจาก unit tests ที่ขอบเขตเครื่องมือ:
การทดสอบเหล่านี้ไม่ขึ้นกับ LLM เรียกเครื่องมือโดยตรงด้วยอินพุตสังเคราะห์และยืนยันเอาต์พุตหรือข้อผิดพลาดที่แน่นอน
Integration tests ทดสอบเวิร์กโฟลว์เอเจนต์แบบ end-to-end: LLM + เครื่องมือ + ออร์เคสตรา
ออกแบบเป็นการทดสอบตามสถานการณ์:
การทดสอบเหล่านี้ยืนยัน การเปลี่ยนสถานะและการเรียกเครื่องมือ ไม่ใช่ทุก token ของคำตอบจาก LLM ตรวจสอบ: เรียกเครื่องมือใด ด้วยอาร์กิวเมนต์อะไร ตามลำดับใด และเอเจนต์จบที่สถานะ/ผลลัพธ์ใด
เพื่อให้การทดสอบทำซ้ำได้ ให้ fixture ทั้งการตอบของ LLM และผลลัพธ์เครื่องมือ:
รูปแบบทั่วไป:
with mocked_llm(fixtures_dir="fixtures/llm"), mocked_tools():
result = run_agent_scenario(input_case)
assert result.state == "COMPLETED"
ทุกการเปลี่ยน prompt หรือสกีมา ต้องรัน regression:
การพัฒนา schema (เพิ่มฟิลด์หรือเข้มข้นชนิด) ต้องมีกรณี regression ของตัวเองเพื่อตรวจจับเอเจนต์หรือเครื่องมือที่ยังสมมติสัญญาเดิม
อย่าส่งโมเดล นโยบาย หรือกลยุทธ์ routing ใหม่ตรงสู่การผลิต:
หลังผ่านเกตออฟไลน์แล้วเท่านั้นจึงอนุญาตให้ variant ใหม่เข้าสู่ production โดยปกติภายใต้ feature flags และการเปิดแบบค่อยเป็นค่อยไป
ล็อกเอเจนต์มักมีข้อมูลผู้ใช้ที่อ่อนไหว การทดสอบต้องเคารพเรื่องนี้:
กำหนดกฎเหล่านี้ใน CI pipeline เพื่อห้ามไม่ให้สร้างหรือเก็บ artifacts ของการทดสอบโดยไม่มีการตรวจสอบการนิรนาม
การปฏิบัติการเอเจนต์ใน productionใกล้เคียงกับการรันระบบกระจายมากกว่าการปล่อยโมเดลนิ่ง คุณต้องมีการควบคุมการเปิดตัว เป้าหมายความน่าเชื่อถือ และการจัดการการเปลี่ยนแปลงอย่างมีวินัย
แนะนำให้แนะนำเอเจนต์หรือพฤติกรรมใหม่แบบค่อยเป็นค่อยไป:
รองรับทั้งหมดด้วย feature flags และนโยบาย config: กฎการ routing เครื่องมือที่เปิดใช้งาน อุณหภูมิ การตั้งค่าความปลอดภัย การเปลี่ยนแปลงควรทำได้ด้วย config ไม่ใช่โค้ด และย้อนกลับได้ทันที
กำหนด SLO ที่สะท้อนทั้งสุขภาพระบบและมูลค่าผู้ใช้:
ผูกเข้ากับการแจ้งเตือนและปฏิบัติการ incident เช่นบริการอื่น ๆ: กำหนดความรับผิดชอบ runbooks สำหรับ triage และขั้นตอนเยียวยามาตรฐาน (rollback flag, drain ทราฟฟิก, safe-mode)
ใช้ล็อก เทรซ และทรานสคริปต์การสนทนาเพื่อปรับแต่ง prompts เครื่องมือ และนโยบาย ทำทุกการเปลี่ยนเป็น artifact ที่มีเวอร์ชัน มีการตรวจสอบ อนุมัติ และย้อนกลับ
หลีกเลี่ยงการเปลี่ยน prompt หรือเครื่องมือแบบเงียบ ๆ หากไม่มีการควบคุมการเปลี่ยนแปลง คุณจะจับสาเหตุการ regressions ไม่ได้และการตอบสนองต่อ incident จะกลายเป็นการเดาแทนการแก้ปัญหาเชิงวิศวกรรม
ระบบเอเจนต์ที่พร้อมใช้งานใน production ได้ประโยชน์จากการแยกความรับผิดชอบให้ชัดเจน เป้าหมายคือให้เอเจนต์ฉลาดในการตัดสินใจ แต่เรียบง่ายในโครงสร้างพื้นฐาน
1. Gateway / API edge
ทางเข้าหนึ่งเดียวสำหรับไคลเอนต์ (apps, services, UIs) ทำหน้าที่:
2. Orchestrator
Orchestrator เป็น "ลำคอ" ไม่ใช่สมอง มันประสานงาน:
LLM อยู่หลัง orchestrator ใช้โดย planner และโดยเครื่องมือที่ต้องการความเข้าใจภาษาเป็นพิเศษ
3. ชั้นเครื่องมือและการเก็บข้อมูล
โลจิกธุรกิจยังคงอยู่ใน microservices, คิว และระบบข้อมูลที่มีอยู่ เครื่องมือเป็น wrapper บาง ๆ รอบ:
Orchestrator เรียกเครื่องมือผ่านสัญญาที่เข้มงวด ขณะที่ระบบจัดเก็บยังคงเป็นแหล่งความจริง
บังคับ auth และ quotas ที่ gateway; บังคับความปลอดภัย การเข้าถึงข้อมูล และนโยบายใน orchestrator การเรียกทั้งหมด (LLM และเครื่องมือ) ปล่อยเทเลเมทรีเชิงโครงสร้างไปยัง pipeline ที่ป้อน:
สถาปัตยกรรมที่เรียบง่าย (gateway → orchestrator เดียว → tools) บริหารง่ายกว่า การเพิ่ม planner แยก policy engine และ model gateways เพิ่มความยืดหยุ่นแต่แลกกับความซับซ้อน เวลาแฝง และงานปฏิบัติการที่มากขึ้น
ตอนนี้คุณมีส่วนประกอบหลักสำหรับเอเจนต์ที่ทำงานทำนายได้ภายใต้ภาระงานจริง: state machines ชัดเจน สัญญาเครื่องมือที่ชัดเจน retry ที่มีวินัย และ observability เชิงลึก ขั้นตอนสุดท้ายคือเปลี่ยนแนวคิดเหล่านี้ให้เป็นแนวปฏิบัติที่ทำซ้ำได้สำหรับทีมของคุณ
คิดเอเจนต์แต่ละตัวเป็น เวิร์กโฟลว์มีสถานะ:
เมื่อชิ้นส่วนเหล่านี้สอดคล้องกัน คุณจะได้ระบบที่ค่อย ๆ ลดความสามารถเมื่อมีปัญหา แทนที่จะล้มครืนเมื่อเจอกรณีขอบ
ก่อนส่งเอเจนต์ต้นแบบให้ผู้ใช้จริง ให้ยืนยัน:
ถ้าข้อใดขาด คุณยังอยู่ในโหมดต้นแบบ
เซ็ตอัพที่ยั่งยืนมักแยกระหว่าง:
วิธีนี้ช่วยให้ทีมผลิตภัณฑ์เคลื่อนที่เร็ว ในขณะที่ทีมแพลตฟอร์มบังคับใช้ความน่าเชื่อถือ ความปลอดภัย และการควบคุมค่าใช้จ่าย
เมื่อคุณวางรากฐานมั่นคงแล้ว คุณสามารถสำรวจ:
ความก้าวหน้าควรเป็นไปแบบค่อยเป็นค่อยไป: ใส่องค์ประกอบการเรียนรู้ใหม่ ๆ ไว้ข้างหลัง feature flags ด้วยการประเมินแบบออฟไลน์และ guardrails ที่เข้มงวด
หัวข้อหลักตลอดบทความนี้คือ: ออกแบบเพื่อรับมือความล้มเหลว, เลือกความชัดเจนเหนือความเฉลียวฉลาด, และทำซ้ำในส่วนที่คุณมองเห็นและย้อนกลับได้ง่าย ภายใต้ข้อจำกัดเหล่านี้ ระบบเอเจนต์จะหยุดเป็นต้นแบบที่น่ากลัวและกลายเป็นโครงสร้างพื้นฐานที่องค์กรของคุณพึ่งพาได้
ระบบเอเจนต์ (agentic system) คือแอปพลิเคชันที่ LLM ไม่ได้ตอบแค่คำถามเดียว แต่ ตัดสินใจว่าจะทำอะไรต่อ: จะเรียกเครื่องมือใด จะดึงข้อมูลอะไร จะทำขั้นตอนไหนใน workflow และเมื่อไรที่ถือว่า "เสร็จ".
ต่างจากการเรียกแชทแบบธรรมดา ระบบเอเจนต์ประกอบด้วย:
ใน production โมเดลภาษาเป็นเพียงส่วนตัดสินใจหนึ่งภายในกรอบระบบที่ deterministic มากขึ้น ไม่ใช่ทั้งระบบทั้งหมด
งานสาธิตมักวิ่งบนเส้นทางที่สมบูรณ์แบบ: ผู้ใช้คนเดียว พฤติกรรมของเครื่องมือเป็นไปตามคาด ไม่มี timeout ไม่มีการเปลี่ยนรูปแบบสกีมา และการสนทนาไม่ยาวมาก ในการใช้งานจริง เอเจนต์ต้องเจอ:
ถ้าไม่มีเวิร์กโฟลว์ที่ชัดเจน สัญญา (contracts) ของเครื่องมือ และการจัดการความล้มเหลว ปัจจัยเหล่านี้จะสร้าง loop, stall, งานที่ทำไม่สมบูรณ์ และข้อผิดพลาดเงียบ ๆ ที่มักไม่ปรากฏในสภาพแวดล้อมสาธิต
ให้ LLM ทำงานภายใน กรอบที่ชัดเจน แทนวงลูปแบบเสรี:
วิธีนี้ช่วยให้คุณอธิบาย ทดสอบ และดีบักพฤติกรรมทีละขั้น แทนที่จะไล่ตาม "ความคิด" ของเอเจนต์ที่ไม่โปร่งใส
หมายถึงการมองเอเจนต์เป็นเวิร์กโฟลว์ที่มีชื่อสถานะและอีเวนต์ที่มีชนิดข้อมูล แทนการเขียน while not done: call LLM แบบทั่วไป
สถานะตัวอย่างอาจได้แก่:
ออกแบบเครื่องมือเหมือน API ที่พร้อมใช้ใน production ไม่ใช่คำอธิบายเป็นย่อหน้าซ่อนใน prompt แต่ละเครื่องมือควรมี:
คาดว่าการเรียกภายนอกทุกครั้งจะล้มเหลวสักครั้ง และออกแบบให้ความล้มเหลวนั้นถูกจัดการได้อย่างปลอดภัย
รูปแบบสำคัญ:
แยกระหว่าง สถานะระยะสั้น กับ หน่วยความจำระยะยาว และถือว่า LLM เป็นฟังก์ชันที่ไร้สถานะ
หลีกเลี่ยงการใช้ raw logs หรือประวัติการสนทนาเป็นหน่วยความจำโดยตรง ให้สกัดเป็นระเบียนเชิงโครงสร้างที่กะทัดรัดพร้อมนโยบายการเก็บรักษาและความเป็นส่วนตัว
มองระบบเอเจนต์เป็นระบบกระจายภายใต้ภาระงาน แม้แต่ flow ลำดับเดียวก็ตาม
เพื่อความน่าเชื่อถือ:
คุณต้องตอบได้ว่า “เอเจนต์ทำอะไร” และ “ทำไปเพราะอะไร” สำหรับแต่ละงานอย่างรวดเร็ว
สิ่งที่ต้องมีในการมองเห็น (observability):
ปฏิบัติกับเอเจนต์เหมือนบริการที่พัฒนาอย่างต่อเนื่อง ไม่ใช่ prompt แบบคงที่ และจัดการด้วยมาตรฐานการผลิตเดียวกับซอฟต์แวร์อื่น ๆ
แนวทางแนะนำ:
PLAN – แปลคำขอของผู้ใช้และสร้างแผนขั้นตอนCALL_TOOL – เรียกเครื่องมือหนึ่งครั้งหรือเป็นชุดของการเรียกVERIFY – ตรวจผลลัพธ์ของเครื่องมือกับกฎง่าย ๆ หรือการตรวจสอบด้วยโมเดลเสริมRECOVER – จัดการข้อผิดพลาดด้วย retry, fallback หรือการยกระดับDONE / FAILED – ผลลัพธ์ปลายทางอีเวนต์ (เช่น ToolCallSucceeded, TimeoutExceeded) บวกกับสถานะปัจจุบันจะกำหนดสถานะถัดไป ซึ่งทำให้การจัดการ retry และ timeout ชัดเจนแทนการกระจาย logic ไว้ใน prompts หรือโค้ดเชื่อม
InvalidInput, NotFound, RateLimited, TransientFailure พร้อมความหมายที่ชัดเจนให้เอกสารสกีมาแบบมีโครงสร้างกับโมเดล แทนที่จะเป็นกำแพงของข้อความ Prompt planner ควรรู้ว่าข้อผิดพลาดแบบใด retry ได้ แบบใดต้องรบกวนผู้ใช้ และแบบใดต้องหยุดเวิร์กโฟลว์
request_idวิธีนี้ช่วยรักษาความน่าเชื่อถือโดยไม่เกิด loop วิ่งไม่หยุด ผลกระทบซ้ำ หรือค่าใช้จ่ายพุ่ง
ติดตามความลึกของคิว latency percentiles และอัตรา 429/503 เป็นสัญญาณเตือนว่าระบบกำลังรับภาระเกิน
ด้วยข้อมูลเหล่านี้ การไล่ปัญหาจะเปลี่ยนจาก "เอเจนต์ดูผิดปกติ" เป็นการชี้จุดสถานะ เครื่องมือ และการเปลี่ยนแปลงที่ก่อปัญหาได้อย่างชัดเจน
วิธีนี้ช่วยให้พัฒนาเอเจนต์ต่อเนื่องได้โดยยังคงควบคุมความล้มเหลวให้อยู่ในขอบเขตที่ตรวจสอบและย้อนกลับได้