--- title: 'أداة البحث المتجهي Qdrant' description: 'إمكانيات البحث الدلالي لوكلاء CrewAI باستخدام قاعدة بيانات Qdrant المتجهية' icon: vector-square mode: "wide" --- ## نظرة عامة تتيح أداة البحث المتجهي Qdrant إمكانيات البحث الدلالي في وكلاء CrewAI من خلال الاستفادة من [Qdrant](https://qdrant.tech/)، محرك بحث التشابه المتجهي. تسمح هذه الأداة لوكلائك بالبحث في المستندات المخزنة في مجموعة Qdrant باستخدام التشابه الدلالي. ## التثبيت قم بتثبيت الحزم المطلوبة: ```bash uv add qdrant-client ``` ## الاستخدام الأساسي إليك مثال بسيط لكيفية استخدام الأداة: ```python from crewai import Agent from crewai_tools import QdrantVectorSearchTool, QdrantConfig # Initialize the tool with QdrantConfig qdrant_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 tool agent = 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 ``` ## مثال عملي كامل إليك مثالاً كاملاً يوضح كيفية: 1. استخراج النص من ملف PDF 2. توليد التضمينات باستخدام OpenAI 3. التخزين في Qdrant 4. إنشاء سير عمل RAG وكيلي باستخدام CrewAI للبحث الدلالي ```python import os import uuid import pdfplumber from openai import OpenAI from dotenv import load_dotenv from crewai import Agent, Task, Crew, Process, LLM from crewai_tools import QdrantVectorSearchTool from qdrant_client import QdrantClient from qdrant_client.models import PointStruct, Distance, VectorParams # Load environment variables load_dotenv() # Initialize OpenAI client client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) # Extract text from PDF def 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 embeddings def 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 Qdrant def 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 data qdrant = 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 tool from 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 agents search_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 tasks search_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 workflow crew = 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) ``` ## معاملات الأداة ### المعاملات المطلوبة - `qdrant_config` (QdrantConfig): كائن التكوين الذي يحتوي على جميع إعدادات Qdrant ### معاملات QdrantConfig - `qdrant_url` (str): عنوان URL لخادم Qdrant الخاص بك - `qdrant_api_key` (str, اختياري): مفتاح API للمصادقة مع Qdrant - `collection_name` (str): اسم مجموعة Qdrant المراد البحث فيها - `limit` (int): الحد الأقصى لعدد النتائج المُرجعة (الافتراضي: 3) - `score_threshold` (float): الحد الأدنى لدرجة التشابه (الافتراضي: 0.35) - `filter` (Any, اختياري): نسخة Filter من Qdrant للتصفية المتقدمة (الافتراضي: None) ### المعاملات الاختيارية للأداة - `custom_embedding_fn` (Callable[[str], list[float]]): دالة مخصصة لتحويل النص إلى متجهات - `qdrant_package` (str): مسار الحزمة الأساسية لـ Qdrant (الافتراضي: "qdrant_client") - `client` (Any): عميل Qdrant مُهيأ مسبقاً (اختياري) ## التصفية المتقدمة تدعم أداة QdrantVectorSearchTool إمكانيات تصفية قوية لتحسين نتائج البحث: ### التصفية الديناميكية استخدم معاملات `filter_by` و `filter_value` في بحثك لتصفية النتائج أثناء التنفيذ: ```python # 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 للتصفية المعقدة، استخدم نسخ Filter من Qdrant في تكوينك: ```python from qdrant_client.http import models as qmodels from crewai_tools import QdrantVectorSearchTool, QdrantConfig # Create a filter for specific conditions preset_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 filter qdrant_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 ) ) ``` ### دمج المرشحات تقوم الأداة تلقائياً بدمج المرشحات المسبقة من `QdrantConfig` مع المرشحات الديناميكية من `filter_by` و `filter_value`: ```python # 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) ``` ## معاملات البحث تقبل الأداة هذه المعاملات في مخططها: - `query` (str): استعلام البحث للعثور على مستندات مشابهة - `filter_by` (str, اختياري): حقل البيانات الوصفية للتصفية عليه - `filter_value` (Any, اختياري): القيمة المراد التصفية بها ## صيغة الإرجاع تُرجع الأداة النتائج بصيغة JSON: ```json [ { "metadata": { // Any metadata stored with the document }, "context": "The actual text content of the document", "distance": 0.95 // Similarity score } ] ``` ## التضمين الافتراضي بشكل افتراضي، تستخدم الأداة نموذج `text-embedding-3-large` من OpenAI للتحويل إلى متجهات. يتطلب ذلك: - تعيين مفتاح OpenAI API في البيئة: `OPENAI_API_KEY` ## التضمينات المخصصة بدلاً من استخدام نموذج التضمين الافتراضي، قد ترغب في استخدام دالة تضمين خاصة بك في الحالات التالية: 1. تريد استخدام نموذج تضمين مختلف (مثل Cohere أو HuggingFace أو نماذج Ollama) 2. تحتاج إلى تقليل التكاليف باستخدام نماذج تضمين مفتوحة المصدر 3. لديك متطلبات محددة لأبعاد المتجهات أو جودة التضمين 4. تريد استخدام تضمينات خاصة بمجال معين (مثل النصوص الطبية أو القانونية) إليك مثال باستخدام نموذج HuggingFace: ```python from transformers import AutoTokenizer, AutoModel import torch # Load model and tokenizer tokenizer = 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 tool from 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 ) ``` ## معالجة الأخطاء تتعامل الأداة مع هذه الأخطاء المحددة: - تُثير ImportError إذا لم يكن `qdrant-client` مثبتاً (مع خيار التثبيت التلقائي) - تُثير ValueError إذا لم يتم تعيين `QDRANT_URL` - تطلب تثبيت `qdrant-client` إذا كان مفقوداً باستخدام `uv add qdrant-client` ## متغيرات البيئة متغيرات البيئة المطلوبة: ```bash export QDRANT_URL="your_qdrant_url" # If not provided in constructor export QDRANT_API_KEY="your_api_key" # If not provided in constructor export OPENAI_API_KEY="your_openai_key" # If using default embeddings ```