Guide de RAG AI Edge pour Android

Le SDK AI Edge RAG fournit les composants fondamentaux pour construire un pipeline de génération augmentée par récupération (RAG) avec l'API LLM Inference. Un pipeline RAG permet aux LLM d'accéder aux données fournies par les utilisateurs, qui peuvent inclure des informations mises à jour, sensibles ou spécifiques à un domaine. Grâce aux fonctionnalités de récupération d'informations supplémentaires de RAG, les LLM peuvent générer des réponses plus précises et plus adaptées au contexte pour des cas d'utilisation spécifiques.

Ce guide vous présente une implémentation de base d'un exemple d'application utilisant l'API LLM Inference avec le SDK AI Edge RAG. Ce guide est axé sur la construction d'un pipeline RAG. Pour en savoir plus sur l'utilisation de l'API LLM Inference, consultez le guide LLM Inference pour Android.

Vous trouverez l'exemple d'application complet sur GitHub. Pour commencer, créez l'application, lisez les données fournies par l'utilisateur (sample_context.txt), puis posez au LLM des questions sur les informations contenues dans le fichier texte.

Exécuter l'exemple d'application

Ce guide fait référence à un exemple d'application de génération de texte de base avec RAG pour Android. Vous pouvez utiliser l'application exemple comme point de départ pour votre propre application Android ou vous y référer lorsque vous modifiez une application existante.

L'application est optimisée pour les appareils haut de gamme tels que Pixel 8, Pixel 9, S23 et S24. Connectez un appareil Android à votre poste de travail et assurez-vous d'avoir la dernière version d'Android Studio. Pour en savoir plus, consultez le guide de configuration d'Android.

Télécharger le code de l'application

Les instructions suivantes vous montrent comment créer une copie locale de l'exemple de code à l'aide de l'outil de ligne de commande git.

Clonez le dépôt Git à l'aide de la commande suivante :

git clone https://github.com/google-ai-edge/ai-edge-apis

Après avoir créé une version locale de l'exemple de code, vous pouvez importer le projet dans Android Studio et exécuter l'application.

Télécharger un modèle

L'exemple d'application est configuré pour utiliser Gemma-3 1B. Gemma-3 1B fait partie de la famille Gemma de modèles ouverts, légers et de pointe conçus à partir des mêmes recherches et technologies que celles utilisées pour créer les modèles Gemini. Le modèle contient 1 milliard de paramètres et des pondérations ouvertes.

Télécharger Gemma-3 1B

Après avoir téléchargé Gemma-3 1B depuis Hugging Face, transférez le modèle sur votre appareil :

cd ~/Downloads
tar -xvzf gemma3-1b-it-int4.tar.gz
$ adb shell rm -r /data/local/tmp/llm/ # Remove any previously loaded models
$ adb shell mkdir -p /data/local/tmp/llm/
$ adb push output_path /data/local/tmp/llm/model_version.task

Vous pouvez également utiliser d'autres modèles avec l'application exemple, mais cela peut nécessiter des étapes de configuration supplémentaires.

Configurer un intégrateur

L'embedder prend des blocs de texte à partir des données fournies par l'utilisateur et les transforme en représentations numériques vectorisées qui capturent leur signification sémantique. Le LLM se réfère à ces embeddings pour identifier les vecteurs pertinents et intègre les blocs les plus pertinents sémantiquement dans le résultat généré.

L'exemple d'application est conçu pour fonctionner avec deux intégrateurs : l'intégrateur Gemini et l'intégrateur Gecko.

Configurer avec Gecko Embedder

Par défaut, l'application exemple est configurée pour utiliser l'intégrateur Gecko (GeckoEmbeddingModel) et exécute le modèle entièrement sur l'appareil.

Télécharger Gecko 110m-en

L'intégrateur Gecko est disponible en tant que modèles flottants et quantifiés, avec plusieurs versions pour différentes longueurs de séquence. Pour en savoir plus, consultez la fiche de modèle Gecko.

Les spécifications du modèle sont indiquées dans le nom du fichier du modèle. Exemple :

  • Gecko_256_f32.tflite : modèle flottant qui accepte les séquences de jetons jusqu'à 256.
  • Gecko_1024_quant.tflite : modèle quantifié qui accepte des séquences de 1 024 jetons maximum.

La longueur de séquence correspond à la taille maximale des blocs que le modèle peut intégrer. Par exemple, si un bloc qui dépasse la longueur de la séquence est transmis au modèle Gecko_256_f32.tflite, le modèle intégrera les 256 premiers jetons et tronquera le reste du bloc.

Transférez le modèle de tokenisation (sentencepiece.model) et l'intégrateur Gecko sur votre appareil :

adb push sentencepiece.model /data/local/tmp/sentencepiece.model
adb push Gecko_256_f32.tflite /data/local/tmp/gecko.tflite

Le modèle d'embedding est compatible avec les CPU et les GPU. Par défaut, l'application exemple est configurée pour extraire les embeddings avec le modèle Gecko sur GPU.

