El SDK de RAG de AI Edge proporciona los componentes fundamentales para construir una canalización de Generación mejorada por recuperación (RAG) con la API de LLM Inference. Una canalización de RAG proporciona a los LLM acceso a los datos proporcionados por el usuario, que pueden incluir información actualizada, sensible o específica del dominio. Con las capacidades adicionales de recuperación de información de la RAG, los LLMs pueden generar respuestas más precisas y conscientes del contexto para casos de uso específicos.
En esta guía, se explica una implementación básica de una aplicación de ejemplo con la API de LLM Inference y el SDK de RAG de AI Edge. En esta guía, nos enfocamos en la construcción de una canalización de RAG. Para obtener más información sobre el uso de la API de LLM Inference, consulta la guía de LLM Inference para Android.
Puedes encontrar la aplicación de muestra completa en GitHub.
Para comenzar, compila la aplicación, lee los datos proporcionados por el usuario (sample_context.txt
) y hazle preguntas al LLM relacionadas con la información del archivo de texto.
Ejecuta la aplicación de ejemplo
En esta guía, se hace referencia a un ejemplo de una app básica de generación de texto con RAG para Android. Puedes usar la app de ejemplo como punto de partida para tu propia app para Android o consultarla cuando modifiques una app existente.
La aplicación está optimizada para dispositivos de gama alta, como Pixel 8, Pixel 9, S23 y S24. Conecta un dispositivo Android a tu estación de trabajo y asegúrate de tener una versión actual de Android Studio. Para obtener más información, consulta la guía de configuración de Android.
Descarga el código de la aplicación
En las siguientes instrucciones, se muestra cómo crear una copia local del código de ejemplo con la herramienta de línea de comandos de Git.
Clona el repositorio de Git con el siguiente comando:
git clone https://github.com/google-ai-edge/ai-edge-apis
Después de crear una versión local del código de ejemplo, puedes importar el proyecto a Android Studio y ejecutar la app.
Descarga un modelo
La aplicación de ejemplo está configurada para usar Gemma-3 1B. Gemma-3 1B forma parte de la familia Gemma de modelos abiertos, ligeros y de vanguardia creados a partir de la misma investigación y tecnología que se utilizaron para crear los modelos de Gemini. El modelo contiene 1,000 millones de parámetros y ponderaciones abiertas.
Después de descargar Gemma-3 1B de Hugging Face, envía el modelo a tu 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
También puedes usar otros modelos con la aplicación de ejemplo, pero es posible que se requieran pasos de configuración adicionales.
Configura un insertador
El incorporador toma fragmentos de texto de los datos proporcionados por el usuario y los convierte en representaciones numéricas vectorizadas que capturan su significado semántico. El LLM consulta estos embeddings para identificar los vectores pertinentes y, luego, incorpora los fragmentos más relevantes semánticamente en el resultado generado.
La aplicación de ejemplo está diseñada para funcionar con dos integradores: el integrador de Gemini y el integrador de Gecko.
Configuración con el embededor de Gecko
De forma predeterminada, la app de ejemplo está configurada para usar el incorporador de Gecko (GeckoEmbeddingModel
) y ejecuta el modelo completamente en el dispositivo.
El incorporador de Gecko está disponible como modelos flotantes y cuantificados, con varias versiones para diferentes longitudes de secuencia. Para obtener más información, consulta la tarjeta del modelo Gecko.
Las especificaciones del modelo se pueden encontrar en el nombre del archivo del modelo. Por ejemplo:
Gecko_256_f32.tflite
: Es un modelo de números de punto flotante que admite secuencias de hasta 256 tokens.Gecko_1024_quant.tflite
: Es un modelo cuantificado que admite secuencias de hasta 1,024 tokens.
La longitud de la secuencia es el tamaño máximo del fragmento que el modelo puede incorporar. Por ejemplo, si se pasa un fragmento que supera la longitud de la secuencia al modelo Gecko_256_f32.tflite
, este incorporará los primeros 256 tokens y truncará el resto del fragmento.
Envía el modelo del tokenizador (sentencepiece.model
) y el modelo de incorporación de Gecko a tu dispositivo:
adb push sentencepiece.model /data/local/tmp/sentencepiece.model
adb push Gecko_256_f32.tflite /data/local/tmp/gecko.tflite
El modelo de incorporación es compatible con la CPU y la GPU. De forma predeterminada, la app de ejemplo está configurada para extraer incorporaciones con el modelo Gecko en la GPU.
companion object {
...
private const val USE_GPU_FOR_EMBEDDINGS = true
}
Configuración con Gemini Embedder
El Gemini Embedder (GeminiEmbedder
) crea embeddings con la API de Gemini Cloud. Para ejecutar la aplicación, se requiere una clave de la API de Google Gemini, que puedes obtener en la página de configuración de la API de Google Gemini.
Obtén una clave de API de Gemini en Google AI Studio
Agrega tu clave de API de Gemini y establece COMPUTE_EMBEDDINGS_LOCALLY
como falso en RagPipeline.kt:
companion object {
...
private const val COMPUTE_EMBEDDINGS_LOCALLY = false
private const val GEMINI_API_KEY = "<API_KEY>"
}
Cómo funciona
En esta sección, se proporciona información más detallada sobre los componentes de la canalización de RAG de la aplicación. Puedes ver la mayor parte del código en RagPipeline.kt.
Dependencias
El SDK de RAG usa la biblioteca com.google.ai.edge.localagents:localagents-rag
.
Agrega esta dependencia al archivo build.gradle
de tu app para Android:
dependencies {
...
implementation("com.google.ai.edge.localagents:localagents-rag:0.1.0")
implementation("com.google.mediapipe:tasks-genai:0.10.22")
}
Datos proporcionados por el usuario
Los datos proporcionados por el usuario en la aplicación son un archivo de texto llamado sample_context.txt
, que se almacena en el directorio assets
. La aplicación toma fragmentos del archivo de texto, crea incorporaciones de esos fragmentos y hace referencia a las incorporaciones cuando genera texto de salida.
El siguiente fragmento de código se puede encontrar en MainActivity.kt:
class MainActivity : ComponentActivity() {
lateinit var chatViewModel: ChatViewModel
...
chatViewModel.memorizeChunks("sample_context.txt")
...
}
Fragmentación
Para simplificar, el archivo sample_context.txt
incluye etiquetas <chunk_splitter>
que la aplicación de muestra usa para crear fragmentos. Luego, se crean embeddings para cada fragmento. En las aplicaciones de producción, el tamaño de los fragmentos es un factor clave a tener en cuenta. Cuando un fragmento es demasiado grande, el vector no contiene la especificidad suficiente para ser útil, y cuando es demasiado pequeño, no contiene suficiente contexto.
La aplicación de ejemplo controla la división en fragmentos a través de la función memorizeChunks
en RagPipeline.kt.
Embedding
La aplicación ofrece dos rutas de acceso para la incorporación de texto:
- Incorporador de Gecko: Extracción local (en el dispositivo) de incorporaciones de texto con el modelo de Gecko.
- Gemini Embedder: Es una extracción de embeddings de texto basada en la nube con la API de Generative Language Cloud.
La aplicación de ejemplo selecciona el modelo de incorporación según si el usuario pretende calcular las incorporaciones de forma local o a través de Google Cloud. El siguiente fragmento de código se puede encontrar en 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 datos
La aplicación de ejemplo usa SQLite (SqliteVectorStore
) para almacenar las incorporaciones de texto. También puedes usar la base de datos DefaultVectorStore
para el almacenamiento de vectores no persistentes.
El siguiente fragmento de código se puede encontrar en RagPipeline.kt:
private val config = ChainConfig.create(
mediaPipeLanguageModel, PromptBuilder(QA_PROMPT_TEMPLATE1),
DefaultSemanticTextMemory(
SqliteVectorStore(768), embedder
)
)
La app de ejemplo establece la dimensión del embedding en 768, lo que hace referencia a la longitud de cada vector en la base de datos de vectores.
Cadena
El SDK de RAG proporciona cadenas, que combinan varios componentes de RAG en una sola canalización. Puedes usar cadenas para coordinar modelos de recuperación y consulta. La API se basa en la interfaz Chain.
La aplicación de ejemplo usa la cadena de recuperación e inferencia. El siguiente fragmento de código se puede encontrar en RagPipeline.kt:
private val retrievalAndInferenceChain = RetrievalAndInferenceChain(config)
La cadena se invoca cuando el modelo genera respuestas:
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
}