AppFunctions কোয়ালিটি সংক্রান্ত নির্দেশিকা

AppFunctions হল Android-এ MCP সার্ভারের প্র্যাকটিক্যাল সমতুল্য। এগুলি আপনাকে AI এজেন্ট ও অ্যাসিস্ট্যান্টের সাথে আপনার অ্যাপের লজিকের অংশ শেয়ার করতে দেয়।

অনুরোধ পূরণ করে এমন AppFunction বেছে নিতে এজেন্ট বিবরণ ব্যবহার করে। এই বাছাই প্রক্রিয়াটি চিরাচরিত MCP টুল ডিসকভারির মতো কাজ করে, যেখানে AI অ্যাপ্লিকেশনগুলি তাদের পছন্দগুলি নির্দেশ করার জন্য MCP সার্ভার এবং টুলের বিবরণ ব্যবহার করে। আপনার অ্যাপ Android MCP সার্ভার হিসেবে কাজ করে এবং প্রতিটি AppFunction এর একটি টুল হিসেবে কাজ করে। নিম্নলিখিত বিবরণ প্রদান করুন:

  • অ্যাপের বিবরণ (Android MCP সার্ভার)। আপনার অ্যাপ কী করতে পারে তা বোঝার জন্য এজেন্টদের প্রথম এন্ট্রি পয়েন্ট হল আপনার অ্যাপের বিবরণ। এজেন্টদের আপনার অ্যাপ খুঁজে পেতে সাহায্য করার জন্য, এর প্রাথমিক ডোমেন দিয়ে শুরু করুন এবং আপনার AppFunctions যে কাজগুলি সম্পন্ন করতে দেয় তার একটি সংক্ষিপ্ত তালিকা তৈরি করুন।
    • আপনার অ্যাপ মেটাডেটা XML ফাইলে, অ্যাপের বিবরণ নিজেই লিখুন।
    • অ্যাপের বিবরণ ব্যবহার করে এমন কিছু বর্ণনা করুন যা আলাদা আলাদা ফাংশনের বিবরণ করতে পারে না, যেমন কোন ক্রমে ফাংশন কল করতে হবে।
  • AppFunction-এর বিবরণ (টুল)। প্রতিটি ফাংশনের বিবরণ একটি AppFunction-এর আচরণ ব্যাখ্যা করে। ফাংশনের বিবরণ সাধারণত আপডেট করুন, তৈরি করুন বা বুক করুন-এর মতো ক্রিয়াপদ এবং সেটিংস, চ্যানেল বা রুম-এর মতো রিসোর্সকে কেন্দ্র করে তৈরি করা হয়।

ফাংশনের বিবরণ সংক্রান্ত নির্দেশিকা

কোন ফাংশন কোনও অনুরোধের জন্য উপযুক্ত এবং কীভাবে এটি কল করতে হবে তা সিদ্ধান্ত নিতে এজেন্টরা ফাংশনের বিবরণের উপর নির্ভর করে।

AppFunction-এর সংক্ষিপ্ত ও স্পষ্ট বিবরণ লিখুন

বিবরণ যত কম অস্পষ্ট হবে, এজেন্ট তত বেশি নির্ভরযোগ্যভাবে কোনও অনুরোধের জন্য সঠিক ফাংশন বেছে নিতে পারবে। ফাংশনের বিবরণে কী করা উচিত এবং কী করা উচিত নয়, তা নিম্নলিখিত সারণীতে তালিকাভুক্ত করা হয়েছে:

