Przewodnik RAG dotyczącej AI na urządzeniach z Androidem

Pakiet SDK AI Edge RAG udostępnia podstawowe komponenty do tworzenia potoku generowania rozszerzonego przez wyszukiwanie w zapisanych informacjach (RAG) za pomocą interfejsu LLM Inference API. Potok RAG zapewnia LLM dostęp do danych przekazywanych przez użytkowników, które mogą zawierać zaktualizowane, poufne lub specyficzne dla danej domeny informacje. Dzięki dodatkowym możliwościom wyszukiwania informacji, jakie daje RAG, modele LLM mogą generować dokładniejsze i uwzględniające kontekst odpowiedzi w przypadku konkretnych zastosowań.

Ten przewodnik przeprowadzi Cię przez podstawową implementację przykładowej aplikacji z użyciem interfejsu LLM Inference API i pakietu AI Edge RAG SDK. W tym przewodniku skupimy się na tworzeniu potoku RAG. Więcej informacji o korzystaniu z interfejsu LLM Inference API znajdziesz w przewodniku po interfejsie LLM Inference API na Androida.

Pełną aplikację przykładową znajdziesz w GitHub. Aby rozpocząć, utwórz aplikację, zapoznaj się z danymi przekazanymi przez użytkownika (sample_context.txt) i zadaj LLM pytania dotyczące informacji w pliku tekstowym.

Uruchamianie przykładowej aplikacji

W tym przewodniku znajdziesz przykład podstawowej aplikacji do generowania tekstu z RAG na Androida. Przykładowej aplikacji możesz użyć jako punktu wyjścia do utworzenia własnej aplikacji na Androida lub jako odniesienia podczas modyfikowania istniejącej aplikacji.

Aplikacja jest zoptymalizowana pod kątem urządzeń z wyższej półki, takich jak Pixel 8, Pixel 9, S23 i S24. Podłącz urządzenie z Androidem do stacji roboczej i upewnij się, że masz aktualną wersję Android Studio. Więcej informacji znajdziesz w przewodniku po konfiguracji Androida.

Pobieranie kodu aplikacji

Poniższe instrukcje pokazują, jak utworzyć lokalną kopię przykładowego kodu za pomocą narzędzia wiersza poleceń Git.

Sklonuj repozytorium Git za pomocą tego polecenia:

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

Po utworzeniu lokalnej wersji przykładowego kodu możesz zaimportować projekt do Android Studio i uruchomić aplikację.

Pobieranie modelu

Przykładowa aplikacja jest skonfigurowana do korzystania z modelu Gemma-3 1B. Gemma-3 1B należy do rodziny lekkich, zaawansowanych otwartych modeli Gemma, które powstały na podstawie tych samych badań i technologii, które zostały wykorzystane do stworzenia modeli Gemini. Model zawiera 1 miliard parametrów i otwarte wagi.

Pobierz model Gemma-3 1B

Po pobraniu modelu Gemma-3 1B z Hugging Face przenieś go na urządzenie:

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

W przykładowej aplikacji możesz też używać innych modeli, ale może to wymagać dodatkowych czynności konfiguracyjnych.

Konfigurowanie narzędzia do osadzania

Wbudowany model pobiera fragmenty tekstu z danych przekazywanych przez użytkowników i przekształca je w wektorowe reprezentacje numeryczne, które odzwierciedlają ich znaczenie semantyczne. Model LLM odwołuje się do tych wektorów dystrybucyjnych, aby zidentyfikować odpowiednie wektory, i uwzględnia w wygenerowanych wynikach fragmenty o największym znaczeniu semantycznym.

Przykładowa aplikacja została zaprojektowana do współpracy z 2 osadzającymi: osadzającym Gemini i osadzającym Gecko.

Konfigurowanie za pomocą komponentu Gecko

Domyślnie przykładowa aplikacja jest skonfigurowana do korzystania z osadzonego komponentu Gecko (GeckoEmbeddingModel) i uruchamia model w całości na urządzeniu.

Pobierz Gecko 110m-en

Gecko Embedder jest dostępny jako modele zmiennoprzecinkowe i skwantyzowane w wielu wersjach dla różnych długości sekwencji. Więcej informacji znajdziesz w karcie modelu Gecko.

Specyfikacje modelu znajdziesz w nazwie pliku modelu. Na przykład:

  • Gecko_256_f32.tflite: model zmiennoprzecinkowy, który obsługuje sekwencje do 256 tokenów.
  • Gecko_1024_quant.tflite: skwantyzowany model, który obsługuje sekwencje zawierające do 1024 tokenów.

