From dcd4481ae2e35b856ebc29738dd65097adbcd966 Mon Sep 17 00:00:00 2001 From: Lorenze Jay Date: Sat, 1 Feb 2025 23:31:15 -0800 Subject: [PATCH 01/11] enable qdrant as vector search tool for crew agents --- src/crewai_tools/__init__.py | 1 + src/crewai_tools/tools/__init__.py | 1 + .../tools/qdrant_vector_search_tool/README.md | 49 +++++ .../qdrant_search_tool.py | 191 ++++++++++++++++++ 4 files changed, 242 insertions(+) create mode 100644 src/crewai_tools/tools/qdrant_vector_search_tool/README.md create mode 100644 src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py diff --git a/src/crewai_tools/__init__.py b/src/crewai_tools/__init__.py index 7a149598a..4d2ea7e16 100644 --- a/src/crewai_tools/__init__.py +++ b/src/crewai_tools/__init__.py @@ -30,6 +30,7 @@ from .tools import ( PatronusPredefinedCriteriaEvalTool, PDFSearchTool, PGSearchTool, + QdrantVectorSearchTool, RagTool, ScrapeElementFromWebsiteTool, ScrapegraphScrapeTool, diff --git a/src/crewai_tools/tools/__init__.py b/src/crewai_tools/tools/__init__.py index 2b83fe278..4a9786fe6 100644 --- a/src/crewai_tools/tools/__init__.py +++ b/src/crewai_tools/tools/__init__.py @@ -35,6 +35,7 @@ from .patronus_eval_tool import ( ) from .pdf_search_tool.pdf_search_tool import PDFSearchTool from .pg_seach_tool.pg_search_tool import PGSearchTool +from .qdrant_vector_search_tool.qdrant_search_tool import QdrantVectorSearchTool from .rag.rag_tool import RagTool from .scrape_element_from_website.scrape_element_from_website import ( ScrapeElementFromWebsiteTool, diff --git a/src/crewai_tools/tools/qdrant_vector_search_tool/README.md b/src/crewai_tools/tools/qdrant_vector_search_tool/README.md new file mode 100644 index 000000000..92aeb60f6 --- /dev/null +++ b/src/crewai_tools/tools/qdrant_vector_search_tool/README.md @@ -0,0 +1,49 @@ +# QdrantVectorSearchTool + +## Description + +This tool is specifically crafted for conducting semantic searches within docs within a Qdrant vector database. Use this tool to find semantically similar docs to a given query. + +Qdrant is a vector database that is used to store and query vector embeddings. You can follow their docs here: https://qdrant.tech/documentation/ + +## Installation + +Install the crewai_tools package by executing the following command in your terminal: + +```shell +uv pip install 'crewai[tools]' +``` + +## Example + +To utilize the QdrantVectorSearchTool for different use cases, follow these examples: + +```python +from crewai_tools import QdrantVectorSearchTool + +# To enable the tool to search any website the agent comes across or learns about during its operation +tool = QdrantVectorSearchTool( + collection_name="example_collections", + limit=3, + qdrant_url="https://your-qdrant-cluster-url.com", + qdrant_api_key="your-qdrant-api-key", +) + + +# Adding the tool to an agent +rag_agent = Agent( + name="rag_agent", + role="You are a helpful assistant that can answer questions with the help of the QdrantVectorSearchTool. Retrieve the most relevant docs from the Qdrant database.", + llm="gpt-4o-mini", + tools=[tool], +) +``` + +## Arguments + +- `collection_name` : The name of the collection to search within. (Required) +- `qdrant_url` : The URL of the Qdrant cluster. (Required) +- `qdrant_api_key` : The API key for the Qdrant cluster. (Required) +- `limit` : The number of results to return. (Optional) +- `vectorizer` : The vectorizer to use. (Optional) + diff --git a/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py b/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py new file mode 100644 index 000000000..307fcb8d1 --- /dev/null +++ b/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py @@ -0,0 +1,191 @@ +import json +from typing import Any, Optional, Type + +try: + from qdrant_client import QdrantClient + from qdrant_client.http.models import Filter, FieldCondition, MatchValue + + QDRANT_AVAILABLE = True +except ImportError: + QDRANT_AVAILABLE = False + QdrantClient = Any + Filter = Any + FieldCondition = Any + MatchValue = Any + +from crewai.tools import BaseTool +from pydantic import BaseModel, Field + + +class QdrantToolSchema(BaseModel): + """Input for QdrantTool.""" + + query: str = Field( + ..., + description="The query to search retrieve relevant information from the Qdrant database. Pass only the query, not the question.", + ) + filter_by: Optional[str] = Field( + default=None, + description="Filter by properties. Pass only the properties, not the question.", + ) + filter_value: Optional[str] = Field( + default=None, + description="Filter by value. Pass only the value, not the question.", + ) + + +class QdrantVectorSearchTool(BaseTool): + """Tool to query and filter results from a Qdrant vector database. + + This tool provides functionality to perform semantic search operations on documents + stored in a Qdrant collection, with optional filtering capabilities. + + Attributes: + name (str): Name of the tool + description (str): Description of the tool's functionality + client (QdrantClient): Qdrant client instance + collection_name (str): Name of the Qdrant collection to search + limit (int): Maximum number of results to return + score_threshold (float): Minimum similarity score threshold + """ + + name: str = "QdrantVectorSearchTool" + description: str = "A tool to search the Qdrant database for relevant information on internal documents." + args_schema: Type[BaseModel] = QdrantToolSchema + + model_config = {"arbitrary_types_allowed": True} + client: Optional[QdrantClient] = None + collection_name: str = Field( + ..., + description="The name of the Qdrant collection to search", + ) + limit: Optional[int] = Field(default=3) + score_threshold: float = Field(default=0.35) + qdrant_url: str = Field( + ..., + description="The URL of the Qdrant server", + ) + qdrant_api_key: Optional[str] = Field( + default=None, + description="The API key for the Qdrant server", + ) + vectorizer: Optional[str] = Field( + default="BAAI/bge-small-en-v1.5", + description="The vectorizer to use for the Qdrant server", + ) + + def __init__( + self, + qdrant_url: str, + collection_name: str, + qdrant_api_key: Optional[str] = None, + vectorizer: Optional[str] = None, + **kwargs, + ) -> None: + """Initialize the QdrantVectorSearchTool. + + Args: + qdrant_url: URL of the Qdrant server + collection_name: Name of the collection to search + qdrant_api_key: Optional API key for authentication + vectorizer: Optional model name for text vectorization + + Raises: + ImportError: If qdrant-client package is not installed + ConnectionError: If unable to connect to Qdrant server + """ + kwargs["qdrant_url"] = qdrant_url + kwargs["collection_name"] = collection_name + kwargs["qdrant_api_key"] = qdrant_api_key + if vectorizer: + kwargs["vectorizer"] = vectorizer + + super().__init__(**kwargs) + + if QDRANT_AVAILABLE: + try: + self.client = QdrantClient( + url=qdrant_url, + api_key=qdrant_api_key, + ) + # Verify connection + self.client.get_collections() + except Exception as e: + raise ConnectionError(f"Failed to connect to Qdrant server: {str(e)}") + else: + import click + + if click.confirm( + "You are missing the 'qdrant-client' package. Would you like to install it?" + ): + import subprocess + + subprocess.run( + ["uv", "add", "crewai[tools]", "qdrant-client"], check=True + ) + else: + raise ImportError( + "The 'qdrant-client' package is required to use the QdrantVectorSearchTool. " + "Please install it with: uv add crewai[tools] qdrant-client" + ) + if vectorizer: + self.client.set_model(self.vectorizer) + + def _run( + self, + query: str, + filter_by: Optional[str] = None, + filter_value: Optional[str] = None, + ) -> str: + """Execute the vector search query. + + Args: + query: Search query text + filter_by: Optional field name to filter results + filter_value: Optional value to filter by + + Returns: + JSON string containing search results with metadata + + Raises: + ValueError: If filter_by is provided without filter_value or vice versa + """ + if bool(filter_by) != bool(filter_value): + raise ValueError( + "Both filter_by and filter_value must be provided together" + ) + + search_filter = None + if filter_by and filter_value: + search_filter = Filter( + must=[ + FieldCondition(key=filter_by, match=MatchValue(value=filter_value)) + ] + ) + + try: + search_results = self.client.query( + collection_name=self.collection_name, + query_text=[query], + query_filter=search_filter, + limit=self.limit, + score_threshold=self.score_threshold, + ) + + results = [ + { + "id": point.id, + "metadata": point.metadata, + "context": point.document, + "score": point.score, + } + for point in search_results + ] + + if not results: + return json.dumps({"message": "No results found", "results": []}) + + return json.dumps(results, indent=2) + + except Exception as e: + raise RuntimeError(f"Error executing Qdrant search: {str(e)}") From aff40529a5f9853e36fd46f420734c6460cdc3f9 Mon Sep 17 00:00:00 2001 From: Lorenze Jay Date: Sat, 1 Feb 2025 23:32:31 -0800 Subject: [PATCH 02/11] updated docs --- src/crewai_tools/tools/qdrant_vector_search_tool/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crewai_tools/tools/qdrant_vector_search_tool/README.md b/src/crewai_tools/tools/qdrant_vector_search_tool/README.md index 92aeb60f6..f5a7f5e30 100644 --- a/src/crewai_tools/tools/qdrant_vector_search_tool/README.md +++ b/src/crewai_tools/tools/qdrant_vector_search_tool/README.md @@ -11,7 +11,7 @@ Qdrant is a vector database that is used to store and query vector embeddings. Y Install the crewai_tools package by executing the following command in your terminal: ```shell -uv pip install 'crewai[tools]' +uv pip install 'crewai[tools] qdrant-client fastembed' ``` ## Example From 052a07ddc7e6a6c83b4a0d85226b1c2b634a3868 Mon Sep 17 00:00:00 2001 From: Lorenze Jay Date: Sat, 1 Feb 2025 23:38:24 -0800 Subject: [PATCH 03/11] setup common default model --- .../tools/qdrant_vector_search_tool/qdrant_search_tool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py b/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py index 307fcb8d1..050862fef 100644 --- a/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py +++ b/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py @@ -70,7 +70,7 @@ class QdrantVectorSearchTool(BaseTool): description="The API key for the Qdrant server", ) vectorizer: Optional[str] = Field( - default="BAAI/bge-small-en-v1.5", + default="fast-bge-small-en-v1.5", description="The vectorizer to use for the Qdrant server", ) From 6b19a3d15646d6dec821a51a3d4a3ab98cf9182b Mon Sep 17 00:00:00 2001 From: Lorenze Jay Date: Sat, 1 Feb 2025 23:40:37 -0800 Subject: [PATCH 04/11] default set --- .../tools/qdrant_vector_search_tool/qdrant_search_tool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py b/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py index 050862fef..307fcb8d1 100644 --- a/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py +++ b/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py @@ -70,7 +70,7 @@ class QdrantVectorSearchTool(BaseTool): description="The API key for the Qdrant server", ) vectorizer: Optional[str] = Field( - default="fast-bge-small-en-v1.5", + default="BAAI/bge-small-en-v1.5", description="The vectorizer to use for the Qdrant server", ) From d6a6325b5579fb2db0ea5bbc0499e894645fecfa Mon Sep 17 00:00:00 2001 From: Lorenze Jay Date: Sat, 1 Feb 2025 23:43:09 -0800 Subject: [PATCH 05/11] set vectorizer --- .../tools/qdrant_vector_search_tool/qdrant_search_tool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py b/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py index 307fcb8d1..5b42bf74b 100644 --- a/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py +++ b/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py @@ -70,7 +70,7 @@ class QdrantVectorSearchTool(BaseTool): description="The API key for the Qdrant server", ) vectorizer: Optional[str] = Field( - default="BAAI/bge-small-en-v1.5", + default="BAAI/bge-base-en-v1.5", description="The vectorizer to use for the Qdrant server", ) From 05982aeef29f3fb3e18d40a6c4a3036b2ed81087 Mon Sep 17 00:00:00 2001 From: Lorenze Jay Date: Sat, 1 Feb 2025 23:44:40 -0800 Subject: [PATCH 06/11] set default vectorizer --- .../tools/qdrant_vector_search_tool/qdrant_search_tool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py b/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py index 5b42bf74b..307fcb8d1 100644 --- a/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py +++ b/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py @@ -70,7 +70,7 @@ class QdrantVectorSearchTool(BaseTool): description="The API key for the Qdrant server", ) vectorizer: Optional[str] = Field( - default="BAAI/bge-base-en-v1.5", + default="BAAI/bge-small-en-v1.5", description="The vectorizer to use for the Qdrant server", ) From 5a9bb24b63a13cddf9bd47645de9fb9b17f5a231 Mon Sep 17 00:00:00 2001 From: Lorenze Jay Date: Mon, 3 Feb 2025 16:19:03 -0800 Subject: [PATCH 07/11] default openai --- .../qdrant_search_tool.py | 200 ++++++++---------- 1 file changed, 91 insertions(+), 109 deletions(-) diff --git a/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py b/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py index 307fcb8d1..1dd8c6078 100644 --- a/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py +++ b/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py @@ -1,5 +1,8 @@ import json +import os from typing import Any, Optional, Type +import ollama + try: from qdrant_client import QdrantClient @@ -8,7 +11,7 @@ try: QDRANT_AVAILABLE = True except ImportError: QDRANT_AVAILABLE = False - QdrantClient = Any + QdrantClient = Any # type placeholder Filter = Any FieldCondition = Any MatchValue = Any @@ -35,101 +38,51 @@ class QdrantToolSchema(BaseModel): class QdrantVectorSearchTool(BaseTool): - """Tool to query and filter results from a Qdrant vector database. + """Tool to query and filter results from a Qdrant database. - This tool provides functionality to perform semantic search operations on documents - stored in a Qdrant collection, with optional filtering capabilities. + This tool enables vector similarity search on internal documents stored in Qdrant, + with optional filtering capabilities. Attributes: - name (str): Name of the tool - description (str): Description of the tool's functionality - client (QdrantClient): Qdrant client instance - collection_name (str): Name of the Qdrant collection to search - limit (int): Maximum number of results to return - score_threshold (float): Minimum similarity score threshold + client: Configured QdrantClient instance + collection_name: Name of the Qdrant collection to search + limit: Maximum number of results to return + score_threshold: Minimum similarity score threshold + qdrant_url: Qdrant server URL + qdrant_api_key: Authentication key for Qdrant """ + model_config = {"arbitrary_types_allowed": True} + client: QdrantClient = None name: str = "QdrantVectorSearchTool" description: str = "A tool to search the Qdrant database for relevant information on internal documents." args_schema: Type[BaseModel] = QdrantToolSchema - - model_config = {"arbitrary_types_allowed": True} - client: Optional[QdrantClient] = None - collection_name: str = Field( - ..., - description="The name of the Qdrant collection to search", - ) + query: Optional[str] = None + filter_by: Optional[str] = None + filter_value: Optional[str] = None + collection_name: Optional[str] = None limit: Optional[int] = Field(default=3) score_threshold: float = Field(default=0.35) qdrant_url: str = Field( ..., description="The URL of the Qdrant server", ) - qdrant_api_key: Optional[str] = Field( - default=None, + qdrant_api_key: str = Field( + ..., description="The API key for the Qdrant server", ) - vectorizer: Optional[str] = Field( - default="BAAI/bge-small-en-v1.5", - description="The vectorizer to use for the Qdrant server", + custom_embedding_fn: Optional[callable] = Field( + default=None, + description="A custom embedding function to use for vectorization. If not provided, the default model will be used.", ) - def __init__( - self, - qdrant_url: str, - collection_name: str, - qdrant_api_key: Optional[str] = None, - vectorizer: Optional[str] = None, - **kwargs, - ) -> None: - """Initialize the QdrantVectorSearchTool. - - Args: - qdrant_url: URL of the Qdrant server - collection_name: Name of the collection to search - qdrant_api_key: Optional API key for authentication - vectorizer: Optional model name for text vectorization - - Raises: - ImportError: If qdrant-client package is not installed - ConnectionError: If unable to connect to Qdrant server - """ - kwargs["qdrant_url"] = qdrant_url - kwargs["collection_name"] = collection_name - kwargs["qdrant_api_key"] = qdrant_api_key - if vectorizer: - kwargs["vectorizer"] = vectorizer - + def __init__(self, **kwargs): super().__init__(**kwargs) - if QDRANT_AVAILABLE: - try: - self.client = QdrantClient( - url=qdrant_url, - api_key=qdrant_api_key, - ) - # Verify connection - self.client.get_collections() - except Exception as e: - raise ConnectionError(f"Failed to connect to Qdrant server: {str(e)}") - else: - import click - - if click.confirm( - "You are missing the 'qdrant-client' package. Would you like to install it?" - ): - import subprocess - - subprocess.run( - ["uv", "add", "crewai[tools]", "qdrant-client"], check=True - ) - else: - raise ImportError( - "The 'qdrant-client' package is required to use the QdrantVectorSearchTool. " - "Please install it with: uv add crewai[tools] qdrant-client" - ) - if vectorizer: - self.client.set_model(self.vectorizer) + self.client = QdrantClient( + url=self.qdrant_url, + api_key=self.qdrant_api_key, + ) def _run( self, @@ -137,24 +90,30 @@ class QdrantVectorSearchTool(BaseTool): filter_by: Optional[str] = None, filter_value: Optional[str] = None, ) -> str: - """Execute the vector search query. + """Execute vector similarity search on Qdrant. Args: - query: Search query text - filter_by: Optional field name to filter results + query: Search query to vectorize and match + filter_by: Optional metadata field to filter on filter_value: Optional value to filter by Returns: - JSON string containing search results with metadata + JSON string containing search results with metadata and scores Raises: - ValueError: If filter_by is provided without filter_value or vice versa + ImportError: If qdrant-client is not installed + ValueError: If Qdrant credentials are missing """ - if bool(filter_by) != bool(filter_value): - raise ValueError( - "Both filter_by and filter_value must be provided together" + if not QDRANT_AVAILABLE: + raise ImportError( + "The 'qdrant-client' package is required to use the QdrantVectorSearchTool. " + "Please install it with: pip install qdrant-client" ) + if not self.qdrant_url: + raise ValueError("QDRANT_URL is not set") + + # Create filter if filter parameters are provided search_filter = None if filter_by and filter_value: search_filter = Filter( @@ -163,29 +122,52 @@ class QdrantVectorSearchTool(BaseTool): ] ) - try: - search_results = self.client.query( - collection_name=self.collection_name, - query_text=[query], - query_filter=search_filter, - limit=self.limit, - score_threshold=self.score_threshold, + # Search in Qdrant using the built-in query method + + query_vector = ( + self._vectorize_query(query) + if not self.custom_embedding_fn + else self.custom_embedding_fn(query) + ) + search_results = self.client.query_points( + collection_name=self.collection_name, + query=query_vector, + query_filter=search_filter, + limit=self.limit, + score_threshold=self.score_threshold, + ) + + # Format results similar to storage implementation + results = [] + # Extract the list of ScoredPoint objects from the tuple + for point in search_results: + result = { + "metadata": point[1][0].payload.get("metadata", {}), + "context": point[1][0].payload.get("text", ""), + "distance": point[1][0].score, + } + results.append(result) + + return json.dumps(results, indent=2) + + def _vectorize_query(self, query: str) -> list[float]: + """Default vectorization function with openai. + + Args: + query (str): The query to vectorize + + Returns: + list[float]: The vectorized query + """ + import openai + + client = openai.Client(api_key=os.getenv("OPENAI_API_KEY")) + embedding = ( + client.embeddings.create( + input=[query], + model="text-embedding-3-small", ) - - results = [ - { - "id": point.id, - "metadata": point.metadata, - "context": point.document, - "score": point.score, - } - for point in search_results - ] - - if not results: - return json.dumps({"message": "No results found", "results": []}) - - return json.dumps(results, indent=2) - - except Exception as e: - raise RuntimeError(f"Error executing Qdrant search: {str(e)}") + .data[0] + .embedding + ) + return embedding From 96c3fbdddfa707062f3f039ca19308916b7534a9 Mon Sep 17 00:00:00 2001 From: Lorenze Jay Date: Mon, 3 Feb 2025 16:19:33 -0800 Subject: [PATCH 08/11] remove ollama from here --- .../tools/qdrant_vector_search_tool/qdrant_search_tool.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py b/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py index 1dd8c6078..aff25d4f1 100644 --- a/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py +++ b/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py @@ -1,7 +1,6 @@ import json import os from typing import Any, Optional, Type -import ollama try: From 12927ba79d8ac9107d3f4b6596dee80e205fb860 Mon Sep 17 00:00:00 2001 From: Lorenze Jay Date: Mon, 3 Feb 2025 16:19:53 -0800 Subject: [PATCH 09/11] cleanup --- .../tools/qdrant_vector_search_tool/qdrant_search_tool.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py b/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py index aff25d4f1..bd9cd8701 100644 --- a/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py +++ b/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py @@ -122,7 +122,6 @@ class QdrantVectorSearchTool(BaseTool): ) # Search in Qdrant using the built-in query method - query_vector = ( self._vectorize_query(query) if not self.custom_embedding_fn From 554bba80360060c9b2d0b7b54e6955f0f64d7bdd Mon Sep 17 00:00:00 2001 From: Lorenze Jay Date: Mon, 3 Feb 2025 16:22:09 -0800 Subject: [PATCH 10/11] clearer docs --- src/crewai_tools/tools/qdrant_vector_search_tool/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crewai_tools/tools/qdrant_vector_search_tool/README.md b/src/crewai_tools/tools/qdrant_vector_search_tool/README.md index f5a7f5e30..131dbca15 100644 --- a/src/crewai_tools/tools/qdrant_vector_search_tool/README.md +++ b/src/crewai_tools/tools/qdrant_vector_search_tool/README.md @@ -11,12 +11,12 @@ Qdrant is a vector database that is used to store and query vector embeddings. Y Install the crewai_tools package by executing the following command in your terminal: ```shell -uv pip install 'crewai[tools] qdrant-client fastembed' +uv pip install 'crewai[tools] qdrant-client openai' ``` ## Example -To utilize the QdrantVectorSearchTool for different use cases, follow these examples: +To utilize the QdrantVectorSearchTool for different use cases, follow these examples: Default model is openai. ```python from crewai_tools import QdrantVectorSearchTool From 837198ae08f07efef14d7a44a0280e23cdd1d3c9 Mon Sep 17 00:00:00 2001 From: Lorenze Jay Date: Fri, 7 Feb 2025 10:03:37 -0800 Subject: [PATCH 11/11] Add interactive Qdrant client installation prompt --- .../qdrant_search_tool.py | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py b/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py index bd9cd8701..c59dd29d5 100644 --- a/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py +++ b/src/crewai_tools/tools/qdrant_vector_search_tool/qdrant_search_tool.py @@ -82,6 +82,21 @@ class QdrantVectorSearchTool(BaseTool): url=self.qdrant_url, api_key=self.qdrant_api_key, ) + else: + import click + + if click.confirm( + "The 'qdrant-client' package is required to use the QdrantVectorSearchTool. " + "Would you like to install it?" + ): + import subprocess + + subprocess.run(["uv", "add", "qdrant-client"], check=True) + else: + raise ImportError( + "The 'qdrant-client' package is required to use the QdrantVectorSearchTool. " + "Please install it with: uv add qdrant-client" + ) def _run( self, @@ -103,11 +118,6 @@ class QdrantVectorSearchTool(BaseTool): ImportError: If qdrant-client is not installed ValueError: If Qdrant credentials are missing """ - if not QDRANT_AVAILABLE: - raise ImportError( - "The 'qdrant-client' package is required to use the QdrantVectorSearchTool. " - "Please install it with: pip install qdrant-client" - ) if not self.qdrant_url: raise ValueError("QDRANT_URL is not set")