ข้าม​ไป​ยัง​เนื้อหา

Anti-Corruption Layer → ต่อ tool/API ภายนอก

บท​ที่ 5 เรา​วาด Context MapContext Mapแผนภาพ​ที่​วาด​ทุก Bounded Context และ​ความ​สัมพันธ์​ระหว่าง​กัน — ใน​ระบบ multi-agent คือ​แผนภาพ​ที่​วาด​ว่า agent ไหน​คุย​กับ agent ไหน ใคร​เป็นต้น​น้ำ (กำหนด​รูปแบบ​ข้อมูล) ใคร​เป็น​ปลาย​น้ำ ก่อน​จะ​ปล่อย​ให้ agent เรียก​กันเอง​มั่ว ๆStrategic Design ของ​ระบบ ops-copilot เสร็จ — ใคร​เป็นต้น​น้ำ ใคร​ปลาย​น้ำ และ​ย้ำ​อีก​ครั้ง​ว่า Multi-agentMulti-agentระบบ​ที่​มี agent มากกว่า​หนึ่ง​ตัว​ทำงาน​ร่วม​กัน แต่ละ​ตัว​ควร​มี Bounded Context ของ​ตัวเอง​ชัดเจน​และ​เชื่อม​กัน​ผ่าน context map/handoff ที่​ออกแบบ​ไว้ — ไม่ใช่​คำ​ตอบ​สำเร็จรูป​สำหรับ​ทุก​ปัญหา หลาย​งาน​ทำ​ด้วย agent เดียว​หรือ workflow ธรรมดา​ก็​เพียงพอ​และ​เชื่อถือ​ได้​กว่าArchitecture เป็น​ข้อ​ยกเว้น​ที่​ต้อง​มี​เหตุผล ไม่ใช่​ค่า​ตั้งต้น บท​นี้​ซูม​เข้าไป​ที่​เส้น​ขอบ เส้น​หนึ่ง บน​แผนที่​นั้น — จุด​ที่ AgentAgentระบบ​ซอฟต์แวร์​ที่​รับ​เป้าหมาย​แล้ว​วางแผน-ตัดสิน​ใจ-เรียก​ใช้ tool ได้​เอง​หลาย​รอบ (agentic loop) โดย​ไม่​ต้อง​มี​มนุษย์​กำกับ​ทุก​ก้าว ต่าง​จาก​โปรแกรม​ทั่วไป​ที่​รัน​ตาม​ลำดับ​คำ​สั่ง​ตายตัว — ใน​คอร์ส​นี้​มอง​แต่ละ agent เหมือน1 Bounded Context ที่​ต้อง​มี​ขอบเขต ภาษา และ​หน้าที่​ของ​ตัวเอง​ชัดเจนArchitecture ตัว​หนึ่ง​เอื้อม​มือ​ออก​ไป​เรียก​ของนอก​ขอบเขต​ของ​มัน: ฐาน​ข้อมูล​ออเดอร์ ระบบ​ชำระ​เงิน คิว​ครัว ระบบ​พวก​นั้น​ไม่​ได้​พูด​ภาษา​เดียว​กับ agent และ​ถ้า​เรา​ต่อ​มัน​เข้า​มา​ดิบๆ ความ​รก​ทั้งหมด​จะ​ไหล​เข้าไป​กอง context ของ agent ทันที คำถาม​ของ​บท​นี้​ประโยค​เดียว: จะ​กั้น​ความ​รก​นั้น​ไว้​ที่​ขอบ​ได้​ยังไง — และ​คำ​ตอบ​คือ​เครื่องมือ​เก่า​แก่​ของ DDD ที่​เกิด​มา​เพื่อ​เส้น​แบบ​นี้​พอดี

📦 code ตัวอย่าง

คอร์ส​นี้​เป็น คอร์ส​ออกแบบ ไม่ใช่​ทัวร์ SDK — code ใน​บท​คือ ภาพร่าง ของ tool schema และโทโพโล​ยี (Thai Mermaid + pseudo-config สั้นๆ) ไม่ใช่ app ที่​รัน​ได้​จริง ตัวอย่าง​ต่อยอด​จาก domain เดิม​ที่ repo kaen-food-ordering (กำลัง​จัด​ทำ) โดย​มอง​มัน​ผ่าน​เลนส์ ops-copilot ที่​ช่วย​ทีม​ปฏิบัติการ​ของ platform

