دليل RAG لميزة الذكاء الاصطناعي على الأجهزة الطرفية لنظام التشغيل Android

توفّر حزمة تطوير البرامج (SDK) الخاصة بـ AI Edge RAG المكوّنات الأساسية لإنشاء مسار التوليد المعزّز بالاسترجاع (RAG) باستخدام LLM Inference API. توفّر عملية التوليد المعزّز بالاسترجاع للنماذج اللغوية الكبيرة إمكانية الوصول إلى البيانات المقدَّمة من المستخدم، والتي يمكن أن تتضمّن معلومات معدَّلة أو حساسة أو خاصة بمجال معيّن. بفضل إمكانات استرجاع المعلومات الإضافية التي يوفّرها "التوليد المعزّز بالاسترجاع"، يمكن للنماذج اللغوية الكبيرة إنشاء ردود أكثر دقة وملاءمةً للسياق في حالات استخدام محدّدة.

يشرح هذا الدليل عملية التنفيذ الأساسية لنموذج تطبيق باستخدام LLM Inference API مع حزمة AI Edge RAG SDK. يركّز هذا الدليل على إنشاء مسار RAG. لمزيد من المعلومات حول استخدام واجهة برمجة التطبيقات LLM Inference، يُرجى الاطّلاع على دليل LLM Inference لنظام التشغيل Android.

يمكنك العثور على نموذج التطبيق الكامل على GitHub. للبدء، أنشئ التطبيق واقرأ البيانات المقدَّمة من المستخدم (sample_context.txt)، ثم اطرح على النموذج اللغوي الكبير أسئلة متعلقة بالمعلومات الواردة في الملف النصي.

تشغيل التطبيق النموذجي

يشير هذا الدليل إلى مثال على تطبيق أساسي لتوليد النصوص باستخدام التوليد المعزّز بالاسترجاع (RAG) على Android. يمكنك استخدام نموذج تطبيق كنقطة بداية لتطبيق Android الخاص بك، أو الرجوع إليه عند تعديل تطبيق حالي.

تم تحسين التطبيق للأجهزة المتطورة، مثل Pixel 8 وPixel 9 وS23 وS24. وصِّل جهاز Android بمحطة العمل وتأكَّد من توفّر أحدث إصدار من استوديو Android. لمزيد من المعلومات، يُرجى الاطّلاع على دليل إعداد Android.

تنزيل الرمز البرمجي للتطبيق

توضّح لك التعليمات التالية كيفية إنشاء نسخة محلية من نموذج الرمز البرمجي باستخدام أداة سطر الأوامر git.

استنسِخ مستودع git باستخدام الأمر التالي:

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

بعد إنشاء نسخة محلية من نموذج الرمز البرمجي، يمكنك استيراد المشروع إلى "استوديو Android" وتشغيل التطبيق.

تنزيل نموذج

تم إعداد التطبيق النموذجي لاستخدام Gemma-3 1B. ‫Gemma-3 1B هو جزء من مجموعة نماذج Gemma المتاحة للجميع والخفيفة والمتطوّرة، والتي تم إنشاؤها بناءً على الأبحاث والتكنولوجيا نفسها المستخدمة في إنشاء نماذج Gemini. يحتوي النموذج على مليار مَعلمة وأوزان مفتوحة.

تنزيل Gemma-3 1B

بعد تنزيل Gemma-3 1B من Hugging Face، يمكنك نقل النموذج إلى جهازك:

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

يمكنك أيضًا استخدام نماذج أخرى مع التطبيق النموذجي، ولكن قد يتطلّب ذلك اتّخاذ خطوات إعداد إضافية.

إعداد أداة تضمين

يأخذ برنامج التضمين أجزاء من النص من البيانات المقدَّمة من المستخدم ويحوّلها إلى تمثيلات رقمية متجهة تلتقط معناها الدلالي. يشير النموذج اللغوي الكبير إلى هذه التضمينات لتحديد المتجهات ذات الصلة، ويضمّن في الناتج الذي يتم إنشاؤه الأجزاء الأكثر صلة من الناحية الدلالية.

تم تصميم التطبيق النموذجي ليعمل مع برنامجَين مضمّنَين، وهما البرنامج المضمّن Gemini والبرنامج المضمّن Gecko.

الإعداد باستخدام Gecko embedder

يتم تلقائيًا ضبط إعدادات نموذج التطبيق لاستخدام أداة التضمين Gecko (GeckoEmbeddingModel)، ويتم تشغيل النموذج بالكامل على الجهاز فقط.

تنزيل Gecko 110m-en

يتوفّر برنامج تضمين Gecko كنموذجَي أعداد عشرية ونموذجَي كمّ، مع توفّر إصدارات متعددة لأطوال تسلسل مختلفة. لمزيد من المعلومات، يُرجى الاطّلاع على بطاقة نموذج Gecko.

يمكن العثور على مواصفات النموذج في اسم ملف النموذج. على سبيل المثال:

  • Gecko_256_f32.tflite: نموذج أرقام فاصلة عائمة يتيح استخدام تسلسلات تصل إلى 256 رمزًا مميزًا.
  • Gecko_1024_quant.tflite: نموذج تم تحويله إلى كميات يدعم تسلسلات تصل إلى 1,024 رمزًا مميزًا.

