AppFunctions 개요

AppFunctions를 사용하면 시스템과 다양한 AI 에이전트 및 어시스턴트가 검색하고 호출할 수 있는 특정 기능을 Android 앱이 공유할 수 있습니다. 이러한 함수를 정의하면 앱이 Android OS에 서비스, 데이터, 작업을 제공할 수 있으므로 사용자가 AI 에이전트와 시스템 수준 상호작용을 통해 작업을 완료할 수 있습니다.

AppFunctions는 모델 컨텍스트 프로토콜 (MCP) 내 도구의 모바일 버전 역할을 합니다. MCP는 기존에 에이전트가 서버 측 도구에 연결하는 방법을 표준화했지만, AppFunctions는 Android 앱에 동일한 메커니즘을 제공합니다. 이를 통해 승인된 앱 (호출자)이 사용자의 의도를 충족하기 위해 검색하고 실행할 수 있는 오케스트레이션 가능한 '도구'로 앱의 기능을 노출할 수 있습니다. 호출자에게는 AppFunctions를 검색하고 실행할 수 있는 EXECUTE_APP_FUNCTIONS 권한이 있어야 하며, 여기에는 에이전트, 앱, Gemini와 같은 AI 어시스턴트가 포함될 수 있습니다.

AppFunctions는 Android 16 이상을 실행하는 기기에서 작동합니다.

사용 사례

AppFunctions는 작업을 자동화하고 사용자 상호작용을 간소화하는 강력한 메커니즘을 제공합니다. 앱의 기능을 노출하면 사용자가 자연어를 사용하여 복잡한 목표를 달성할 수 있으며, UI를 사용한 단계별 수동 탐색이 필요하지 않은 경우가 많습니다.

다음 시나리오에서는 다양한 앱 카테고리 내에서 환경을 개선하기 위해 AppFunctions를 사용하는 방법을 보여줍니다.

  • 할 일 관리 및 생산성
    • 사용자 요청: "오늘 오후 5시에 회사에서 택배를 찾아오라고 알려 줘."
    • AppFunction 작업: 호출자가 관련 작업 관리 앱을 식별하고 함수를 호출하여 작업을 만듭니다. 사용자 프롬프트에 따라 제목, 시간, 위치 필드가 자동으로 채워집니다.
  • 미디어 및 엔터테인먼트
    • 사용자 요청: "올해 최고의 재즈 앨범으로 새 재생목록을 만들어 줘".
    • AppFunction 작업: 호출자가 음악 앱 내에서 재생목록 생성 함수를 실행하여 '2026년 인기 재즈 앨범'과 같은 컨텍스트를 쿼리로 전달하여 콘텐츠를 즉시 생성하고 실행합니다.
  • 교차 앱 워크플로
    • 사용자 요청: "Lisa의 이메일에서 국수 레시피를 찾아 재료를 내 쇼핑 목록에 추가해 줘."
    • AppFunction 작업: 이 요청은 여러 앱의 함수를 사용합니다. 먼저 호출자가 이메일 앱의 검색 기능을 사용하여 콘텐츠를 가져옵니다. 그런 다음 관련 재료를 추출하고 쇼핑 목록 앱의 기능을 호출하여 사용자의 목록을 채웁니다.
  • 캘린더 및 일정
    • 사용자 요청: "다음 주 월요일 오후 6시에 엄마 생일 파티를 내 캘린더에 추가해 줘".
    • AppFunction 작업: 승인된 에이전트 앱이 캘린더 앱의 '일정 만들기' 함수를 호출하여 '다음 월요일', '오후 6시'와 같은 관련 컨텍스트를 파싱하여 사용자가 캘린더를 수동으로 열지 않아도 항목을 만듭니다.

AppFunctions 작동 방식

AppFunctionsAndroid 16 플랫폼 기능이자 앱이 호출자(예: 에이전트 앱)가 기기에서 액세스하고 실행할 수 있도록 특정 기능을 노출할 수 있는 Jetpack 라이브러리입니다.

다음 다이어그램은 앱이 AppFunctions를 에이전트와 공유하고 이후에 실행하는 일반적인 흐름을 보여줍니다. 에이전트는 사용자 요청을 처리할 때 서버 측 원격 MCP 도구와 로컬 AppFunctions를 함께 고려할 가능성이 높습니다. 로컬 AppFunctions 사용을 위한 자세한 흐름은 다음과 같습니다.

  • AppFunction 선언: Android 앱은 '메모 작성' 또는 '메시지 보내기'와 같은 AppFunction을 노출하도록 빌드됩니다.
  • 스키마 생성: AppFunctions Jetpack 라이브러리는 앱에 선언된 모든 AppFunctions를 나열하는 XML 스키마 파일을 생성합니다. 이 파일은 Android OS에서 사용 가능한 AppFunctions를 색인하는 데 사용됩니다.
  • 메타데이터 검색: 에이전트는 쿼리를 통해 AppFunction 메타데이터를 검색할 수 있습니다.
  • AppFunction 선택 및 실행: 사용자 프롬프트에 따라 에이전트가 적절한 매개변수로 적절한 AppFunction을 선택하고 실행합니다.
앱 노출에서 에이전트 실행까지의 일반적인 AppFunctions 흐름을 보여주는 다이어그램
그림 1: AppFunction이 노출되고 에이전트에 의해 실행되는 일반적인 흐름

AppFunctions Jetpack 라이브러리를 사용하면 앱의 기능을 쉽게 노출할 수 있습니다. 주석 프로세서를 사용하면 개발자가 노출하려는 함수에 주석을 추가합니다. 그런 다음 호출자는 AppFunctionManager를 사용하여 이러한 색인이 생성된 함수를 검색하고 호출할 수 있습니다.

앱에서 AppFunction 기능이 지원되는지 확인할 필요는 없습니다. Jetpack 라이브러리 내에서 자동으로 처리됩니다. 예를 들어 AppFunctionManager는 기능이 지원되는지 확인할 수 있습니다.

다음은 메모를 만들고, 수정하고, 나열하는 기능을 갖춘 메모 앱의 AppFunctions 예시입니다.

class NoteFunctions(
  private val noteRepository: NoteRepository
) {
    /**
     * A note.
     *
     * @param id The note's ID.
     * @param title The note's title.
     * @param content The note's content.
     */
    @AppFunctionSerializable(isDescribedByKDoc = true)
    data class Note(val id: Int, val title: String, val content: String)

    /**
     * Lists all available notes.
     *
     * @param appFunctionContext The context in which the AppFunction is executed.
     */
    @AppFunction(isDescribedByKDoc = true)
    suspend fun listNotes(appFunctionContext: AppFunctionContext): List<Note>? {
        return if (noteRepository.appNotes.isEmpty()) null else viewModel.appNotes
    }

    /**
     * Adds a new note to the app.
     *
     * @param appFunctionContext The context in which the AppFunction is executed.
     * @param title The title of the note.
     * @param content The note's content.
     */
    @AppFunction(isDescribedByKDoc = true)
    suspend fun createNote(
      appFunctionContext: AppFunctionContext,
      title: String,
      content: String
    ): Note {
        return noteRepository.createNote(title, content)
    }

    /**
     * Edits a single note.
     *
     * @param appFunctionContext The context in which the AppFunction is executed.
     * @param noteId The target note's ID.
     * @param title The new title if it should be updated.
     * @param content The new content if it should be updated.
     */
    @AppFunction(isDescribedByKDoc = true)
    suspend fun editNote(
      appFunctionContext: AppFunctionContext,
      noteId: String,
      title: String?,
      content: String,
    ): Note? {
        return noteRepository.updateNote(noteId, title, content)
    }
}