order-service ที่​เก็บ​ออเดอร์​ไม่​ได้​ถูก​ออกแบบ​มา​ให้ model อ่าน มัน​ถูก​ออกแบบ​มา​ให้​เครื่อง​อ่าน — มัน​คืน UUID เป็น​ตัว​ระบุ, payload JSON สี่10 field, สถานะ​เป็น enum ตัวเลข​ภายใน, และ​เวลา​พัง​ก็​โยน HTTP 500 พร้อม stack trace กลับ​มา นี่​คือ model ของ SubdomainSubdomainส่วน​ย่อย​ของ​ปัญหา​ทาง​ธุรกิจ (problem space) แบ่ง​เป็น core, supporting, generic — ก่อน​จะ​ออกแบบ​ว่า​จะ​มี agent กี่​ตัว​และ​แต่ละ​ตัว​ทำ​อะไร ต้อง​วิเคราะห์ subdomain ของ​ธุรกิจ​ก่อน​เสมอ ไม่ใช่​เริ่ม​จาก​อยาก 'มี agent' แล้ว​ค่อย​หา​เรื่อง​ให้​มัน​ทำStrategic Design คนละ​อัน​กับ Order-Tracking agent — มัน​มี​เหตุผล​ของ​มัน​ใน​บริบท​ของ​มัน​เอง แต่​ไม่ใช่​ภาษา​ที่ agent ใช้​ตัดสิน​ใจ​ได้

ถ้า​เรา​ปั้น ToolToolfunction หรือ API ภายนอก​ที่ agent เรียก​ใช้ได้​เพื่อ​กระทำ​สิ่ง​ที่ model ภาษา​เอง​ทำ​ไม่​ได้ เช่น ค้น​เว็บ อ่าน file เรียก​ฐาน​ข้อมูล — ขอบเขต​ของ​ชุด tool ที่ agent หนึ่ง​ถือ​อยู่​ก็​คือ​ส่วน​หนึ่ง​ที่​นิยาม Bounded Context ของ agent นั้น ยิ่ง tool set กว้าง​เกิน​หน้าที่ ยิ่ง​เสี่ยง​ให้ agent ล้ำ​ขอบเขตArchitecture ที่​แค่​ส่ง response ก้อน​นั้น​กลับ​เข้า​มาตรงๆ ปัญหา​ไม่​ได้​จบ​แค่ “อ่าน​ยาก” — ทุก field ที่ agent ไม่​ได้​ใช้​ก็​ยัง​กิน งบ attention เท่ากับ field ที่​ใช้ นี่​คือ Context RotContext Rotอาการ​ที่​คุณภาพ​การ​ตอบ​ของ agent เสื่อม​ลง​เมื่อ context window ยาว​ขึ้น​และ​สะสม​สิ่ง​ไม่​เกี่ยวข้อง​มาก​ขึ้น​เรื่อย ๆ ระหว่าง​วน agentic loop หลาย​รอบ — เป็น​เหตุผล​เชิง​เทคนิค​ข้อ​หนึ่ง​ที่ agent ควร​มี​ขอบเขต​หน้าที่​แคบ (เหมือน Bounded Context) แทนที่​จะ​ยัด​ทุก​อย่าง​ไว้​ใน agent เดียว​ที่ context ยาว​ขึ้น​เรื่อย ๆProcess จาก​บท​ที่ 1 ใน​คราบ​ใหม่: ยิ่ง payload บวม ความ​สามารถ​ใน​การ​ดึง​ข้อเท็จจริง​ชิ้น​ที่​สำคัญ ณ ตา​นั้น​ยิ่ง​จาง และ​เพราะ Agentic LoopAgentic Loopวงจร​ที่ agent ทำซ้ำ​จนกว่า​จะ​บรรลุ​เป้าหมาย: รับ input → วางแผน/ตัดสิน​ใจ → เรียก tool → สังเกต​ผลลัพธ์ → วน​กลับ​ไป​ตัดสิน​ใจ​ใหม่ — ต่าง​จาก​โปรแกรม​ทั่วไป​ที่​รัน​เส้นทาง​เดียว​จบ วงจร​นี้​เอง​ที่​ทำให้ agent ยืดหยุ่น แต่​ก็​เสี่ยง context rot ถ้า​วน​นาน​เกิน​ไป​โดย​ไม่มี​ขอบเขตProcess เอา​ผล tool กลับ​เข้า context ทุกรอบ ต้นทุน​ก้อน​นี้​จ่าย​ซ้ำ​ทุกรอบ​ที่​วน ไม่ใช่​ครั้ง​เดียว​จบ

