Persona: ฝัง AI agent ลงเว็บด้วย vanilla JS แล้วให้มันกดใช้ฟีเจอร์บนหน้าเว็บเองผ่าน WebMCP
Persona คือไลบรารี UI สำหรับ AI agent ที่เขียนด้วย JavaScript ล้วน ไม่ผูกเฟรมเวิร์กใด จุดที่น่าสนใจคือมันให้ agent กดใช้ฟีเจอร์ที่มีอยู่บนหน้าเว็บได้จริงผ่าน WebMCP โดยถามผู้ใช้ก่อนทุกครั้ง

ลองนึกภาพหน้าเว็บร้านค้าที่มีกล่องแชต AI อยู่มุมจอ ผู้ใช้พิมพ์ว่า "หารองเท้าวิ่งไซส์ 42 ให้หน่อย" แล้วแทนที่ agent จะตอบเป็นข้อความเฉย ๆ มันกดปุ่ม "ค้นหาสินค้า" บนหน้าเว็บจริง เลือกของ แล้วเด้งป็อปอัปขึ้นมาถามก่อนว่า "จะใส่ลงตะกร้าเลยไหม" ภาพนี้คือสิ่งที่ Persona ทำได้ · Persona เป็นไลบรารี UI สำหรับ AI agent แบบ open-source ที่เขียนด้วย JavaScript ล้วน ไม่ผูกกับ React หรือเฟรมเวิร์กไหนเลย พัฒนาโดยทีม Runtype ใช้ชื่อแพ็กเกจว่า @runtypelabs/persona และเป็น MIT license
เหตุผลที่ควรสนใจไม่ใช่เพราะ "มีกล่องแชตอีกตัวแล้ว" เพราะกล่องแชตมีให้เลือกเป็นสิบ แต่เพราะ Persona ตอบโจทย์ที่ยากกว่านั้นมาก เวลาจะเอา AI agent ฝังลงเว็บ ปัญหาใหญ่จริง ๆ ไม่ใช่หน้าตาของกล่องแชต แต่คือ "จะให้ agent กดใช้ฟีเจอร์ที่หน้าเว็บมีอยู่แล้วได้ยังไง โดยไม่ต้องรื้อ backend ใหม่ทั้งระบบ" · Persona ตอบคำถามนี้ด้วยมาตรฐานเปิดที่ชื่อ WebMCP บทความนี้จะพาไปดูว่ามันทำงานยังไง และเริ่มลงมือเองได้จากตรงไหน
ติดตั้งไม่กี่บรรทัดก็ขึ้นใช้งานได้
เริ่มจากวิธีที่ง่ายที่สุดก่อน คือทำให้กล่องแชตโผล่บนหน้าเว็บ · ติดตั้งผ่าน npm ด้วยคำสั่งเดียว
npm install @runtypelabs/personaแล้วเรียกฟังก์ชันเดียวเพื่อ mount widget ลงบน element ที่ต้องการ
initAgentWidget({ target: "#chat", config: { apiUrl: "..." } })
ถ้าไม่อยากตั้ง bundler ให้ยุ่งยาก แปะ <script> tag จาก CDN ลงหน้าเว็บตรง ๆ ก็ได้ widget ขึ้นเหมือนกัน เหมาะกับเว็บที่เขียนเป็น HTML ธรรมดาไม่มีระบบ build · ขั้นตอนนี้ยังไม่มีอะไรพิเศษ มันก็คือกล่องแชตหนึ่งกล่อง · ของจริงอยู่ที่ขั้นต่อไป
หัวใจอยู่ที่ WebMCP ไม่ใช่กล่องแชต