কী করতে হবে করবেন না
ফাংশনের উদ্দেশ্য এবং এটি চালানোর ফলাফল, স্পষ্ট এবং নিরপেক্ষ ভাষায় বর্ণনা করুন। প্রম্পট হিসেবে বিবরণ ব্যবহার করবেন না। "আপনাকে বলতেই হবে" এবং "আপনাকে ব্যবহারকারীকে জিজ্ঞাসা করতেই হবে"-এর মতো কমান্ড এজেন্টকে ফাংশন বর্ণনা করার পরিবর্তে কীভাবে আচরণ করতে হবে তার নির্দেশ দেয়।
বিবরণের শুরুতে মূল তথ্য দিন এবং বিবরণ সংক্ষিপ্ত রাখুন। বিবরণে "এই ফাংশনটি ব্যবহার করা হয়" এই ধরনের ফিলার ব্যবহার করবেন না। ফিলার কোনও বিবরণকে আরও স্পষ্ট না করেই দীর্ঘ করে তোলে।
কোডটি কী করে তা সঠিকভাবে প্রতিফলিত করুন, এর প্যারামিটার এবং আউটপুট সহ। যেমন, শুধুমাত্র-পড়ার-জন্য হিসেবে বর্ণনা করা কোনও ফাংশন ডেটা লিখতে বা মুছতে পারবে না। বিভ্রান্তিকর নাম ব্যবহার করবেন না, যেমন fetchData নামের ফাংশন ব্যবহারকারীর ডেটা মুছে দেয়।
প্যারামিটার ও রিটার্ন টাইপ সহ KDoc ফর্ম্যাটে ফাংশনের বিবরণ লেখো। নামকরণের জন্য Kotlin স্টাইল গাইড অনুসরণ করুন এবং ইমপ্লিমেন্টেশন সম্পর্কে না জেনেও বোঝা যায় এমন বিবরণ তৈরি করুন। বিবরণের কোনও অংশের প্রতি দৃষ্টি আকর্ষণ করার জন্য অতিরিক্ত বড় হাতের অক্ষর বা বিশেষ অক্ষর ব্যবহার করবেন না, যেমন **CRITICAL** বা VERY IMPORTANT।
AppFunctions-এর জন্য মানুষের-পঠনযোগ্য নাম ব্যবহার করুন।
প্রতিটি AppFunction কী করে সেই সম্পর্কে স্পষ্ট ও সরাসরি তথ্য দিন। অন্যান্য ফাংশন জড়িত এমন পদ্ধতিগত নির্দেশাবলী দেবেন না, যেমন "প্রথমে পরিচিতি সার্চ করুন।" এজেন্ট আপনার অ্যাপের বিবরণ ব্যবহার করে বিভিন্ন ফাংশন জুড়ে কল করার পরিকল্পনা করে, তাই সেখানে সেই ক্রম বর্ণনা করুন।
ফাংশন থেকে এজেন্ট কী আশা করতে পারে তা বর্ণনা করুন, যেমন "আপনার কাছে X থাকলে, Y" এই ধরনের ভাষা ব্যবহার করুন।
Assume that agents have their own instructions for using AppFunctions in general. ফাংশনের বিবরণ থেকে জানা যায় যে ফাংশনটি কী করে এবং এজেন্টের নির্দেশাবলী থেকে জানা যায় যে এটি কীভাবে ব্যবহার করতে হয়। ফাংশনের বিবরণে এজেন্ট-লেভেল নির্দেশাবলী ওভাররাইড বা এম্বেড করার চেষ্টা করবেন না।

এনক্যাপসুলেশন মাথায় রেখে লিখুন

প্রতিটি ফাংশনের বিবরণ স্বয়ংসম্পূর্ণ রাখুন, যাতে এটি এজেন্টকে সেই ফাংশনটি ব্যবহার করার জন্য গাইড করে এবং অন্য কোনও ফাংশন নয়। নিম্নলিখিত সারণীতে এনক্যাপসুলেশন নির্দেশিকা তালিকাভুক্ত করা হয়েছে:

কী করতে হবে করবেন না
ফাংশনের এমন বিবরণ লিখুন যা নির্দিষ্ট এবং ফোকাসড, যার একটি একক, সুনির্দিষ্ট উদ্দেশ্য রয়েছে। যেমন, "ব্যক্তিগত টাস্ক তৈরি করা, খোঁজা এবং মুছে ফেলা।" এমন বিবরণ লিখবেন না যা খুব বেশি বিস্তৃত, কারণ এর ফলে এজেন্ট অনুপযুক্ত সময়ে বা ভুল কারণে আপনার ফাংশন কল করতে পারে।
মাল্টিপারপাস AppFunctions তৈরি করবেন না বা একই ব্যবহারের ক্ষেত্রে অনেক AppFunctions প্রকাশ করবেন না। একাধিক ফাংশনের একই ধরনের ইনটেন্ট থাকলে, এজেন্ট ভুল ফাংশন বেছে নেওয়ার সম্ভাবনা বেশি থাকে।
আপনার অ্যাপে বা অন্যান্য অ্যাপে অন্যান্য AppFunctions-এর আচরণকে প্রভাবিত করার চেষ্টা করবেন না বা উল্লেখ করবেন না। এর ফলে অযাচিত ডিপেনডেন্সি এবং সাইড এফেক্ট তৈরি হতে পারে।

অনুমতিযোগ্য অ্যাকশন ও ডেটা শেয়ারিং

এজেন্ট আপনার অ্যাপের ফাংশন ব্যবহার করার সময় ব্যবহারকারীর গোপনীয়তা ও নিরাপত্তা রক্ষা করতে এইসব নির্দেশিকা অনুসরণ করুন:

কী করতে হবে করবেন না
শুধুমাত্র নিরাপদ, ধ্বংসাত্মক নয় এমন টাস্ক পারফর্ম করুন যা ব্যবহারকারী সাধারণত আপনার অ্যাপে করে থাকেন, যেখানে এজেন্ট ব্যবহারকারীর অনুরোধ থেকে স্পষ্ট প্যারামিটার প্রদান করতে পারে—যেমন, কোনও শীর্ষক সহ টাস্ক তৈরি করা বা নোট সার্চ করা।
শুধুমাত্র এমন তথ্য শেয়ার করুন যা অত্যন্ত ব্যক্তিগত বা গোপনীয় নয়, অথবা এমন ডেটা যা শেয়ার করার জন্য ব্যবহারকারী স্পষ্টভাবে সম্মতি দিয়েছেন। এজেন্টকে ব্যবহারকারীর ডেটা বা সিস্টেম রিসোর্সের বিস্তৃত অ্যাক্সেস দেবেন না।
এমন AppFunctions ডিজাইন করবেন না যার জন্য পাসওয়ার্ড, আর্থিক বিবরণ, ব্যক্তিগত কী বা অন্যান্য অত্যন্ত সংবেদনশীল ব্যক্তিগত তথ্য প্রয়োজন হয় বা রিটার্ন করে।
ব্যবহারকারীর অনুরোধ করা অ্যাকশন পারফর্ম করা, এমনকি সেগুলি পরে বা ব্যাকগ্রাউন্ডে রান করলেও—যেমন, ব্যবহারকারীর বেছে নেওয়া সময়ে মেসেজ পাঠানো। ব্যবহারকারী অনুরোধ করেননি এমন অ্যাকশন পারফর্ম করবেন না, যেমন এমন টাস্ক যা নিজে থেকে শুরু হয় বা অনুরোধের বাইরে যায়।
ন্যাচারাল ল্যাঙ্গুয়েজ থেকে সুবিধা পায় এমন ফাংশনের উপর ফোকাস করুন, যেমন UI নেভিগেশনের মাধ্যমে করার চেয়ে কথোপকথনে প্রকাশ করা সহজ এমন টাস্ক— যেমন, "[AI এজেন্ট], তুমি কি আমার ক্যালেন্ডারে আগামী সপ্তাহে কিছু উপলভ্য সময় খুঁজে পেতে সাহায্য করতে পারবে এবং তারপর সেই দিনগুলির মধ্যে কোনও একটিতে শিকাগো যাওয়ার ফ্লাইটের সাজেশন দিতে পারবে?"
ফোন ছাড়া অন্যান্য ফর্ম ফ্যাক্টরে, টিভি, Android Auto এবং Android Automotive OS-এর মতো শেয়ার করা ডিভাইসে ব্যবহারকারীর গোপনীয়তাকে সম্মান করুন। আপনার অ্যাপের UI সেই ফর্ম ফ্যাক্টরে কাজ করে না এমন তথ্য প্রকাশ করবেন না বা অ্যাকশন পারফর্ম করবেন না।
আপনার ফাংশনের উদ্দেশ্য স্পষ্টভাবে এবং অনন্যভাবে শনাক্ত করুন। অন্য কোনও টুল বা পরিষেবা হিসেবে নিজেকে দেখাবেন না। আপনার ফাংশনের নাম এবং বিবরণ যেন অন্যান্য টুলের সাথে বিভ্রান্তিকরভাবে একই রকম না হয়, যার ফলে এজেন্ট ভুল করে আপনার ফাংশন বেছে নিতে পারে।