ตรง​นี้​เอง​ที่ Anti-Corruption LayerAnti-Corruption Layer (ACL)ชั้น​แปล​ภาษา/model ที่​กั้น​ระหว่าง context สอง​อัน ไม่​ให้ model ของ​อีก​ฝ่าย​รั่ว​เข้า​มา​ปน​เปื้อน — เมื่อ agent เรียก tool หรือ agent อื่น​จาก​ภายนอก ควร​มี​ชั้น​แปล​ผลลัพธ์​กลับ​มา​เป็น​ภาษา​ของ agent เรา​เอง ไม่​ปล่อย​ให้ schema แปลก ๆ ของ​ฝั่ง​นู้น​ไหล​เข้า​มา​ปน​ใน context ของ​เราStrategic Design ของ DDD เข้า​มา​เป๊ะๆ ACL คลาสสิก​คือ​ชั้น​แปล​ที่​คั่น​ระหว่าง Bounded ContextBounded Contextขอบเขต​ที่ ubiquitous language และ model หนึ่ง​ชุด​มี​ความหมาย​คง​เส้น​คง​วา นอก​ขอบเขต​นี้​คำ​เดียวกัน​อาจ​หมาย​ถึง​คนละ​อย่าง — เมื่อ​ออกแบบ​ระบบ agent ให้​คิด​ว่า​แต่ละ agent (หรือ​กลุ่ม agent ที่​ทำงาน​ร่วม​กัน) ควร​รับผิดชอบ Bounded Context เดียว ไม่ใช่​ยัด​ทุก​หน้าที่​ไว้​ใน agent เดียว หรือ​กระจาย agent ตาม​อำเภอ​ใจStrategic Design สอง​อัน ไม่​ให้ model ของ​ฝั่ง​ต้นน้ำ​รั่ว​เข้า​มา​ปน​เปื้อน code เรา — สิ่ง​ที่​มัน​รักษา​คือ code ของ​เรา จาก​การ​เปลี่ยน​รูป​ของ schema ต้นน้ำ tool ของ agent ทำงาน​นั้น​เหมือน​กัน​ทุก​ประการ บวก​อีก​หนึ่ง​หน้าที่: มัน​ยัง​ต้อง​รักษา ตัว model จาก​รูป​ดิบ​และ​ความ verbose ของ backend ด้วย เพราะ​ฝั่ง​ที่​บริโภค​ผล​ไม่ใช่ code deterministic แต่​เป็น model ภาษา​ที่​มี​งบ attention จำกัด

