AppFunctions की क्वालिटी के लिए दिशा-निर्देश

AppFunctions, Android पर एमसीपी सर्वर की तरह ही काम करते हैं. इनकी मदद से, अपने ऐप्लिकेशन के लॉजिक के कुछ हिस्सों को एआई एजेंट और असिस्टेंट के साथ शेयर किया जा सकता है.

एजेंट, ब्यौरों का इस्तेमाल करके उस AppFunction को चुनते हैं जो किसी अनुरोध को पूरा करता है. चुनने की यह प्रोसेस, एमसीपी टूल खोजने के पारंपरिक तरीके की तरह काम करती है. इसमें एआई ऐप्लिकेशन, एमसीपी सर्वर और टूल के ब्यौरे का इस्तेमाल करके, अपने विकल्पों को चुनते हैं. आपका ऐप्लिकेशन, Android MCP सर्वर के तौर पर काम करता है. साथ ही, हर AppFunction इसके एक टूल के तौर पर काम करता है. जानकारी वाली ये ऐसेट जोड़ें:

  • ऐप्लिकेशन का ब्यौरा (Android एमसीपी सर्वर). आपके ऐप्लिकेशन का ब्यौरा, एजेंट के लिए पहला एंट्री पॉइंट होता है. इससे एजेंट को यह समझने में मदद मिलती है कि आपका ऐप्लिकेशन क्या कर सकता है. एजेंट को आपका ऐप्लिकेशन खोजने में मदद करने के लिए, इसके मुख्य डोमेन के बारे में बताएं. साथ ही, उन टास्क की सूची बनाएं जिन्हें AppFunctions की मदद से पूरा किया जा सकता है.
    • ऐप्लिकेशन के मेटाडेटा की एक्सएमएल फ़ाइल में, ऐप्लिकेशन का ब्यौरा खुद लिखें.
    • ऐप्लिकेशन के ब्यौरे का इस्तेमाल करके, उन चीज़ों के बारे में बताएं जिनके बारे में अलग-अलग फ़ंक्शन के ब्यौरे में नहीं बताया जा सकता. जैसे, फ़ंक्शन को कॉल करने का क्रम.
  • AppFunction के ब्यौरे (टूल). हर फ़ंक्शन के ब्यौरे में, एक AppFunction के काम करने के तरीके के बारे में बताया जाता है. फ़ंक्शन के ब्यौरे आम तौर पर, किसी वर्ब और रिसॉर्स के आस-पास स्ट्रक्चर किए जाते हैं. जैसे, अपडेट करें, बनाएं या बुक करें और सेटिंग, चैनल या कमरा.

फ़ंक्शन के ब्यौरे से जुड़े दिशा-निर्देश

एजेंट, फ़ंक्शन के ब्यौरे के आधार पर यह तय करते हैं कि किसी अनुरोध के लिए कौनसा फ़ंक्शन सही है और उसे कैसे कॉल करना है.

AppFunction के बारे में कम शब्दों में और साफ़ तौर पर जानकारी देना

जानकारी जितनी साफ़ होगी, एजेंट किसी अनुरोध के लिए सही फ़ंक्शन को उतनी ही भरोसेमंद तरीके से चुन पाएगा. नीचे दी गई टेबल में बताया गया है कि फ़ंक्शन की जानकारी में क्या करना चाहिए और क्या नहीं:

