หลักเกณฑ์ด้านคุณภาพของ AppFunctions

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 ซึ่งไม่ได้ระบุประเภทของความล้มเหลว