WebMCP คือมาตรฐานเปิดที่กำหนดให้ "เครื่องมือบนหน้าเว็บ" มารวมไว้ที่จุดเดียวกัน คือ document.modelContext · พูดง่าย ๆ คือมันเป็นจุดมาตรฐานให้หน้าเว็บประกาศว่า "ฉันมีอะไรให้ agent กดใช้ได้บ้าง" · จุดสำคัญคือ Persona ไม่ได้เป็นเจ้าของมาตรฐานนี้ Persona แค่เป็นตัวที่อ่านมันเป็น
วิธีใช้คือหน้าเว็บลงทะเบียน tool ของตัวเองเข้าไป เช่น
document.modelContext.registerTool({
name: "search_products",
description: "ค้นหาสินค้าจากคำค้นที่ผู้ใช้พิมพ์",
inputSchema: { /* ... */ },
execute: async (input) => { /* เรียกฟังก์ชันค้นหาที่หน้าเว็บมีอยู่แล้ว */ }
})
จากนั้น Persona จะค้นเจอ tool ตัวนี้เอง · พอผู้ใช้พิมพ์อะไรที่ตรงกับงานนี้ agent ก็รู้ว่ามีเครื่องมือ search_products ให้เรียก แล้วเรียกมันได้เลย · tool ไม่จำกัดแค่ค้นหาสินค้า จะใส่ตะกร้า จองคิว กรอกฟอร์ม หรืออะไรก็แล้วแต่ที่หน้าเว็บทำได้อยู่แล้ว แค่ห่อมันเป็น tool หนึ่งตัว
จุดที่ทำให้แนวคิดนี้น่าใช้คือ ฟีเจอร์เดิมยังอยู่ที่เดิมในโค้ดหน้าเว็บ ไม่ต้องย้ายไปไหน · แชตแค่กลายเป็นอีกช่องทางหนึ่งที่เรียกฟังก์ชันเดิมเหล่านั้น · เพราะตรรกะการทำงานยังอยู่ใน execute ของแต่ละ tool บน frontend จึงไม่ต้องไปสร้าง endpoint ใหม่หรือรื้อ backend เพื่อรองรับ agent
ถามผู้ใช้ก่อนกดทุกครั้ง