พูด​ให้​เป็น​วินัย: tool ที่​ดี​คือ Anti-Corruption Layer ไม่ใช่​ท่อ​ส่ง API ดิบ Writing effective tools for AI agents (Anthropic) สรุป​หน้าที่​ของ​ชั้น​แปล​นี้​ไว้​สาม​อย่าง:

  • คืน​ข้อมูล​สัญญาณ​สูง (high-signal) — เฉพาะ field ที่ agent ต้อง​ใช้​ตัดสิน​ใจ​ก้าว​ถัด​ไป ไม่ใช่ payload ทั้ง​ก้อน ทุก field ที่​ตัด​ออก​คือ​งบ attention ที่​คืน​กลับ​มา
  • ใช้​ตัว​ระบุ​เชิง​ความหมาย​ที่​เสถียร — คืน​ชื่อ/slug/เลข​ออเดอร์​ที่​มนุษย์​กับ model reason ด้วย​ได้ ไม่ใช่ UUID ดิบ​หรือ handle ทึบๆ ผลลัพธ์​ที่​สะอาด​นี้​เอง​คือ Ubiquitous LanguageUbiquitous Languageภาษา​กลาง​ที่​ทีม​และ​ผู้เชี่ยวชาญ​ธุรกิจ​ใช้​ร่วม​กัน อิง​กับ model โดยตรง — สำหรับ agent แล้ว ภาษา​นี้​คือ​คำ​ศัพท์​ที่​ปรากฏ​ใน system prompt ชื่อ tool และ schema ของ​มัน​ด้วย ถ้า​คำ​ใน code agent ไม่​ตรง​กับ​คำ​ที่​ผู้เชี่ยวชาญ​ธุรกิจ​ใช้ แปล​ว่า​กำลัง​หลง​ทางStrategic Design ของ agent ที่​ปรากฏ​จริง​ใน​บริบท
  • error ที่​เจาะจง​และ​แก้​ได้ — ไม่ใช่ HTTP 500 กับ stack trace แต่​เป็น​ข้อความ​ที่​บอก model ว่า เกิด​อะไร และ ควร​ลอง​อะไร​ต่อ

version ที่​พลาด​คือ​ปล่อย​ให้ backend ไหล​เข้า​มา​ทั้งดุ้น:

❌ version ดิบ: tool ที่​ยัด response ดิบ​ของ backend เข้า context ตรง ๆ
tool: get_order
returns: |
# ส่ง response ของ order-service กลับตรง ๆ ทั้งก้อน
{
"order_id": "9f2c1b7a-3e5d-4a11-b2c8-77e0a1f3de71", # UUID ทึบ
"customer_id": "c_0b9e4f...",
"restaurant_id": "r_5521aa...",
"line_items": [ ... 30 บรรทัด ... ],
"status_code": 7, # enum ภายใน ไม่มีความหมายใน context
"internal_flags": { ... },
"audit_trail": [ ... ],
# ...อีกสามสิบกว่า field ที่ agent ไม่ได้ใช้ แต่กินงบ attention เท่ากัน
}
error: "HTTP 500: NullPointerException at OrderService.java:214"

version ที่​เป็น ACL แปล​ทุก​อย่าง​ให้​เป็น​ภาษา​สะอาด​ก่อน​คืน:

✅ tool ใน​ฐานะ ACL: แปล backend เป็น​ภาษา​สะอาด​ของ agent
tool: get_order_status
description: |
ดูสถานะและ ETA ของออเดอร์จากเลขออเดอร์ 6 หลัก (เช่น A-4821)
ใช้เมื่อผู้ใช้ถามว่า "ออเดอร์ถึงไหนแล้ว"
input:
order_no: string # เลขที่ลูกค้าเห็นบนใบเสร็จ ไม่ใช่ UUID ภายใน
returns: |
{
"order_no": "A-4821",
"status": "กำลังจัดส่ง", # แปลจาก enum 7 -> คำที่มีความหมาย
"eta_min": 12,
"restaurant": { "name": "ส้มตำนัว", "slug": "somtam-nua" }
}
errors:
- not_found: "ไม่พบออเดอร์ A-4821 — ขอเลขออเดอร์ 6 หลักจากลูกค้าอีกครั้ง"
- ambiguous: "พบหลายออเดอร์ใกล้เคียง ระบุเลขให้ครบ 6 หลัก"