companion object {
  ...
  private const val USE_GPU_FOR_EMBEDDINGS = true
}

Configurer avec Gemini Embedder

L'outil Gemini Embedder (GeminiEmbedder) crée des embeddings à l'aide de l'API Gemini Cloud. Pour exécuter l'application, vous avez besoin d'une clé API Google Gemini, que vous pouvez obtenir sur la page de configuration de l'API Google Gemini.

Obtenir une clé API Gemini dans Google AI Studio

Ajoutez votre clé API Gemini et définissez COMPUTE_EMBEDDINGS_LOCALLY sur "false" dans RagPipeline.kt :

companion object {
  ...
  private const val COMPUTE_EMBEDDINGS_LOCALLY = false
  private const val GEMINI_API_KEY = "<API_KEY>"
}

Fonctionnement

Cette section fournit des informations plus détaillées sur les composants du pipeline RAG de l'application. Vous pouvez consulter la majeure partie du code sur RagPipeline.kt.

Dépendances

Le SDK RAG utilise la bibliothèque com.google.ai.edge.localagents:localagents-rag. Ajoutez cette dépendance au fichier build.gradle de votre application Android :

dependencies {
    ...
    implementation("com.google.ai.edge.localagents:localagents-rag:0.1.0")
    implementation("com.google.mediapipe:tasks-genai:0.10.22")
}

Données fournies par l'utilisateur

Les données fournies par l'utilisateur dans l'application sont un fichier texte nommé sample_context.txt, qui est stocké dans le répertoire assets. L'application prend des blocs du fichier texte, crée des embeddings de ces blocs et se réfère aux embeddings lors de la génération du texte de sortie.

L'extrait de code suivant se trouve dans MainActivity.kt :

class MainActivity : ComponentActivity() {
  lateinit var chatViewModel: ChatViewModel
...
    chatViewModel.memorizeChunks("sample_context.txt")
...
}

Fragmentation

Pour plus de simplicité, le fichier sample_context.txt inclut des tags <chunk_splitter> que l'exemple d'application utilise pour créer des blocs. Des embeddings sont ensuite créés pour chaque bloc. Dans les applications de production, la taille des blocs est un élément clé à prendre en compte. Lorsqu'un bloc est trop grand, le vecteur ne contient pas suffisamment de spécificité pour être utile. Lorsqu'il est trop petit, il ne contient pas assez de contexte.

L'application exemple gère le découpage en blocs via la fonction memorizeChunks dans RagPipeline.kt.

Embedding

L'application propose deux chemins pour l'embedding de texte :

  • Embedder Gecko : extraction locale (sur l'appareil) des embeddings de texte avec le modèle Gecko.
  • Embedder Gemini : extraction d'embeddings textuels basés sur le cloud avec l'API Generative Language Cloud.

L'application exemple sélectionne l'intégrateur en fonction de l'intention de l'utilisateur de calculer les embeddings en local ou via Google Cloud. L'extrait de code suivant se trouve dans RagPipeline.kt :

private val embedder: Embedder<String> = if (COMPUTE_EMBEDDINGS_LOCALLY) {
  GeckoEmbeddingModel(
    GECKO_MODEL_PATH,
    Optional.of(TOKENIZER_MODEL_PATH),
    USE_GPU_FOR_EMBEDDINGS,
    )
  } else {
    GeminiEmbedder(
      GEMINI_EMBEDDING_MODEL,
      GEMINI_API_KEY
      )
  }

Base de données

L'application exemple utilise SQLite (SqliteVectorStore) pour stocker les embeddings de texte. Vous pouvez également utiliser la base de données DefaultVectorStore pour le stockage de vecteurs non persistants.

L'extrait de code suivant se trouve dans RagPipeline.kt :

private val config = ChainConfig.create(
    mediaPipeLanguageModel, PromptBuilder(QA_PROMPT_TEMPLATE1),
    DefaultSemanticTextMemory(
        SqliteVectorStore(768), embedder
    )
)

L'application exemple définit la dimension d'embedding sur 768, ce qui correspond à la longueur de chaque vecteur dans la base de données vectorielle.

Chaîne

Le SDK RAG fournit des chaînes qui combinent plusieurs composants RAG en un seul pipeline. Vous pouvez utiliser des chaînes pour orchestrer les modèles de récupération et de requête. L'API est basée sur l'interface Chain.

L'exemple d'application utilise la chaîne de récupération et d'inférence. L'extrait de code suivant se trouve dans RagPipeline.kt :

private val retrievalAndInferenceChain = RetrievalAndInferenceChain(config)

La chaîne est appelée lorsque le modèle génère des réponses :

suspend fun generateResponse(
    prompt: String,
    callback: AsyncProgressListener<LanguageModelResponse>?
): String =
    coroutineScope {
        val retrievalRequest =
            RetrievalRequest.create(
                prompt,
                RetrievalConfig.create(2, 0.0f, TaskType.QUESTION_ANSWERING)
            )
        retrievalAndInferenceChain.invoke(retrievalRequest, callback).await().text
    }