AppFunction เป็นฟังก์ชันที่เทียบเท่ากับเซิร์ฟเวอร์ MCP บน Android ในทางปฏิบัติ ซึ่งช่วยให้คุณแชร์ตรรกะบางส่วนของแอปกับ AI Agent และผู้ช่วย AI ได้
Agent จะใช้คำอธิบายเพื่อเลือก AppFunction ที่ตอบสนองคำขอ กระบวนการเลือกนี้ทำงานเหมือนกับการค้นพบเครื่องมือ MCP แบบดั้งเดิม ซึ่งแอปพลิเคชัน AI จะใช้คำอธิบายเซิร์ฟเวอร์และเครื่องมือ MCP เพื่อเป็นแนวทางในการเลือก แอปของคุณจะทำหน้าที่เป็นเซิร์ฟเวอร์ Android MCP และ AppFunction แต่ละรายการจะทำหน้าที่เป็นเครื่องมืออย่างหนึ่งของเซิร์ฟเวอร์ ระบุคำอธิบายต่อไปนี้
- คำอธิบายแอป (เซิร์ฟเวอร์ Android MCP) คำอธิบายแอปเป็นจุดแรกที่ Agent จะเข้าใจว่าแอปของคุณทำอะไรได้บ้าง หากต้องการช่วยให้ Agent ค้นพบแอปของคุณ ให้ระบุโดเมนหลักและระบุงานที่ AppFunctions ช่วยให้แอปทำได้โดยย่อ
- เขียนคำอธิบายแอปด้วยตนเองในไฟล์ XML ของข้อมูลเมตาของแอป
- ใช้คำอธิบายแอปเพื่ออธิบายสิ่งที่คำอธิบายฟังก์ชันแต่ละรายการอธิบายไม่ได้ เช่น ลำดับในการเรียกใช้ฟังก์ชัน
- คำอธิบาย AppFunction (เครื่องมือ) คำอธิบายฟังก์ชันแต่ละรายการจะอธิบายลักษณะการทำงานของ AppFunction 1 รายการ โดยทั่วไปแล้ว คำอธิบายฟังก์ชันจะประกอบด้วยคำกริยา เช่น อัปเดต สร้าง หรือจอง และทรัพยากร เช่น การตั้งค่า ช่อง หรือห้อง
หลักเกณฑ์เกี่ยวกับคำอธิบายฟังก์ชัน
Agent จะอาศัยคำอธิบายฟังก์ชันเพื่อตัดสินใจว่าฟังก์ชันใดเหมาะกับคำขอและวิธีเรียกใช้ฟังก์ชันนั้น
เขียนคำอธิบาย AppFunction ที่สั้นกระชับและไม่กำกวม
ยิ่งคำอธิบายมีความกำกวมน้อยเท่าใด ตัวแทนก็จะยิ่งเลือกฟังก์ชันที่เหมาะสมสำหรับคำขอได้อย่างน่าเชื่อถือมากขึ้นเท่านั้น ตารางต่อไปนี้แสดงสิ่งที่ควรทำและสิ่งที่ควรหลีกเลี่ยงในคำอธิบายฟังก์ชัน
| ควรทำ | สิ่งที่ไม่ควรทำ |
|---|---|
| อธิบายวัตถุประสงค์ของฟังก์ชันและผลลัพธ์ของการเรียกใช้ฟังก์ชันด้วยภาษาที่ชัดเจนและเป็นกลาง | อย่าใช้คำอธิบายเป็นพรอมต์ คำสั่งต่างๆ เช่น "คุณต้องพูดว่า" และ "คุณต้องขอข้อมูลจากผู้ใช้" จะบอกให้ Agent ทราบว่าควรทำงานอย่างไรแทนที่จะอธิบายฟังก์ชัน |
| ใส่ข้อมูลสำคัญไว้ที่ส่วนต้นของคำอธิบายและเขียนให้กระชับ | อย่าใส่คำอธิบายด้วยคำที่ไม่มีความหมาย เช่น "ฟังก์ชันนี้ใช้เพื่อ" ฟิลเลอร์ทำให้คำอธิบายยาวขึ้นโดยไม่ได้ทำให้ชัดเจนขึ้น |
| อธิบายสิ่งที่โค้ดทำอย่างถูกต้อง รวมถึงพารามิเตอร์และเอาต์พุต ตัวอย่างเช่น ฟังก์ชันที่อธิบายว่าเป็นแบบอ่านอย่างเดียวไม่ควรเขียนหรือลบข้อมูล | อย่าใช้ชื่อที่ทำให้เข้าใจผิด เช่น ฟังก์ชันชื่อ fetchData ที่ลบข้อมูลผู้ใช้ |
| เขียนคำอธิบายฟังก์ชันในรูปแบบ KDoc รวมถึงพารามิเตอร์และประเภทการแสดงผล ทำตามคู่มือสไตล์ Kotlin สำหรับการตั้งชื่อ และทำให้คำอธิบายเข้าใจได้โดยไม่ต้องมีความรู้เกี่ยวกับการใช้งาน | อย่าใช้อักษรตัวพิมพ์ใหญ่หรือสัญลักษณ์พิเศษมากเกินไปเพื่อดึงดูดความสนใจไปยังส่วนต่างๆ ของคำอธิบาย เช่น **CRITICAL** หรือ VERY IMPORTANT |
| ใช้ชื่อที่มนุษย์อ่านได้สำหรับ AppFunction | |
| อธิบายสิ่งที่ AppFunction แต่ละรายการทำอย่างชัดเจนและตรงไปตรงมา | อย่าให้คำแนะนำเกี่ยวกับขั้นตอนที่เกี่ยวข้องกับฟังก์ชันอื่นๆ เช่น "ค้นหาผู้ติดต่อก่อน" Agent จะใช้คำอธิบายแอปเพื่อวางแผนการเรียกใช้ฟังก์ชันต่างๆ ดังนั้นให้อธิบายลำดับนั้นในคำอธิบายแทน |
| อธิบายสิ่งที่ Agent คาดหวังได้จากฟังก์ชัน โดยใช้ภาษา เช่น "หากคุณมี X แล้ว Y" | |
| สมมติว่า Agent มีวิธีการของตนเองในการใช้ AppFunctions โดยทั่วไป คำอธิบายฟังก์ชันจะระบุสิ่งที่ฟังก์ชันทำ และวิธีการของ Agent จะครอบคลุมวิธีใช้ฟังก์ชัน | อย่าพยายามลบล้างหรือฝังคำสั่งระดับ Agent ในคำอธิบายฟังก์ชัน |
เขียนโดยคำนึงถึงการห่อหุ้ม
เขียนคำอธิบายฟังก์ชันแต่ละรายการให้สมบูรณ์ในตัว เพื่อให้คำแนะนำแก่ Agent ในการใช้ฟังก์ชันนั้นๆ โดยไม่ใช้ฟังก์ชันอื่น ตารางต่อไปนี้แสดงหลักเกณฑ์การห่อหุ้ม
| ควรทำ | สิ่งที่ไม่ควรทำ |
|---|---|
| เขียนคำอธิบายฟังก์ชันที่เฉพาะเจาะจงและมุ่งเน้น โดยมีวัตถุประสงค์เดียวที่ชัดเจน เช่น "สร้าง ค้นหา และลบงานส่วนตัว" | อย่าเขียนคำอธิบายที่กว้างเกินไป ซึ่งอาจทำให้ Agent เรียกใช้ฟังก์ชันในเวลาที่ไม่เหมาะสมหรือด้วยเหตุผลที่ไม่ถูกต้อง |
| อย่าสร้าง AppFunction อเนกประสงค์ หรือแสดง AppFunction หลายรายการสำหรับ Use Case เดียวกัน Agent มีแนวโน้มที่จะเลือกฟังก์ชันผิดเมื่อฟังก์ชันหลายรายการมี Intent คล้ายกัน | |
| อย่าอ้างอิงหรือพยายามส่งผลต่อลักษณะการทำงานของ AppFunction อื่นๆ ในแอปของคุณหรือในแอปอื่นๆ ซึ่งอาจสร้างทรัพยากร Dependency และผลข้างเคียงที่ไม่ได้ตั้งใจ |
การดำเนินการที่อนุญาตและการแชร์ข้อมูล
ปฏิบัติตามหลักเกณฑ์ต่อไปนี้เพื่อปกป้องความเป็นส่วนตัวและความปลอดภัยของผู้ใช้เมื่อ Agent ใช้ฟังก์ชันของแอป
| ควรทำ | สิ่งที่ไม่ควรทำ |
|---|---|
| ดำเนินการเฉพาะงานที่ปลอดภัยและไม่ก่อให้เกิดความเสียหายซึ่งผู้ใช้จะทำตามปกติในแอปของคุณ โดยที่ Agent สามารถระบุพารามิเตอร์ที่ชัดเจนจากคำขอของผู้ใช้ได้ เช่น การสร้างงานที่มีชื่อหรือการค้นหาโน้ต | |
| แชร์เฉพาะข้อมูลที่ไม่ใช่ข้อมูลส่วนบุคคลหรือข้อมูลลับที่มีความละเอียดอ่อนสูง หรือข้อมูลที่ผู้ใช้ให้ความยินยอมอย่างชัดแจ้งในการแชร์สำหรับการดำเนินการ | อย่าให้สิทธิ์เข้าถึงข้อมูลผู้ใช้หรือทรัพยากรระบบแก่ Agent ในวงกว้าง |
| อย่าออกแบบ AppFunction ที่ต้องใช้หรือแสดงผลรหัสผ่าน รายละเอียดทางการเงิน คีย์ส่วนตัว หรือข้อมูลส่วนบุคคลอื่นๆ ที่มีความละเอียดอ่อนสูง | |
| ดำเนินการตามที่ผู้ใช้ขอ แม้ว่าจะทำงานในภายหลังหรือในเบื้องหลัง เช่น การส่งข้อความในเวลาที่ผู้ใช้เลือก | อย่าดำเนินการที่ผู้ใช้ไม่ได้ขอ เช่น งานที่เริ่มต้นเองหรือเกินกว่าคำขอ |
| มุ่งเน้นที่ฟังก์ชันการทำงานที่ได้ประโยชน์จากภาษาธรรมชาติ เช่น งานที่แสดงออกในการสนทนาได้ง่ายกว่าการไปยังส่วนต่างๆ ของ UI เช่น "[AI Agent] ช่วยฉันค้นหาเวลาว่างในปฏิทินสัปดาห์หน้า แล้วแนะนำเที่ยวบินไปชิคาโกในวันใดวันหนึ่งเหล่านั้นได้ไหม" | |
| ในอุปกรณ์รูปแบบอื่นๆ นอกเหนือจากโทรศัพท์ ให้เคารพความเป็นส่วนตัวของผู้ใช้ในอุปกรณ์ที่ใช้ร่วมกัน เช่น ทีวี, Android Auto และ Android Automotive OS | อย่าเปิดเผยข้อมูลหรือดำเนินการที่ UI ของแอปไม่รองรับในรูปแบบของอุปกรณ์นั้น |
| ระบุวัตถุประสงค์ของฟังก์ชันอย่างชัดเจนและไม่ซ้ำกัน | อย่าแอบอ้างเป็นเครื่องมือหรือบริการอื่น ชื่อและคำอธิบายของฟังก์ชันต้องไม่คล้ายกับเครื่องมืออื่นๆ จนทำให้สับสน ซึ่งอาจทำให้ Agent เลือกฟังก์ชันของคุณโดยไม่ตั้งใจ |
การออกแบบพารามิเตอร์และค่าที่แสดงผล
การออกแบบพารามิเตอร์และค่าที่แสดงผลอย่างรอบคอบจะช่วยป้องกันความกำกวมและลดโอกาสในการเรียกใช้ที่ไม่ถูกต้อง โปรดทำตามรูปแบบต่อไปนี้
| ควรทำ | สิ่งที่ไม่ควรทำ |
|---|---|
| กำหนดพารามิเตอร์สำหรับข้อมูลที่ฟังก์ชันต้องการเท่านั้น | อย่าขอข้อมูลที่ฟังก์ชันไม่ได้ใช้ ซึ่งจะช่วยลดการเปิดเผยข้อมูลและทำให้การใช้ฟังก์ชันง่ายขึ้น |
ใช้ชื่อพารามิเตอร์ที่แสดงถึงอินพุตที่คาดไว้ เช่น taskId, searchQuery หรือ recipientEmail |
อย่าใช้ชื่ออย่าง full_context หรือ conversation_history ชื่อดังกล่าวมีความกำกวมเนื่องจาก Agent ใช้คำเหล่านี้สำหรับบริบทและประวัติการสนทนาของตนเอง ตัวแทนอาจตีความผิดและส่งข้อมูลที่ไม่จำเป็นจำนวนมากไปยังฟังก์ชันของคุณ ซึ่งจะนำไปสู่การขโมยข้อมูล |
ใช้ประเภทที่ AppFunctions รองรับแทนการกำหนดประเภทของคุณเอง เช่น LocalDate, LocalTime, LocalDateTime หรือ Instant สำหรับวันที่และเวลา และ Uri สำหรับลิงก์ ไลบรารีจะแสดงประเภทเหล่านี้ในลักษณะเดียวกันในทุกแอป เพื่อให้ตัวแทนได้รับรูปแบบที่สอดคล้องกัน ดูรายการประเภทที่รองรับทั้งหมดได้ที่ AppFunctionSerializable |
|
| หากพารามิเตอร์ไม่จำเป็นต่อวัตถุประสงค์ของฟังก์ชัน ให้กำหนดให้เป็นพารามิเตอร์ที่ไม่บังคับ ซึ่งจะช่วยให้ Agent มีความยืดหยุ่นเมื่อมีข้อมูลจากผู้ใช้เพียงบางส่วน ดูข้อมูลเพิ่มเติมได้ที่พารามิเตอร์ที่ไม่บังคับ | |
| หาก AppFunction อัปเดตทรัพยากรที่มีอยู่ ให้ตรวจสอบว่าพารามิเตอร์แต่ละรายการสามารถแยกความแตกต่างระหว่าง "ตั้งค่าเป็น Null" กับ "ไม่เปลี่ยนแปลง" ได้ ดูตัวอย่างได้ที่การอัปเดตทรัพยากรที่มีอยู่ | |
หากต้องการให้ Agent เปิดหน้าจอที่เฉพาะเจาะจงในแอป ให้แสดงผล PendingIntent สำหรับหน้าจอนั้น Agent สามารถเปิด PendingIntent ได้ตามที่เป็นอยู่โดยไม่ต้องสร้าง Intent สำหรับแอปของคุณ สร้างด้วย Intent ที่ชัดเจนและ FLAG_IMMUTABLE เพื่อไม่ให้ Agent เปลี่ยนปลายทางได้ |
พารามิเตอร์ที่ไม่บังคับ
เฉพาะประเภทที่อนุญาตค่า Null, ประเภทพื้นฐาน, ประเภทรายการ และประเภทอาร์เรย์เท่านั้นที่สามารถเป็นตัวเลือกได้ เมื่อ Agent ละเว้นพารามิเตอร์ที่ไม่บังคับ ไลบรารีจะส่งค่าเริ่มต้นของประเภท ซึ่งก็คือ null, 0, false หรือว่างเปล่า แทนค่าเริ่มต้นที่คุณประกาศ
แก้ไขค่าเริ่มต้นที่มีความหมายในเนื้อหาฟังก์ชัน ดังตัวอย่างต่อไปนี้
/**
* Creates a note.
*
* @param title The title of the note.
* @param content The body text of the note.
* @param attachments The files to attach to the note.
* @param owner The ID of the user who owns the note.
* @return The created note.
*/
@AppFunctionDeclaration(isDescribedByKDoc = true)
suspend fun createNote(
title: String, // Required
content: String? = null, // Optional
attachments: List<Attachment> = emptyList(), // Optional
owner: String? = null, // Optional
): Note = withContext(Dispatchers.IO) {
noteRepository.createNote(
title = title,
// The library ignores declared default values and passes null for
// omitted nullable parameters, so resolve meaningful defaults here.
content = content ?: "",
attachments = attachments,
owner = owner ?: currentUserId(),
)
}
การอัปเดตแหล่งข้อมูลที่มีอยู่
ตัวอย่างต่อไปนี้ใช้ Wrapper SetField ที่เป็นค่า Null ได้สำหรับแต่ละช่องที่ตัวแทนอัปเดตได้ SetField ที่เป็นค่าว่างหมายถึง "ไม่ต้องเปลี่ยนแปลง" และ SetField(null) หมายถึง "ตั้งค่าเป็นค่าว่าง" ดังนี้
/** A new value for a field of an existing item. */
@AppFunctionSerializable(isDescribedByKDoc = true)
data class SetField<T>(
/** The new value of the field. */
val value: T,
)
/**
* Updates an existing note. Omitted fields keep their values.
*
* @param noteId The ID of the note to update.
* @param title The new title of the note.
* @param content The new body text of the note.
* @return The updated note.
*/
@AppFunctionDeclaration(isDescribedByKDoc = true)
suspend fun updateNote(
noteId: String,
title: SetField<String>? = null,
content: SetField<String?>? = null,
): Note = withContext(Dispatchers.IO) {
val note = noteRepository.getNote(noteId)
?: throw AppFunctionElementNotFoundException(
"No note found with ID $noteId"
)
noteRepository.updateNote(
noteId = noteId,
// A null SetField means "don't change", and SetField(null) means
// "set to null", so don't use ?: for nullable fields.
title = title?.value ?: note.title,
content = if (content != null) content.value else note.content,
)
}
การจัดการข้อผิดพลาด
เมื่อการเรียกใช้ไม่สำเร็จ Agent จะได้รับข้อยกเว้นที่ฟังก์ชันแสดงขึ้น รวมถึงประเภทและข้อความ ปฏิบัติตามรูปแบบต่อไปนี้เพื่อให้ Agent สามารถกู้คืนจากความล้มเหลวหรือรายงานให้ผู้ใช้ทราบได้
| ควรทำ | สิ่งที่ไม่ควรทำ |
|---|---|
ส่งคลาสย่อย AppFunctionException ที่ตรงกับสาเหตุ พร้อมข้อความที่อธิบายปัญหาเป็นภาษาที่เข้าใจง่าย เช่น AppFunctionInvalidArgumentException เมื่ออาร์กิวเมนต์ไม่ถูกต้อง หรือ AppFunctionElementNotFoundException เมื่อไม่มีรายการที่ขอ ประเภทจะบอก Agent ว่าเกิดความล้มเหลวประเภทใด และข้อความจะให้รายละเอียดที่จำเป็นในการกู้คืน เช่น การแก้ไขอาร์กิวเมนต์หรือการแจ้งผู้ใช้ ตัวอย่าง updateNote ในการอัปเดตทรัพยากรที่มีอยู่แสดงรูปแบบนี้ |
อย่าปล่อยให้ข้อยกเว้นอื่นๆ หลุดออกจากฟังก์ชัน ตัวแทนจะได้รับข้อผิดพลาดเป็น AppFunctionAppUnknownException ซึ่งไม่ได้ระบุประเภทของความล้มเหลว |