จุด​ที่​ดู​เล็ก​แต่​สำคัญ​ที่สุด​คือ ตัว​ระบุ UUID ดิบ​เป็น​ค่า opaque — model reason กับ​มัน​ไม่​ได้ จำ​ข้าม​รอบ​ได้​ยาก และ​ถ้า​มัน​จำ/พิมพ์​ผิด​ตัว​เดียว​ใน 9f2c1b7a... การ​เรียก​ครั้ง​ต่อ​ไป​ก็​พลาด​แบบ​เงียบๆ โดย​ไม่มี​สัญญาณ​ว่า​เพราะ​อะไร ตรง​ข้าม​กับ​ตัว​ระบุ​เชิง​ความหมาย​ที่​เสถียร​อย่าง​เลข​ออเดอร์ A-4821 หรือ​ร้าน slug somtam-nua:

  • มัน​เป็น​ส่วน​หนึ่ง​ของ ubiquitous language อยู่​แล้ว — ทั้ง​ลูกค้า พนักงาน และ model ใช้​คำ​เดียวกัน tool จึง​ไม่​ได้​สร้าง​ศัพท์​ใหม่​ให้​จำ
  • มัน​รอด compaction/summarization ได้​ดี​กว่า เพราะ​เป็น​คำ​ที่​มี​ความหมาย ไม่ใช่​สาย​อักขระ​สุ่ม​ที่​ถูก​ย่อ​แล้ว​เพี้ยน​ง่าย
  • มัน​ตรวจสอบ​ได้ — รูปแบบ A-4821 ผิด​ปกติ​เมื่อไร​ก็​เห็น ต่าง​จาก UUID ที่​ผิด​หนึ่ง​ตัว​ก็​ยัง​ดู “เหมือน​จริง”

การ​คืน slug จึง​ไม่ใช่​แค่​เรื่อง​ความ​สวยงาม​ของ output แต่​คือ​การ​เลือก​ภาษา​ที่ caller ซึ่ง​เป็น model ใช้​ต่อ​ได้​จริง

นี่​คือ​ความ​ต่าง​ที่​ลึก​ที่สุด​ระหว่าง tool ของ agent กับ API ธรรมดา API ทั่วไป​สมมติ​ว่า caller เป็น code deterministic — เรียก​ตรง​ตาม​เอกสาร​เป๊ะ​ทุก​ครั้ง แต่ caller ของ tool คือ agent ที่ ไม่ deterministic: มัน​อาจ​อ่าน schema ผิด, hallucinate parameter ที่​ไม่มี​จริง, เรียก​ผิด​ตัว, หรือ​ส่ง id ที่​มัน​แต่ง​ขึ้น​เอง tool ที่​ดี​จึง​ไม่ใช่ passthrough ที่​เชื่อ​ว่า caller เรียก​ถูก​เสมอ แต่​เป็น contract ที่​ถูก harden ไว้​ต่อ caller ที่​ใช้​ผิด​ได้ — ออกแบบ​โดย​ตั้ง​สมมติฐาน​ว่าการ​ใช้​ผิด​จะ​เกิด​ขึ้น​จริง:

  • schema ที่​บรรยาย​ชัด​และ​ตั้ง​ชื่อ​ตรง​กับ ubiquitous language — เพื่อ​ให้ model เลือก tool ถูก​ตัว​และ​กรอก field ถูก​ตั้งแต่​แรก
  • ตรวจ input ให้ fail เร็ว​และ​ดัง — id รูปแบบ​ผิด​ต้อง​ถูก​ปฏิเสธ​ทันที​พร้อม​บอกว่า​ผิด​ตรง​ไหน ไม่ใช่​ยิง​เข้า backend แล้ว​พัง​ลึก
  • รับ input ที่​ผ่อนปรน — รับ​เลข​ออเดอร์ 6 หลัก​ที่​ลูกค้า​มี​จริง แทนที่​จะ​บังคับ UUID ภายใน​ที่ model ไม่มี​ทาง​รู้
  • เขียน error ให้​สอน model ว่า​จะ​กู้​ยังไงไม่พบออเดอร์ A-4821 — ขอเลขออเดอร์ 6 หลักจากลูกค้าอีกครั้ง มี​ค่า​กว่า HTTP 404 มหาศาล เพราะ​มัน​บอก​ก้าว​ถัด​ไป

นี่​คือ GuardrailGuardrailกติกา​ที่​ควบคุม​ไม่​ให้ agent ทำ​เกิน​ขอบเขต​หรือ​ก่อ​ความ​เสียหาย เช่น จำกัด tool ที่​เรียก​ได้ ตรวจ output ก่อน​ส่ง​ออก บังคับ human approval สำหรับ​การกระทำ​ที่​ย้อน​กลับ​ไม่​ได้ — เป็น​สิ่ง​ที่​รักษา​ขอบเขต​ของ Bounded Context ของ agent ให้​ไม่​ล้ำเส้นProcess ที่​ระดับ tool boundary โดยตรง: ชั้น​แปล​ไม่​ได้​แค่​ทำให้​ข้อมูล​สะอาด แต่​ทำให้​ตัว contract ทน​ต่อ​การ​ถูก​เรียก​แบบมั่วๆ ได้​ด้วย