यह करें क्या न करें
फ़ंक्शन के मकसद और उसे चलाने के नतीजे के बारे में साफ़ और न्यूट्रल भाषा में बताएं. प्रॉम्प्ट के तौर पर ब्यौरों का इस्तेमाल न करें. "आपको यह कहना होगा" और "आपको उपयोगकर्ता से यह पूछना होगा" जैसे निर्देश, एजेंट को फ़ंक्शन के बारे में बताने के बजाय, यह बताते हैं कि उसे कैसा व्यवहार करना चाहिए.
जानकारी की शुरुआत में अहम जानकारी दें और उसे कम शब्दों में रखें. ब्यौरे में "इस फ़ंक्शन का इस्तेमाल इसके लिए किया जाता है" जैसे फ़िलर का इस्तेमाल न करें. फ़िलर, ब्यौरे को लंबा बनाता है, लेकिन उसे साफ़ तौर पर नहीं समझाता.
कोड के काम करने के तरीके के बारे में सटीक जानकारी दें. इसमें उसके पैरामीटर और आउटपुट की जानकारी भी शामिल होनी चाहिए. उदाहरण के लिए, अगर किसी फ़ंक्शन को सिर्फ़ पढ़ने के लिए सेट किया गया है, तो वह डेटा को न तो लिख सकता है और न ही मिटा सकता है. गुमराह करने वाले नामों का इस्तेमाल न करें. जैसे, fetchData नाम का कोई फ़ंक्शन, जो उपयोगकर्ता का डेटा मिटाता हो.
फ़ंक्शन के ब्यौरे को KDoc फ़ॉर्मैट में लिखें. इसमें पैरामीटर और रिटर्न टाइप शामिल करें. नाम रखने के लिए, Kotlin स्टाइल गाइड का पालन करें. साथ ही, जानकारी को इस तरह से लिखें कि उसे समझने के लिए, लागू करने के तरीके की जानकारी होना ज़रूरी न हो. ब्यौरे के किसी हिस्से पर ध्यान खींचने के लिए, कैपिटल लेटर या खास वर्णों का बहुत ज़्यादा इस्तेमाल न करें. जैसे, **CRITICAL** या VERY IMPORTANT.
AppFunctions के लिए, ऐसे नामों का इस्तेमाल करें जिन्हें आसानी से पढ़ा जा सके.
हर AppFunction के काम के बारे में साफ़ तौर पर बताएं. प्रक्रिया से जुड़े ऐसे निर्देश न दें जिनमें अन्य फ़ंक्शन शामिल हों. जैसे, "पहले संपर्क खोजें." एजेंट आपके ऐप्लिकेशन की जानकारी का इस्तेमाल, अलग-अलग फ़ंक्शन के लिए कॉल शेड्यूल करने के लिए करते हैं. इसलिए, उस क्रम की जानकारी यहां दें.
एजेंट को बताएं कि फ़ंक्शन से क्या उम्मीद की जा सकती है. इसके लिए, "अगर आपके पास X है, तो Y" जैसी भाषा का इस्तेमाल करें.
यह मान लें कि एजेंट के पास AppFunctions का इस्तेमाल करने के लिए, अपने निर्देश होते हैं. फ़ंक्शन के ब्यौरे में बताया जाता है कि फ़ंक्शन क्या काम करता है. वहीं, एजेंट के निर्देशों में बताया जाता है कि इसका इस्तेमाल कैसे करना है. फ़ंक्शन के ब्यौरे में, एजेंट-लेवल के निर्देशों को बदलने या उन्हें एम्बेड करने की कोशिश न करें.

एनकैप्सुलेशन को ध्यान में रखकर कोड लिखें

हर फ़ंक्शन के ब्यौरे को पूरी तरह से अपने-आप में पूरा रखें, ताकि वह एजेंट को उस फ़ंक्शन का इस्तेमाल करने में मदद करे, न कि किसी दूसरे फ़ंक्शन का. यहां दी गई टेबल में, एनकैप्सुलेशन के दिशा-निर्देशों की सूची दी गई है:

यह करें क्या न करें
फ़ंक्शन के बारे में खास और सटीक जानकारी दें. साथ ही, उसके मकसद के बारे में साफ़ तौर पर बताएं. उदाहरण के लिए, "निजी टास्क बनाना, ढूंढना, और मिटाना." ब्यौरे में बहुत ज़्यादा जानकारी न दें. इससे एजेंट, आपके फ़ंक्शन को गलत समय पर या गलत वजहों से कॉल कर सकता है.
एक से ज़्यादा काम करने वाले AppFunctions न बनाएं या एक ही इस्तेमाल के उदाहरण के लिए कई AppFunctions न दिखाएं. जब कई फ़ंक्शन के इंटेंट एक जैसे होते हैं, तो एजेंट गलत फ़ंक्शन चुन सकते हैं.
अपने ऐप्लिकेशन या अन्य ऐप्लिकेशन में मौजूद अन्य AppFunctions का रेफ़रंस न दें या उनके व्यवहार पर असर डालने की कोशिश न करें. इससे अनचाही डिपेंडेंसी और खराब असर हो सकते हैं.

अनुमति वाली कार्रवाइयां और डेटा शेयर करना

जब एजेंट आपके ऐप्लिकेशन के फ़ंक्शन इस्तेमाल करें, तब उपयोगकर्ता की निजता और सुरक्षा को बनाए रखने के लिए इन दिशा-निर्देशों का पालन करें:

