Guia de RAG de IA de borda para Android

O SDK RAG de IA de borda fornece os componentes fundamentais para construir um pipeline de geração aumentada de recuperação (RAG, na sigla em inglês) com a API de inferência de LLM. Um pipeline de RAG oferece aos LLMs acesso a dados fornecidos pelo usuário, que podem incluir informações atualizadas, sensíveis ou específicas do domínio. Com os recursos de recuperação de informações adicionais da RAG, os LLMs podem gerar respostas mais precisas e sensíveis ao contexto para casos de uso específicos.

Este guia orienta você em uma implementação básica de um aplicativo de exemplo usando a API LLM Inference com o SDK de RAG de IA. Este guia se concentra na construção de um pipeline RAG. Para mais informações sobre como usar a API LLM Inference, consulte o guia LLM Inference para Android.

Confira o aplicativo de exemplo completo no GitHub. Para começar, crie o aplicativo, leia os dados fornecidos pelo usuário (sample_context.txt) e faça perguntas ao LLM relacionadas às informações no arquivo de texto.

Executar o aplicativo de exemplo

Este guia se refere a um exemplo de app básico de geração de texto com RAG para Android. Você pode usar o app de exemplo como ponto de partida para seu próprio app Android ou consultá-lo ao modificar um app existente.

O aplicativo é otimizado para dispositivos mais avançados, como Pixel 8, Pixel 9, S23 e S24. Conecte um dispositivo Android à sua estação de trabalho e confira se você tem uma versão atual do Android Studio. Para mais informações, consulte o Guia de configuração do Android.

Fazer o download do código do aplicativo

As instruções a seguir mostram como criar uma cópia local do código de exemplo usando a ferramenta de linha de comando do git.

Clone o repositório do Git usando o seguinte comando:

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

Depois de criar uma versão local do código de exemplo, você pode importar o projeto para o Android Studio e executar o app.

Fazer o download de um modelo

O aplicativo de exemplo está configurado para usar o Gemma-3 1B. O Gemma-3 1B faz parte da família Gemma de modelos abertos leves e de última geração criados com base na mesma pesquisa e tecnologia usadas para criar os modelos do Gemma. O modelo contém 1 bilhão de parâmetros e pesos abertos.

Faça o download do Gemma-3 1B

Depois de fazer o download do Gemma-3 1B do Hugging Face, envie o modelo para o dispositivo:

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

Você também pode usar outros modelos com o aplicativo de exemplo, mas isso pode exigir outras etapas de configuração.

Configurar um incorporação

O incorporador pega pedaços de texto dos dados fornecidos pelo usuário e os transforma em representações numéricas vetorizadas que capturam o significado semântico deles. O LLM se refere a esses embeddings para identificar vetores relevantes e incorporar os blocos mais semanticamente relevantes na saída gerada.

O aplicativo de exemplo foi projetado para funcionar com dois incorporadores, o Gemini e o Gecko.

Configurar com o embedder da Gecko

Por padrão, o app de exemplo é configurado para usar o incorporador do Gecko (GeckoEmbeddingModel) e executa o modelo completamente no dispositivo.

Fazer o download do Gecko 110m-pt

O incorporador do Gecko está disponível como modelos flutuantes e quantizados, com várias versões para diferentes comprimentos de sequência. Para mais informações, consulte o card de modelo Gecko.

As especificações do modelo podem ser encontradas no nome do arquivo. Exemplo:

  • Gecko_256_fp32.tflite: modelo de ponto flutuante compatível com sequências de até 256 tokens.
  • Gecko_1024_quant.tflite: modelo quantizado que aceita sequências de até 1.024 tokens.

A duração da sequência é o tamanho máximo do bloco que o modelo pode incorporar. Por exemplo, o modelo Gecko_256_fp32.tflite recebe um bloco que excede o comprimento da sequência. O modelo incorpora os primeiros 256 tokens e trunca o restante do bloco.

Envie o modelo de tokenizador (sentencepiece.model) e o incorporador do Gecko para seu dispositivo:

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

O modelo de incorporação é compatível com CPU e GPU. Por padrão, o app de exemplo é configurado para extrair embeddings com o modelo Gecko na GPU.

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

Configurar com o Gemini Embedder

O Embedder do Gemini (GeminiEmbedder) cria embeddings usando a API Gemini Cloud. Para executar o aplicativo, é necessário ter uma chave da API Google Gemini, que pode ser concedida na página de configuração da API Google Gemini.

Conseguir uma chave da API Gemini no Google AI Studio

Adicione sua chave da API Gemini e defina COMPUTE_EMBEDDINGS_LOCALLY como falso em RagPipeline.kt:

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

Como funciona

Esta seção fornece informações mais detalhadas sobre os componentes do pipeline RAG do aplicativo. É possível conferir a maior parte do código em RagPipeline.kt.

Dependências

O SDK do RAG usa a biblioteca com.google.ai.edge.localagents:localagents-rag. Adicione esta dependência ao arquivo build.gradle do app Android:

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

Dados fornecidos pelo usuário

Os dados fornecidos pelo usuário no aplicativo são um arquivo de texto chamado sample_context.txt, que é armazenado no diretório assets. O aplicativo pega partes do arquivo de texto, cria embeddings dessas partes e se refere a elas ao gerar o texto de saída.

O snippet de código a seguir pode ser encontrado em MainActivity.kt:

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

Divisão

Para simplificar, o arquivo sample_context.txt inclui tags <chunk_splitter> que o aplicativo de exemplo usa para criar fragmentos. Em seguida, as incorporações são criadas para cada bloco. Em aplicativos de produção, o tamanho dos blocos é uma consideração importante. Quando um bloco é muito grande, o vetor não tem especificidade suficiente para ser útil. Quando ele é muito pequeno, ele não tem contexto suficiente.

O aplicativo de exemplo processa o agrupamento pela função memorizeChunks em RagPipeline.kt.

Incorporação

O aplicativo oferece duas opções para embedding de texto:

  • Embedding da Gecko: extração local (no dispositivo) de embedding de texto com o modelo Gecko.
  • Gemini Embedder: extração de embeddings de texto baseada na nuvem com a API do Gênero de linguagem generativa.

O aplicativo de exemplo seleciona o incorporador com base na intenção do usuário de calcular incorporações localmente ou pelo Google Cloud. O snippet de código abaixo pode ser encontrado em 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
      )
  }

Banco de dados

O aplicativo de exemplo usa o SQLite (SqliteVectorStore) para armazenar incorporações de texto. Também é possível usar o banco de dados DefaultVectorStore para armazenamento de vetores não persistentes.

O snippet de código a seguir pode ser encontrado em RagPipeline.kt:

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

O app de exemplo define a dimensão de incorporação como 768, que se refere ao comprimento de cada vetor no banco de dados de vetores.

Cadeia

O SDK da RAG oferece cadeias, que combinam vários componentes da RAG em um único pipeline. Você pode usar cadeias para orquestrar modelos de recuperação e consulta. A API é baseada na interface Chain.

O aplicativo de exemplo usa a cadeia de recuperação e inferência. O snippet de código a seguir pode ser encontrado em RagPipeline.kt:

private val retrievalAndInferenceChain = RetrievalAndInferenceChain(config)

A cadeia é invocada quando o modelo gera respostas:

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
    }