ต้อง​พูด​ให้​ตรง​จุด​หนึ่ง​ไม่​ให้​เข้าใจ​ผิด ใน​โลก DDD บาง Bounded Context มี aggregate ที่ enforce invariant แบบ atomic — พอ aggregate รับคำ​สั่ง invariant ก็​เป็น​จริง​ทันที ณ วินาที​นั้น แบบ transaction มัน​น่า​เผลอ​คิด​ว่า tool-ใน​ฐานะ-ACL ให้​หลัก​ประกัน​เดียวกัน คือ “ข้อมูล​สะอาด​เข้าไป​แล้ว กฎ​ก็​ถูก​รักษา” — แต่​มัน​ไม่ใช่ tool ทำความ​สะอาด​ข้อมูล ตรง​จุด​เข้า เท่านั้น ส่วน context ของ agent ที่​อยู่​ถัด​จาก​นั้น​ไม่ใช่​ขอบเขต transaction หลัง compaction หรือ summarization ข้อเท็จจริง​สะอาด​ที่ tool คืน​มา (เลข​ออเดอร์​ที่​ถูกต้อง หรือ​กฎ “คืน​เงิน​ต้อง​มี​คน​อนุมัติ”) อาจ​ถูก​ตัด​ทิ้ง ถูก​บีบ​จน​เพี้ยน หรือ​ถูก hallucinate ขึ้น​ใหม่​ได้

ดังนั้น ACL ที่​ระดับ tool เป็นการ​รักษา​แบบ best-effort ไม่ใช่​การ​บังคับ​แบบ atomic ตลอด​กาล มัน​ลด​การ​ปน​เปื้อน​ที่​ประตู แต่​ไม่​การันตี​ว่า​ความ​สะอาด​จะ​อยู่​ยง​ตลอด session — และ​นี่​คือ​เหตุผลตรงๆ ว่า​ทำไม​บท​ก่อนๆ ถึง​ต้อง​วาง​ชั้น​อื่น​ทับ​เข้าไป: Agent MemoryAgent Memoryกลไก​ที่ agent เก็บ​ข้อมูล​ข้าม​รอบ​ของ agentic loop หรือ​ข้าม session เช่น สรุป​บทสนทนา​เก่า บันทึก​ข้อเท็จจริง​ระยะ​ยาว หรือ​ผลลัพธ์​ก่อน​หน้าที่​ต้อง​อ้างอิง​ต่อ — ออกแบบ​ให้​ดี​ต้อง​เลือก​ว่า​อะไร​ควร​เก็บ อะไร​ควร​ทิ้ง ไม่ใช่​ยัด​ประวัติ​ทั้งหมด​กลับ​เข้า context ทุก​ครั้ง​จน​เกิด context rotArchitecture เพื่อ​ดึง​ข้อเท็จจริง​กลับ​ขึ้น​มา​ย้ำ, guardrail กับ Human-in-the-loopHuman-in-the-loopการ​ออกแบบ​ให้​มนุษย์​เข้า​มา​ตรวจสอบ​หรือ​อนุมัติ​ใน​จุด​ที่​การกระทำ​ของ agent มี​ความ​เสี่ยง​สูง​หรือ​ย้อน​กลับ​ไม่​ได้ เช่น ก่อน​โอน​เงิน​หรือ​ลบ​ข้อมูล​จริง — เป็น guardrail ชนิด​หนึ่ง​ที่​ยัง​จำเป็น​แม้ agent จะ​ฉลาด​ขึ้น​เรื่อย ๆ เพราะ​บาง​การ​ตัดสิน​ใจ​ไม่​ควร​ปล่อย​ให้ agent ตัดสิน​ใจ​เอง​ทั้งหมดProcess เพื่อ hard-stop การกระทำ​ที่​ย้อน​ไม่​ได้​ไม่​ว่า context จะ​บอก​อะไร, และ EvalEvalการ​วัดผล​อย่าง​เป็น​ระบบ​ว่า agent ทำงาน​ตรง​ตาม​ที่​ออกแบบ​ไว้​จริง​หรือ​ไม่ ด้วย​ชุด​กรณี​ทดสอบ​และ​เกณฑ์​ที่​ชัดเจน แทน​การ​ดู​จาก​ความ​รู้สึก​ว่า 'ตอบ​ดู​ดี' — จำเป็น​เพราะ agentic loop มี​ความ​ไม่​แน่นอน​สูง​กว่า code ทั่วไป ต้อง​มี eval ก่อน​เชื่อ​ว่า Bounded Context ของ agent ทำงาน​ถูกต้อง​ตาม​สัญญาProcess เพื่อ​วัด​ว่า​ขอบ​นี้​กั้น​ได้​จริง​ใน​ทาง​ปฏิบัติ​หรือ​เปล่า tool boundary จำเป็น แต่​ไม่​พอ​ด้วย​ตัว​มัน​เอง

