تقنية وتكنولوجيا

الجيل المتقدم للاسترجاع المعزز: من النظرية إلى تنفيذ LlamaIndex | بواسطة ليوني مونيجاتي


للحصول على أفكار إضافية حول كيفية تحسين أداء خط أنابيب RAG الخاص بك لجعله جاهزًا للإنتاج، تابع القراءة هنا:

يناقش هذا القسم الحزم المطلوبة ومفاتيح واجهة برمجة التطبيقات (API) التي يجب متابعتها في هذه المقالة.

الحزم المطلوبة

سترشدك هذه المقالة خلال تنفيذ مسار RAG البسيط والمتقدم باستخدام LlamaIndex في Python.

pip install llama-index

في هذه المقالة، سوف نستخدم LlamaIndex v0.10. إذا كنت تقوم بالترقية من إصدار LlamaIndex أقدم، فستحتاج إلى تشغيل الأوامر التالية لتثبيت LlamaIndex وتشغيله بشكل صحيح:

pip uninstall llama-index
pip install llama-index --upgrade --no-cache-dir --force-reinstall

يوفر LlamaIndex خيارًا لتخزين تضمينات المتجهات محليًا في ملفات JSON للتخزين المستمر، وهو أمر رائع لإنشاء نماذج أولية سريعة للفكرة. ومع ذلك، سوف نستخدم قاعدة بيانات متجهة للتخزين المستمر نظرًا لأن تقنيات RAG المتقدمة تهدف إلى التطبيقات الجاهزة للإنتاج.

نظرًا لأننا سنحتاج إلى تخزين البيانات الوصفية وإمكانيات البحث المختلط بالإضافة إلى تخزين تضمينات المتجهات، فسنستخدم قاعدة بيانات المتجهات مفتوحة المصدر Weaviate (v3.26.2)، الذي يدعم هذه الميزات.

pip install weaviate-client llama-index-vector-stores-weaviate

مفاتيح واجهة برمجة التطبيقات

سوف نستخدم Weaviate المضمن، والذي يمكنك استخدامه مجانًا دون التسجيل للحصول على مفتاح API. ومع ذلك، يستخدم هذا البرنامج التعليمي نموذج التضمين وLLM من OpenAI، حيث ستحتاج إلى مفتاح OpenAI API. للحصول على واحد، تحتاج إلى حساب OpenAI ثم “إنشاء مفتاح سري جديد” ضمن مفاتيح API.

بعد ذلك، قم بإنشاء محلي .env الملف في الدليل الجذر الخاص بك وحدد مفاتيح API الخاصة بك فيه:

OPENAI_API_KEY="<YOUR_OPENAI_API_KEY>"

بعد ذلك، يمكنك تحميل مفاتيح API الخاصة بك بالرمز التالي:

# !pip install python-dotenv
import os
from dotenv import load_dotenv,find_dotenv

load_dotenv(find_dotenv())

يناقش هذا القسم كيفية تنفيذ خط أنابيب RAG البسيط باستخدام LlamaIndex. يمكنك العثور على خط أنابيب RAG الساذج بالكامل في Jupyter Notebook. بالنسبة للتنفيذ باستخدام LangChain، يمكنك المتابعة في هذه المقالة (خط أنابيب RAG البسيط باستخدام LangChain).

الخطوة 1: تحديد نموذج التضمين وLLM

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

  • نموذج التضمين: يستخدم لإنشاء عمليات تضمين متجهة لأجزاء المستند والاستعلام.
  • LLM: يُستخدم لإنشاء إجابة بناءً على استعلام المستخدم والسياق ذي الصلة.
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.llms.openai import OpenAI
from llama_index.core.settings import Settings

Settings.llm = OpenAI(model="gpt-3.5-turbo", temperature=0.1)
Settings.embed_model = OpenAIEmbedding()

الخطوة 2: تحميل البيانات

بعد ذلك، ستقوم بإنشاء دليل محلي باسم data في الدليل الجذر الخاص بك وقم بتنزيل بعض نماذج البيانات من مستودع LlamaIndex GitHub (ترخيص MIT).

!mkdir -p 'data'
!wget '<https://raw.githubusercontent.com/run-llama/llama_index/main/docs/examples/data/paul_graham/paul_graham_essay.txt>' -O 'data/paul_graham_essay.txt'

بعد ذلك، يمكنك تحميل البيانات لمزيد من المعالجة:

from llama_index.core import SimpleDirectoryReader

# Load data
documents = SimpleDirectoryReader(
input_files=["./data/paul_graham_essay.txt"]
).load_data()

الخطوة 3: قم بتقسيم المستندات إلى عقد

نظرًا لأن المستند بأكمله كبير جدًا بحيث لا يتناسب مع نافذة سياق LLM، فسوف تحتاج إلى تقسيمه إلى أجزاء نصية أصغر، والتي تسمى Nodes في مؤشر اللاما. يمكنك تحليل المستندات المحملة إلى عقد باستخدام الملف SimpleNodeParser مع حجم قطعة محددة من 1024.

from llama_index.core.node_parser import SimpleNodeParser

node_parser = SimpleNodeParser.from_defaults(chunk_size=1024)

# Extract nodes from documents
nodes = node_parser.get_nodes_from_documents(documents)

الخطوة 4: بناء الفهرس

بعد ذلك، ستقوم ببناء الفهرس الذي يخزن كل المعرفة الخارجية في Weaviate، وهي قاعدة بيانات متجهة مفتوحة المصدر.