طول التسلسل هو الحد الأقصى لحجم الجزء الذي يمكن للنموذج تضمينه. على سبيل المثال، إذا تم تمرير جزء يتجاوز طول التسلسل إلى نموذج Gecko_256_f32.tflite، سيضمّن النموذج أول 256 رمزًا مميزًا ويقتطع الجزء المتبقي من الجزء.

أرسِل نموذج الترميز (sentencepiece.model) وبرنامج Gecko المضمّن إلى جهازك:

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

يتوافق نموذج التضمين مع كلّ من وحدة المعالجة المركزية (CPU) ووحدة معالجة الرسومات (GPU). يتم تلقائيًا ضبط تطبيق العيّنة لاستخراج التضمينات باستخدام نموذج Gecko على وحدة معالجة الرسومات.

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

الإعداد باستخدام Gemini Embedder

تنشئ أداة Gemini Embedder (GeminiEmbedder) عمليات التضمين باستخدام Gemini Cloud API. يتطلّب ذلك مفتاح Google Gemini API لتشغيل التطبيق، ويمكنك الحصول عليه من صفحة إعداد Google Gemini API.

الحصول على مفتاح Gemini API في Google AI Studio

أضِف مفتاح Gemini API واضبط قيمة COMPUTE_EMBEDDINGS_LOCALLY على false في RagPipeline.kt:

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

آلية العمل

يقدّم هذا القسم معلومات أكثر تفصيلاً حول مكوّنات مسار RAG في التطبيق. يمكنك الاطّلاع على معظم الرمز البرمجي في RagPipeline.kt.

الاعتمادية

تستخدم حزمة تطوير البرامج (SDK) الخاصة بميزة "الاسترجاع والإنشاء" المكتبة com.google.ai.edge.localagents:localagents-rag. أضِف هذه التبعية إلى ملف build.gradle في تطبيق Android:

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

البيانات المقدَّمة من المستخدم

البيانات المقدَّمة من المستخدم في التطبيق هي ملف نصي باسم sample_context.txt، ويتم تخزينها في الدليل assets. يأخذ التطبيق أجزاء من الملف النصي، وينشئ تضمينات لهذه الأجزاء، ويشير إلى التضمينات عند إنشاء نص الإخراج.

يمكن العثور على مقتطف الرمز التالي في ملف MainActivity.kt:

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

التقطيع

لتبسيط الأمر، يتضمّن ملف sample_context.txt العلامات <chunk_splitter> التي يستخدمها التطبيق النموذجي لإنشاء أجزاء. بعد ذلك، يتم إنشاء تضمينات لكل جزء. في تطبيقات الإنتاج، يُعدّ حجم الأجزاء عاملاً أساسيًا يجب أخذه في الاعتبار. عندما تكون الأجزاء كبيرة جدًا، لا يحتوي المتّجه على تفاصيل كافية ليكون مفيدًا، وعندما تكون صغيرة جدًا، لا يحتوي على سياق كافٍ.

يتعامل التطبيق النموذجي مع تقسيم المحتوى إلى أجزاء من خلال الدالة memorizeChunks في RagPipeline.kt.

تضمين

يوفّر التطبيق مسارَين لتضمين النص:

  • Gecko embedder: استخراج تضمينات النصوص على الجهاز فقط باستخدام نموذج Gecko.
  • ‫Gemini Embedder: استخراج عمليات تضمين النصوص المستندة إلى السحابة الإلكترونية باستخدام واجهة برمجة التطبيقات Generative Language Cloud.

يختار التطبيق النموذجي أداة التضمين استنادًا إلى ما إذا كان المستخدم ينوي حساب عمليات التضمين محليًا أو من خلال Google Cloud. يمكن العثور على مقتطف الرمز التالي في 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
      )
  }

قاعدة البيانات

يستخدم التطبيق النموذجي SQLite (SqliteVectorStore) لتخزين تضمينات النص. يمكنك أيضًا استخدام قاعدة بيانات DefaultVectorStore لتخزين المتجهات غير الدائم.

يمكن العثور على مقتطف الرمز التالي في RagPipeline.kt:

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

يضبط نموذج التطبيق حجم التضمين على 768، وهو ما يشير إلى طول كل متّجه في قاعدة بيانات المتّجهات.

سلسلة

توفّر حزمة تطوير البرامج (SDK) الخاصة بتكنولوجيا التوليد المعزّز بالاسترجاع (RAG) سلاسل تجمع عدة مكوّنات من تكنولوجيا التوليد المعزّز بالاسترجاع (RAG) في مسار واحد. يمكنك استخدام السلاسل لتنظيم نماذج الاسترجاع والاستعلام. تستند واجهة برمجة التطبيقات إلى واجهة Chain.

يستخدم التطبيق النموذجي سلسلة الاسترجاع والاستدلال. يمكن العثور على مقتطف الرمز التالي في RagPipeline.kt:

private val retrievalAndInferenceChain = RetrievalAndInferenceChain(config)

يتم استدعاء السلسلة عندما ينشئ النموذج ردودًا:

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
    }