flowchart LR
  subgraph BE["❌ backend รก — model ภายในของ order-service"]
    RAW["order_id: 9f2c...de71 (UUID ทึบ)<br/>payload JSON เต็ม 40 field<br/>status_code: 7 (enum ภายใน)<br/>error: HTTP 500 + stack trace"]
  end
  subgraph ACL["tool = Anti-Corruption Layer (ชั้นแปล)"]
    T["get_order_status(order_no)<br/>• ตัดเหลือ field สัญญาณสูง<br/>• UUID → เลขออเดอร์/slug ที่เสถียร<br/>• enum → คำที่มีความหมาย<br/>• error ดิบ → error เจาะจงที่แก้ได้"]
  end
  subgraph AG["✅ ภาษาสะอาดของ agent — Order-Tracking"]
    CLEAN["order_no: A-4821<br/>status: กำลังจัดส่ง<br/>eta_min: 12<br/>restaurant: ส้มตำนัว (somtam-nua)"]
  end
  RAW ==>|"agent ไม่ต้องเห็นความรกนี้"| T
  T ==>|"คืนเฉพาะสิ่งที่ใช้ตัดสินใจรอบถัดไป"| CLEAN
  classDef raw fill:#dc2626,stroke:#7f1d1d,color:#f8fafc;
  classDef acl fill:#fde68a,stroke:#b45309,color:#1a1a1f;
  classDef clean fill:#c7d2fe,stroke:#3730a3,color:#1a1a1f;
  class RAW raw;
  class T acl;
  class CLEAN clean;

คำ​บรรยาย​ภาพ: ฝั่ง​ซ้าย (แดง) คือ model ภายใน​ของ order-service ที่​รก​ด้วย UUID ทึบ payload เต็ม​ก้อน enum ภายใน และ error ดิบ — เหมาะ​กับ caller ที่​เป็น code ไม่ใช่ model ตรง​กลาง (เหลือง) คือ tool ที่​ทำ​หน้าที่ Anti-Corruption Layer: ตัด​ให้​เหลือ field สัญญาณ​สูง แปลง UUID เป็น​เลข​ออเดอร์/slug ที่​เสถียร แปลง enum เป็น​คำ​ที่​มี​ความหมาย และ​เปลี่ยน error ดิบ​เป็น error ที่​บอก​ก้าว​ถัด​ไป ฝั่ง​ขวา (น้ำเงิน) คือ​ภาษา​สะอาด​ที่ agent อ่าน​แล้ว​ตัดสิน​ใจ​ต่อ​ได้​ทันที ย้ำ​ว่า​เส้น​แปล​นี้​กั้น​ความ​ปน​เปื้อน​ได้​แค่ ตรง​จุด​เข้า — context ที่​อยู่​ถัด​ไป​ไม่ใช่​ขอบเขต atomic แบบ aggregate ความ​สะอาด​จึง​เป็น best-effort ที่​ยัง​ต้อง​มี memory + guardrail + eval หนุนหลัง