أولاً، ستحتاج إلى الاتصال بمثيل Weaviate. في هذه الحالة، نحن نستخدم Weaviate Embedded، الذي يسمح لك بتجربة أجهزة الكمبيوتر المحمولة مجانًا بدون مفتاح API. للحصول على حل جاهز للإنتاج، يوصى بنشر Weaviate بنفسك، على سبيل المثال، عبر Docker أو الاستفادة من خدمة مُدارة.

import weaviate

# Connect to your Weaviate instance
client = weaviate.Client(
embedded_options=weaviate.embedded.EmbeddedOptions(),
)

بعد ذلك، سوف تقوم ببناء VectorStoreIndex من عميل Weaviate لتخزين بياناتك والتفاعل معها.

from llama_index.core import VectorStoreIndex, StorageContext
from llama_index.vector_stores.weaviate import WeaviateVectorStore

index_name = "MyExternalContext"

# Construct vector store
vector_store = WeaviateVectorStore(
weaviate_client = client,
index_name = index_name
)

# Set up the storage for the embeddings
storage_context = StorageContext.from_defaults(vector_store=vector_store)

# Setup the index
# build VectorStoreIndex that takes care of chunking documents
# and encoding chunks to embeddings for future retrieval
index = VectorStoreIndex(
nodes,
storage_context = storage_context,
)

الخطوة 5: إعداد محرك الاستعلام

وأخيرًا، ستقوم بإعداد الفهرس كمحرك الاستعلام.

# The QueryEngine class is equipped with the generator
# and facilitates the retrieval and generation steps
query_engine = index.as_query_engine()

الخطوة 6: قم بتشغيل استعلام RAG البسيط على بياناتك

الآن، يمكنك تشغيل استعلام RAG بسيط على بياناتك، كما هو موضح أدناه:

# Run your naive RAG query
response = query_engine.query(
"What happened at Interleaf?"
)

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

وبما أننا سنغطي التعديلات هنا فقط، يمكنك العثور على مسار RAG المتقدم الكامل والشامل في دفتر Jupyter Notebook هذا.

بالنسبة لتقنية استرجاع نافذة الجملة، تحتاج إلى إجراء تعديلين: أولاً، يجب عليك ضبط كيفية تخزين بياناتك ومعالجتها بعد ذلك. بدلا من ال SimpleNodeParser، سوف نستخدم SentenceWindowNodeParser.

from llama_index.core.node_parser import SentenceWindowNodeParser

# create the sentence window node parser w/ default settings
node_parser = SentenceWindowNodeParser.from_defaults(
window_size=3,
window_metadata_key="window",
original_text_metadata_key="original_text",
)

ال SentenceWindowNodeParser يفعل شيئين:

  1. فهو يفصل المستند إلى جمل مفردة، والتي سيتم تضمينها.
  2. لكل جملة، فإنه يخلق نافذة السياق. إذا قمت بتحديد أ window_size = 3، ستكون النافذة الناتجة مكونة من ثلاث جمل طويلة، تبدأ من الجملة السابقة من الجملة المضمنة وتمتد إلى الجملة التالية. سيتم تخزين النافذة كبيانات وصفية.

أثناء الاسترداد، يتم إرجاع الجملة الأكثر تطابقًا مع الاستعلام. بعد الاسترجاع، تحتاج إلى استبدال الجملة بالنافذة بأكملها من البيانات الوصفية عن طريق تحديد أ MetadataReplacementPostProcessor واستخدامها في القائمة node_postprocessors.

from llama_index.core.postprocessor import MetadataReplacementPostProcessor

# The target key defaults to `window` to match the node_parser's default
postproc = MetadataReplacementPostProcessor(
target_metadata_key="window"
)

...

query_engine = index.as_query_engine(
node_postprocessors = [postproc],
)

يعد تنفيذ بحث مختلط في LlamaIndex أمرًا سهلاً مثل تغيير معلمتين في ملف query_engine إذا كانت قاعدة بيانات المتجهات الأساسية تدعم استعلامات البحث المختلطة. ال alpha تحدد المعلمة الترجيح بين البحث المتجه والبحث القائم على الكلمات الرئيسية، حيث alpha=0 يعني البحث على أساس الكلمات الرئيسية و alpha=1 يعني البحث المتجه النقي.

query_engine = index.as_query_engine(
...,
vector_store_query_mode="hybrid",
alpha=0.5,
...
)

لا تستغرق إضافة أداة إعادة ترتيب إلى مسار RAG المتقدم سوى ثلاث خطوات بسيطة:

  1. أولاً، حدد نموذج إعادة الترتيب. وهنا نستخدم BAAI/bge-reranker-baseمن عناق الوجه.
  2. في محرك الاستعلام، قم بإضافة نموذج إعادة الترتيب إلى قائمة node_postprocessors.
  3. زيادة similarity_top_k في محرك الاستعلام لاسترداد المزيد من مقاطع السياق، والتي يمكن تقليلها إلى top_n بعد إعادة الترتيب.
# !pip install torch sentence-transformers
from llama_index.core.postprocessor import SentenceTransformerRerank

# Define reranker model
rerank = SentenceTransformerRerank(
top_n = 2,
model = "BAAI/bge-reranker-base"
)

...

# Add reranker to query engine
query_engine = index.as_query_engine(
similarity_top_k = 6,
...,
node_postprocessors = [rerank],
...,
)

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *

زر الذهاب إلى الأعلى