यह करें क्या न करें
सिर्फ़ सुरक्षित और नुकसान न पहुंचाने वाले टास्क करें. ये ऐसे टास्क होने चाहिए जो उपयोगकर्ता आम तौर पर आपके ऐप्लिकेशन में करता है. इनमें एजेंट, उपयोगकर्ता के अनुरोध के आधार पर साफ़ तौर पर पैरामीटर दे सकता है. उदाहरण के लिए, टाइटल के साथ कोई टास्क बनाना या नोट खोजना.
सिर्फ़ ऐसी जानकारी शेयर करें जो बेहद निजी या गोपनीय न हो. इसके अलावा, ऐसा डेटा शेयर करें जिसे शेयर करने के लिए उपयोगकर्ता ने साफ़ तौर पर सहमति दी हो. एजेंट को उपयोगकर्ता के डेटा या सिस्टम के संसाधनों का ज़्यादा ऐक्सेस न दें.
ऐसे AppFunctions डिज़ाइन न करें जिनके लिए पासवर्ड, वित्तीय जानकारी, निजी पासकोड या अन्य बेहद संवेदनशील निजी जानकारी की ज़रूरत हो या जो इस तरह की जानकारी दिखाते हों.
उपयोगकर्ता के अनुरोध पर कार्रवाइयां करना. भले ही, वे कार्रवाइयां बाद में या बैकग्राउंड में की जाएं. उदाहरण के लिए, उपयोगकर्ता के चुने गए समय पर मैसेज भेजना. ऐसी कार्रवाइयां न करें जिनका अनुरोध उपयोगकर्ता ने नहीं किया है. जैसे, ऐसे टास्क जो अपने-आप शुरू हो जाते हैं या जो अनुरोध से ज़्यादा काम करते हैं.
ऐसी सुविधाओं पर फ़ोकस करें जो नैचुरल लैंग्वेज का इस्तेमाल करने पर बेहतर तरीके से काम करती हैं. जैसे, ऐसे टास्क जिन्हें यूज़र इंटरफ़ेस (यूआई) नेविगेशन के बजाय, बातचीत के ज़रिए ज़्यादा आसानी से पूरा किया जा सकता है. उदाहरण के लिए, "[एआई एजेंट], क्या तुम अगले हफ़्ते मेरे कैलेंडर पर कुछ खाली स्लॉट ढूंढने में मेरी मदद कर सकते हो? इसके बाद, उन दिनों में से किसी एक दिन के लिए, शिकागो की फ़्लाइट का सुझाव दो."
फ़ोन के अलावा, अन्य डिवाइसों पर उपयोगकर्ताओं की निजता का सम्मान करें. जैसे, टीवी, Android Auto, और Android Automotive OS. ऐसी जानकारी ज़ाहिर न करें या ऐसी कार्रवाइयां न करें जो आपके ऐप्लिकेशन का यूज़र इंटरफ़ेस (यूआई), उस डिवाइस के साइज़, डाइमेंशन या कॉन्फ़िगरेशन पर सपोर्ट नहीं करता.
अपने फ़ंक्शन के मकसद को साफ़ तौर पर और यूनीक तरीके से बताएं. किसी दूसरे टूल या सेवा के तौर पर खुद को पेश न करें. आपके फ़ंक्शन का नाम और ब्यौरा, अन्य टूल से काफ़ी मिलता-जुलता नहीं होना चाहिए. इससे एजेंट गलती से आपके फ़ंक्शन को चुन सकता है.

पैरामीटर और रिटर्न वैल्यू का डिज़ाइन

पैरामीटर और रिटर्न वैल्यू को ध्यान से डिज़ाइन करने से, भ्रम की स्थिति पैदा नहीं होती. साथ ही, अमान्य कॉल की संभावना कम हो जाती है. इन नियमों का पालन करें:

यह करें क्या न करें
सिर्फ़ उस डेटा के लिए पैरामीटर तय करें जिसकी ज़रूरत आपके फ़ंक्शन को है. ऐसी जानकारी का अनुरोध न करें जिसका इस्तेमाल फ़ंक्शन नहीं करता. इससे डेटा एक्सपोज़र कम होता है और फ़ंक्शन का इस्तेमाल करना आसान हो जाता है.
पैरामीटर के ऐसे नाम इस्तेमाल करें जिनसे यह पता चले कि किस तरह का इनपुट देना है. जैसे, taskId, searchQuery या recipientEmail. full_context या conversation_history जैसे नामों का इस्तेमाल न करें. ऐसे नाम साफ़ तौर पर समझ नहीं आते, क्योंकि एजेंट इन शब्दों का इस्तेमाल अपने कॉन्टेक्स्ट और बातचीत के इतिहास के लिए करते हैं. कोई एजेंट इन्हें गलत समझ सकता है और आपके फ़ंक्शन को बहुत सारा ग़ैर-ज़रूरी डेटा भेज सकता है. इससे डेटा चोरी हो सकता है.
अपने टाइप तय करने के बजाय, AppFunctions के साथ काम करने वाले टाइप इस्तेमाल करें. उदाहरण के लिए, तारीख और समय के लिए LocalDate, LocalTime, LocalDateTime या Instant और लिंक के लिए Uri. लाइब्रेरी, हर ऐप्लिकेशन में इन टाइप को एक ही तरह से दिखाती है. इससे एजेंट को एक जैसा फ़ॉर्मैट मिलता है. इस्तेमाल किए जा सकने वाले टाइप की पूरी सूची देखने के लिए, AppFunctionSerializable पर जाएं.
अगर कोई पैरामीटर, फ़ंक्शन के मकसद के लिए ज़रूरी नहीं है, तो उसे वैकल्पिक बनाएं. इससे एजेंट को तब मदद मिलती है, जब उसके पास उपयोगकर्ता से मिली अधूरी जानकारी होती है. ज़्यादा जानकारी के लिए, वैकल्पिक पैरामीटर देखें.
अगर आपका AppFunction मौजूदा संसाधनों को अपडेट करता है, तो पक्का करें कि हर पैरामीटर "शून्य पर सेट करें" और "बदलाव न करें" के बीच अंतर कर सके. उदाहरण के लिए, मौजूदा संसाधनों के अपडेट देखें.
एजेंट को आपके ऐप्लिकेशन में कोई खास स्क्रीन खोलने की अनुमति देने के लिए, उस स्क्रीन के लिए PendingIntent दिखाएं. एजेंट, आपके ऐप्लिकेशन के लिए इंटेंट बनाए बिना, PendingIntent को लॉन्च कर सकता है. इसे साफ़ तौर पर इंटेंट और FLAG_IMMUTABLE के साथ बनाएं, ताकि एजेंट यह न बदल सके कि यह कहां ले जाता है.

वैकल्पिक पैरामीटर

सिर्फ़ नलेबल, प्रिमिटिव, लिस्ट, और अरे टाइप को वैकल्पिक बनाया जा सकता है. जब एजेंट किसी वैकल्पिक पैरामीटर को शामिल नहीं करता है, तो लाइब्रेरी आपके तय किए गए डिफ़ॉल्ट वैल्यू के बजाय, टाइप की डिफ़ॉल्ट वैल्यू पास करती है. जैसे, null, शून्य, 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(),
    )
}

मौजूदा संसाधनों से जुड़े अपडेट

यहां दिए गए उदाहरण में, हर उस फ़ील्ड के लिए नलेबल SetField रैपर का इस्तेमाल किया गया है जिसे एजेंट अपडेट कर सकता है. SetField की वैल्यू null होने का मतलब है कि "कोई बदलाव न करें" और SetField(null) का मतलब है कि "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,
    )
}

गड़बड़ी ठीक करना

कॉल न हो पाने पर, एजेंट को आपके फ़ंक्शन से मिलने वाला अपवाद मिलता है. इसमें अपवाद का टाइप और मैसेज शामिल होता है. इन नियमों का पालन करें, ताकि एजेंट गड़बड़ी को ठीक कर सके या उपयोगकर्ता को इसकी जानकारी दे सके:

यह करें क्या न करें
वजह से मैच करने वाले AppFunctionException सबक्लास को थ्रो करें. साथ ही, समस्या के बारे में आसान भाषा में बताने वाला मैसेज दें. उदाहरण के लिए, जब कोई आर्ग्युमेंट मान्य न हो, तो AppFunctionInvalidArgumentException या जब अनुरोध किया गया आइटम मौजूद न हो, तो AppFunctionElementNotFoundException. टाइप से एजेंट को पता चलता है कि किस तरह की गड़बड़ी हुई है. साथ ही, मैसेज से उसे गड़बड़ी को ठीक करने के लिए ज़रूरी जानकारी मिलती है. जैसे, आर्ग्युमेंट को ठीक करना या उपयोगकर्ता को बताना. मौजूदा संसाधनों के अपडेट में updateNote का उदाहरण, यह पैटर्न दिखाता है. अपने फ़ंक्शन से अन्य अपवादों को न निकलने दें. एजेंट को ये AppFunctionAppUnknownException के तौर पर मिलते हैं. इससे यह पता नहीं चलता कि गड़बड़ी किस तरह की है.