tool ไม่ใช่​แค่ “ปุ่ม​ให้ agent กด” แต่​คือ Anti-Corruption Layer ที่​ลาก​เส้น​ภาษา​ระหว่าง agent กับ​โลก​ภายนอก — คืน​ข้อมูล​สัญญาณ​สูง ใช้​ตัว​ระบุ​ที่​เสถียร​และ​มี​ความหมาย โยน error ที่​แก้​ได้ และ​ถูก harden ไว้​ต่อ caller ที่​ไม่ deterministic ทำ​ถูก ความ​รก​ของ backend ก็​จบ​ที่​ขอบ ไม่​ไหล​เข้าไป​เน่า context

สังเกต​ว่า schema ของ tool ที่​เรา​ตั้งใจ​ออกแบบ​ตรง​นี้ คือ​รูป​แรก​ของ สัญญา​ข้าม​ขอบเขต — มัน​คือ Published LanguagePublished Languageภาษา​กลาง​ที่​เอกสาร​ไว้​ชัดเจน​สำหรับ​แลกเปลี่ยน​ข้อมูล​ข้าม context — คือ schema ของ tool call ข้อความ handoff และ output format ที่ agent หนึ่ง​ส่ง​ให้​อีก agent หนึ่ง ต้อง​นิ่ง​และ​มี​สัญญา​ชัดเจน​เหมือน API ระหว่าง​ทีม ไม่ใช่​ข้อความ​ธรรมชาติ​ที่​ตีความ​เอา​เองStrategic Design version ย่อ ระหว่าง agent กับ backend หนึ่ง​ตัว บท​ที่ 7 จะ​ยก​แนวคิด​เดียวกัน​นี้​ขึ้น​อีก​ชั้น: เมื่อ agent ต้อง​คุย กับ agent อีก​ตัว สัญญา​นั้น​ต้อง​นิ่ง​และ​ชัด​ยิ่ง​กว่า​เดิม เรา​จะ​แยก HandoffHandoffการ​ส่ง​ต่อ​การ​ควบคุม​บทสนทนา/งาน​จาก agent หนึ่ง​ไป​อีก agent หนึ่ง​อย่าง​มี​สัญญา​ชัดเจน​ว่า​ส่ง​อะไร​ไป​พร้อม​บริบท​เท่า​ไหร่ — คือ​จุด​ที่ Published Language ระหว่าง2 Bounded Context ถูก​ใช้งาน​จริง ถ้า handoff ไม่​ชัด บริบท​จะ​หาย​หรือ​ปน​กัน​ระหว่าง​ทางProcess (โอน​การ​ควบคุม​ถาวร) ออก​จาก delegation (มอบ​งาน​แล้ว​รอ​ผลกลับ) ให้​ขาด และ​ดู​ว่า published language ทำให้​สอง​ขอบเขต​คุย​กัน​ได้​โดย​ไม่​ปน​เปื้อน​กัน​ยังไง


🔗 อ้างอิง​เพิ่มเติม​ใน DevIQ

เจาะ​ลึก​แนวคิด​ใน​บท​นี้​ต่อ​ได้ที่​คลัง​อ้างอิง DevIQ:

  • Anti-Corruption Layer (ACL) — ชั้น​แปล​ที่​คั่น2 context ไม่​ให้ model ของ​อีก​ฝ่าย​รั่ว​เข้า​มา​ปน หัวใจ​ที่​บท​นี้​ยก​มา​สวม​ร่าง​เป็น tool ของ agent
  • Context Mapping — แผนที่​ความ​สัมพันธ์​ระหว่าง context ที่​บอกว่า​เส้น​ไหน​ต้อง​มี ACL คั่น
  • Bounded Context — ขอบเขต​ที่​ภาษา​หนึ่ง​ชุด​คง​ความหมาย​ไว้ สิ่ง​ที่ ACL คอย​รักษา​ไม่​ให้​ปน​เปื้อน

เช็กความเข้าใจ — บทที่ 6

ข้อ 1 / 3

tool ของ agent ทำหน้าที่เป็น Anti-Corruption Layer อย่างไร?