Ubiquitous Language ของ MCP server
บทที่ 4 ปิดด้วยเส้นแบ่ง “ใครควบคุมการเรียก” ระหว่าง tool กับ resource บทนี้ถอยออกมามองพื้นผิวทั้งก้อน แล้วถามคำถามที่ลึกกว่า: เมื่อ server เปิด primitive ออกมา มันไม่ได้เปิดแค่ function — มันเปิด ภาษา ออกมาด้วย ชื่อ tool, ชื่อ resource, ข้อความอธิบายแต่ละบรรทัด คือถ้อยคำที่ model อ่านแล้วใช้ตัดสินใจว่าจะทำอะไรต่อ นี่คือจุดที่วินัยของ DDD ที่คอร์สนี้ยืมมาตลอดกลับมาเต็มตัว: พื้นผิวของ server คือ ubiquitous language ของ bounded context นั้น
คอร์สนี้เป็น คอร์สออกแบบ ไม่ใช่ทัวร์ SDK — code ในบทนี้คือ ภาพร่าง ของ schema และการตั้งชื่อ (tool-schema sketch + Thai Mermaid) ไม่ใช่ server ที่รันได้จริง ตัวอย่างต่อยอดจาก domain เดิมที่ repo kaen-food-ordering (กำลังจัดทำ) โดยมองระบบภายในของ platform ฟู้ดเดลิเวอรี (ออเดอร์ ครัว การเงิน) ที่ถูกห่อเป็น MCP server ให้ ops-copilot เรียกใช้
spec MCP ไม่มีคำว่า “ubiquitous language” อยู่ในนั้น — การมองพื้นผิว server เป็น UL เป็น มุมเชิงการสอนของคอร์สนี้เอง (ต่อยอดจากสายเลือด DDD ของมัน) สิ่งที่มาจากแหล่งปฐมภูมิจริงๆ คือหลักการออกแบบ tool (การตั้ง namespace และชื่อที่มีความหมาย) และหลักความปลอดภัย (คำอธิบายไม่น่าเชื่อถือโดยปริยาย) ที่เราจะเอามาร้อยเข้าด้วยกันด้วยเลนส์นี้
ชื่อและคำอธิบายคือภาษาที่ model ใช้คิด
หัวข้อที่มีชื่อว่า “ชื่อและคำอธิบายคือภาษาที่ model ใช้คิด”ToolToolfunction ที่ Server ประกาศให้ model เรียกเองได้ระหว่างให้เหตุผล เช่น ค้นหาออเดอร์ หรือยิง refund มักมีผลข้างเคียงจริง (side effect) — เป็น Primitive แบบ Model-controlled ต้องระวัง parameter ผิด สิทธิ์เกินจำเป็น และคำอธิบาย tool ที่ถูกฝังคำสั่งแฝงTactical Design แต่ละตัวที่ server ประกาศออกมา model ไม่ได้ “เห็น code” ของมัน — มันเห็นแค่ ชื่อ กับ คำอธิบาย กับ รูปร่าง parameter แล้วต้องตัดสินใจจากเท่านั้นว่าจะเรียกตัวไหน ด้วยค่าอะไร ในจังหวะไหน กล่าวอีกแบบ ชื่อและคำอธิบายคือ ส่วนต่อประสานเดียว ระหว่าง domain ของคุณกับการให้เหตุผลของ model มันจึงไม่ใช่เรื่อง “ความสวยงามของ code” แต่เป็นเรื่องว่า model จะเข้าใจ domain ถูกหรือผิด
คู่มือออกแบบ tool ของ Anthropic วางกฎที่ตรงกับหลัก ubiquitous language อย่างน่าประหลาด: ให้ตั้ง namespace ตามบริการ/ทรัพยากร (เช่น orders_find_late ไม่ใช่กอง function แบนๆ ที่ชนกันเอง) และให้เลือก field ที่ มีความหมายต่อมนุษย์ (name, file_type) แทน id ทึบๆ (uuid, mime_type) เพราะการทำแบบนี้ “ช่วยเพิ่มความแม่นยำของ Claude อย่างมีนัยสำคัญ… ด้วยการลดการ hallucinate” (Anthropic, “Writing effective tools for agents”) — พูดในภาษา DDD ก็คือ การตั้งชื่อ namespace และชื่อเชิงความหมาย คือการตัดสินใจเรื่อง ubiquitous language ตรงๆ
และเหมือนกับ UL ในทีมมนุษย์เป๊ะ: ชื่อรั่ว → เข้าใจผิด ถ้าชื่อ tool กำกวมหรือรูปมาจาก backend (เช่น run_query, upd_stat, parameter ชื่อ oid, s) model ก็จะเดาความหมายเอง แล้วเลือก tool ผิดหรือใส่ค่าผิด — เหมือนทีมที่ใช้คำคลุมเครือแล้วเข้าใจ bounded context กันคนละอย่าง ความกำกวมของภาษาแปลเป็นการกระทำที่ผิดพลาดเสมอ ไม่ว่าผู้ฟังจะเป็นคนหรือ model
tools: - name: run_query # ยิง SQL อะไรก็ได้ — model เดาไม่ออกว่าปลอดภัยแค่ไหน description: "exec sql on orders db" - name: upd_stat # ย่อจนอ่านไม่รู้เรื่อง กริยาไม่ชัด params: { oid: uuid, s: int } # id ไร้ความหมาย + สถานะเป็นตัวเลขดิบtools: - name: orders_find_late # namespace ตามบริการ + กริยา domain ชัด description: "ค้นออเดอร์ที่เกินกำหนดส่งในโซนที่ระบุ ตั้งแต่เวลาหนึ่ง" params: { zone: string, since: datetime } - name: orders_issue_refund # ขอบเขตแคบ ทำสิ่งเดียวที่ domain เข้าใจ description: "คืนเงินให้ออเดอร์ตามเลขที่ออเดอร์ ต้องแนบเหตุผลกำกับ" params: { orderId: string, reason: string }กฎการตั้งชื่อเหล่านี้มาจากคู่มือ วิศวกรรม ของ Anthropic ไม่ใช่ถ้อยคำบังคับ (normative) ใน spec MCP — อ่านว่า “ออกแบบให้ดีอย่างไร” ไม่ใช่ “spec สั่งให้ทำอะไร”
Server คือ Anti-Corruption Layer ระหว่าง backend กับ model
หัวข้อที่มีชื่อว่า “Server คือ Anti-Corruption Layer ระหว่าง backend กับ model”เหตุผลที่การตั้งชื่อกลายเป็นงานหนักก็เพราะ server อยู่ตรงรอยต่อระหว่างสองโลกที่พูดคนละภาษา ฝั่งหนึ่งคือ backend จริงที่เต็มไปด้วย status_code=3, uuid, ตาราง และ error code อีกฝั่งคือ model ที่ต้องการภาษา domain ที่อ่านแล้วเข้าใจ งานของ server คือ แปล — และนี่คือนิยามของ Anti-Corruption LayerAnti-Corruption Layer (ACL)แนวคิดจาก DDD ที่ยืมมาใช้มองงานออกแบบ MCP Server: มอง Tool แต่ละตัวเป็นชั้นแปลระหว่าง model กับระบบภายนอกจริง ไม่ปล่อยให้ model ของระบบเดิม (schema, error code, id ที่ไม่มีความหมาย) รั่วตรงเข้าสู่บริบทของ agent — Tool ที่ดีคือ ACL ที่รักษา model ของ agent ไม่ให้ปนเปื้อนStrategic Design ในภาษา DDD เป๊ะๆ: ชั้นที่กันไม่ให้ model ของระบบเดิม (schema ดิบ, id ไร้ความหมาย, สถานะเป็นตัวเลข) รั่วตรงเข้าสู่บริบทของ agent
มองแบบนี้แล้ว การตั้งชื่อ tool ที่ดีไม่ใช่แค่ “เรื่องสไตล์” แต่คือ การทำหน้าที่ ACL ให้ครบ — ทุกชื่อที่คุณเปลี่ยนจาก upd_stat เป็น orders_mark_delivered คือการแปลหนึ่งครั้งที่ทำให้ภาษาของ backend หยุดตรงพื้นผิว ไม่ไหลเข้าไปในหัวของ model บทที่ 3 เรียกสิ่งนี้ว่า “tool เป็น ACL” ในแง่ ขอบเขตสิทธิ์ บทนี้เติมอีกครึ่ง: มันเป็น ACL ในแง่ ภาษา ด้วย
คำอธิบายเป็น artifact ที่ model อ่าน และไม่น่าเชื่อถือโดยปริยาย
หัวข้อที่มีชื่อว่า “คำอธิบายเป็น artifact ที่ model อ่าน และไม่น่าเชื่อถือโดยปริยาย”นี่คือหัวใจที่ทำให้บทนี้ไม่ใช่แค่เรื่อง “ตั้งชื่อให้สวย” คำอธิบายของ tool ไม่ใช่คอมเมนต์ที่มนุษย์อ่าน — มันเป็น artifact ชั้นหนึ่งที่ไหลตรงเข้า context ของ model ทุกครั้งที่ server ประกาศ tool model อ่านมันเต็มๆ และใช้มันตัดสินใจ ซึ่งแปลว่าใครก็ตามที่เขียนคำอธิบายนั้นได้ ก็เขียนคำสั่งลงในหัวของ model ได้ทางอ้อม
spec จึงระบุไว้ตรงๆ ในหมวด Security & Trust ว่า “คำอธิบายพฤติกรรมของ tool เช่น annotation ควรถือว่าไม่น่าเชื่อถือ เว้นแต่ได้มาจาก server ที่เชื่อถือได้” (descriptions of tool behavior such as annotations should be considered untrusted, unless obtained from a trusted server — MCP spec, Security section, 2025-11-25) คือ ณ spec 2025-11-25 คำอธิบายที่มากับ tool ไม่มีสถานะน่าเชื่อถือในตัวเอง — มันน่าเชื่อได้ก็ต่อเมื่อ server ที่ยื่นมันมาเป็น server ที่เราเชื่อถืออยู่แล้วเท่านั้น
จุดนี้เองที่ทำให้ การออกแบบ ubiquitous language กับการออกแบบความปลอดภัยกลายเป็นการกระทำเดียวกัน: ถ้อยคำชุดเดียวที่คุณเปิดออกมาเป็นทั้ง API (ภาษาที่ model ใช้ทำงาน) และ พื้นผิวการโจมตี (ช่องที่คำสั่งแฝงเข้ามาได้) ในเวลาเดียวกัน คุณออกแบบภาษาที่เผยแพร่ของ context ก็คือคุณกำลังตัดสินใจเรื่องความปลอดภัยไปพร้อมกัน — นี่คือสะพานตรงไปบทที่ 6 ที่จะแยกให้เห็นว่าทำไม annotation อย่าง readOnlyHint จึงไม่ใช่ trust boundary และ server ที่ไม่น่าเชื่อถือ โกหกได้
พื้นผิว server = published language ของ bounded context
หัวข้อที่มีชื่อว่า “พื้นผิว server = published language ของ bounded context”รวมทุกอย่างเข้าด้วยกันด้วยเลนส์หลักของคอร์สพี่ Agent as Bounded Context — agent as bounded context: ถ้าเรามอง server หนึ่งตัว (เช่น ระบบออเดอร์) เป็น bounded context หนึ่ง พื้นผิวที่มันเปิดออกมา — ชื่อ tool, ชื่อ resource, คำอธิบายทั้งชุด — ก็คือ published language ของ context นั้น คือภาษาทางการที่ context นี้ตกลงจะพูดกับโลกภายนอก ทุกคำในพื้นผิวนั้นถูกทั้ง model อ่านเพื่อทำงาน และถูกผู้ไม่หวังดีอ่านเพื่อหาช่อง มันจึงต้องถูกออกแบบด้วยความตั้งใจระดับเดียวกับที่ทีม DDD ออกแบบ context map ระหว่าง bounded context
flowchart LR
subgraph BC["Bounded Context — ระบบออเดอร์ (backend จริง)"]
RAW["model ภายใน<br/>ตาราง orders, status_code=3<br/>uuid, mime_type"]
end
subgraph SRV["MCP Server = Anti-Corruption Layer"]
ACL["ชั้นแปล: ตั้งชื่อ + คำอธิบายเชิง domain"]
end
subgraph PUB["พื้นผิว server = published language ของ context"]
T1["orders_find_late — ค้นออเดอร์ที่ช้า"]
T2["orders_issue_refund — คืนเงินออเดอร์"]
RES["orders_status — สถานะออเดอร์ (resource)"]
end
MODEL["model ของ ops-copilot<br/>อ่านชื่อ+คำอธิบายเพื่อเลือกและเรียก"]
RAW -->|"แปลหยุดตรงนี้"| ACL
ACL --> T1
ACL --> T2
ACL --> RES
T1 -->|"ชื่อชัด เลือกถูก"| MODEL
T2 --> MODEL
RES --> MODEL
classDef bc fill:#fde68a,stroke:#92400e,color:#1a1a1f;
classDef acl fill:#c7d2fe,stroke:#3730a3,color:#1a1a1f;
classDef pub fill:#bbf7d0,stroke:#065f46,color:#1a1a1f;
class RAW bc;
class ACL acl;
class T1,T2,RES pub;
คำบรรยายภาพ: model ภายในของ bounded context (เหลือง) ที่เต็มไปด้วยศัพท์ backend ถูก MCP server ในฐานะ Anti-Corruption Layer (น้ำเงิน) แปลให้กลายเป็นพื้นผิวเชิง domain (เขียว) — ชื่อ tool/resource กับคำอธิบายของมันคือ published language ที่ model ops-copilot อ่านเพื่อเลือกและเรียก การแปลต้องหยุดที่ชั้น ACL ให้ครบ ไม่ปล่อยให้ status_code=3 หรือ uuid รั่วข้ามไปถึง model เพราะถ้อยคำชุดนี้คือทั้ง API และพื้นผิวการโจมตีในเวลาเดียวกัน
- ชื่อและคำอธิบายของ primitive คือ ภาษา domain ที่ model ใช้ให้เหตุผล ไม่ใช่คอมเมนต์ประดับ
- การตั้ง namespace และชื่อเชิงความหมายคือ การตัดสินใจเรื่อง ubiquitous language — ชื่อรั่วทำให้ model เลือก tool ผิด เหมือน UL รั่วทำให้คนเข้าใจ context ผิด
- server เป็น Anti-Corruption Layer เชิงภาษา: แปล backend ให้หยุดตรงพื้นผิว
- คำอธิบายเป็น artifact ที่ model อ่าน และ ไม่น่าเชื่อถือโดยปริยาย (ณ spec 2025-11-25) — จึงทำให้การออกแบบ UL กับความปลอดภัยเป็นเรื่องเดียวกัน และเป็นสะพานเข้าบทที่ 6
เจาะลึกแนวคิดในบทนี้ต่อได้ที่คลังอ้างอิง DevIQ:
- Ubiquitous Language — ภาษากลางที่ model ของ domain ต้องสะท้อนตรงกัน บทนี้ยืมมันมาใช้กับพื้นผิว MCP server ในฐานะภาษาที่ model อ่านและใช้ให้เหตุผล
- Anti-Corruption Layer — ชั้นแปลที่กัน model ของระบบเดิมไม่ให้รั่วข้ามขอบเขต — บทนี้ชี้ว่าการตั้งชื่อ tool/resource คือการทำหน้าที่ ACL เชิงภาษา
เช็กความเข้าใจ — บทที่ 5
ข้อ 1 / 3ชื่อของ tool ทำหน้าที่เป็น ubiquitous language อย่างไรในมุมของบทนี้?