การปล่อยให้ AI ไปกดปุ่มบนหน้าเว็บแทนคนฟังดูน่ากลัว เพราะมันอาจกดผิด กดสิ่งที่ผู้ใช้ไม่ได้ตั้งใจ · Persona จัดการตรงนี้ด้วย approval gate ซึ่งเป็นกลไกแบบ human-in-the-loop
ก่อน agent จะเรียก tool ใด มันต้องผ่านป็อปอัปขออนุมัติจากผู้ใช้ก่อน · ป็อปอัปนั้นมีสรุปสั้น ๆ ที่อ่านเข้าใจง่ายว่ากำลังจะทำอะไร พร้อมรายละเอียดทางเทคนิคที่กดดูเพิ่มได้ถ้าอยากรู้ลึก · ผู้ใช้กดอนุมัติหรือปฏิเสธก็ได้ และนักพัฒนายังเขียน handler เองได้ว่าจะให้คำขออนุมัติแต่ละครั้งทำอะไรต่อ
หลังผู้ใช้กดอนุมัติ Persona จึงเรียก tool นั้น แล้ว stream ผลลัพธ์กลับเข้าบทสนทนาให้เห็นเป็นขั้น ๆ · วงจรทั้งหมดนี้ ตั้งแต่พิมพ์ → agent เลือก tool → ถามอนุมัติ → เรียก → ส่งผลกลับ คือสิ่งที่ทำให้ภาพ "แชตที่กดใช้งานหน้าเว็บได้จริง" เกิดขึ้นได้
แปะลงหน้าไหนก็ไม่ทำสไตล์เว็บพัง
ปัญหาคลาสสิกของการเอา widget คนอื่นมาแปะคือ CSS ตีกัน · สไตล์ของ widget รั่วไปทับหน้าเว็บ หรือสไตล์ของหน้าเว็บไหลเข้าไปทำ widget เพี้ยน · Persona ตัดปัญหานี้ด้วยการ render ผ่าน Shadow DOM พร้อม prefixed CSS · ผลคือสไตล์ของ widget กับสไตล์ของ host page แยกจากกันชัดเจน ไม่มีฝั่งไหนรั่วใส่อีกฝั่ง · แปะลงเว็บไหนก็หน้าตาเหมือนกัน ไม่ต้องมานั่งไล่แก้ CSS ทีหลัง
ส่วนหน้าตา ปรับได้ผ่านระบบ design token สามชั้น ตั้งแต่ palette ไปจนถึง semantic และ component · รองรับ dark mode และมี live theme editor ให้ลองสีแบบเห็นผลทันที · ใครอยากลงลึกกว่านั้นก็มี render hook ให้สลับชิ้นส่วน UI เองได้ ตั้งแต่ปุ่ม launcher, header, ช่องพิมพ์ ไปจนถึงหน้าตาของ tool call
ต่อกับ backend ตัวไหนก็ได้
อีกเรื่องที่มักทำให้ของแบบนี้ใช้ยากคือมันบังคับให้ใช้ backend ของเจ้าของไลบรารีเท่านั้น · Persona ไม่บังคับ · มันรับข้อมูลแบบ SSE streaming และให้จัดรูปข้อมูลเองได้ผ่าน customFetch กับ parseSSEEvent · พูดง่าย ๆ คือถ้า backend ส่งข้อมูลมาหน้าตาไม่ตรงเป๊ะ ก็เขียนตัวแปลงคั่นกลางได้ ไม่ต้องไปแก้ backend
แล้วต่อกับอะไรได้บ้าง · Persona มี adapter ตัวอย่างให้พร้อมหลายตัว เลือกตามของที่ทีมใช้อยู่
- Vercel AI SDK · สำหรับทีมที่อยู่บน stack ของ Vercel หรือใช้ Next.js เป็นหลัก
- OpenAI Agents SDK · สำหรับคนที่สร้าง agent ด้วยเครื่องมือฝั่ง OpenAI โดยตรง
- LangGraph.js · สำหรับงานที่ flow ของ agent ซับซ้อน มีหลายขั้นตอนเป็นกราฟ
เลือกตัวไหนเมื่อไหร่ ก็ดูจากว่าตอนนี้ backend ของงานสร้างด้วยอะไรอยู่แล้ว แล้วหยิบ adapter ที่ตรงกับตัวนั้น ไม่ต้องเปลี่ยน stack ตาม widget
นอกจากนี้ยังมีของเสริมที่เปิดใช้ได้ตามต้องการ เช่น voice I/O ที่ให้ผู้ใช้พูดสั่งและตอบกลับด้วยเสียง แถมขัดจังหวะกลางประโยคได้, reasoning bubble ที่พับเก็บความคิดของ agent ไว้ดูได้, และ artifacts panel ที่ render markdown หรือคอมโพเนนต์ออกมาเป็นหน้าต่างข้าง ๆ · ของพวกนี้ไม่ใช่หัวใจ แต่มีไว้เปิดใช้เมื่อจำเป็น
ต้นทุนของแนวคิดนี้
ของแบบนี้ไม่ได้มาแบบไม่มีต้นทุน · การให้ agent กดใช้ฟีเจอร์บนหน้าเว็บได้ แปลว่าต้องนั่งเขียน tool ทีละตัว ออกแบบ inputSchema ให้ชัด เขียน execute ให้ถูก และคิดให้รอบว่า tool ไหนควรให้ agent แตะ tool ไหนไม่ควร · งานออกแบบ approval flow ที่ดีก็ต้องใช้ความคิด ไม่ใช่แค่เปิดให้ผ่านทุกอัน
แต่นี่คือต้นทุนที่ตรงจุด เพราะมันคือการลงแรงกับ "หน้าเว็บจะให้ agent ทำอะไรได้บ้าง" ซึ่งเป็นคำถามที่ควรคิดอยู่แล้วไม่ว่าจะใช้เครื่องมือไหน · สิ่งที่ Persona ช่วยลดคืองานต่อท่อ ต่อ stream และต่อ UI ที่ไม่ใช่หัวใจ ให้เหลือแค่งานที่สำคัญจริง
สำหรับนักพัฒนาเว็บที่อยากใส่ AI assistant ลงเว็บลูกค้าแล้วให้มัน "กดใช้งานได้จริง" ไม่ใช่แค่ตอบคำถาม ตัวอย่างโค้ดและรายละเอียดทั้งหมดอยู่ในรีโป runtypelabs/persona เริ่มจากลง widget ให้ขึ้นก่อน แล้วค่อยลงทะเบียน tool แรกผ่าน document.modelContext หนึ่งตัว เท่านี้ก็เห็นแล้วว่ามันต่างจากกล่องแชตทั่วไปยังไง
WebMCP คือการขยับเส้นแบ่งใหม่ จากเดิมที่ AI ทำได้แค่ "บอกผู้ใช้ว่าให้กดปุ่มไหน" มาเป็น "กดให้เลยโดยขออนุญาตก่อน" · และเส้นแบ่งที่ขยับนี้ไม่ได้อยู่ที่ฝั่ง server แต่อยู่บนหน้าเว็บที่ผู้ใช้มองเห็นตรงหน้าพอดี
ที่มา:
- เว็บไซต์ Persona: Open-source Agent UI Library in VanillaJS จาก persona-chat.dev
- รีโป runtypelabs/persona จาก GitHub · runtypelabs/persona



