أداة البحث المتجهي Qdrant
نظرة عامة
Section titled “نظرة عامة”تتيح أداة البحث المتجهي Qdrant إمكانيات البحث الدلالي في وكلاء CrewAI من خلال الاستفادة من Qdrant، محرك بحث التشابه المتجهي. تسمح هذه الأداة لوكلائك بالبحث في المستندات المخزنة في مجموعة Qdrant باستخدام التشابه الدلالي.
التثبيت
Section titled “التثبيت”قم بتثبيت الحزم المطلوبة:
uv add qdrant-clientالاستخدام الأساسي
Section titled “الاستخدام الأساسي”إليك مثال بسيط لكيفية استخدام الأداة:
from crewai import Agentfrom crewai_tools import QdrantVectorSearchTool, QdrantConfig
# Initialize the tool with QdrantConfigqdrant_tool = QdrantVectorSearchTool( qdrant_config=QdrantConfig( qdrant_url="your_qdrant_url", qdrant_api_key="your_qdrant_api_key", collection_name="your_collection" ))
# Create an agent that uses the toolagent = Agent( role="Research Assistant", goal="Find relevant information in documents", tools=[qdrant_tool])
# The tool will automatically use OpenAI embeddings# and return the 3 most relevant results with scores > 0.35مثال عملي كامل
Section titled “مثال عملي كامل”إليك مثالاً كاملاً يوضح كيفية:
- استخراج النص من ملف PDF
- توليد التضمينات باستخدام OpenAI
- التخزين في Qdrant
- إنشاء سير عمل RAG وكيلي باستخدام CrewAI للبحث الدلالي
import osimport uuidimport pdfplumberfrom openai import OpenAIfrom dotenv import load_dotenvfrom crewai import Agent, Task, Crew, Process, LLMfrom crewai_tools import QdrantVectorSearchToolfrom qdrant_client import QdrantClientfrom qdrant_client.models import PointStruct, Distance, VectorParams
# Load environment variablesload_dotenv()
# Initialize OpenAI clientclient = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
# Extract text from PDFdef extract_text_from_pdf(pdf_path): text = [] with pdfplumber.open(pdf_path) as pdf: for page in pdf.pages: page_text = page.extract_text() if page_text: text.append(page_text.strip()) return text
# Generate OpenAI embeddingsdef get_openai_embedding(text): response = client.embeddings.create( input=text, model="text-embedding-3-large" ) return response.data[0].embedding
# Store text and embeddings in Qdrantdef load_pdf_to_qdrant(pdf_path, qdrant, collection_name): # Extract text from PDF text_chunks = extract_text_from_pdf(pdf_path)
# Create Qdrant collection if qdrant.collection_exists(collection_name): qdrant.delete_collection(collection_name) qdrant.create_collection( collection_name=collection_name, vectors_config=VectorParams(size=3072, distance=Distance.COSINE) )
# Store embeddings points = [] for chunk in text_chunks: embedding = get_openai_embedding(chunk) points.append(PointStruct( id=str(uuid.uuid4()), vector=embedding, payload={"text": chunk} )) qdrant.upsert(collection_name=collection_name, points=points)
# Initialize Qdrant client and load dataqdrant = QdrantClient( url=os.getenv("QDRANT_URL"), api_key=os.getenv("QDRANT_API_KEY"))collection_name = "example_collection"pdf_path = "path/to/your/document.pdf"load_pdf_to_qdrant(pdf_path, qdrant, collection_name)
# Initialize Qdrant search toolfrom crewai_tools import QdrantConfig
qdrant_tool = QdrantVectorSearchTool( qdrant_config=QdrantConfig( qdrant_url=os.getenv("QDRANT_URL"), qdrant_api_key=os.getenv("QDRANT_API_KEY"), collection_name=collection_name, limit=3, score_threshold=0.35 ))
# Create CrewAI agentssearch_agent = Agent( role="Senior Semantic Search Agent", goal="Find and analyze documents based on semantic search", backstory="""You are an expert research assistant who can find relevant information using semantic search in a Qdrant database.""", tools=[qdrant_tool], verbose=True)
answer_agent = Agent( role="Senior Answer Assistant", goal="Generate answers to questions based on the context provided", backstory="""You are an expert answer assistant who can generate answers to questions based on the context provided.""", tools=[qdrant_tool], verbose=True)
# Define taskssearch_task = Task( description="""Search for relevant documents about the {query}. Your final answer should include: - The relevant information found - The similarity scores of the results - The metadata of the relevant documents""", agent=search_agent)
answer_task = Task( description="""Given the context and metadata of relevant documents, generate a final answer based on the context.""", agent=answer_agent)
# Run CrewAI workflowcrew = Crew( agents=[search_agent, answer_agent], tasks=[search_task, answer_task], process=Process.sequential, verbose=True)
result = crew.kickoff( inputs={"query": "What is the role of X in the document?"})print(result)معاملات الأداة
Section titled “معاملات الأداة”المعاملات المطلوبة
Section titled “المعاملات المطلوبة”qdrant_config(QdrantConfig): كائن التكوين الذي يحتوي على جميع إعدادات Qdrant
معاملات QdrantConfig
Section titled “معاملات QdrantConfig”qdrant_url(str): عنوان URL لخادم Qdrant الخاص بكqdrant_api_key(str, اختياري): مفتاح API للمصادقة مع Qdrantcollection_name(str): اسم مجموعة Qdrant المراد البحث فيهاlimit(int): الحد الأقصى لعدد النتائج المُرجعة (الافتراضي: 3)score_threshold(float): الحد الأدنى لدرجة التشابه (الافتراضي: 0.35)filter(Any, اختياري): نسخة Filter من Qdrant للتصفية المتقدمة (الافتراضي: None)
المعاملات الاختيارية للأداة
Section titled “المعاملات الاختيارية للأداة”custom_embedding_fn(Callable[[str], list[float]]): دالة مخصصة لتحويل النص إلى متجهاتqdrant_package(str): مسار الحزمة الأساسية لـ Qdrant (الافتراضي: “qdrant_client”)client(Any): عميل Qdrant مُهيأ مسبقاً (اختياري)
التصفية المتقدمة
Section titled “التصفية المتقدمة”تدعم أداة QdrantVectorSearchTool إمكانيات تصفية قوية لتحسين نتائج البحث:
التصفية الديناميكية
Section titled “التصفية الديناميكية”استخدم معاملات filter_by و filter_value في بحثك لتصفية النتائج أثناء التنفيذ:
# Agent will use these parameters when calling the tool# The tool schema accepts filter_by and filter_value# Example: search with category filter# Results will be filtered where category == "technology"المرشحات المسبقة مع QdrantConfig
Section titled “المرشحات المسبقة مع QdrantConfig”للتصفية المعقدة، استخدم نسخ Filter من Qdrant في تكوينك:
from qdrant_client.http import models as qmodelsfrom crewai_tools import QdrantVectorSearchTool, QdrantConfig
# Create a filter for specific conditionspreset_filter = qmodels.Filter( must=[ qmodels.FieldCondition( key="category", match=qmodels.MatchValue(value="research") ), qmodels.FieldCondition( key="year", match=qmodels.MatchValue(value=2024) ) ])
# Initialize tool with preset filterqdrant_tool = QdrantVectorSearchTool( qdrant_config=QdrantConfig( qdrant_url="your_url", qdrant_api_key="your_key", collection_name="your_collection", filter=preset_filter # Preset filter applied to all searches ))دمج المرشحات
Section titled “دمج المرشحات”تقوم الأداة تلقائياً بدمج المرشحات المسبقة من QdrantConfig مع المرشحات الديناميكية من filter_by و filter_value:
# If QdrantConfig has a preset filter for category="research"# And the search uses filter_by="year", filter_value=2024# Both filters will be combined (AND logic)معاملات البحث
Section titled “معاملات البحث”تقبل الأداة هذه المعاملات في مخططها:
query(str): استعلام البحث للعثور على مستندات مشابهةfilter_by(str, اختياري): حقل البيانات الوصفية للتصفية عليهfilter_value(Any, اختياري): القيمة المراد التصفية بها
صيغة الإرجاع
Section titled “صيغة الإرجاع”تُرجع الأداة النتائج بصيغة JSON:
[ { "metadata": { // Any metadata stored with the document }, "context": "The actual text content of the document", "distance": 0.95 // Similarity score }]التضمين الافتراضي
Section titled “التضمين الافتراضي”بشكل افتراضي، تستخدم الأداة نموذج text-embedding-3-large من OpenAI للتحويل إلى متجهات. يتطلب ذلك:
- تعيين مفتاح OpenAI API في البيئة:
OPENAI_API_KEY
التضمينات المخصصة
Section titled “التضمينات المخصصة”بدلاً من استخدام نموذج التضمين الافتراضي، قد ترغب في استخدام دالة تضمين خاصة بك في الحالات التالية:
- تريد استخدام نموذج تضمين مختلف (مثل Cohere أو HuggingFace أو نماذج Ollama)
- تحتاج إلى تقليل التكاليف باستخدام نماذج تضمين مفتوحة المصدر
- لديك متطلبات محددة لأبعاد المتجهات أو جودة التضمين
- تريد استخدام تضمينات خاصة بمجال معين (مثل النصوص الطبية أو القانونية)
إليك مثال باستخدام نموذج HuggingFace:
from transformers import AutoTokenizer, AutoModelimport torch
# Load model and tokenizertokenizer = AutoTokenizer.from_pretrained('sentence-transformers/all-MiniLM-L6-v2')model = AutoModel.from_pretrained('sentence-transformers/all-MiniLM-L6-v2')
def custom_embeddings(text: str) -> list[float]: # Tokenize and get model outputs inputs = tokenizer(text, return_tensors="pt", padding=True, truncation=True) outputs = model(**inputs)
# Use mean pooling to get text embedding embeddings = outputs.last_hidden_state.mean(dim=1)
# Convert to list of floats and return return embeddings[0].tolist()
# Use custom embeddings with the toolfrom crewai_tools import QdrantConfig
tool = QdrantVectorSearchTool( qdrant_config=QdrantConfig( qdrant_url="your_url", qdrant_api_key="your_key", collection_name="your_collection" ), custom_embedding_fn=custom_embeddings # Pass your custom function)معالجة الأخطاء
Section titled “معالجة الأخطاء”تتعامل الأداة مع هذه الأخطاء المحددة:
- تُثير ImportError إذا لم يكن
qdrant-clientمثبتاً (مع خيار التثبيت التلقائي) - تُثير ValueError إذا لم يتم تعيين
QDRANT_URL - تطلب تثبيت
qdrant-clientإذا كان مفقوداً باستخدامuv add qdrant-client
متغيرات البيئة
Section titled “متغيرات البيئة”متغيرات البيئة المطلوبة:
export QDRANT_URL="your_qdrant_url" # If not provided in constructorexport QDRANT_API_KEY="your_api_key" # If not provided in constructorexport OPENAI_API_KEY="your_openai_key" # If using default embeddings