Długość sekwencji to maksymalny rozmiar fragmentu, który model może osadzić. Jeśli na przykład model Gecko_256_f32.tflite otrzyma fragment, który przekracza długość sekwencji, osadzi pierwsze 256 tokenów i obetnie resztę fragmentu.

Wypchnij model tokenizera (sentencepiece.model) i osadzony komponent Gecko na urządzenie:

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

Model osadzania jest zgodny zarówno z procesorem, jak i z kartą graficzną. Domyślnie przykładowa aplikacja jest skonfigurowana tak, aby wyodrębniać wektory za pomocą modelu Gecko na GPU.

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

Konfigurowanie za pomocą Gemini Embedder

Usługa Gemini Embedder (GeminiEmbedder) tworzy embeddingi za pomocą interfejsu Gemini Cloud API. Do uruchomienia aplikacji wymagany jest klucz interfejsu Google Gemini API, który możesz uzyskać na stronie konfiguracji interfejsu Google Gemini API.

Uzyskiwanie klucza interfejsu Gemini API w Google AI Studio

Dodaj klucz interfejsu Gemini API i ustaw wartość COMPUTE_EMBEDDINGS_LOCALLY na false w pliku RagPipeline.kt:

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

Jak to działa

Ta sekcja zawiera bardziej szczegółowe informacje o komponentach potoku RAG aplikacji. Większość kodu możesz zobaczyć w pliku RagPipeline.kt.

Zależności

Pakiet SDK RAG korzysta z biblioteki com.google.ai.edge.localagents:localagents-rag. Dodaj tę zależność do pliku build.gradle aplikacji na Androida:

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

Dane przekazywane przez użytkowników

Dane przekazywane przez użytkowników w aplikacji to plik tekstowy o nazwie sample_context.txt, który jest przechowywany w katalogu assets. Aplikacja dzieli plik tekstowy na części, tworzy ich osadzenia i wykorzystuje je podczas generowania tekstu wyjściowego.

Ten fragment kodu znajdziesz w pliku MainActivity.kt:

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

Chunking

Dla uproszczenia plik sample_context.txt zawiera tagi <chunk_splitter>, których przykładowa aplikacja używa do tworzenia fragmentów. Następnie dla każdego fragmentu tworzone są wektory. W aplikacjach produkcyjnych rozmiar fragmentów jest kluczowym czynnikiem. Gdy fragment jest zbyt duży, wektor nie zawiera wystarczającej ilości szczegółów, aby był przydatny. Z kolei gdy jest zbyt mały, nie zawiera wystarczającego kontekstu.

Przykładowa aplikacja obsługuje dzielenie na części za pomocą funkcji memorizeChunksw pliku RagPipeline.kt.

Umieszczanie

Aplikacja oferuje 2 ścieżki wektora dystrybucyjnego tekstu:

  • Gecko embedder: lokalne (na urządzeniu) wyodrębnianie wektorów dystrybucyjnych tekstu za pomocą modelu Gecko.
  • Gemini Embedder: wyodrębnianie wektorów dystrybucyjnych tekstu w chmurze za pomocą interfejsu Generative Language Cloud API.

Przykładowa aplikacja wybiera moduł do osadzania na podstawie tego, czy użytkownik chce obliczać osadzanie lokalnie, czy w Google Cloud. Ten fragment kodu znajduje się w pliku 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
      )
  }

Baza danych

Przykładowa aplikacja używa SQLite (SqliteVectorStore) do przechowywania wektorów tekstowych. Możesz też używać bazy danych DefaultVectorStore do nietrwałego przechowywania wektorów.

Ten fragment kodu znajdziesz w pliku RagPipeline.kt:

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

Przykładowa aplikacja ustawia wymiar wektora na 768, co odnosi się do długości każdego wektora w bazie danych wektorów.

Łańcuch

Pakiet SDK RAG udostępnia łańcuchy, które łączą kilka komponentów RAG w jeden potok. Łańcuchów możesz używać do koordynowania modeli pobierania i zapytań. Interfejs API jest oparty na interfejsie Chain.

Przykładowa aplikacja korzysta z łańcucha Retrieval and Inference. Ten fragment kodu znajdziesz w pliku RagPipeline.kt:

private val retrievalAndInferenceChain = RetrievalAndInferenceChain(config)

Łańcuch jest wywoływany, gdy model generuje odpowiedzi:

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
    }