প্যারামিটার ও রিটার্ন ভ্যালু ডিজাইন

সতর্কতার সাথে প্যারামিটার ও রিটার্ন ভ্যালু ডিজাইন করলে অস্পষ্টতা এড়ানো যায় এবং ভুল কল করার সম্ভাবনা কমে। এইসব কনভেনশন অনুসরণ করুন:

কী করতে হবে করবেন না
আপনার ফাংশনের জন্য প্রয়োজনীয় ডেটার জন্য শুধু প্যারামিটার নির্ধারণ করুন। ফাংশন ব্যবহার করে না এমন তথ্যের জন্য অনুরোধ করবেন না। এটি ডেটা এক্সপোজার কম করে এবং ফাংশনের ব্যবহার সহজ করে।
প্রত্যাশিত ইনপুট প্রতিফলিত করে এমন প্যারামিটারের নাম ব্যবহার করুন, যেমন 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-এর ভ্যালু নাল হওয়ার অর্থ হল "পরিবর্তন করবেন না" এবং 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,
    )
}

সমস্যা ম্যানেজ করা

কল ব্যর্থ হলে, এজেন্ট আপনার ফাংশন থেকে ব্যতিক্রমটি গ্রহণ করে, যার মধ্যে এর ধরন এবং মেসেজ অন্তর্ভুক্ত থাকে। এইসব কনভেনশন অনুসরণ করুন যাতে এজেন্ট ব্যর্থতা থেকে রিকভার করতে পারে বা ব্যবহারকারীকে এই বিষয়ে রিপোর্ট করতে পারে:

কী করতে হবে করবেন না
কারণটির সাথে মেলে এমন AppFunctionException সাবক্লাস থ্রো করুন, সাথে এমন একটি মেসেজ দিন যা সহজ ভাষায় সমস্যাটি বর্ণনা করে—যেমন, AppFunctionInvalidArgumentException যখন কোনও আর্গুমেন্ট সঠিক নয়, অথবা AppFunctionElementNotFoundException যখন অনুরোধ করা আইটেমটি নেই। এই ধরনটি এজেন্টকে বলে যে কী ধরনের ব্যর্থতা ঘটেছে এবং মেসেজটি এটিকে রিকভার করার জন্য প্রয়োজনীয় বিবরণ দেয়, যেমন একটি আর্গুমেন্ট সংশোধন করা বা ব্যবহারকারীকে বলা। আগে থেকে থাকা রিসোর্সে আপডেট বিভাগে updateNote উদাহরণে এই প্যাটার্ন দেখানো হয়েছে। অন্যান্য ব্যতিক্রম যেন আপনার ফাংশন এড়িয়ে না যায়। এজেন্ট সেগুলি AppFunctionAppUnknownException হিসেবে পায়, যা থেকে ব্যর্থতার ধরন শনাক্ত করা যায় না।