diff --git a/.gitignore b/.gitignore index 5dd4b1f17..643028711 100644 --- a/.gitignore +++ b/.gitignore @@ -273,4 +273,4 @@ _includes/code/csharp/quickstart/obj tests/backups/ # Ignore LLM/agent config files -.claude/ +.claude/ \ No newline at end of file diff --git a/README.md b/README.md index cf9988a95..5d7bdb115 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ -This repository contains the documentation for Weaviate (vector database), Weaviate Cloud, and Weaviate Agents. It's built with Docusaurus 3. +This repository contains the documentation for Weaviate (vector database), Weaviate Cloud, and Query Agent. It's built with Docusaurus 3. # Contributor Quickstart @@ -34,7 +34,7 @@ The docs are in the following directories: - **`/docs/weaviate/`** → Main database documentation - **`/docs/deploy/`** → Deployment documentation - **`/docs/cloud/`** → Weaviate Cloud docs -- **`/docs/agents/`** → Weaviate Agents docs +- **`/docs/query-agent/`** → Query Agent docs They are rendered using the following mapping files: - **`secondaryNavbar.js`** → Top navigation bar (add new sections here) diff --git a/_build_scripts/update-config-versions.js b/_build_scripts/update-config-versions.js index 4228a812d..4b2d97a10 100644 --- a/_build_scripts/update-config-versions.js +++ b/_build_scripts/update-config-versions.js @@ -14,7 +14,7 @@ const getRepoVersion = async (repoName, attempt = 1) => { 'User-Agent': 'request', 'authorization': // Use the github token if available (process.env.GH_API_TOKEN) ? - `Bearer ${ process.env.GH_API_TOKEN }` : '' + `Bearer ${process.env.GH_API_TOKEN}` : '' } } ); @@ -70,6 +70,8 @@ const appendVersionsToConfig = async (config) => { config.typescript_client_version = await getRepoVersion('typescript-client'); config.helm_version = await getRepoVersion('weaviate-helm'); config.weaviate_cli_version = await getRepoVersion('weaviate-cli'); + config.agents_python_version = await getRepoVersion('weaviate-agents-python-client'); + config.agents_typescript_version = await getRepoVersion('agents-typescript-client'); config.spark_connector_version = await getRepoVersion('spark-connector'); } @@ -88,10 +90,10 @@ const updateConfigFile = async () => { await appendVersionsToConfig(config); fs.writeFile(path, JSON.stringify(config, null, 2), (err) => { - if (err) return console.log(err); + if (err) return console.log(err); - console.log(`Updating ${path}`) - console.log(JSON.stringify(config, null, 2)); + console.log(`Updating ${path}`) + console.log(JSON.stringify(config, null, 2)); }); } diff --git a/_includes/agents/query-agent-execution-times.mdx b/_includes/agents/query-agent-execution-times.mdx index ca5c42869..e98fb38ee 100644 --- a/_includes/agents/query-agent-execution-times.mdx +++ b/_includes/agents/query-agent-execution-times.mdx @@ -4,4 +4,4 @@ This typically requires multiple calls to generative models (e.g. LLMs) and mult As a result, each Query Agent run may take some time to complete. Depending on the query complexity, it may not be uncommon to see execution times of ~10 seconds. -**For long-running or complex queries**, consider using [streaming responses](/agents/query/usage#stream-responses) rather than non-streaming requests. Streaming provides progress updates and sends heartbeats to maintain the connection, preventing timeout issues that can occur with long-running non-streaming requests. +**For long-running or complex queries**, consider using [streaming responses](/query-agent/guides/ask_mode#streaming) rather than non-streaming requests. Streaming provides progress updates and sends heartbeats to maintain the connection, preventing timeout issues that can occur with long-running non-streaming requests. diff --git a/docs/agents/_includes/agents_coming_soon_dark.png b/docs/agents/_includes/agents_coming_soon_dark.png deleted file mode 100644 index 7ccba120e..000000000 Binary files a/docs/agents/_includes/agents_coming_soon_dark.png and /dev/null differ diff --git a/docs/agents/_includes/agents_coming_soon_light.png b/docs/agents/_includes/agents_coming_soon_light.png deleted file mode 100644 index f9c051526..000000000 Binary files a/docs/agents/_includes/agents_coming_soon_light.png and /dev/null differ diff --git a/docs/agents/_includes/agents_tech_preview_dark.png b/docs/agents/_includes/agents_tech_preview_dark.png deleted file mode 100644 index cd4986dd0..000000000 Binary files a/docs/agents/_includes/agents_tech_preview_dark.png and /dev/null differ diff --git a/docs/agents/_includes/agents_tech_preview_light.png b/docs/agents/_includes/agents_tech_preview_light.png deleted file mode 100644 index 9392a5aa6..000000000 Binary files a/docs/agents/_includes/agents_tech_preview_light.png and /dev/null differ diff --git a/docs/agents/_includes/personalization_agent.excalidraw.zip b/docs/agents/_includes/personalization_agent.excalidraw.zip deleted file mode 100644 index 2c97624eb..000000000 Binary files a/docs/agents/_includes/personalization_agent.excalidraw.zip and /dev/null differ diff --git a/docs/agents/_includes/personalization_agent.py b/docs/agents/_includes/personalization_agent.py deleted file mode 100644 index 9d0e13f1c..000000000 --- a/docs/agents/_includes/personalization_agent.py +++ /dev/null @@ -1,385 +0,0 @@ -# START ConnectToWeaviate -import os -import weaviate -from weaviate.classes.init import Auth - -# END ConnectToWeaviate -# START InstantiatePersonalizationAgent # START CreateOrConnectToAgent -from weaviate.agents.personalization import PersonalizationAgent -from weaviate.classes.config import DataType - -# END InstantiatePersonalizationAgent # END CreateOrConnectToAgent -# START AddUserPersona -from weaviate.agents.classes import Persona - -# END AddUserPersona -# START AddUserInteractions -from weaviate.agents.classes import PersonaInteraction - -# END AddUserInteractions - -# Additional helpers (not shown in the docs) -from tqdm import tqdm -from datasets import load_dataset -from weaviate.classes.config import Configure, Property, DataType -from typing import Dict, Any - -# START ConnectToWeaviate - -# Provide your required API key(s), e.g. for the configured vectorizer(s) -headers = { - # END ConnectToWeaviate - "X-Cohere-API-Key": os.environ.get("COHERE_API_KEY", ""), - # START ConnectToWeaviate - # Provide your required API key(s), e.g. Cohere, OpenAI, etc. for the configured vectorizer(s) - "X-INFERENCE-PROVIDER-API-KEY": os.environ.get("YOUR_INFERENCE_PROVIDER_KEY", ""), -} - -client = weaviate.connect_to_weaviate_cloud( - cluster_url=os.environ.get("WEAVIATE_URL"), - auth_credentials=Auth.api_key(os.environ.get("WEAVIATE_API_KEY")), - headers=headers, -) - -# END ConnectToWeaviate # END InstantiatePersonalizationAgent - -# Delete the collection if we want to start fresh -client.collections.delete("Movie") - -client.collections.create( - "Movie", - description="A dataset of movies including their metadata.", - vector_config=Configure.Vectors.text2vec_weaviate( - model="Snowflake/snowflake-arctic-embed-m-v1.5" - ), - properties=[ - Property( - name="release_date", - data_type=DataType.TEXT, - description="release date of the movie", - skip_vectorization=True, - ), - Property( - name="title", data_type=DataType.TEXT, description="title of the movie" - ), - Property( - name="overview", - data_type=DataType.TEXT, - description="overview of the movie", - ), - Property( - name="genres", - data_type=DataType.TEXT_ARRAY, - description="genres of the movie", - ), - Property( - name="vote_average", - data_type=DataType.NUMBER, - description="vote average of the movie", - ), - Property( - name="vote_count", - data_type=DataType.INT, - description="vote count of the movie", - ), - Property( - name="popularity", - data_type=DataType.NUMBER, - description="popularity of the movie", - ), - Property( - name="poster_url", - data_type=DataType.TEXT, - description="poster path of the movie", - skip_vectorization=True, - ), - Property( - name="original_language", - data_type=DataType.TEXT, - description="Code of the language of the movie", - skip_vectorization=True, - ), - ], -) - -# Load the movies dataset -movies_dataset = load_dataset("Pablinho/movies-dataset", split="train", streaming=True) - -# Get the Movies collection -movies_collection = client.collections.use("Movie") - - -def load_movie_row(item: Dict[str, Any]) -> Dict[str, Any]: - """ - Load movie data to output matching Weaviate object - - Args: - item: Dictionary containing movie data with original keys - - Returns: - Dictionary matching Weaviate data schema - """ - if item.get("Genre"): - genres = [genre.strip() for genre in item["Genre"].split(",") if genre.strip()] - else: - genres = [] - - if item.get("Original_Language"): - original_language = item["Original_Language"].lower() - else: - original_language = "" - - if item.get("Vote_Average"): - try: - vote_average = float(item["Vote_Average"]) - except ValueError: - vote_average = 0.0 - else: - vote_average = 0.0 - - if item.get("Vote_Count"): - try: - vote_count = int(item["Vote_Count"]) - except ValueError: - vote_count = 0 - else: - vote_count = 0 - - if item.get("Popularity"): - try: - popularity = float(item["Popularity"]) - except ValueError: - popularity = 0.0 - else: - popularity = 0.0 - - return { - "release_date": item["Release_Date"], - "title": item["Title"], - "overview": item["Overview"], - "genres": genres, - "vote_average": vote_average, - "vote_count": vote_count, - "popularity": popularity, - "poster_url": item["Poster_Url"], - "original_language": original_language, - } - - -# Batch import the appropriate data -with movies_collection.batch.fixed_size(batch_size=200) as batch: - for i, item in tqdm(enumerate(movies_dataset)): - data_object = load_movie_row(item) - batch.add_object(properties=data_object) - -# TODO[g-despot] Why is vector_name="default" needed here? -# START CreateOrConnectToAgent - -if PersonalizationAgent.exists(client, "Movie"): - # Connect to an existing agent - pa = PersonalizationAgent.connect( - client=client, reference_collection="Movie", vector_name="default" - ) -else: - # Instantiate a new agent, and specify the collection to query - # The Personalization Agent will automatically also connect to the user data collection - pa = PersonalizationAgent.create( - client=client, - reference_collection="Movie", - vector_name="default", - user_properties={ - "age": DataType.NUMBER, - "favorite_genres": DataType.TEXT_ARRAY, - "favorite_years": DataType.NUMBER_ARRAY, - "language": DataType.TEXT, - }, - ) -# END CreateOrConnectToAgent - -# START CreatePersona -from weaviate.util import generate_uuid5 -from uuid import uuid4 # If you want to generate a random UUID - -persona_id = generate_uuid5("sebawita") # To generate a deterministic UUID -# persona_id = uuid4() # To generate a random UUID - -# END CreatePersona - -# START DeletePersona -from weaviate.util import generate_uuid5 - -persona_id = generate_uuid5("sebawita") # To generate a deterministic UUID - -# Delete the persona -pa.delete_persona(persona_id) -# END DeletePersona - -# START CreatePersona -pa.add_persona( - Persona( - persona_id=persona_id, - properties={ - "age": 74, - "favorite_genres": ["Action", "Horror", "Romance"], - "favorite_years": [1979, 1981, 1984, 1985], - "language": "Hungarian", - }, - ) -) -# END CreatePersona - -# START UpdatePersona -from weaviate.util import generate_uuid5 - -persona_id = generate_uuid5("sebawita") # To generate a deterministic UUID - -# Update the persona -pa.update_persona( - Persona( - persona_id=persona_id, - properties={ - "age": 35, - "favorite_genres": ["Action", "Adventure", "Drama", "Sci-Fi"], - "favorite_years": [1999, 2005, 2010, 2014, 2016], - "language": "English", - }, - ) -) -# END UpdatePersona - -# START CheckPersonaExists -from weaviate.util import generate_uuid5 - -persona_id = generate_uuid5("sebawita") # To generate a deterministic UUID - -# Check if the persona exists -try: - assert pa.has_persona(persona_id) - print(f"Persona with ID {persona_id} exists.") -except AssertionError: - print(f"Persona with ID {persona_id} does not exist.") -# END CheckPersonaExists - -# START GetPersona -from weaviate.util import generate_uuid5 - -persona_id = generate_uuid5("sebawita") # To generate a deterministic UUID - -# Get the persona -persona = pa.get_persona(persona_id) -print(persona) -# END GetPersona - -from weaviate.classes.query import Filter - -movie_titles = [ - "Avatar 2", - "Big Daddy", - "White House Down", - "Tales from the Crypt", - "Twister", - "West Side Story", - "The Howling", - "The Emoji Movie", - "Magic Mike", - "Godzilla: Planet of the Monsters", -] - -movies_collection = client.collections.use("Movie") - -movie_dict = { - movie.properties["title"]: movie - for movie in movies_collection.query.fetch_objects( - filters=Filter.by_property("title").contains_any(movie_titles), limit=200 - ).objects -} - -# START AddUserInteractions -# Note: `movie_dict` is a dictionary of movie titles to their corresponding objects -interactions = [ - PersonaInteraction( - persona_id=persona_id, item_id=movie_dict["Avatar 2"].uuid, weight=0.8 - ), # Strongly positive - PersonaInteraction( - persona_id=persona_id, item_id=movie_dict["Twister"].uuid, weight=0.5 - ), # Somewhat positive - PersonaInteraction( - persona_id=persona_id, item_id=movie_dict["The Howling"].uuid, weight=0.1 - ), # Almost neutral - PersonaInteraction( - persona_id=persona_id, item_id=movie_dict["Magic Mike"].uuid, weight=-0.3 - ), # Somewhat negative - PersonaInteraction( - persona_id=persona_id, item_id=movie_dict["The Emoji Movie"].uuid, weight=-1.0 - ), # Strongly negative -] - -pa.add_interactions(interactions=interactions) -# END AddUserInteractions - -# START BasicQuery -response = pa.get_objects(persona_id) - -for i, obj in enumerate(response.objects): - print(obj.properties) -# END BasicQuery - -# START QueryParameters -response = pa.get_objects( - persona_id=persona_id, - limit=10, - recent_interactions_count=100, - exclude_interacted_items=False, - decay_rate=0.1, - exclude_items=[], - use_agent_ranking=True, - explain_results=True, - instruction=None, -) - -for i, obj in enumerate(response.objects): - print(obj.properties) -# END QueryParameters - -# START InspectResults -print(response.ranking_rationale) -for i, obj in enumerate(response.objects): - print(obj.properties) - print(f"original rank: {obj.original_rank}") - print(f"Personalized rank: {obj.personalized_rank}") -# END InspectResults - -# START PersonalizedWeaviateQuery -personalized_query = pa.query(persona_id=persona_id, strength=0.95) - -response = personalized_query.near_text( # Or .bm25 / .hybrid - query="A movie about a giant monster", - limit=20, - # Other normal `near_text` parameters can be added here - # e.g. filter, auto_limit, distance, include_vector, include_metadata, etc. -) - -for i, obj in enumerate(response.objects): - print(obj.properties) -# END PersonalizedWeaviateQuery - -# START ParamsPersonalizedWeaviateQuery -personalized_query = pa.query( - persona_id=persona_id, # The ID of the persona to use for personalization - strength=0.95, # The strength of the personalization (0.0 = none, 1.0 = full) - overfetch_factor=2, # The number of objects to fetch before personalization - recent_interactions_count=50, # The number of recent interactions to consider - decay_rate=0.2, # The decay rate for the interactions -) - -response = personalized_query.hybrid( # Or .near_text / .bm25 - query="A movie about a giant monster", - limit=20, - # Other normal `hybrid` parameters can be added here -) - -for i, obj in enumerate(response.objects): - print(obj.properties) -# END ParamsPersonalizedWeaviateQuery - -client.close() diff --git a/docs/agents/_includes/personalization_agent_architecture.png b/docs/agents/_includes/personalization_agent_architecture.png deleted file mode 100644 index c6a34f32f..000000000 Binary files a/docs/agents/_includes/personalization_agent_architecture.png and /dev/null differ diff --git a/docs/agents/_includes/personalization_agent_architecture_dark.png b/docs/agents/_includes/personalization_agent_architecture_dark.png deleted file mode 100644 index c9c39fb6a..000000000 Binary files a/docs/agents/_includes/personalization_agent_architecture_dark.png and /dev/null differ diff --git a/docs/agents/_includes/personalization_agent_architecture_light.png b/docs/agents/_includes/personalization_agent_architecture_light.png deleted file mode 100644 index 33222b363..000000000 Binary files a/docs/agents/_includes/personalization_agent_architecture_light.png and /dev/null differ diff --git a/docs/agents/_includes/personalization_agent_overview.png b/docs/agents/_includes/personalization_agent_overview.png deleted file mode 100644 index 4b20cbe5c..000000000 Binary files a/docs/agents/_includes/personalization_agent_overview.png and /dev/null differ diff --git a/docs/agents/_includes/personalization_agent_overview_dark.png b/docs/agents/_includes/personalization_agent_overview_dark.png deleted file mode 100644 index 910066e19..000000000 Binary files a/docs/agents/_includes/personalization_agent_overview_dark.png and /dev/null differ diff --git a/docs/agents/_includes/personalization_agent_overview_light.png b/docs/agents/_includes/personalization_agent_overview_light.png deleted file mode 100644 index 4b20cbe5c..000000000 Binary files a/docs/agents/_includes/personalization_agent_overview_light.png and /dev/null differ diff --git a/docs/agents/_includes/personalization_agent_rank.png b/docs/agents/_includes/personalization_agent_rank.png deleted file mode 100644 index ad1c4f7ab..000000000 Binary files a/docs/agents/_includes/personalization_agent_rank.png and /dev/null differ diff --git a/docs/agents/_includes/personalization_agent_rank_dark.png b/docs/agents/_includes/personalization_agent_rank_dark.png deleted file mode 100644 index 7d18f8d17..000000000 Binary files a/docs/agents/_includes/personalization_agent_rank_dark.png and /dev/null differ diff --git a/docs/agents/_includes/personalization_agent_rank_light.png b/docs/agents/_includes/personalization_agent_rank_light.png deleted file mode 100644 index f50f9fdb7..000000000 Binary files a/docs/agents/_includes/personalization_agent_rank_light.png and /dev/null differ diff --git a/docs/agents/_includes/personalization_agent_search.png b/docs/agents/_includes/personalization_agent_search.png deleted file mode 100644 index 7f55ed0b1..000000000 Binary files a/docs/agents/_includes/personalization_agent_search.png and /dev/null differ diff --git a/docs/agents/_includes/personalization_agent_search_dark.png b/docs/agents/_includes/personalization_agent_search_dark.png deleted file mode 100644 index bfcf8e0a2..000000000 Binary files a/docs/agents/_includes/personalization_agent_search_dark.png and /dev/null differ diff --git a/docs/agents/_includes/personalization_agent_search_light.png b/docs/agents/_includes/personalization_agent_search_light.png deleted file mode 100644 index 49b8d2f57..000000000 Binary files a/docs/agents/_includes/personalization_agent_search_light.png and /dev/null differ diff --git a/docs/agents/_includes/personalization_agent_tutorial_food_recommender.py b/docs/agents/_includes/personalization_agent_tutorial_food_recommender.py deleted file mode 100644 index 9a9940e53..000000000 --- a/docs/agents/_includes/personalization_agent_tutorial_food_recommender.py +++ /dev/null @@ -1,217 +0,0 @@ -# 1. Set up Weaviate -# 1.1 Connect to Weaviate Cloud -# START ConnectToWeaviate -import os -import weaviate -from weaviate.auth import Auth - -# Best practice: store your credentials in environment variables -weaviate_url = os.environ["WEAVIATE_URL"] -weaviate_api_key = os.environ["WEAVIATE_API_KEY"] - -client = weaviate.connect_to_weaviate_cloud( - cluster_url=weaviate_url, - auth_credentials=Auth.api_key(weaviate_api_key), -) - -print(client.is_ready()) # Should print: `True` - -# Your work goes here! - -client.close() # Free up resources -# END ConnectToWeaviate - -client = weaviate.connect_to_weaviate_cloud( - cluster_url=weaviate_url, - auth_credentials=Auth.api_key(weaviate_api_key), -) - -client.collections.delete("Recipes") - -# 2. Prepare the Collection -# 2.1 Define the Collection -# START DefineCollection -from weaviate.classes.config import Configure, DataType, Property - - -client.collections.create( - "Recipes", - description="A dataset that lists recipes with titles, descriptions, and labels indicating cuisine", - vector_config=Configure.Vectors.text2vec_weaviate(), - properties=[ - Property( - name="title", data_type=DataType.TEXT, description="title of the recipe" - ), - Property( - name="labels", - data_type=DataType.TEXT, - description="the cuisine the recipe belongs to", - ), - Property( - name="description", - data_type=DataType.TEXT, - description="short description of the recipe", - ), - ], -) -# END DefineCollection - -# 2.2 Populate the database -# START PopulateDatabase -from datasets import load_dataset - -# Ensure datasets library is installed: pip install datasets -dataset = load_dataset( - "weaviate/agents", - "personalization-agent-recipes", - split="train", - streaming=True, -) -recipes_collection = client.collections.use("Recipes") - -with recipes_collection.batch.fixed_size(batch_size=200) as batch: - for item in dataset: - batch.add_object(properties=item["properties"]) - -failed_objects = recipes_collection.batch.failed_objects -if failed_objects: - print(f"Number of failed imports: {len(failed_objects)}") - print(f"First failed object: {failed_objects[0]}") - -# END PopulateDatabase - - -# 2.3 Check the number of objects -# START CheckCollectionSize -print(f"Size of the Recipes dataset: {len(recipes_collection)}") -# END CheckCollectionSize - -# 3. Set up the Personalization Agent -# 3.1 Create or connect to the agent and define user_properties -# START CreateOrConnectAgent -from weaviate.agents.personalization import PersonalizationAgent -from weaviate.classes.config import DataType - - -agent_exists = PersonalizationAgent.exists(client, "Recipes") -if agent_exists: - print("Connecting to existing Personalization Agent for 'Recipes' collection...") - agent = PersonalizationAgent.connect( - client=client, - reference_collection="Recipes", - vector_name="default" - ) - print("Connected to existing agent.") -else: - print("Creating new Personalization Agent for 'Recipes' collection...") - agent = PersonalizationAgent.create( - client=client, - reference_collection="Recipes", - vector_name="default", - user_properties={ - "favorite_cuisines": DataType.TEXT_ARRAY, - "likes": DataType.TEXT_ARRAY, - "dislikes": DataType.TEXT_ARRAY, - }, - ) - print("New agent created.") -# END CreateOrConnectAgent - -# 4. Use the Personalization Agent -# 4.1 Add a New Persona -# START AddPersona -from uuid import uuid4 -from weaviate.agents.classes import Persona - - -persona_id = uuid4() -print(f"Adding persona with ID: {persona_id}") -agent.add_persona( - Persona( - persona_id=persona_id, - properties={ - "favorite_cuisines": ["Italian", "Thai"], - "likes": ["chocolate", "salmon", "pasta", "most veggies"], - "dislikes": ["okra", "mushroom"], - }, - ) -) -# END AddPersona - -# 4.2 Add Interactions -# START AddInteractions -from weaviate.agents.classes import PersonaInteraction -from weaviate.collections.classes.filters import Filter - - -reviewed_foods = [ - "Coq au Vin", - "Chicken Tikka Masala", - "Gnocchi alla Sorrentina", - "Matcha Ice Cream", - "Fiorentina Steak", - "Nabe", - "Duck Confit", - "Pappardelle with Porcini", -] - -# Fetch the recipe objects to get their UUIDs -reviews_dict = { - recipe.properties["title"]: recipe - for recipe in recipes_collection.query.fetch_objects( - filters=Filter.by_property("title").contains_any(reviewed_foods), - limit=len(reviewed_foods), # Use len for limit - ).objects -} - -# Define the mapping of food titles to interaction weights -interaction_map = { - "Coq au Vin": 0.8, - "Chicken Tikka Masala": 0.8, - "Matcha Ice Cream": 0.8, - "Gnocchi alla Sorrentina": 0.5, - "Fiorentina Steak": 0.8, - "Nabe": 0.5, - "Duck Confit": 1.0, - "Pappardelle with Porcini": -1.0, -} - -interactions = [] -for food_title, weight in interaction_map.items(): - if food_title in reviews_dict: - # If the recipe was found, create the interaction object - interaction = PersonaInteraction( - persona_id=persona_id, - item_id=reviews_dict[food_title].uuid, # Get UUID from fetched recipe - weight=weight, - ) - interactions.append(interaction) - -# Add the created interactions list to the agent -agent.add_interactions(interactions=interactions) -# END AddInteractions - - -# 4.3 Get Recommendations -# START GetRecommendations -print(f"\nGetting recommendations for persona {persona_id}...") -response = agent.get_objects(persona_id, limit=10, use_agent_ranking=True) - -print("\nRanking Rationale:") -print( - response.ranking_rationale - if response.ranking_rationale - else "No rationale provided." -) -print("\nRecommended Recipes:") -if response.objects: - for i, obj in enumerate(response.objects): - print(f"----- Recommendation {i+1} -----") - print(f" Title: {obj.properties.get('title', 'N/A')}") - print(f" Cuisine: {obj.properties.get('labels', 'N/A')}") - print(f" UUID: {obj.uuid}") -else: - print("No recommendations found.") -# END GetRecommendations - -client.close() diff --git a/docs/agents/_includes/personalization_agent_tutorial_food_recommender_dataset.png b/docs/agents/_includes/personalization_agent_tutorial_food_recommender_dataset.png deleted file mode 100644 index e0dd08d57..000000000 Binary files a/docs/agents/_includes/personalization_agent_tutorial_food_recommender_dataset.png and /dev/null differ diff --git a/docs/agents/_includes/personalization_agent_tutorial_food_recommender_flowchart.png b/docs/agents/_includes/personalization_agent_tutorial_food_recommender_flowchart.png deleted file mode 100644 index 5b4d9f5f7..000000000 Binary files a/docs/agents/_includes/personalization_agent_tutorial_food_recommender_flowchart.png and /dev/null differ diff --git a/docs/agents/_includes/personalization_agent_tutorial_food_recommender_user.png b/docs/agents/_includes/personalization_agent_tutorial_food_recommender_user.png deleted file mode 100644 index e4c0c0fb8..000000000 Binary files a/docs/agents/_includes/personalization_agent_tutorial_food_recommender_user.png and /dev/null differ diff --git a/docs/agents/_includes/personalization_agent_users.png b/docs/agents/_includes/personalization_agent_users.png deleted file mode 100644 index 9fe3c057c..000000000 Binary files a/docs/agents/_includes/personalization_agent_users.png and /dev/null differ diff --git a/docs/agents/_includes/personalization_agent_users_dark.png b/docs/agents/_includes/personalization_agent_users_dark.png deleted file mode 100644 index 02840ff75..000000000 Binary files a/docs/agents/_includes/personalization_agent_users_dark.png and /dev/null differ diff --git a/docs/agents/_includes/personalization_agent_users_light.png b/docs/agents/_includes/personalization_agent_users_light.png deleted file mode 100644 index 9fe3c057c..000000000 Binary files a/docs/agents/_includes/personalization_agent_users_light.png and /dev/null differ diff --git a/docs/agents/_includes/query_agent.mts b/docs/agents/_includes/query_agent.mts deleted file mode 100644 index a671d6526..000000000 --- a/docs/agents/_includes/query_agent.mts +++ /dev/null @@ -1,613 +0,0 @@ -import 'dotenv/config' - -interface DatasetItem { - properties: any; - vector?: number[]; - } - -async function populateWeaviate(client: WeaviateClient, overwriteExisting: boolean = false): Promise { - if (overwriteExisting) { - try { - await client.collections.delete('ECommerce'); - await client.collections.delete('Weather'); - await client.collections.delete('FinancialContracts'); - } catch (error) { - // Collections may not exist, continue - } - } - - // Create ECommerce collection - if (!(await client.collections.exists('ECommerce'))) { - await client.collections.create({ - name: 'ECommerce', - description: 'A dataset that lists clothing items, their brands, prices, and more.', - vectorizers: [ - vectors.text2VecWeaviate({ - name: 'description_vector', - sourceProperties: ['description'], - vectorIndexConfig: configure.vectorIndex.hnsw() - }), - vectors.text2VecWeaviate({ - name: 'name_description_brand_vector', - sourceProperties: ['name', 'description', 'brand'], - vectorIndexConfig: configure.vectorIndex.hnsw() - }) - ], - properties: [ - { - name: 'collection', - dataType: dataType.TEXT - }, - { - name: 'category', - dataType: dataType.TEXT, - description: 'The category to which the clothing item belongs' - }, - { - name: 'tags', - dataType: dataType.TEXT_ARRAY, - description: 'The tags that are associated with the clothing item' - }, - { - name: 'subcategory', - dataType: dataType.TEXT - }, - { - name: 'name', - dataType: dataType.TEXT - }, - { - name: 'description', - dataType: dataType.TEXT, - description: 'A detailed description of the clothing item' - }, - { - name: 'brand', - dataType: dataType.TEXT, - description: 'The brand of the clothing item' - }, - { - name: 'product_id', - dataType: dataType.UUID - }, - { - name: 'colors', - dataType: dataType.TEXT_ARRAY, - description: 'The colors on the clothing item' - }, - { - name: 'reviews', - dataType: dataType.TEXT_ARRAY - }, - { - name: 'image_url', - dataType: dataType.TEXT - }, - { - name: 'price', - dataType: dataType.NUMBER, - description: 'The price of the clothing item in USD' - } - ] - }); - } - - // Create Weather collection - if (!(await client.collections.exists('Weather'))) { - await client.collections.create({ - name: 'Weather', - description: 'Daily weather information including temperature, wind speed, precipitation, pressure etc.', - vectorizers: vectors.text2VecWeaviate(), - properties: [ - { - name: 'date', - dataType: dataType.DATE - }, - { - name: 'humidity', - dataType: dataType.NUMBER - }, - { - name: 'precipitation', - dataType: dataType.NUMBER - }, - { - name: 'wind_speed', - dataType: dataType.NUMBER - }, - { - name: 'visibility', - dataType: dataType.NUMBER - }, - { - name: 'pressure', - dataType: dataType.NUMBER - }, - { - name: 'temperature', - dataType: dataType.NUMBER, - description: 'temperature value in Celsius' - } - ] - }); - } - - // Create FinancialContracts collection - if (!(await client.collections.exists('FinancialContracts'))) { - await client.collections.create({ - name: 'FinancialContracts', - description: 'A dataset of financial contracts between individuals and/or companies, as well as information on the type of contract and who has authored them.', - vectorizers: vectors.text2VecWeaviate() - }); - } - - // Load datasets from Hugging Face - console.log('Loading datasets from Hugging Face...'); - - // Helper function to load dataset from HF Datasets Viewer API - async function loadHFDataset(repo: string, config: string, split: string = 'train'): Promise { - const url = `https://datasets-server.huggingface.co/rows?dataset=${repo}&config=${config}&split=${split}&limit=1000`; - - try { - const response = await fetch(url); - if (!response.ok) { - throw new Error(`Failed to fetch dataset: ${response.statusText}`); - } - - const data = await response.json(); - return data.rows.map((row: any) => row.row); - } catch (error) { - console.error(`Error loading dataset ${repo}/${config}:`, error); - return []; - } - } - - const ecommerceCollection = client.collections.use('ECommerce'); - const weatherCollection = client.collections.use('Weather'); - const financialCollection = client.collections.use('FinancialContracts'); - - try { - // Load datasets from Hugging Face - const [ecommerceData, weatherData, financialData] = await Promise.all([ - loadHFDataset('weaviate/agents', 'query-agent-ecommerce', 'train'), - loadHFDataset('weaviate/agents', 'query-agent-weather', 'train'), - loadHFDataset('weaviate/agents', 'query-agent-financial-contracts', 'train') - ]); - - console.log(`Loaded ${ecommerceData.length} ecommerce items`); - console.log(`Loaded ${weatherData.length} weather items`); - console.log(`Loaded ${financialData.length} financial items`); - - // Batch insert ecommerce data - if (ecommerceData.length > 0) { - await ecommerceCollection.data.insertMany( - ecommerceData.map(item => ({ properties: item.properties || item })) - ); - } - - // Batch insert weather data - if (weatherData.length > 0) { - await weatherCollection.data.insertMany( - weatherData.map(item => ({ - properties: item.properties || item, - vectors: item.vector ? { default: item.vector } : undefined - })) - ); - } - - // Batch insert financial data - if (financialData.length > 0) { - await financialCollection.data.insertMany( - financialData.map(item => ({ - properties: item.properties || item, - vectors: item.vector ? { default: item.vector } : undefined - })) - ); - } - } catch (error) { - console.error('Error loading or inserting data:', error); - } - - // Get collection sizes - const ecommerceCount = await ecommerceCollection.aggregate.overAll(); - const weatherCount = await weatherCollection.aggregate.overAll(); - const financialCount = await financialCollection.aggregate.overAll(); - - console.log(`Size of the ECommerce dataset: ${ecommerceCount.totalCount}`); - console.log(`Size of the Weather dataset: ${weatherCount.totalCount}`); - console.log(`Size of the Financial dataset: ${financialCount.totalCount}`); -} - - -// START InstantiateQueryAgent -import weaviate, { WeaviateClient, vectors, dataType, configure } from 'weaviate-client'; -import { QueryAgent, ChatMessage } from 'weaviate-agents'; - -// END InstantiateQueryAgent - -async function main() { -// START InstantiateQueryAgent -const headers = { - // END InstantiateQueryAgent - 'X-Cohere-API-Key': process.env.COHERE_API_KEY as string, - 'X-OpenAI-API-Key': process.env.OPENAI_API_KEY as string, - // START InstantiateQueryAgent - // Provide your required API key(s), e.g. Cohere, OpenAI, etc. for the configured vectorizer(s) - // "X-INFERENCE-PROVIDER-API-KEY": process.env.YOUR_INFERENCE_PROVIDER_KEY, -}; - -const client = await weaviate.connectToWeaviateCloud(process.env.WEAVIATE_URL as string, { - authCredentials: new weaviate.ApiKey(process.env.WEAVIATE_API_KEY as string), - headers -}); -// END InstantiateQueryAgent - -// Populate Weaviate with data -await populateWeaviate(client); - -// START InstantiateQueryAgent -// Instantiate a new agent object -const queryAgent = new QueryAgent( - client, { - collections: [ - { - name: 'ECommerce', - // ECommerce has named vectors, so a target vector must be specified - targetVector: ['name_description_brand_vector'], - }, - 'FinancialContracts', - 'Weather', - ], -}); -// END InstantiateQueryAgent - -// START SystemPromptExample -// Define a custom system prompt to guide the agent's behavior -const systemPrompt = `You are a helpful assistant that can answer questions about the products and - users in the database. When you write your response use standard markdown - formatting for lists, tables, and other structures. Emphasize key insights - and provide actionable recommendations when relevant.` - -const qaWithPrompt = new QueryAgent( - client, { - collections: [{ - name: 'ECommerce', - targetVector: ['name_description_brand_vector'], - viewProperties: ['description'] - // tenant: 'tenantA' // Optional for multi-tenancy - }, "FinancialContracts", "Weather"], - systemPrompt: systemPrompt -}) - -const responseWithPrompt = await qaWithPrompt.ask("What are the most expensive items in the store?") - -responseWithPrompt.display() -// END SystemPromptExample - -// START QueryAgentCollectionConfiguration -const qaWithConfig = new QueryAgent(client, { - collections: [ - { - name: 'ECommerce', - targetVector: ['name_description_brand_vector'], - viewProperties: ['description'] - // tenant: 'tenantA' // Optional for multi-tenancy - }, - { name: 'FinancialContracts' }, - { name: 'Weather' } - ] -}); -// END QueryAgentCollectionConfiguration - -// START UserDefinedFilters -// Apply persistent filters that will always be combined with agent-generated filters - -const eCommerceCollection = client.collections.use("ECommerce") - -const qaWithFilter = new QueryAgent( - client, { - collections: [{ - name: "ECommerce", - // This filter ensures only items above $50 are considered - additionalFilters: eCommerceCollection.filter.byProperty("price").greaterThan(50), - targetVector:[ - "name_description_brand_vector" - ], // Required target vector name(s) for collections with named vectors - }], -}) - -// The agent will automatically combine these filters with any it generates -const responseWithFilter = await qaWithFilter.ask("Find me some affordable clothing items") - -responseWithFilter.display() - -// You can also apply filters dynamically at runtime -const runtimeConfig = { - name: "ECommerce", - additionalFilters: eCommerceCollection.filter.byProperty("category").equal("Footwear"), - targetVector:["name_description_brand_vector"] -} - -const responseWithRuntimeFilter = await queryAgent.ask("What products are available?", { - collections: [runtimeConfig] -}) - -responseWithRuntimeFilter.display() -// END UserDefinedFilters - - -// Reset qa to original configuration for following examples -const qa = new QueryAgent( - client, { - collections: [ - { - name:"ECommerce", - targetVector: ["name_description_brand_vector"], - viewProperties: ["name", "description", "price"], - }, - "FinancialContracts", - "Weather", - ], -}) - -// START QueryAgentAskBasicCollectionSelection -const contractResponse = await qa.ask( - "What kinds of contracts are listed? What's the most common type of contract?", { - collections: ['FinancialContracts'] -}); - -contractResponse.display(); -// END QueryAgentAskBasicCollectionSelection - -// START QueryAgentAskCollectionConfig -const clothingResponse = await qaWithConfig.ask( - "I like vintage clothes and nice shoes. Recommend some of each below $60.", { - collections: [ - { - name: 'ECommerce', - targetVector: ['name_description_brand_vector'], - viewProperties: ['name', 'description', 'category', 'brand'] - }, - { - name: 'FinancialContracts' - } - ] -}); - -clothingResponse.display(); -// END QueryAgentAskCollectionConfig - -// START BasicSearchQuery -// Perform a search using Search Mode (retrieval only, no answer generation) -const basicSearchResponse = await qa.search("Find me some vintage shoes under $70", { - limit: 10 -} ) - -// Access the search results -for (const obj of basicSearchResponse.searchResults.objects) { - console.log(`Product: ${obj.properties['name']} - ${obj.properties['price']}`) -} -// END BasicSearchQuery - -// START DiversityRanking -const diversitySearchResponse = await qa.search("summer shoes", { - limit: 10, - diversityWeight: 0.5, - collections: [{ - name: "ECommerce", - targetVector: ["name_description_brand_vector"], - }] -}) - -// Access the search results -for (const obj of diversitySearchResponse.searchResults.objects) { - console.log(`Product: ${obj.properties['name']} - ${obj.properties['price']}`) -} -// END DiversityRanking - -// START BasicAskQuery -// Perform a query -const basicQuery = "I like vintage clothes and nice shoes. Recommend some of each below $60." -const basicResponse = await qaWithConfig.ask(basicQuery); - -basicResponse.display(); -// END BasicAskQuery - -// START SearchModeResponseStructure -// SearchModeResponse structure for TypeScript -const searchResponse = await qa.search("winter boots for under $100", { - limit: 5 -}) - -// Access different parts of the response -console.log("Original query:", basicQuery) -console.log("Total time:", searchResponse.totalTime) - -// Access usage statistics -console.log("Usage statistics:", searchResponse.usage) - -// Access the searches performed (if any) -if (searchResponse.searches) { - for (const search in searchResponse.searches) { - console.log("Search performed:", search) - } -} -// Access the search results (QueryReturn object) -for (const obj of searchResponse.searchResults.objects){ - console.log("Properties:", obj.properties) - console.log("Metadata:", obj.metadata) -} -// END SearchModeResponseStructure - -// START SearchPagination -// Search with pagination -const responsePage1 = await qa.search( - "Find summer shoes and accessories between $50 and $100 that have the tag 'sale'", { - limit: 3, -}) - -// Get the next page of results -const responsePage2 = await responsePage1.next({ - limit: 3, - offset: 3, -}) - -// Continue paginating -const responsePage3 = await responsePage2.next({ - limit: 3, - offset: 6, -}) - -const pages = [responsePage1, responsePage2, responsePage3]; - -pages.forEach((pageResponse, index) => { - const pageNum = index + 1; - console.log(`Page ${pageNum}:`); - - pageResponse.searchResults.objects.forEach(obj => { - // Safely access properties in case they don't exist - const name = obj.properties.name || "Unknown Product"; - const price = obj.properties.price || "Unknown Price"; - console.log(`${name} - $${price}`); - }); -}); -// END SearchPagination - - -// START FollowUpQuery -// Perform a follow-up query and include the answer from the previous query - -const basicConversation: ChatMessage[] = [ - { - role: "assistant", - content: basicResponse.finalAnswer - }, - { - role: "user", - content: "I like the vintage clothes options, can you do the same again but above $200?", - }, -] - -const followingResponse = await qaWithConfig.ask(basicConversation) - -// Print the response -followingResponse.display() -// END FollowUpQuery - -// START ConversationalQuery -// Create a conversation with multiple turns -const conversation: ChatMessage[] = [ - { - role: "user", - content: "Hi!" - }, - { - role: "assistant", - content: "Hello! How can I assist you today?" - }, - { - role: "user", - content: "I have some questions about the weather data. You can assume the temperature is in Fahrenheit and the wind speed is in mph.", - }, - { - role: "assistant", - content: "I can help with that. What specific information are you looking for?", - }, -] - -// Add the user's query -conversation.push( - { - role: "user", - content: "What's the average wind speed, the max wind speed, and the min wind speed", - } -) - -// Get the response -const response = await qaWithConfig.ask(conversation) -console.log(response.finalAnswer) - -// Continue the conversation -conversation.push({role: "assistant", content: response.finalAnswer}) -conversation.push({role: "user", content: "and for the temperature?"}) - -const followUpResponse = await qaWithConfig.ask(conversation) -console.log(followUpResponse.finalAnswer) -// END ConversationalQuery - -var query = "What is the weather like in San Francisco?"; - -// START StreamResponse -// Setting includeProgress to false will skip progressMessages, and only stream -// the streamedTokens / the final response. -for await (const event of qa.askStream(query, { - includeProgress: true, // Default: True - includeFinalState: true, // Default: True -})) { - if (event.outputType === "progressMessage") { - // The message is a human-readable string, structured info available in event.details - console.log(event.message); - } else if (event.outputType === "streamedTokens") { - // The delta is a string containing the next chunk of the final answer - process.stdout.write(event.delta); - } else { - // This is the final response, as returned by queryAgent.ask() - event.display(); - } -} -// END StreamResponse - -// START InspectResponseExample -console.log('\n=== Query Agent Response ==='); -console.log(`Original Query: ${basicQuery}\n`); // Pre-defined by user - -console.log('🔍 Final Answer Found:'); -console.log(`${basicResponse.finalAnswer}\n`); - -console.log('🔍 Searches Executed:'); -for (const collectionSearches of basicResponse.searches) { - console.log(`- ${collectionSearches.query}\n`); -} - -if (basicResponse.aggregations) { - console.log('📊 Aggregation Results:'); - for (const collectionAggs of basicResponse.aggregations) { - for (const agg in collectionAggs) { - console.log(`- ${agg}\n`); - } - } -} - -if (basicResponse.missingInformation && basicResponse.missingInformation.length > 0) { - if (basicResponse.isPartialAnswer) { - console.log('⚠️ Answer is Partial - Missing Information:'); - } else { - console.log('⚠️ Missing Information:'); - } - for (const missing of basicResponse.missingInformation) { - console.log(`- ${missing}`); - } -} -// END InspectResponseExample - -if (!basicResponse.finalAnswer || basicResponse.finalAnswer === '') { - throw new Error('Final answer is empty or null'); -} - -// START SuggestQueries -const suggestResponse = await qa.suggestQueries({ - collections: ["ArxivPapers"], - numQueries: 3, - instructions: "High-level themes and open-ended exploration", -}); - -for (const suggestedQuery of suggestResponse.queries) { - console.log(suggestedQuery.query); -} -// END SuggestQueries - -await client.close() - -} - -void main(); diff --git a/docs/agents/_includes/query_agent_info_dark.png b/docs/agents/_includes/query_agent_info_dark.png deleted file mode 100644 index f7d400505..000000000 Binary files a/docs/agents/_includes/query_agent_info_dark.png and /dev/null differ diff --git a/docs/agents/_includes/query_agent_info_light.png b/docs/agents/_includes/query_agent_info_light.png deleted file mode 100644 index f5c8e4f99..000000000 Binary files a/docs/agents/_includes/query_agent_info_light.png and /dev/null differ diff --git a/docs/agents/_includes/query_agent_usage_dark.png b/docs/agents/_includes/query_agent_usage_dark.png deleted file mode 100644 index 331f5ca2d..000000000 Binary files a/docs/agents/_includes/query_agent_usage_dark.png and /dev/null differ diff --git a/docs/agents/_includes/query_agent_usage_light.png b/docs/agents/_includes/query_agent_usage_light.png deleted file mode 100644 index 8f10e20aa..000000000 Binary files a/docs/agents/_includes/query_agent_usage_light.png and /dev/null differ diff --git a/docs/agents/_includes/transformation_agent.excalidraw.zip b/docs/agents/_includes/transformation_agent.excalidraw.zip deleted file mode 100644 index 7c4d33a6c..000000000 Binary files a/docs/agents/_includes/transformation_agent.excalidraw.zip and /dev/null differ diff --git a/docs/agents/_includes/transformation_agent.py b/docs/agents/_includes/transformation_agent.py deleted file mode 100644 index 2deeae77f..000000000 --- a/docs/agents/_includes/transformation_agent.py +++ /dev/null @@ -1,144 +0,0 @@ -# START-ANY -# [🚧 CAUTION 🚧] DO NOT USE ON PRODUCTION DATA. -# The Transformation Agent will modify your data in place. -# While the Transformation Agent is in technical preview, -# it is recommended to only use it on test data. - -# END-ANY - -# START SimpleTransformationAgentExample # START ConnectToWeaviate -import os -import weaviate -from weaviate.classes.init import Auth -# START SimpleTransformationAgentExample # START StartTransformationOperations # END ConnectToWeaviate -from weaviate.agents.transformation import TransformationAgent -# START SimpleTransformationAgentExample # END StartTransformationOperations -from weaviate.agents.classes import Operations - -# END SimpleTransformationAgentExample - -# START DefineOperationsAppend # START DefineOperationsUpdate -from weaviate.agents.classes import Operations - -# END DefineOperationsAppend # END DefineOperationsUpdate - -from weaviate.classes.config import Configure, Property, DataType -from datasets import load_dataset - -# START SimpleTransformationAgentExample # START ConnectToWeaviate - -headers = { - # END SimpleTransformationAgentExample - "X-Cohere-API-Key": os.environ.get("COHERE_API_KEY"), - # START SimpleTransformationAgentExample - # Provide your required API key(s), e.g. Cohere, OpenAI, etc. for the configured vectorizer(s) - "X-INFERENCE-PROVIDER-API-KEY": os.environ.get("YOUR_INFERENCE_PROVIDER_KEY", ""), -} - -client = weaviate.connect_to_weaviate_cloud( - cluster_url=os.environ.get("WEAVIATE_URL"), - auth_credentials=Auth.api_key(os.environ.get("WEAVIATE_API_KEY")), - headers=headers, -) - -# END SimpleTransformationAgentExample # END ConnectToWeaviate - -client.collections.delete("ArxivPapers") - -client.collections.create( - "ArxivPapers", - description="A dataset that lists research paper titles and abstracts", - vector_config=Configure.Vectors.text2vec_weaviate(), -) - -dataset = load_dataset( - "weaviate/agents", "transformation-agent-papers", split="train", streaming=True -) - -papers_collection = client.collections.use("ArxivPapers") - -with papers_collection.batch.fixed_size(batch_size=100) as batch: - for i, item in enumerate(dataset): - if i < 10: - batch.add_object(properties=item["properties"]) - - -# START SimpleTransformationAgentExample -add_topics = Operations.append_property( - property_name="topics", - data_type=DataType.TEXT_ARRAY, - view_properties=["abstract", "title"], - instruction="""Create a list of topic tags based on the title and abstract. - Topics should be distinct from eachother. Provide a maximum of 5 topics. - Group similar topics under one topic tag.""", -) - -agent = TransformationAgent( - client=client, - collection="ArxivPapers", - operations=[add_topics], -) - -response = agent.update_all() # The response is a TransformationResponse object - -agent.get_status(workflow_id=response.workflow_id) # Use the workflow_id to check the status of each workflow -# END SimpleTransformationAgentExample - -# START DefineOperationsAppend -add_french_abstract = Operations.append_property( - property_name="french_abstract", - data_type=DataType.TEXT, - view_properties=["abstract"], - instruction="Translate the abstract to French", -) - -add_nlp_relevance = Operations.append_property( - property_name="nlp_relevance", - data_type=DataType.INT, - view_properties=["abstract"], - instruction="""Give a score from 0-10 based on how relevant the abstract is to Natural Language Processing. - The scale is from 0 (not relevant at all) to 10 (very relevant)""", -) - -is_survey_paper = Operations.append_property( - property_name="is_survey_paper", - data_type=DataType.BOOL, - view_properties=["abstract"], - instruction="""Determine if the paper is a "survey". - A paper is considered survey it's a surveys existing techniques, and not if it presents novel techniques""", -) -# END DefineOperationsAppend - -# START DefineOperationsUpdate -update_topics = Operations.update_property( - property_name="topics", - view_properties=["abstract", "title"], - instruction="""Create a list of topic tags based on the title and abstract. - Topics should be distinct from eachother. Provide a maximum of 3 topics. - Group similar topics under one topic tag.""", -) -# END DefineOperationsUpdate - -# START StartTransformationOperations - -agent = TransformationAgent( - client=client, - collection="ArxivPapers", - operations=[ - add_french_abstract, - add_nlp_relevance, - is_survey_paper, - update_topics, - ], -) - -response = agent.update_all() - -print(response) # The response is a TransformationResponse object, including the workflow_id -# END StartTransformationOperations - -# START MonitorJobStatus -print(agent.get_status(workflow_id=response.workflow_id)) # Use the workflow_id to check the status of each operation -# END MonitorJobStatus - -client.close() diff --git a/docs/agents/_includes/transformation_agent_append_example_dark.png b/docs/agents/_includes/transformation_agent_append_example_dark.png deleted file mode 100644 index 3e7efe5cb..000000000 Binary files a/docs/agents/_includes/transformation_agent_append_example_dark.png and /dev/null differ diff --git a/docs/agents/_includes/transformation_agent_append_example_light.png b/docs/agents/_includes/transformation_agent_append_example_light.png deleted file mode 100644 index aa42eb13a..000000000 Binary files a/docs/agents/_includes/transformation_agent_append_example_light.png and /dev/null differ diff --git a/docs/agents/_includes/transformation_agent_existing_append_dark.png b/docs/agents/_includes/transformation_agent_existing_append_dark.png deleted file mode 100644 index 23c5e01ac..000000000 Binary files a/docs/agents/_includes/transformation_agent_existing_append_dark.png and /dev/null differ diff --git a/docs/agents/_includes/transformation_agent_existing_append_light.png b/docs/agents/_includes/transformation_agent_existing_append_light.png deleted file mode 100644 index 86d629c6e..000000000 Binary files a/docs/agents/_includes/transformation_agent_existing_append_light.png and /dev/null differ diff --git a/docs/agents/_includes/transformation_agent_existing_update_dark.png b/docs/agents/_includes/transformation_agent_existing_update_dark.png deleted file mode 100644 index 15c9b289a..000000000 Binary files a/docs/agents/_includes/transformation_agent_existing_update_dark.png and /dev/null differ diff --git a/docs/agents/_includes/transformation_agent_existing_update_light.png b/docs/agents/_includes/transformation_agent_existing_update_light.png deleted file mode 100644 index eba918ef9..000000000 Binary files a/docs/agents/_includes/transformation_agent_existing_update_light.png and /dev/null differ diff --git a/docs/agents/_includes/transformation_agent_overview_dark.png b/docs/agents/_includes/transformation_agent_overview_dark.png deleted file mode 100644 index 491ab8d74..000000000 Binary files a/docs/agents/_includes/transformation_agent_overview_dark.png and /dev/null differ diff --git a/docs/agents/_includes/transformation_agent_overview_light.png b/docs/agents/_includes/transformation_agent_overview_light.png deleted file mode 100644 index e28a2c3b9..000000000 Binary files a/docs/agents/_includes/transformation_agent_overview_light.png and /dev/null differ diff --git a/docs/agents/_includes/transformation_agent_tutorial_arxiv_dataset.png b/docs/agents/_includes/transformation_agent_tutorial_arxiv_dataset.png deleted file mode 100644 index b4da0eaf3..000000000 Binary files a/docs/agents/_includes/transformation_agent_tutorial_arxiv_dataset.png and /dev/null differ diff --git a/docs/agents/_includes/transformation_agent_tutorial_arxiv_flowchart.png b/docs/agents/_includes/transformation_agent_tutorial_arxiv_flowchart.png deleted file mode 100644 index 75d264522..000000000 Binary files a/docs/agents/_includes/transformation_agent_tutorial_arxiv_flowchart.png and /dev/null differ diff --git a/docs/agents/_includes/transformation_agent_tutorial_enrich_dataset.py b/docs/agents/_includes/transformation_agent_tutorial_enrich_dataset.py deleted file mode 100644 index 50c43a5ed..000000000 --- a/docs/agents/_includes/transformation_agent_tutorial_enrich_dataset.py +++ /dev/null @@ -1,139 +0,0 @@ -# START ConnectToWeaviate -import os -import time -import weaviate -from weaviate.auth import Auth - -# Best practice: store your credentials in environment variables -weaviate_url = os.environ["WEAVIATE_URL"] -weaviate_api_key = os.environ["WEAVIATE_API_KEY"] - -client = weaviate.connect_to_weaviate_cloud( - cluster_url=weaviate_url, - auth_credentials=Auth.api_key(weaviate_api_key), -) - -print(client.is_ready()) # Should print: `True` - -# Your work goes here! - -client.close() # Free up resources -# END ConnectToWeaviate - -client = weaviate.connect_to_weaviate_cloud( - cluster_url=weaviate_url, - auth_credentials=Auth.api_key(weaviate_api_key), -) - -client.collections.delete("ArxivPapers") - -# START DefineCollections -from weaviate.classes.config import Configure - -client.collections.create( - "ArxivPapers", - description="A dataset that lists research paper titles and abstracts", - vector_config=Configure.Vectors.text2vec_weaviate(), -) -# END DefineCollections - -# START PopulateDatabase -from datasets import load_dataset - -dataset = load_dataset( - "weaviate/agents", "transformation-agent-papers", split="train", streaming=True -) - -papers_collection = client.collections.use("ArxivPapers") - -with papers_collection.batch.fixed_size(batch_size=200) as batch: - for item in dataset: - batch.add_object(properties=item["properties"]) - -failed_objects = papers_collection.batch.failed_objects -if failed_objects: - print(f"Number of failed imports: {len(failed_objects)}") - print(f"First failed object: {failed_objects[0]}") - -print(f"Size of the ArxivPapers dataset: {len(papers_collection)}") -# END PopulateDatabase - -# START AddListOfTopics -from weaviate.agents.classes import Operations -from weaviate.collections.classes.config import DataType - -add_topics = Operations.append_property( - property_name="topics", - data_type=DataType.TEXT_ARRAY, - view_properties=["abstract"], - instruction="""Create a list of topic tags based on the abstract. - Topics should be distinct from each other. Provide a maximum of 5 topics. - Group similar topics under one topic tag.""", -) -# END AddListOfTopics - -# START AddFrenchAbstract -add_french_abstract = Operations.append_property( - property_name="french_abstract", - data_type=DataType.TEXT, - view_properties=["abstract"], - instruction="Translate the abstract to French.", -) -# END AddFrenchAbstract - -# START AddNlpRelevance -add_nlp_relevance = Operations.append_property( - property_name="nlp_relevance", - data_type=DataType.INT, - view_properties=["abstract"], - instruction="""Give a score from 0-10 based on how relevant the abstract is to Natural Language Processing. - The scale is from 0 (not relevant at all) to 10 (very relevant).""", -) -# END AddNlpRelevance - -# START IsSurveyPaper -add_is_survey_paper = Operations.append_property( - property_name="is_survey_paper", - data_type=DataType.BOOL, - view_properties=["abstract"], - instruction="""Determine if the paper is a "survey". - A paper is considered a survey if it surveys existing techniques and not if it presents novel techniques.""", -) -# END IsSurveyPaper - -# START UpdateProperty -update_title = Operations.update_property( - property_name="title", - view_properties=["abstract"], - instruction="""Insert the label MACHINE_LEARNING before the original title if the abstract mentions machine learning techniques.""", -) -# END UpdateProperty - -# START CreateTransformationAgent -from weaviate.agents.transformation import TransformationAgent - -agent = TransformationAgent( - client=client, - collection="ArxivPapers", - operations=[ - add_topics, - add_french_abstract, - add_nlp_relevance, - add_is_survey_paper, - update_title, - ], -) -# END CreateTransformationAgent - -# START ExecutingTransformations -response = agent.update_all() -print(response) -# END ExecutingTransformations - -time.sleep(5) - -# START GetStatus -print(agent.get_status(workflow_id=response.workflow_id)) -# END GetStatus - -client.close() # Free up resources diff --git a/docs/agents/_includes/transformation_agent_tutorial_explorer_tool.png b/docs/agents/_includes/transformation_agent_tutorial_explorer_tool.png deleted file mode 100644 index 4f5c1ef26..000000000 Binary files a/docs/agents/_includes/transformation_agent_tutorial_explorer_tool.png and /dev/null differ diff --git a/docs/agents/index.md b/docs/agents/index.md deleted file mode 100644 index f6fdebdb9..000000000 --- a/docs/agents/index.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -title: Introduction -sidebar_position: 10 -description: "Overview of Weaviate AI Agents documentation for personalization, querying, and data transformation agents." -image: og/docs/agents.jpg -# tags: ['agents', 'getting started'] ---- - -# Weaviate Agents - Introduction - - - -Weaviate Agents are pre-built agentic services designed for specific tasks. They are available out-of-the-box for Weaviate Cloud users to interact with their data in Weaviate Cloud to simplify data engineering and AI development workflows. - -:::info Changelog and feedback -The official changelog for Weaviate Agents can be [found here](https://weaviateagents.featurebase.app/changelog). If you have feedback, such as feature requests, bug reports or questions, please [submit them here](https://weaviateagents.featurebase.app/), where you will be able to see the status of your feedback and vote on others' feedback. -::: - -:::tip Looking for agent memory? -[Engram](/engram/) is a managed memory service that gives your agents persistent, searchable memory across conversations and users. -::: - -## How Weaviate Agents work - -Weaviate Agents have been pre-trained on Weaviate’s APIs, making them experts in performing Weaviate-specific data tasks. - -All you need to do is provide inputs, and the particular Agent will perform the required task using your data. - -:::info Weaviate Agents is not an agent framework -Weaviate Agents is not a framework for building agents. It is a set of pre-built agentic services for Weaviate. -::: - -## Query Agent - -The [Query Agent](./query/index.md) provides an answer to your natural language questions, by querying your stored data. - -[![Click to read more about the Query Agent](./_includes/query_agent_usage_light.png#gh-light-mode-only "Click to read more about the Query Agent")](./query/index.md) -[![Click to read more about the Query Agent](./_includes/query_agent_usage_dark.png#gh-dark-mode-only "Click to read more about the Query Agent")](./query/index.md) - -[Read more about the Query Agent](./query/index.md) - -## Transformation Agent - -:::caution Technical Preview - -![Weaviate Agents are in technical preview.](./_includes/agents_tech_preview_light.png#gh-light-mode-only "Weaviate Agents are in technical preview.") -![Weaviate Agents are in technical preview.](./_includes/agents_tech_preview_dark.png#gh-dark-mode-only "Weaviate Agents are in technical preview.") - -[Sign up here](https://events.weaviate.io/weaviate-agents) for notifications on Weaviate Agents, or visit [this page](https://weaviateagents.featurebase.app/) to see the latest updates and provide feedback. - -::: - -The [Transformation Agent](./transformation/index.md) enhances your data by manipulating it based on your instructions. - -[![Click to read more about the Transformation Agent](./_includes/transformation_agent_overview_light.png#gh-light-mode-only "Click to read more about the Transformation Agent")](./transformation/index.md) -[![Click to read more about the Transformation Agent](./_includes/transformation_agent_overview_dark.png#gh-dark-mode-only "Click to read more about the Transformation Agent")](./transformation/index.md) - -[Read more about the Transformation Agent](./transformation/index.md) - -## Personalization Agent - -:::caution Technical Preview - -![Weaviate Agents are in technical preview.](./_includes/agents_tech_preview_light.png#gh-light-mode-only "Weaviate Agents are in technical preview.") -![Weaviate Agents are in technical preview.](./_includes/agents_tech_preview_dark.png#gh-dark-mode-only "Weaviate Agents are in technical preview.") - -[Sign up here](https://events.weaviate.io/weaviate-agents) for notifications on Weaviate Agents, or visit [this page](https://weaviateagents.featurebase.app/) to see the latest updates and provide feedback. - -::: - -The [Personalization Agent](./personalization/index.md) customizes outputs based on persona-specific information, which can even be learned over time. - -[![Click to read more about the Personalization Agent](./_includes/personalization_agent_overview_light.png#gh-light-mode-only "Click to read more about the Personalization Agent")](./personalization/index.md) -[![Click to read more about the Personalization Agent](./_includes/personalization_agent_overview_dark.png#gh-dark-mode-only "Click to read more about the Personalization Agent")](./personalization/index.md) - -[Read more about the Personalization Agent](./personalization/index.md) - -## Questions and feedback - -import DocsFeedback from '/_includes/docs-feedback.mdx'; - - diff --git a/docs/agents/personalization/index.md b/docs/agents/personalization/index.md deleted file mode 100644 index 84e667b5f..000000000 --- a/docs/agents/personalization/index.md +++ /dev/null @@ -1,193 +0,0 @@ ---- -title: Personalization Agent -sidebar_position: 10 -description: "Overview of the AI agent that provides personalized recommendations based on user profiles and interaction history." -image: og/docs/agents.jpg -# tags: ['agents', 'getting started', 'personalization agent'] ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; -import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; -import PyCode from '!!raw-loader!/docs/agents/_includes/personalization_agent.py'; - -# Weaviate Personalization Agent - - - -:::caution Technical Preview - -![This Weaviate Agent is in technical preview.](../_includes/agents_tech_preview_light.png#gh-light-mode-only "This Weaviate Agent is in technical preview.") -![This Weaviate Agent is in technical preview.](../_includes/agents_tech_preview_dark.png#gh-dark-mode-only "This Weaviate Agent is in technical preview.") - -[Sign up here](https://events.weaviate.io/weaviate-agents) for notifications on Weaviate Agents, or visit [this page](https://weaviateagents.featurebase.app/) to see the latest updates and provide feedback. - -::: - -The Weaviate Personalization Agent is an agentic service designed to return personalized recommendations tailored to each user. The Personalization Agent uses data from the associated Weaviate Cloud instance to provide these recommendations. - -:::tip Nomenclature: User vs Developer -The Personalization Agent is all about providing personalized recommendations tailored to a particular person. In this context, that person will be referred to as the `user`. The developer is the person who is using the Personalization Agent to provide these recommendations. -::: - -The developer would simply provide a user profile, and the Personalization Agent takes care of all intervening steps to provide a set of personalized recommendations from Weaviate. The resulting workflow for the developer looks as follows: - -![Weaviate Personalization Agent from a developer perspective](../_includes/personalization_agent_overview_light.png#gh-light-mode-only "Weaviate Personalization Agent from a developer perspective") -![Weaviate Personalization Agent from a developer perspective](../_includes/personalization_agent_overview_dark.png#gh-dark-mode-only "Weaviate Personalization Agent from a developer perspective") - -:::info Changelog and feedback -The official changelog for Weaviate Agents can be [found here](https://weaviateagents.featurebase.app/changelog). If you have feedback, such as feature requests, bug reports or questions, please [submit them here](https://weaviateagents.featurebase.app/), where you will be able to see the status of your feedback and vote on others' feedback. -::: - -## Architecture - -The Personalization Agent is provided as a service on Weaviate Cloud. - -When a user-specific recommendations request is made, the Personalization Agent analyses the user profile and any other known context to autonomously carry out the searches itself. The context may include data about the previous user interactions, information about the user themselves, and any other relevant information. - -The Personalization Agent uses the contextual information to not only retrieve the most relevant recommendations, but also to rank them for the user. - -## Personalization Agent: visualized workflow - -![Weaviate Personalization Agent at a high level](../_includes/personalization_agent_architecture_light.png#gh-light-mode-only "Weaviate Personalization Agent at a high level") -![Weaviate Personalization Agent at a high level](../_includes/personalization_agent_architecture_dark.png#gh-dark-mode-only "Weaviate Personalization Agent at a high level") - -The Personalization Agent works as follows at a high level: - -- Create a Weaviate-managed user collection, which will store each user's profiles & previous interactions for each user. -- When a request for personalized recommendations is made, the Personalization Agent fetches the user data, and analyze it to determine patterns and preferences. -- Perform initial searches in Weaviate based on the analysis to retrieve the most relevant recommendations. -- Use appropriate generative models to determine any additional search strategies, and to re-rank fetched data as required. -- Perform additional searches in Weaviate as needed to retrieve the final set of recommendations. -- Combine and rank the recommendations based on the user's profile and preferences. - -Then, the Personalization Agent returns the user-specific recommendations in the response. The response will also include intermediate outputs, such as the underlying search results from Weaviate. - -Let's dive into a little more detail about the Personalization Agent. - -### User profiles - -The Personalization Agent uses user profiles to provide personalized recommendations. This information is stored in a collection in your Weaviate instance under a specific name. The user profile may include the user's preferences and previous interactions, such as their likes and dislikes. - -![Weaviate Personalization Agent - User Data Collection](../_includes/personalization_agent_users_light.png#gh-light-mode-only "Weaviate Personalization Agent - User Data Collection") -![Weaviate Personalization Agent - User Data Collection](../_includes/personalization_agent_users_dark.png#gh-dark-mode-only "Weaviate Personalization Agent - User Data Collection") - -As shown here, the user data collection can be updated over time. It can be updated with information about new users, or with new information about existing users. - -This will help the Personalization Agent continue to learn and provide the most relevant, up-to-date recommendations to each user. - -### Recommendations - -There are two major components to the Personalization Agent's recommendations, the searches it performs to retrieve the recommendations, and the ranking of the recommendations. - -#### Searches - -The Personalization Agent performs searches in Weaviate to retrieve the most relevant recommendations for the user from the specified collections. - -![Weaviate Personalization Agent - Searches](../_includes/personalization_agent_search_light.png#gh-light-mode-only "Weaviate Personalization Agent - Searches") -![Weaviate Personalization Agent - Searches](../_includes/personalization_agent_search_dark.png#gh-dark-mode-only "Weaviate Personalization Agent - Searches") - -The diagram depicts that the search process may be based on a number of factors: - -- The user's profile and preferences, fetched from the user data collection. -- The user's previous interactions, fetched from the user data collection. -- The recommendation context, such as the type of recommendations requested or any other relevant information. -- Additional search strategies, as determined by the Personalization Agent. - -The Personalization Agent may perform multiple searches in Weaviate to retrieve the most relevant recommendations, before combining and ranking them. - -#### (Re-)Ranking - -The Personalization Agent uses multiple factors to rank the recommendations it retrieves from Weaviate, so that the final result set is tailored to the user's preferences. - -![Weaviate Personalization Agent - (re)rank](../_includes/personalization_agent_rank_light.png#gh-light-mode-only "Weaviate Personalization Agent - (re)rank") -![Weaviate Personalization Agent - (re)rank](../_includes/personalization_agent_rank_dark.png#gh-dark-mode-only "Weaviate Personalization Agent - (re)rank") - -The rankings may be based on a number of factors: - -- The user's profile and preferences, fetched from the user data collection. -- The user's previous interactions, fetched from the user data collection. -- The recommendation context, such as the type of recommendations requested or any other relevant information. -- Additional ranking strategies, as determined by the Personalization Agent. - -This process ranks the combined result set as a whole, before serving them back in the response. - -## Basic Usage - -Here is an overview of how to use the this Weaviate Agent. For more detailed information, refer to the [Usage](./usage.md) page. - -### Prerequisites - -This Agent is available exclusively for use with a Weaviate Cloud instance, and a supported version of the Weaviate client library. - -### Example Usage - -To use the Personalization Agent, instantiate it with the following inputs: - -- An instance of the Weaviate client (e.g. the `WeaviateClient` object in Python), connected to a Weaviate Cloud instance. -- Name of the target collection to get personalized items from. -- A list of user properties to base the personalization on. - -Note that the Personalization Agent persists. This means that if you have previously created a Personalization Agent, you can connect to it again without having to create a new one. - - - - - - - -Then, add a persona, which will be used to personalize the recommendations. - - - - - - - -Then you can add a set of interactions to that persona. - - - - - - - -Once user data is added, the Personalization Agent can be used to get personalized recommendations from the Weaviate collection. - - - - - - - - -### Further Documentation - -For more detailed information on how to use this Agent, refer to the [Usage](./usage.md) page. - -## Questions and feedback - -import DocsFeedback from '/_includes/docs-feedback.mdx'; - - - diff --git a/docs/agents/personalization/tutorial-recipe-recommender.mdx b/docs/agents/personalization/tutorial-recipe-recommender.mdx deleted file mode 100644 index a2e60d051..000000000 --- a/docs/agents/personalization/tutorial-recipe-recommender.mdx +++ /dev/null @@ -1,373 +0,0 @@ ---- -title: Build a recipe recommender with the Personalization Agent -sidebar_label: "Tutorial: Recipe recommender" -description: "Tutorial for creating a recipe recommendation system using the Personalization Agent." -sidebar_position: 40 -image: og/docs/tutorials.jpg -# tags: ['personalization', 'recommendation'] ---- - -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; -import FilteredTextBlock from "@site/src/components/Documentation/FilteredTextBlock"; -import PyCode from "!!raw-loader!/docs/agents/_includes/personalization_agent_tutorial_food_recommender.py"; - - - -:::caution Technical Preview - -![This Weaviate Agent is in technical preview.](../_includes/agents_tech_preview_light.png#gh-light-mode-only "This Weaviate Agent is in technical preview.") -![This Weaviate Agent is in technical preview.](../_includes/agents_tech_preview_dark.png#gh-dark-mode-only "This Weaviate Agent is in technical preview.") - -[Sign up here](https://events.weaviate.io/weaviate-agents) for notifications on Weaviate Agents, or visit [this page](https://weaviateagents.featurebase.app/) to see the latest updates and provide feedback. - -::: - -:::info Data Storage Note -The Weaviate Personalization Agent stores user persona profiles and interaction data within your Weaviate instance alongside your main data collection. Be mindful of data privacy regulations when implementing this agent. -::: - -In this tutorial, we will be building a simple food recommender service using the **[Weaviate Personalization Agent](./index.md)**. This agent will learn about user preferences based on their defined profile (persona) and past interactions (e.g., recipe reviews) to provide personalized recommendations from a collection of recipes. - -We've prepared a public dataset that you can use to explore the Personalization Agent: -It is available on HuggingFace: - -- [**Recipes:**](https://huggingface.co/datasets/weaviate/agents/viewer/personalization-agent-recipes) A dataset that lists recipe names, short descriptions, and cuisine types. - -## Introduction: What are Personalization Agents? - -The Weaviate Personalization Agent is a pre-built agentic service designed to retrieve objects from a Weaviate collection in a way that is tailored to individual users. It achieves this by considering a user's defined persona (profile) and their history of interactions with items in the collection. - -import WeaviateAgentsPersonalizationFoodFlowchart from "/docs/agents/_includes/personalization_agent_tutorial_food_recommender_flowchart.png"; - -
-
-
- Weaviate Personalization Agent flowchart -
-
-
-
- -The Personalization Agent: - -1. **Receives a request** for recommendations for a specific user (persona). -2. **Retrieves the user's persona profile** (e.g., likes, dislikes, favorite cuisines) and **interaction history** (e.g., liked/disliked recipes with associated weights). -3. **Queries the reference collection** (e.g., "Recipes") to find candidate items. -4. **(Optionally) Uses an appropriate generative model** (e.g., large language model) to re-rank the candidate items based on the persona, interactions, and potentially a specific instruction, providing a rationale for the ranking. -5. **Returns a personalized, ranked list** of objects to the user. - -
- -## Prerequisites - -To use the Weaviate Agents and Weaviate Embedding service, you need to have a **[Weaviate Cloud](/go/console?utm_content=agents)** account. - -## Step 1: Set up Weaviate - -Now, let's get started by setting up a Weaviate Cloud instance that we will use for this tutorial and connecting it to the Python client. - -### 1.1 Create a Weaviate Cloud cluster - -1. Create a [free Sandbox cluster](/cloud/manage-clusters/create#sandbox-clusters) in Weaviate Cloud. -1. Take note of the `REST Endpoint` and `Admin` API key to connect to your cluster. (for more info, check out the [quickstart](/cloud/manage-clusters/connect.mdx) - -:::tip -In this tutorial, we are using the [Weaviate Embeddings](../../weaviate/model-providers/weaviate/index.md) service as the vectorizer, so you do not have to provide any extra keys for external embedding providers. Weaviate Embeddings uses the `Snowflake/snowflake-arctic-embed-l-v2.0` as the default embedding model.

-If you want to use another vectorizer, check out the list of supported [model providers](../../weaviate/model-providers/index.md). -::: - -### 1.2 Install the Python libraries - -In order to install the Weaviate Python client together with the `agents` component, run: - - - - -``` -pip install "weaviate-client[agents]" -``` - - - - -You will also need `datasets`, a lightweight library providing access to the publicly hosted datasets on HuggingFace. - - - - -``` -pip install datasets -``` - - - - -import ForcePipInstall from "../_includes/_force_pip_install.mdx"; - - - -### 1.3 Connect to your instance - -Now, you can finally connect to your Weaviate Cloud instance with the parameters from the first step: - - - - - - - -After running this snippet, you should see the message `True` printed out, which means that you have successfully connected to your instance. - -## Step 2: Prepare the collection - -In the following code blocks, we will pull our demo recipe dataset from Hugging Face and write it to a new collection in our Weaviate Sandbox cluster. Before importing the data, we need to **define the collection**, setting up its schema and choosing the vectorizer. - -### 2.1 Define the collection - -Below you can see what the objects in the `Recipes` dataset look like. - -import WeaviateAgentsPersonalizationFoodDataset from "/docs/agents/_includes/personalization_agent_tutorial_food_recommender_dataset.png"; - -
-
-
- The Recipes dataset structure -
-
-
-
- -For the collection `Recipes`, we will manually define the properties and include descriptions. While using [`auto-schema`](../../weaviate/config-refs/collections.mdx#auto-schema) is an option, providing explicit descriptions helps the Personalization Agent (especially the underlying LLM, when used for re-ranking) understand the context of your data better. - - - - - - - -### 2.2 Populate the database - -Now, we can import the recipe data ([Recipes](https://huggingface.co/datasets/weaviate/agents/viewer/personalization-agent-recipes)) into our Weaviate Cloud instance: - - - - - - - -By calling `len()` on our collections, we can check that the import has successfully concluded and see what the size of our collections is: - - - - - - - -``` -Size of the Recipes dataset: 5117 -``` - -## Step 3: Set up the Personalization Agent - -Now, let's create the `PersonalizationAgent` instance linked to our "Recipes" collection. - -When creating a new `PersonalizationAgent` for the first time, we define `user_properties`. These are the fields that will make up each user's persona profile. For our food recommender, properties like favorite cuisines, general food likes, and dislikes are relevant. - -If an agent for this collection already exists (e.g., from a previous run), we can simply connect to it using `PersonalizationAgent.connect()`. The code below handles both cases. - - - - - - - -You should see a message indicating whether a new agent was created or an existing one was connected. - -## Step 4: Use the Personalization Agent - -With the agent set up, we can now add user data and retrieve recommendations. - -### 4.1 Add a new persona - -A "persona" represents a user profile. We use the `agent.add_persona()` method, providing a unique `persona_id` (a UUID is recommended) and the `properties` we defined during agent creation. - -Feel free to modify the example below to represent your own food preferences\! - - - - - - - -### 4.2 Add interactions - -"Interactions" represent how a user has engaged with items in the collection. For our recommender, these could be explicit reviews, ratings, or implicit signals like viewing a recipe page. - -Each `PersonaInteraction` links a `persona_id` to an `item_id` (the UUID of an object in the "Recipes" collection) and includes a `weight` from -1.0 (strong dislike) to 1.0 (strong like). - -import WeaviateAgentsPersonalizationFoodUser from "/docs/agents/_includes/personalization_agent_tutorial_food_recommender_user.png"; - -
-
-
- Weaviate Personalization Agent User -
-
-
-
- -First, we fetch the UUIDs of some specific recipes the user has interacted with. Then, we define the interactions with appropriate weights. Finally, we add them to the agent using `agent.add_interactions()`. - - - - - - - -This block prepares the interaction data and sends it to the agent. - -### 4.3 Get recommendations - -Now for the core functionality: retrieving personalized recommendations using `agent.get_objects()`. We provide the `persona_id` for whom we want recommendations. - -We can set `use_agent_ranking=True` to enable the LLM-based re-ranking. This leverages the persona profile and interaction history to provide a more nuanced ranking and also generates a `ranking_rationale` explaining _why_ certain items were recommended. - - - - - - - -The output will first show the `ranking_rationale` generated by the agent's LLM, followed by the list of recommended recipes, including their title, description, and cuisine labels. - -
- Example response (will vary based on persona/interactions and LLM): - -``` -Getting recommendations for persona e7239e3f-97f5-41b3-939a-5fbf3e0c7f16... - -Ranking Rationale: -Because you love Italian dishes and have shown an interest in different cuisines, we've prioritized dishes with Italian, Japanese, and Indian labels, reflecting your preferences for Italian and Thai cuisines and prior positive interactions. We avoided items with mushroom content. - -Recommended Recipes: ------ Recommendation 1 ----- -Title: Chicken Tikka Masala -Cuisine: Indian -UUID: 5785f023-5ab2-49d8-bb43-0ab047083e16 ------ Recommendation 2 ----- -Title: Spicy Indian Tikka Masala -Cuisine: Indian -UUID: 753a036f-ec83-4efa-8a1a-5afa021acbc2 ------ Recommendation 3 ----- -Title: Paneer Tikka -Cuisine: Indian -UUID: 323b6f11-c026-4367-801b-b21f40e6591b ------ Recommendation 4 ----- -Title: Paneer Butter Masala -Cuisine: Indian -UUID: 3bd11bc9-d329-4039-9f4a-205f1719048d ------ Recommendation 5 ----- -Title: Butter Chicken -Cuisine: Indian -UUID: 4e056c59-e843-419a-8129-b6633fb8c2d3 ------ Recommendation 6 ----- -Title: Shabu-Shabu -Cuisine: Japanese -UUID: df0ae465-f724-42ed-9876-2c9b91516c13 ------ Recommendation 7 ----- -Title: Oden -Cuisine: Japanese -UUID: eb6088c1-05a6-46ed-9adc-477313c051d2 ------ Recommendation 8 ----- -Title: Tempura -Cuisine: Japanese -UUID: 625a5164-e150-4966-a3c6-0aed406db416 ------ Recommendation 9 ----- -Title: Ramen -Cuisine: Japanese -UUID: 708824b3-fc4a-4927-82bb-a8a4dbd5ee89 ------ Recommendation 10 ----- -Title: Udon Noodles -Cuisine: Japanese -UUID: 8d6a94b7-c9ae-4d1c-b29a-885717b9a55a -``` - -
- -## Summary - -This guide demonstrated how to build a personalized food recommendation service using Weaviate's Personalization Agent. We covered: - -- Setting up a Weaviate Cloud instance with the Python client. -- Defining a "Recipes" collection with descriptive properties. -- Importing data into the collection. -- Creating a Personalization Agent linked to the collection and defining user profile properties (`user_properties`). -- Adding user profiles (`personas`) with specific preferences. -- Recording user interactions with items, using weighted scores. -- Retrieving personalized recommendations using `get_objects`, leveraging LLM-based re-ranking (`use_agent_ranking=True`) to get tailored results and explanations (`ranking_rationale`). - -The Personalization Agent allows you to easily add sophisticated, personalized retrieval capabilities to your applications built on Weaviate. - -## Further resources - -- [Weaviate Agents - Personalization Agent](./index.md) - -## Questions and feedback - -:::info Changelog and feedback -The official changelog for Weaviate Agents can be [found here](https://weaviateagents.featurebase.app/changelog). If you have feedback, such as feature requests, bug reports or questions, please [submit them here](https://weaviateagents.featurebase.app/), where you will be able to see the status of your feedback and vote on others' feedback. -::: - -import DocsFeedback from "/_includes/docs-feedback.mdx"; - - diff --git a/docs/agents/personalization/usage.md b/docs/agents/personalization/usage.md deleted file mode 100644 index d6032fc26..000000000 --- a/docs/agents/personalization/usage.md +++ /dev/null @@ -1,400 +0,0 @@ ---- -title: Usage -sidebar_position: 30 -description: "Technical documentation and usage examples for implementing the Personalization Agent." -image: og/docs/agents.jpg -# tags: ['agents', 'getting started', 'personalization agent'] ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; -import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; -import PyCode from '!!raw-loader!/docs/agents/\_includes/personalization_agent.py'; - -# Weaviate Personalization Agent: Usage - - - -:::caution Technical Preview - -![This Weaviate Agent is in technical preview.](../_includes/agents_tech_preview_light.png#gh-light-mode-only "This Weaviate Agent is in technical preview.") -![This Weaviate Agent is in technical preview.](../_includes/agents_tech_preview_dark.png#gh-dark-mode-only "This Weaviate Agent is in technical preview.") - -[Sign up here](https://events.weaviate.io/weaviate-agents) for notifications on Weaviate Agents, or visit [this page](https://weaviateagents.featurebase.app/) to see the latest updates and provide feedback. - -::: - -The Weaviate Personalization Agent is an agentic service designed to return personalized recommendations tailored to each user. The Personalization Agent uses data from the associated Weaviate Cloud instance to provide these recommendations. - -:::tip Nomenclature: User vs Developer -The Personalization Agent is all about providing personalized recommendations tailored to a particular person. In this context, that person will be referred to as the `user`. The developer is the person who is using the Personalization Agent to provide these recommendations. -::: - -The developer would simply provide a user profile, and the Personalization Agent takes care of all intervening steps to provide a set of personalized recommendations from Weaviate. The resulting workflow for the developer looks as follows: - -![Weaviate Personalization Agent from a developer perspective](../_includes/personalization_agent_overview_light.png#gh-light-mode-only "Weaviate Personalization Agent from a developer perspective") -![Weaviate Personalization Agent from a developer perspective](../_includes/personalization_agent_overview_dark.png#gh-dark-mode-only "Weaviate Personalization Agent from a developer perspective") - -This page describes how to use the Weaviate Personalization Agent to obtain personalized recommendations from your data stored in Weaviate. - -:::info Changelog and feedback -The official changelog for Weaviate Agents can be [found here](https://weaviateagents.featurebase.app/changelog). If you have feedback, such as feature requests, bug reports or questions, please [submit them here](https://weaviateagents.featurebase.app/), where you will be able to see the status of your feedback and vote on others' feedback. -::: - -## Prerequisites - -### Weaviate instance - -This Agent is available exclusively for use with a Weaviate Cloud instance. - -Refer to the [Weaviate Cloud documentation](/cloud/index.mdx) for more information on how to set up a Weaviate Cloud instance. - -You can try this Weaviate Agent with a free Sandbox instance on [Weaviate Cloud](/go/console?utm_content=agents). - -### Client library - -:::note Supported languages -At this time, this Agent is available only for Python. Support for other languages will be added in the future. -::: - -You can install the Weaviate client library with the optional `agents` extras to use Weaviate Agents. This will install the `weaviate-agents` package along with the `weaviate-client` package. - -Install the client library using the following command: - - - - -```shell -pip install -U weaviate-client[agents] -``` - -#### Troubleshooting: Force `pip` to install the latest version - -For existing installations, even `pip install -U "weaviate-client[agents]"` may not upgrade `weaviate-agents` to the [latest version](https://pypi.org/project/weaviate-agents/). If this occurs, additionally try to explicitly upgrade the `weaviate-agents` package: - -```shell -pip install -U weaviate-agents -``` - -Or install a [specific version](https://github.com/weaviate/weaviate-agents-python-client/tags): - -```shell -pip install -U weaviate-agents==||site.weaviate_agents_version|| -``` - - - - - -## Usage - -To use the Personalization Agent, follow the below high-level steps: - -- Create or connect to a personalization agent -- Create or select a user persona -- Add interactions for the given persona -- Obtain personalized recommendations - -Optionally, the personalization agent can: - -- Perform reranking of the results -- With a further option of custom instructions for the reranking - -Example usage is shown below. - -### Prerequisites - -The Personalization Agent is tightly integrated with Weaviate Cloud. As a result, the Personalization Agent is available exclusively for use with a Weaviate Cloud instance, and a supported version of the client library. - -### Connect to Weaviate - -You must connect to the Weaviate Cloud instance to use the Personalization Agent. Connect to the Weaviate Cloud instance using the Weaviate client library. - - - - - - - -### Create or connect to a personalization agent - -Personalization Agents are stateful, with user persona data persisting in Weaviate. As a result, you can create a new Personalization Agent or connect to an existing one. - - - - - - - -### Create a user persona - -The Personalization Agent is designed to provide personalized recommendations for a specific user. - -You can do this through a `Persona`, which is a collection of user properties and interactions. - -Each persona will include a user ID, a set of user properties, and a set of interactions. - -To create a persona, specify a user ID and the set of user properties to be used for personalization. - - - - - - - - -### Manage a user persona - -You can delete or update an existing user persona, as well as to check if a user persona exists. - -#### Delete a user persona - -To delete a user persona, specify the user ID of the persona to be deleted. - - - - - - -#### Update a user persona - -To update a user persona, specify the user ID of the persona to be updated and the new set of user properties. - - - - - - - -#### Check if a user persona exists - -To check if a user persona exists, specify the user ID of the persona to be checked. - - - - - - - -#### Get a user persona - -To get a user persona, specify the user ID of the persona to be retrieved. - - - - - - - -### Add interactions - -Interactions form the basis of the personalization process. They are the data points that the Personalization Agent uses to learn about the user and provide personalized recommendations. - -To add interactions, select the user persona and provide the interaction details. - -The available parameters are: - -- `persona_id`: ID of the user persona -- `item_id`: ID of the item being interacted with -- `weight`: weight of the interaction (e.g. 1 for strongest like, -1 for strongest dislike) -- `replace_previous_interaction`: whether to replace the previous interaction with the same item ID -- `created_at`: timestamp of the interaction (affects how much weight the interaction has) - - - - - - - - -### Get personalized objects - -Once a user persona has been created, you can get personalized objects. - -As a minimum, simply provide the user ID to the Personalization Agent. The Personalization Agent will process the user ID, perform the necessary searches in Weaviate, and return the personalized recommendations. - - - - - - - -#### Get objects: Available ranking strategies - -When using `get_objects`, you can select a ranking strategy. - -The Personalization Agent can use a combination of vector search and LLM-based ranking to provide personalized recommendations. The vector search is based on our analysis of the set of interactions for the user persona. The LLM can optionally be used to rerank the results. - -You can use it in one of three modes: - -- **Agent-based reranking**: The Personalization Agent will first perform a vector search to retrieve a set of items, and then rerank them using an LLM, based on the user persona. This is the default mode. -- **Agent-based reranking with custom instructions**: If a custom instruction is provided, the Personalization Agent will use this instruction to rerank the results. This allows you to customize the ranking process based on your specific needs. -- **Vector search only**: If you retrieve results without using the agent ranking, the results will be based solely on the vector search. - -#### Get objects: Parameters - -The available parameters for getting personalized objects are: - -- `limit`: maximum number of items to return -- `recent_interactions_count`: number of recent interactions to consider for personalization -- `exclude_interacted_items`: whether to exclude items that the user has already interacted with -- `decay_rate`: decay rate for older interactions (1.0 = heavily discount older interactions; 0.0 = no discount) -- `exclude_items`: list of item IDs to exclude from the recommendations -- `use_agent_ranking`: whether to use the agent to rerank the results -- `instruction`: custom instructions for the reranking -- `explain_results`: whether to include explanations for the results - - - - - - - -#### Get objects: Inspect results - -The response from the Personalization Agent will include the personalized recommendations. - -In addition to the response objects, the response may include the following information (depending on the options selected): - -- Rationale for the recommendations -- For each object: - - Original rank of the item - - Personalized rank of the item - - - - - - - -### Personalized Weaviate queries - -The Personalization Agent can also be used to perform personalized Weaviate queries. - -In contrast to the [`get_objects` method](#get-personalized-objects), a personalized query includes an additional Weaviate query. - -Weaviate's `near_text`, `bm25` and `hybrid` queries can be combined with the Personalization Agent to provide personalized results. - - - - - - - -Use a personalized Weaviate query when you want to use the Personalization Agent to rerank the results of a Weaviate query. - -The Personalization Agent will first perform the Weaviate query to retrieve a set of items, and then rerank them using an LLM, based on the user persona. - -#### Personalized Weaviate query: Parameters - -The available parameters for personalizing a Weaviate query can be specified upstream of the query method (`near_text`, `bm25`, `hybrid`). - -- `persona_id`: ID of the user persona -- `strength`: strength of the personalization (0.0 = no personalization, 1.0 = complete personalization, disregard query results) -- `overfetch_factor`: number of objects to fetch before personalization -- `recent_interactions_count`: number of recent interactions to consider for personalization -- `decay_rate`: decay rate for older interactions (1.0 = heavily discount older interactions; 0.0 = no discount) - - - - - - - -## Limitations & Troubleshooting - -:::caution Technical Preview - -![This Weaviate Agent is in technical preview.](../_includes/agents_tech_preview_light.png#gh-light-mode-only "This Weaviate Agent is in technical preview.") -![This Weaviate Agent is in technical preview.](../_includes/agents_tech_preview_dark.png#gh-dark-mode-only "This Weaviate Agent is in technical preview.") - -[Sign up here](https://events.weaviate.io/weaviate-agents) for notifications on Weaviate Agents, or visit [this page](https://weaviateagents.featurebase.app/) to see the latest updates and provide feedback. - -::: - -### Usage limits - -At this stage, there is a limit of 100 Personalization Agent queries per day per Weaviate Cloud [organization](/cloud/platform/users-and-organizations.mdx#organizations) where the agent-based reranking is used. - -There are no limits on the number of queries per day for the vector search only (i.e. without the agent-based reranking). - -This limit may change in future versions of the Personalization Agent. - -### Known issues - -The combined Weaviate query and personalization agent query is not available for named vectors at this time. This is a known issue and will be addressed shortly. - -## Questions and feedback - -:::info Changelog and feedback -The official changelog for Weaviate Agents can be [found here](https://weaviateagents.featurebase.app/changelog). If you have feedback, such as feature requests, bug reports or questions, please [submit them here](https://weaviateagents.featurebase.app/), where you will be able to see the status of your feedback and vote on others' feedback. -::: - -import DocsFeedback from '/\_includes/docs-feedback.mdx'; - - diff --git a/docs/agents/query/index.md b/docs/agents/query/index.md deleted file mode 100644 index f85e5dd23..000000000 --- a/docs/agents/query/index.md +++ /dev/null @@ -1,172 +0,0 @@ ---- -title: Query Agent -description: "Overview of the AI agent that handles complex queries across multiple Weaviate collections with natural language understanding." -image: og/docs/agents.jpg -# tags: ['agents', 'getting started', 'query agent'] ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; -import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; -import PyCode from '!!raw-loader!/docs/agents/\_includes/query_agent.py'; -import TSCode from '!!raw-loader!/docs/agents/\_includes/query_agent.mts'; - -# Weaviate Query Agent: Overview - - - -The Weaviate Query Agent is a pre-built agentic service designed to answer natural language queries based on the data stored in Weaviate Cloud. - -The user simply provides a prompt/question in natural language, and the Query Agent takes care of all intervening steps to provide an answer. - -![Weaviate Query Agent from a user perspective](../_includes/query_agent_usage_light.png#gh-light-mode-only "Weaviate Query Agent from a user perspective") -![Weaviate Query Agent from a user perspective](../_includes/query_agent_usage_dark.png#gh-dark-mode-only "Weaviate Query Agent from a user perspective") - -## Architecture - -The Query Agent is provided as a service on Weaviate Cloud. - -When a user provides a prompt/query, the query agent analyses it and any other known context to autonomously carry out the searches itself. - -:::tip Query Agent context -The Query agent analyses collection and property descriptions to better understand how to construct relevant queries.
- -The context may also include previous conversation history, and any other relevant information. -::: - -## Query Agent: visualized workflow - -![Weaviate Query Agent at a high level](../_includes/query_agent_architecture_light.png#gh-light-mode-only "Weaviate Query Agent at a high level") -![Weaviate Query Agent at a high level](../_includes/query_agent_architecture_dark.png#gh-dark-mode-only "Weaviate Query Agent at a high level") - -The Query Agent follows these high-level steps: - -- Use appropriate generative models (e.g. large language models) to analyze the task & the required queries. Determine the exact queries to perform. (Steps 1 & 2) -- Send queries to Weaviate. Weaviate vectorizes the queries as needed using the specified vectorizer integration. (Steps 3-5) -- Receive the results from Weaviate, and use appropriate generative models to generate the final respond to the user prompt/query. (Step 6) - -Then, the Query Agent returns the answer to the user, as well as intermediate outputs, such as the underlying search results from Weaviate. - -Note that the term `Query Agent` refers to the entire system. The Query Agent may comprise multiple subsystems, such as microservices and/or agents under the hood, each responsible for a specific task. - -![Weaviate Query Agent comprises multiple agents](../_includes/query_agent_info_light.png#gh-light-mode-only "Weaviate Query Agent comprises multiple agents") -![Weaviate Query Agent comprises multiple agents](../_includes/query_agent_info_dark.png#gh-dark-mode-only "Weaviate Query Agent comprises multiple agents") - -## Querying - -The Query Agent supports two query types: - -- **`Search`** Weaviate with the Query Agent using natural langauge. The Query Agent will process the question, perform the necessary searches in Weaviate, and return the relevant objects. - -- **`Ask`** the Query Agent a question using natural language. The Query Agent will process the question, perform the necessary searches in Weaviate, and return the answer. - -## Basic usage - -Here is an overview of how to use the this Weaviate Agent. For more detailed information, refer to the [Usage](./usage.md) page. - -:::note Prerequisites - -This Agent is available exclusively for use with a [Weaviate Cloud](/cloud/index.mdx) instance, and a supported version of the Weaviate [client library](./usage.md#client-library). - -::: - -### Example usage - -Pass an instance of the Weaviate client to the Query Agent, and the Query Agent will extract the necessary information from the client to perform the query. - - - - - - - - - - - -Then, provide a natural language query input. The Query Agent will process the query, perform the necessary searches in Weaviate, and return the answer. - -### `Search` (retrieval only) - - - - - - - - - - - -The Query Agent can even handle follow-up queries, using the previous response as additional context. - - - - - - - - - - - -### `Ask` (with answer generation) - - - - - - - - - - -## Further resources - -For more detailed information on how to use this Agent, refer to the [Usage](./usage.md) page. - -## Questions and feedback - -import DocsFeedback from '/\_includes/docs-feedback.mdx'; - - diff --git a/docs/agents/query/tutorial-ecommerce.mdx b/docs/agents/query/tutorial-ecommerce.mdx deleted file mode 100644 index bc48ffbad..000000000 --- a/docs/agents/query/tutorial-ecommerce.mdx +++ /dev/null @@ -1,650 +0,0 @@ ---- -title: Build an E-Commerce assistant with Query Agents -sidebar_label: "Tutorial: E-Commerce assistant" -description: "Tutorial for creating an e-commerce assistant that answers product and brand queries using the Query Agent." -sidebar_position: 40 -image: og/docs/tutorials.jpg -# tags: ['basics'] ---- - -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; -import FilteredTextBlock from "@site/src/components/Documentation/FilteredTextBlock"; -import PyCode from "!!raw-loader!/docs/agents/_includes/query_agent_tutorial_ecommerce.py"; - - - -In this tutorial, we will be building a simple e-commerce assistant agent with the **[Weaviate Query Agent](./index.md)**. This agent will have access to multiple Weaviate collections, and will be capable of answering complex queries about brands and clothing items, accessing information from each collection. - -We've prepared a few public datasets that you can use to explore the Query Agent. -They are available on HuggingFace: - -- [**E-Commerce:**](https://huggingface.co/datasets/weaviate/agents/viewer/query-agent-ecommerce) A dataset that lists clothing items, prices, brands, reviews, etc. -- [**Brands:**](https://huggingface.co/datasets/weaviate/agents/viewer/query-agent-brands) A dataset that lists clothing brands and information about them, such as their parent brand, child brands, average customer rating, etc. - -## Introduction: What are Query Agents? - -The Weaviate Query Agent is a pre-built agentic service designed to answer natural language queries based on the data stored in Weaviate Cloud. The user simply provides a prompt/question in natural language, and the Query Agent takes care of all intervening steps to provide an answer. - -import WeaviateAgentsECommerceFlowchart from "/docs/agents/_includes/query_agent_tutorial_ecommerce_flowchart.png"; - -
-
-
- Weaviate Query Agent flowchart -
-
-
-
- -The Query Agent: - -1. **Receives a task** in the form of a question or instructions. -2. **Uses an appropriate generative model** (e.g. large language model) to analyze the task and determine the exact queries to perform. -3. **Sends the queries to Weaviate**, which vectorizes the queries as needed using the specified vectorizer integration (we will use Weaviate Embeddings). -4. **Receives the results from Weaviate** and uses appropriate generative models to generate the final response to the user prompt/query. - -
- -## Prerequisites - -To use the Weaviate Agents and Weaviate Embedding service, you need to have a **[Weaviate Cloud](/go/console?utm_content=agents)** account. - -## Step 1: Set up Weaviate - -Now, let's get started by setting up a Weaviate Cloud instance that we will use for this tutorial and connecting it to the Python client. - -### 1.1 Create a Weaviate Cloud cluster - -1. Create a [free Sandbox cluster](/cloud/manage-clusters/create#sandbox-clusters) in Weaviate Cloud. -1. Take note of the `REST Endpoint` and `Admin` API key to connect to your cluster. (for more info, check out the [quickstart](/cloud/manage-clusters/connect.mdx)) - -:::tip -In this tutorial, we are using the [Weaviate Embeddings](/weaviate/model-providers/weaviate/embeddings.md) service as the vectorizer, so you do not have to provide any extra keys for external embedding providers. Weaviate Embeddings uses the `Snowflake/snowflake-arctic-embed-l-v2.0` as the default embedding model.

-If you want to use another vectorizer, check out the list of supported [model providers](../../weaviate/model-providers/index.md). -::: - -### 1.2 Install the Python libraries - -In order to install the Weaviate Python client together with the `agents` component, run: - - - - -``` -pip install "weaviate-client[agents]" -``` - - - - -You will also need `datasets`, a lightweight library providing access to the publicly hosted datasets on HuggingFace. - - - - -``` -pip install datasets -``` - - - - -import ForcePipInstall from "../_includes/_force_pip_install.mdx"; - - - -### 1.3 Connect to your instance - -Now, you can finally connect to your Weaviate Cloud instance with the parameters from the first step: - - - - - - - -After running this snippet, you should see the message `True` printed out, which means that you have successfully connected to your instance. - -## Step 2: Prepare the Collections - -In the following code blocks, we are pulling our demo datasets from Hugging Face and writing them to new collections in our Weaviate Sandbox cluster. Before we can start importing the data into Weaviate, we need to **define the collections**, which means setting up the data schema and choosing the vectorizer/embedding service. - -### 2.1 Define the Collections - -Below you can see what the objects in the datasets `E-Commerce` and `Brands` look like. - -import WeaviateAgentsEcommerceDataset from "/docs/agents/_includes/query_agent_tutorial_ecommerce_dataset.png"; - -
-
-
- The E-Commerce and Brands datasets -
-
-
-
- -For the collection `Brands`, we are going to use the [`auto-schema`](../../weaviate/config-refs/collections.mdx#auto-schema) option which creates properties automatically based on the imported data. -However, this is not the best way of importing the data. - -The Query Agent uses the **descriptions of collections and properties** to decide which ones to use when solving queries. You can experiment by changing these descriptions and providing more details. -This is why it's recommended to manually define the data schema and add the property descriptions. - -For example, below we make sure that the Query Agent knows that prices are all in USD, which is information that would otherwise be unavailable. - - - - - - - -### 2.2 Populate the database - -Now, we can import the pre-vectorized data ([E-Commerce](https://huggingface.co/datasets/weaviate/agents/viewer/query-agent-ecommerce) and [Brands](https://huggingface.co/datasets/weaviate/agents/viewer/query-agent-brands)) into our Weaviate Cloud instance: - - - - - - - -By calling `len()` on our collections, we can check that the import has successfully concluded and see what the size of our collections is. - -``` -Size of the E-Commerce dataset: 448 -Size of the Brands dataset: 104 -``` - -## Step 3: Set up the Query Agent - -### 3.1 Basic Query Agent - -When setting up the query agent, we have to provide a few things: - -- The `client` -- The `collections` which we want the agent to have access to. -- (Optionally) A `system_prompt` that describes how our agent should behave -- (Optionally) Timeout - which for now defaults to 60s. - -Let's start with a simple agent. Here, we're creating a `qa` agent that has access to our `Brands` and `ECommerce` datasets. - - - - - - - -And that's about it! Now, you can start using the Query Agent. - -### 3.2 Customized Query Agent (with system prompt) {#system-prompt-agent} - -In some cases, you may want to define a custom `system_prompt` for your agent. This can help you provide the agent with some default instructions for how to behave. For example, let's create an agent that will always answer the query in the user's language. - - - - - - - -We will use this custom agent `multi_lingual_qa` in [step 4.5](#use-system-prompt-agent). - -## Step 4: Run the Query Agent - -When we run the agent, it will first make a few decisions depending on the query: - -1. The agent will decide which collection (or multiple collections) to look up an answer in. -2. The agent will also decide whether to perform a regular **_search query_**, what **_filters_** to use, whether to do an **_aggregation query_**, or all of them together. -3. It will then provide a response within **`QueryAgentResponse`**. - -### 4.1 Ask a question - -Let's start with a simple question: - -- "I like vintage clothes, can you list me some options that are less than $200?" - - - - - - - -The response from the agent is: - -``` -original_query='I like vintage clothes, can you list me some options that are less than $200?' collection_names=['ECommerce'] searches=[[QueryResultWithCollection(queries=['vintage clothes'], filters=[[IntegerPropertyFilter(property_name='price', operator=, value=200.0)]], filter_operators='AND', collection='ECommerce')]] aggregations=[] usage=Usage(requests=3, request_tokens=7681, response_tokens=428, total_tokens=8109, details=None) total_time=11.588264226913452 aggregation_answer=None has_aggregation_answer=False has_search_answer=True is_partial_answer=False missing_information=[] final_answer='Here are some vintage-inspired clothing options under $200:\n\n1. **Vintage Philosopher Midi Dress ($125.00)** - A deep green velvet fabric dress with antique gold button detailing, perfect for an academic or sophisticated setting. [Echo & Stitch]\n\n2. **Vintage Gale Pleated Dress ($120.00)** - A burgundy pleated dress capturing the Dark Academia aesthetic, great for poetry readings or contemplative afternoons. [Solemn Chic]\n\n3. **Retro Groove Flared Pants ($59.00)** - Electric blue flared pants capturing early 2000s millennial pop culture chic. [Vivid Verse]\n\n4. **Vintage Scholar Tote ($90.00)** - A deep green canvas tote with brown leather accents, ideal for carrying scholarly essentials. [Echo & Stitch]\n\n5. **Retro Futura Tee ($29.98)** - A bold graphic tee with early 2000s pop culture references, perfect for a nostalgic throwback. [Vivid Verse]\n\n6. **Electric Velvet Trousers ($60.00)** - Neon green velvet trousers with a flared leg, inspired by turn-of-the-century fashion icons. [Vivid Verse]\n\n7. **Vintage Ivy Loafers ($120.00)** - Burgundy leather loafers offering timeless sophistication, suitable for academic settings. [Solemn Chic]' sources=[Source(object_id='6040c373-9cce-421d-8f4e-e01346cbf29f', collection='ECommerce'), Source(object_id='06a83da4-92ff-4cbc-9cc6-c55fc6ed49b9', collection='ECommerce'), Source(object_id='a5a0927d-2859-47e6-8455-d77e0190aa53', collection='ECommerce'), Source(object_id='a5f3c394-d207-4064-a2bc-b9f655d09ddc', collection='ECommerce'), Source(object_id='5d7bb719-2df5-4a7c-9bbc-275450ab29c6', collection='ECommerce'), Source(object_id='50f4c89c-faf9-4430-b393-c39ede5d511d', collection='ECommerce'), Source(object_id='5b6d5a1f-e218-4400-ac9f-df59466f3c97', collection='ECommerce')] -``` - -But this output is a bit too much, so let's just return the field `final_answer`: - - - - - - - -The output is: - -``` -Here are some vintage-inspired clothing options under $200: - -1. **Vintage Philosopher Midi Dress ($125.00)** - A deep green velvet fabric dress with antique gold button detailing, perfect for an academic or sophisticated setting. [Echo & Stitch] - -2. **Vintage Gale Pleated Dress ($120.00)** - A burgundy pleated dress capturing the Dark Academia aesthetic, great for poetry readings or contemplative afternoons. [Solemn Chic] - -3. **Retro Groove Flared Pants ($59.00)** - Electric blue flared pants capturing early 2000s millennial pop culture chic. [Vivid Verse] - -4. **Vintage Scholar Tote ($90.00)** - A deep green canvas tote with brown leather accents, ideal for carrying scholarly essentials. [Echo & Stitch] - -5. **Retro Futura Tee ($29.98)** - A bold graphic tee with early 2000s pop culture references, perfect for a nostalgic throwback. [Vivid Verse] - -6. **Electric Velvet Trousers ($60.00)** - Neon green velvet trousers with a flared leg, inspired by turn-of-the-century fashion icons. [Vivid Verse] - -7. **Vintage Ivy Loafers ($120.00)** - Burgundy leather loafers offering timeless sophistication, suitable for academic settings. [Solemn Chic] -``` - -By using the `display()` method on a `QueryAgentResponse`, you can get a user-friendly output of the following information: - -- 🔍 Original Query - `original_query` -- 📝 Final Answer - `final_answer` -- 🔭 Searches Executed - `searches` -- 📊 Aggregations Run - `aggregations` -- 📚 Sources - `sources` -- ⚠️ Missing Information - `missing_information` -- 📊 Usage Statistics - `usage` -- Total Time Taken - `total_time` - - - - - - - -
- The response is: - -``` -╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────── 🔍 Original Query ────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ I like vintage clothes, can you list me some options that are less than $200? │ -│ │ -╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────── 📝 Final Answer ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ Here are some vintage-inspired clothing options under $200: │ -│ │ -│ 1. **Vintage Philosopher Midi Dress ($125.00)** - A deep green velvet fabric dress with antique gold button detailing, perfect for an academic or sophisticated setting. [Echo & Stitch] │ -│ │ -│ 2. **Vintage Gale Pleated Dress ($120.00)** - A burgundy pleated dress capturing the Dark Academia aesthetic, great for poetry readings or contemplative afternoons. [Solemn Chic] │ -│ │ -│ 3. **Retro Groove Flared Pants ($59.00)** - Electric blue flared pants capturing early 2000s millennial pop culture chic. [Vivid Verse] │ -│ │ -│ 4. **Vintage Scholar Tote ($90.00)** - A deep green canvas tote with brown leather accents, ideal for carrying scholarly essentials. [Echo & Stitch] │ -│ │ -│ 5. **Retro Futura Tee ($29.98)** - A bold graphic tee with early 2000s pop culture references, perfect for a nostalgic throwback. [Vivid Verse] │ -│ │ -│ 6. **Electric Velvet Trousers ($60.00)** - Neon green velvet trousers with a flared leg, inspired by turn-of-the-century fashion icons. [Vivid Verse] │ -│ │ -│ 7. **Vintage Ivy Loafers ($120.00)** - Burgundy leather loafers offering timeless sophistication, suitable for academic settings. [Solemn Chic] │ -│ │ -╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭──────────────────────────────────────────────────────────────────────────────────────────────────────────── 🔭 Searches Executed 1/1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ QueryResultWithCollection(queries=['vintage clothes'], filters=[[IntegerPropertyFilter(property_name='price', operator=, value=200.0)]], filter_operators='AND', collection='ECommerce') │ -│ │ -╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ 📊 No Aggregations Run │ -│ │ -╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────── 📚 Sources ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ - object_id='6040c373-9cce-421d-8f4e-e01346cbf29f' collection='ECommerce' │ -│ - object_id='06a83da4-92ff-4cbc-9cc6-c55fc6ed49b9' collection='ECommerce' │ -│ - object_id='a5a0927d-2859-47e6-8455-d77e0190aa53' collection='ECommerce' │ -│ - object_id='a5f3c394-d207-4064-a2bc-b9f655d09ddc' collection='ECommerce' │ -│ - object_id='5d7bb719-2df5-4a7c-9bbc-275450ab29c6' collection='ECommerce' │ -│ - object_id='50f4c89c-faf9-4430-b393-c39ede5d511d' collection='ECommerce' │ -│ - object_id='5b6d5a1f-e218-4400-ac9f-df59466f3c97' collection='ECommerce' │ -│ │ -╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ - - - 📊 Usage Statistics -┌────────────────┬──────┐ -│ LLM Requests: │ 3 │ -│ Input Tokens: │ 7681 │ -│ Output Tokens: │ 428 │ -│ Total Tokens: │ 8109 │ -└────────────────┴──────┘ - -Total Time Taken: 11.59s -``` - -
- -### 4.2 Ask a follow-up question - -The agent can also be provided with additional context. For example, we can provide the previous response as context using `ChatMessage` objects to create a conversation and get a `new_response`: - - - - - - - -
- The response is: - -``` -╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────── 🔍 Original Query ────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ What about some nice shoes, same budget as before? │ -│ │ -╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────── 📝 Final Answer ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ Here are some great vintage-style shoes priced under $200 from various collections that blend style with nostalgia: │ -│ │ -│ 1. **Vintage Noir Loafers** ($125): These dress shoes, part of the Dark Academia collection, come in black and grey, offering a timeless look with subtle modern twists. They have received positive reviews for style and comfort, once broken │ -│ in (Source: 1). │ -│ │ -│ 2. **Vintage Ivy Loafers** ($120): Another classic from the Dark Academia line, these deep burgundy loafers combine elegance with comfort, as appreciated by users in their reviews (Source: 2). │ -│ │ -│ 3. **Glide Platforms** ($90): For a more playful option, these high-shine pink platform sneakers offer a nod to the Y2K era, receiving praise for their comfort and unique look (Source: 3). │ -│ │ -│ 4. **Celestial Step Platform Sneakers** ($90): With a dreamy sky blue color, these Y2K-inspired sneakers provide comfort and a touch of whimsy (Source: 4). │ -│ │ -│ 5. **Garden Stroll Loafers** ($90): From the Cottagecore collection, these cream loafers feature delicate floral motifs for a chic, countryside-inspired look (Source: 5). │ -│ │ -│ 6. **Bramble Brogues** ($120): In dusky green, these suede brogues add pastoral elegance to any outfit, admired for their craftsmanship (Source: 7). │ -│ │ -│ 7. **Garden Fête Heels** ($125): These cottagecore heels feature floral embroidery for a touch of elegance perfect for garden parties (Source: 10). │ -│ │ -│ 8. **Garden Gala T-Straps** ($125): Elegant cream and sage T-strap heels featuring floral embellishments, perfect for a whimsical yet classy touch (Source: 18). │ -│ │ -│ All these options fall under the $200 budget, offering a variety of styles from classic and elegant to colorful and playful, accommodating different fashion tastes and preferences. │ -│ │ -╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭──────────────────────────────────────────────────────────────────────────────────────────────────────────── 🔭 Searches Executed 1/1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ QueryResultWithCollection(queries=['vintage shoes'], filters=[[IntegerPropertyFilter(property_name='price', operator=, value=200.0)]], filter_operators='AND', collection='Ecommerce') │ -│ │ -╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭───────────────────────────────────────────────────────────────────────────────────────────────────────────── 📊 Aggregations Run 1/1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ AggregationResultWithCollection( │ -│ search_query=None, │ -│ groupby_property=None, │ -│ aggregations=[IntegerPropertyAggregation(property_name='price', metrics=)], │ -│ filters=[TextPropertyFilter(property_name='subcategory', operator=, value='vintage')], │ -│ collection='Ecommerce' │ -│ ) │ -│ │ -╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────── 📚 Sources ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ - object_id='92efe1bb-77ee-4002-8618-4c9d7c3972c2' collection='Ecommerce' │ -│ - object_id='f51001bf-c0c6-47d5-b165-4e7ce878900e' collection='Ecommerce' │ -│ - object_id='9ba9ed81-c917-4e13-8058-d6ad81896ef3' collection='Ecommerce' │ -│ - object_id='41f324c2-a8e8-4cde-87d0-42661435a32c' collection='Ecommerce' │ -│ - object_id='d8d8e59e-d935-4a6f-9df1-bc2477452b11' collection='Ecommerce' │ -│ - object_id='505238e0-9993-4838-89fc-513c8f53d9f8' collection='Ecommerce' │ -│ - object_id='4a1321dc-d3f5-405d-8b21-e656c448ccfd' collection='Ecommerce' │ -│ - object_id='b59f7700-2633-43d6-807e-72dda35d545c' collection='Ecommerce' │ -│ │ -╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ - - - 📊 Usage Statistics -┌────────────────┬───────┐ -│ LLM Requests: │ 5 │ -│ Input Tokens: │ 15998 │ -│ Output Tokens: │ 906 │ -│ Total Tokens: │ 16904 │ -└────────────────┴───────┘ - -Total Time Taken: 22.77s -``` - -
- -### 4.3 Perform an aggregation - -Now, let's try a question that requires an aggregation. Let's see which brand lists the most shoes. - - - - - - - -
- The response is: - -``` -╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────── 🔍 Original Query ────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ What is the the name of the brand that lists the most shoes? │ -│ │ -╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────── 📝 Final Answer ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ The brand that lists the most shoes is Loom & Aura, with a total count of 118 shoes across various styles such as Cottagecore, Fairycore, Goblincore, Light Academia, and Dark Academia. │ -│ │ -╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ 🔭 No Searches Run │ -│ │ -╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭───────────────────────────────────────────────────────────────────────────────────────────────────────────── 📊 Aggregations Run 1/1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ AggregationResultWithCollection( │ -│ search_query=None, │ -│ groupby_property='brand', │ -│ aggregations=[TextPropertyAggregation(property_name='collection', metrics=, top_occurrences_limit=1)], │ -│ filters=[], │ -│ collection='ECommerce' │ -│ ) │ -│ │ -╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ - - - 📊 Usage Statistics -┌────────────────┬──────┐ -│ LLM Requests: │ 3 │ -│ Input Tokens: │ 5794 │ -│ Output Tokens: │ 238 │ -│ Total Tokens: │ 6032 │ -└────────────────┴──────┘ - -Total Time Taken: 7.52s -``` - -
- -### 4.4 Search over multiple collections - -In some cases, we need to combine the results of searches across multiple collections. From the result above, we can see that "Loom & Aura" lists the most shoes. - -Let's imagine a scenario where the user would now want to find out more about this company, _as well_ as the items that they sell. - - - - - - - -
- The response is: - -``` -╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────── 🔍 Original Query ────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ Does the brand 'Loom & Aura' have a parent brand or child brands and what countries do they operate from? Also, what's the average price of a shoe from 'Loom & Aura'? │ -│ │ -╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────── 📝 Final Answer ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ The brand "Loom & Aura" operates as a parent brand with several child brands, including "Loom & Aura Active," "Loom & Aura Kids," "Nova Nest," "Vivid Verse," "Loom Luxe," "Saffrom Sage," "Stellar Stitch," "Nova Nectar," "Canvas Core," and │ -│ "Loom Lure." "Loom & Aura" itself is based in Italy and operates in multiple countries where its child brands are located, such as the USA, Japan, South Korea, Spain, the UK, and France. │ -│ │ -│ The average price of a shoe from "Loom & Aura" is approximately $87.11, based on the aggregation of available data on shoe prices. │ -│ │ -╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭──────────────────────────────────────────────────────────────────────────────────────────────────────────── 🔭 Searches Executed 1/2 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ QueryResultWithCollection(queries=['Loom parent brand and child brands', 'Aura parent brand and child brands'], filters=[[], []], filter_operators='AND', collection='Brands') │ -│ │ -╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭──────────────────────────────────────────────────────────────────────────────────────────────────────────── 🔭 Searches Executed 2/2 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ QueryResultWithCollection(queries=['countries where Loom & Aura operates'], filters=[[TextPropertyFilter(property_name='name', operator=)], │ -│ filters=[TextPropertyFilter(property_name='brand', operator= - -### 4.5 Use a system prompt {#use-system-prompt-agent} - -We are going to use the custom agent from [step 3.2](#system-prompt-agent) with the system prompt that says: - -``` -"You are a helpful assistant that always generates the final response in the user's language." -"You may have to translate the user query to perform searches. But you must always respond to the user in their own language." -``` - -For example, try to ask if the brand "Eko & Stitch" has a branch or associated company in the UK but using Japanese instead of English: - - - - - - - -
- The response is: - -``` -Eko & Stitchは、英国に拠点があります。1974年に設立され、品質の高いクラフトマンシップとタイムレスなエレガンスで知られています。関連ブランドとして「Eko & Stitch Active」と「Eko & Stitch Kids」があります。また、Eko & Stitchの親会社はNova Nestです。 -``` - -Or translated to English: - -``` -Eko & Stitch is based in the UK. It was established in 1974 and is known for its high-quality craftsmanship and timeless elegance. It has associated brands, "Eko & Stitch Active" and "Eko & Stitch Kids." Additionally, the parent company of Eko & Stitch is Nova Nest. -``` - -
- -## Summary - -This guide shows you how to build an end-to-end e-commerce assistant using Weaviate's agentic services — from setting up your Weaviate Cloud instance and importing datasets to configuring a Query Agent that intelligently handles natural language queries. - -The Query Agent automatically interprets queries to decide whether to run standard searches, filters, or aggregations. It connects to multiple collections and selects the right source based on your query. The agent can also use previous interactions to provide more relevant follow-up answers and you can define system prompts to ensure the agent always responds in the user's preferred language or style. - -## Further resources - -- [Weaviate Agents - Query Agent](./index.md) - -## Questions and feedback - -import DocsFeedback from "/_includes/docs-feedback.mdx"; - - diff --git a/docs/agents/query/usage.md b/docs/agents/query/usage.md deleted file mode 100644 index 9d6bbe8e9..000000000 --- a/docs/agents/query/usage.md +++ /dev/null @@ -1,733 +0,0 @@ ---- -title: Usage -sidebar_position: 30 -description: "Technical documentation and usage examples for implementing the Query Agent." -image: og/docs/agents.jpg -# tags: ['agents', 'getting started', 'query agent'] ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; -import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; -import PyCode from '!!raw-loader!/docs/agents/\_includes/query_agent.py'; -import TSCode from '!!raw-loader!/docs/agents/\_includes/query_agent.mts'; - -# Weaviate Query Agent: Usage - - - -The Weaviate Query Agent is a pre-built agentic service designed to answer natural language queries based on the data stored in Weaviate Cloud. - -The user simply provides a prompt/question in natural language, and the Query Agent takes care of all intervening steps to provide an answer. - -![Weaviate Query Agent from a user perspective](../_includes/query_agent_usage_light.png#gh-light-mode-only "Weaviate Query Agent from a user perspective") -![Weaviate Query Agent from a user perspective](../_includes/query_agent_usage_dark.png#gh-dark-mode-only "Weaviate Query Agent from a user perspective") - -This page describes how to use the Query Agent to answer natural language queries, using your data stored in Weaviate Cloud. - -## Prerequisites - -### Weaviate instance - -This Agent is available exclusively for use with a Weaviate Cloud instance. Refer to the [Weaviate Cloud documentation](/cloud/index.mdx) for more information on how to set up a Weaviate Cloud instance. - -You can try this Weaviate Agent with a free Sandbox instance on [Weaviate Cloud](/go/console?utm_content=agents). - -### Client library - -:::note Supported languages -At this time, this Agent is available only for Python and TypeScript/JavaScript. Support for other languages will be added in the future. -::: - -For Python, you can install the Weaviate client library with the optional `agents` extras to use Weaviate Agents. This will install the `weaviate-agents` package along with the `weaviate-client` package. For TypeScript/JavaScript, you can install the `weaviate-agents` package alongside the `weaviate-client` package. - -Install the client library using the following command: - - - - -```shell -pip install -U "weaviate-client[agents]" -``` - -#### Troubleshooting: Force `pip` to install the latest version - -For existing installations, even `pip install -U "weaviate-client[agents]"` may not upgrade `weaviate-agents` to the [latest version](https://pypi.org/project/weaviate-agents/). If this occurs, additionally try to explicitly upgrade the `weaviate-agents` package: - -```shell -pip install -U weaviate-agents -``` - -Or install a [specific version](https://github.com/weaviate/weaviate-agents-python-client/tags): - -```shell -pip install -U weaviate-agents==||site.weaviate_agents_version|| -``` - - - - -```shell -npm install weaviate-agents@latest -``` - - - - - -## Instantiate the Query Agent - -### Basic instantiation - -Provide: - -- Target [Weaviate Cloud instance details](/cloud/manage-clusters/connect.mdx) (e.g. the `WeaviateClient` object). -- A default list of the collections to be queried - - - - - - - - - - - -### Configure collections - -The list of collections to be queried are further configurable with: - -- Tenant names (required for a multi-tenant collection) -- Target vector(s) of the collection to query (optional) -- List of property names for the agent to use (optional) -- [Additional filters](#user-defined-filters) to always apply on top of agent-generated ones (optional) - - - - - - - - - - - -:::info What does the Query Agent have access to? - -The Query Agent derives its access credentials from the Weaviate client object passed to it. This can be further restricted by the collection names provided to the Query Agent. - -For example, if the associated Weaviate credentials' user has access to only a subset of collections, the Query Agent will only be able to access those collections. - -::: - -### Additional options - -The Query Agent can be instantiated with additional options, such as: - -- `system_prompt`: A custom system prompt to replace the default system prompt provided by the Weaviate team (`systemPrompt` for JavaScript). -- `timeout`: The maximum time the Query Agent will spend on a single query, in seconds (server-side default: 60). - -:::tip For long-running queries -If you're experiencing timeouts or expect complex queries that take a long time, consider using [streaming responses](#stream-responses) as well as increasing the timeout value. - -Streaming handles long-running requests better by sending heartbeats to keep the connection alive and providing progress updates as the query processes. -::: - -#### Custom system prompt - -You can provide a custom system prompt to guide the Query Agent's behavior: - - - - - - - - - - - -### User-defined filters - -You can apply persistent filters that will always be combined with any agent-generated filters using logical `AND` operations. - - - - - - - - - - - -### Async Python client - -For usage example with the async Python client, see the [Async Python client section](#usage---async-python-client). - -## Querying - -The Query Agent supports three query types: - -- [**`Search`**](#search) -- [**`Ask`**](#ask) -- [**`Suggest Queries`**](#suggest-queries) - -### `Search` - -`Search` Weaviate with the Query Agent using natural langauge. The Query Agent will process the question, perform the necessary searches in Weaviate, and return the relevant objects. - - - - - - - - - - - -#### `Search` response structure - - - - - - - - - - - -
- Example output - -``` -Original query: winter boots for under $100 -Total time: 4.695224046707153 -Usage statistics: requests=2 request_tokens=143 response_tokens=9 total_tokens=152 details=None -Search performed: queries=['winter boots'] filters=[[IntegerPropertyFilter(property_name='price', operator=, value=100.0)]] filter_operators='AND' collection='ECommerce' -Properties: {'name': 'Bramble Berry Loafers', 'description': 'Embrace your love for the countryside with our soft, hand-stitched loafers, perfect for quiet walks through the garden. Crafted with eco-friendly dyed soft pink leather and adorned with a subtle leaf embossing, these shoes are a testament to the beauty of understated simplicity.', 'price': 75.0} -Metadata: {'creation_time': None, 'last_update_time': None, 'distance': None, 'certainty': None, 'score': 0.4921875, 'explain_score': None, 'is_consistent': None, 'rerank_score': None} -Properties: {'name': 'Glitter Bootcut Fantasy', 'description': "Step back into the early 2000s with these dazzling silver bootcut jeans. Embracing the era's optimism, these bottoms offer a comfortable fit with a touch of stretch, perfect for dancing the night away.", 'price': 69.0} -Metadata: {'creation_time': None, 'last_update_time': None, 'distance': None, 'certainty': None, 'score': 0.47265625, 'explain_score': None, 'is_consistent': None, 'rerank_score': None} -Properties: {'name': 'Celestial Step Platform Sneakers', 'description': 'Stride into the past with these baby blue platforms, boasting a dreamy sky hue and cushy soles for day-to-night comfort. Perfect for adding a touch of whimsy to any outfit.', 'price': 90.0} -Metadata: {'creation_time': None, 'last_update_time': None, 'distance': None, 'certainty': None, 'score': 0.48828125, 'explain_score': None, 'is_consistent': None, 'rerank_score': None} -Properties: {'name': 'Garden Bliss Heels', 'description': 'Embrace the simplicity of countryside elegance with our soft lavender heels, intricately designed with delicate floral embroidery. Perfect for occasions that call for a touch of whimsy and comfort.', 'price': 90.0} -Metadata: {'creation_time': None, 'last_update_time': None, 'distance': None, 'certainty': None, 'score': 0.45703125, 'explain_score': None, 'is_consistent': None, 'rerank_score': None} -Properties: {'name': 'Garden Stroll Loafers', 'description': 'Embrace the essence of leisurely countryside walks with our soft, leather loafers. Designed for the natural wanderer, these shoes feature delicate, hand-stitched floral motifs set against a soft, cream background, making every step a blend of comfort and timeless elegance.', 'price': 90.0} -Metadata: {'creation_time': None, 'last_update_time': None, 'distance': None, 'certainty': None, 'score': 0.451171875, 'explain_score': None, 'is_consistent': None, 'rerank_score': None} -``` - -
- -#### `Search` with pagination - -`Search` supports pagination to handle large result sets efficiently: - - - - - - - - - - - -
- Example output - -``` -Page 1: - Glide Platforms - $90.0 - Garden Haven Tote - $58.0 - Sky Shimmer Sneaks - $69.0 - -Page 2: - Garden Haven Tote - $58.0 - Celestial Step Platform Sneakers - $90.0 - Eloquent Satchel - $59.0 - -Page 3: - Garden Haven Tote - $58.0 - Celestial Step Platform Sneakers - $90.0 - Eloquent Satchel - $59.0 -``` - -
- -#### `Search` with diversity ranking - -`Search` supports adding diversity weighting to search result rankings using Maximal Marginal Relevance (MMR). This is enabled by passing a `diversity_weight` parameter in the range of 0.0 to 1.0. To use diversity ranking with target vectors, set the single target vector that you want to use in the Query Agent's constructor. Diversity ranking is not yet supported with collections using multi-vector embeddings. Diversity ranking will work with multiple collections, unless they are using **different** embedding models. - - - - - - - - - - - - - -### `Ask` - -`Ask` the Query Agent a question using natural language. The Query Agent will process the question, perform the necessary searches in Weaviate, and return the answer. - -:::tip Consider your query carefully -The Query Agent will formulate its strategy based on your query. So, aim to be unambiguous, complete, yet concise in your query as much as possible. -::: - - - - - - - - - - - -### Configure collections at runtime - -The list of collections to be queried can be overridden at query time, as a list of names, or with further configurations: - -#### Specify collection names only - -This example overrides the configured Query Agent collections for this query only. - - - - - - - - - - - -#### Configure collections in detail - -This example overrides the configured Query Agent collections for this query only, specifying additional options where relevant, such as: - -- Target vector -- Properties to view -- Target tenant -- Additional filters - - - - - - - - - - - -### Conversational queries - -The Query Agent supports multi-turn conversations by passing a list of `ChatMessage` objects. This works with both `Search` and `Ask` query types. - -When building conversations with `ChatMessage` there are two available roles for messages: - -- **`user`** - Represents messages from the human user asking questions or providing context -- **`assistant`** - Represents the Query Agent's responses or any AI assistant responses in the conversation history - -The conversation history helps the Query Agent understand context from previous exchanges, enabling more coherent multi-turn dialogues. Always alternate between user and assistant roles to maintain a proper conversation flow. - - - - - - - - - - - -### `Suggest Queries` - -The Query Agent can suggest queries based on the data in your collections. This is useful for helping users discover what kinds of questions they can ask, or for generating example queries for a new dataset. - -You can optionally specify: - -- `collections`: Override the collections configured at instantiation. -- `num_queries` (`numQueries` in TypeScript): The number of queries to suggest (default: 3). -- `instructions`: Guide the style or focus of the suggested queries. - - - - - - - - - - -## Stream responses - -The Query Agent can also stream responses, allowing you to receive the answer as it is being generated. - -A streaming response can be requested with the following optional parameters: - -- `include_progress`: If set to `True`, the Query Agent will stream a progress update as it processes the query. -- `include_final_state`: If set to `True`, the Query Agent will stream the final answer as it is generated, rather than waiting for the entire answer to be generated before returning it. - -If both `include_progress` and `include_final_state` are set to `False`, the Query Agent will only include the answer tokens as they are generated, without any progress updates or final state. - - - - - - - - - - -## Inspect responses - -The response from the Query Agent will contain the final answer, as well as additional supporting information. - -The supporting information may include searches or aggregations carried out, what information may have been missing, and how many LLM tokens were used by the Agent. - -### Helper function - -Try the provided helper functions (e.g. `.display()` method) to display the response in a readable format. - - - - - - - - - - - -This will print the response and a summary of the supporting information found by the Query Agent. - -
- Example output - -```text -╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────── 🔍 Original Query ────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ I like vintage clothes and nice shoes. Recommend some of each below $60. │ -│ │ -╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────── 📝 Final Answer ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ For vintage clothing under $60, you might like the Vintage Philosopher Midi Dress by Echo & Stitch. It features deep green velvet fabric with antique gold button details, tailored fit, and pleated skirt, perfect for a classic vintage look. │ -│ │ -│ For nice shoes under $60, consider the Glide Platforms by Vivid Verse. These are high-shine pink platform sneakers with cushioned soles, inspired by early 2000s playful glamour, offering both style and comfort. │ -│ │ -│ Both options combine vintage or retro aesthetics with an affordable price point under $60. │ -│ │ -╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭──────────────────────────────────────────────────────────────────────────────────────────────────────────── 🔭 Searches Executed 1/2 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ QueryResultWithCollection(queries=['vintage clothing'], filters=[[]], filter_operators='AND', collection='ECommerce') │ -│ │ -╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭──────────────────────────────────────────────────────────────────────────────────────────────────────────── 🔭 Searches Executed 2/2 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ QueryResultWithCollection(queries=['nice shoes'], filters=[[]], filter_operators='AND', collection='ECommerce') │ -│ │ -╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ 📊 No Aggregations Run │ -│ │ -╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────── 📚 Sources ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ │ -│ - object_id='a7aa8f8a-f02f-4c72-93a3-38bcbd8d5581' collection='ECommerce' │ -│ - object_id='ff5ecd6e-8cb9-47a0-bc1c-2793d0172984' collection='ECommerce' │ -│ │ -╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ - - - 📊 Usage Statistics -┌────────────────┬─────┐ -│ LLM Requests: │ 5 │ -│ Input Tokens: │ 288 │ -│ Output Tokens: │ 17 │ -│ Total Tokens: │ 305 │ -└────────────────┴─────┘ - -Total Time Taken: 7.58s -``` - -
- -### Inspection example - -This example outputs: - -- The original user query -- The answer provided by the Query Agent -- Searches & aggregations (if any) conducted by the Query Agent -- Any missing information - - - - - - - - - - -
- Example output - -``` -=== Query Agent Response === -Original Query: vintage style clothing - -🔍 Final Answer Found: -For vintage-style clothing under $60, I recommend the Vintage Scholar Turtleneck priced at $55. It features a soft, stretchable fabric with timeless pleated details, perfect for a Dark Academia-inspired intellectual and moody look, whether layered or worn solo. - -However, based on the available information, no shoes under $60 were found. If you want, I can help search further for nice shoes within your budget. Let me know! - -🔍 Searches Executed: -- ('query', 'vintage style clothing') - -- ('filters', IntegerPropertyFilter(property_name='price', operator=, value=60.0)) - -- ('collection', 'ECommerce') - -- ('query', 'nice shoes') - -- ('filters', IntegerPropertyFilter(property_name='price', operator=, value=60.0)) - -- ('collection', 'ECommerce') - -⚠️ Answer is Partial - Missing Information: -- No recommendations were provided for nice shoes under $60, though the user specifically requested shoes as well as vintage clothes. -``` - -
- -## Usage - Async Python client - -If you are using the async Python Weaviate client, the instantiation pattern remains similar. The difference is use of the `AsyncQueryAgent` class instead of the `QueryAgent` class. - -The resulting async pattern works as shown below: - - - - - - - -### Streaming - -The async Query Agent can also stream responses, allowing you to receive the answer as it is being generated. - - - - - - - -## Limitations & Troubleshooting - -### Usage limits - -import UsageLimits from "/\_includes/agents/query-agent-usage-limits.mdx"; - - - -### Custom collection descriptions - -import CollectionDescriptions from "/\_includes/agents/query-agent-collection-descriptions.mdx"; - - - -### Execution times - -import ExecutionTimes from "/\_includes/agents/query-agent-execution-times.mdx"; - - - -## Questions and feedback - -import DocsFeedback from '/\_includes/docs-feedback.mdx'; - - diff --git a/docs/agents/recipes.mdx b/docs/agents/recipes.mdx deleted file mode 100644 index 34d71bc24..000000000 --- a/docs/agents/recipes.mdx +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: Weaviate Recipes (code examples) -hide_table_of_contents: true ---- - -This page contains recipes for common Weaviate operations. You can also check out the original [Jupyter Notebooks](https://github.com/weaviate/recipes) the recipes where created from. - -import RecipesCards from "@site/src/components/RecipesCards"; - - diff --git a/docs/agents/recipes/personalization-agent-get-started-movies.md b/docs/agents/recipes/personalization-agent-get-started-movies.md deleted file mode 100644 index df4441a9f..000000000 --- a/docs/agents/recipes/personalization-agent-get-started-movies.md +++ /dev/null @@ -1,578 +0,0 @@ ---- -layout: recipe -colab: https://colab.research.google.com/github/weaviate/recipes/blob/main/weaviate-services/agents/personalization-agent-get-started-movies.ipynb -toc: True -title: "Build a Weaviate Personalization Agent - Movie Recommender" -featured: True -integration: False -agent: True -tags: ['Personalization Agent'] ---- - - Open In Google Colab - - -In this recipe, we will use the new Weaviate `PersonalizationAgent` to fetch personalized objects from a Weaviate collection, in a user personalized way. This new agentic way of retrieving objects is based on a users persona profile and past interactions with your collection. - -> 📚 You can learn more about how to use the `PersonalizationAgent`, in our ["Introducing the Weaviate Personalization Agent"](https://weaviate.io/blog/personalization-agent?utm_source=recipe&utm_campaign=agents) blog and [documentation](https://docs.weaviate.io/agents/personalization). - -To help you get started, we're providing a few demo datasets, available on Hugging Face datasets 🤗: - -- [Movies](https://huggingface.co/datasets/weaviate/agents/viewer/personalization-agent-movies): A dataset that lists movies, their ratings, original language etc. -- [Recipes](https://huggingface.co/datasets/weaviate/agents/viewer/personalization-agent-recipes): A dataset that lists the name, short description and cuisine of a dish. - -For this example, we will be using the movies dataset to create a movie recommender service - -```python -!pip install "weaviate-client[agents]" datasets -``` - -## Setting Up Weaviate & Importing Data - -To use the Weaviate Personalization Agent, first, create a [Weaviate Cloud](tps://weaviate.io/deployment/serverless?utm_source=recipe&utm_campaign=agents) account👇 -1. [Create Serverless Weaviate Cloud account](https://weaviate.io/deployment/serverless?utm_source=recipe&utm_campaign=agents) and setup a free [Sandbox](https://docs.weaviate.io/cloud/manage-clusters/create#sandbox-clusters?utm_source=recipe&utm_campaign=agents) -2. Go to 'Embedding' and enable it, by default, this will make it so that we use `Snowflake/snowflake-arctic-embed-l-v2.0` as the embedding model -3. Take note of the `WEAVIATE_URL` and `WEAVIATE_API_KEY` to connect to your cluster below - -> Info: We recommend using [Weaviate Embeddings](https://docs.weaviate.io/weaviate/model-providers/weaviate) so you do not have to provide any extra keys for external embedding providers. - -```python -import os - -import weaviate -from weaviate.auth import Auth -from getpass import getpass - -if "WEAVIATE_API_KEY" not in os.environ: - os.environ["WEAVIATE_API_KEY"] = getpass("Weaviate API Key") -if "WEAVIATE_URL" not in os.environ: - os.environ["WEAVIATE_URL"] = getpass("Weaviate URL") - -client = weaviate.connect_to_weaviate_cloud( - cluster_url=os.environ.get("WEAVIATE_URL"), - auth_credentials=Auth.api_key(os.environ.get("WEAVIATE_API_KEY")), -) -``` - -### Create a New Collection - -Next, we create a new collection in Weaviate called "Movies". For the agentic services in Weaviate, it's a good idea to include descriptions of the properties in your collection. These descriptions can then be used by the agent. - -```python -from weaviate.classes.config import Configure, DataType, Property - -# if client.collections.exists("Movies"): - # client.collections.delete("Movies") - -client.collections.create( - "Movies", - description="A dataset that lists movies, including their release dates, ratings, popularity etc.", - vector_config=Configure.Vectors.text2vec_weaviate(), - properties=[ - Property( - name="release_date", - data_type=DataType.TEXT, - description="release date of the movie", - skip_vectorization=True, - ), - Property( - name="title", data_type=DataType.TEXT, description="title of the movie" - ), - Property( - name="overview", - data_type=DataType.TEXT, - description="overview of the movie", - ), - Property( - name="genres", - data_type=DataType.TEXT_ARRAY, - description="genres of the movie", - ), - Property( - name="vote_average", - data_type=DataType.NUMBER, - description="vote average of the movie", - ), - Property( - name="vote_count", - data_type=DataType.INT, - description="vote count of the movie", - ), - Property( - name="popularity", - data_type=DataType.NUMBER, - description="popularity of the movie", - ), - Property( - name="poster_url", - data_type=DataType.TEXT, - description="poster path of the movie", - skip_vectorization=True, - ), - Property( - name="original_language", - data_type=DataType.TEXT, - description="Code of the language of the movie", - skip_vectorization=True, - ), - ], -) -``` - -Python output: -```text - -``` -```python -from datasets import load_dataset - -dataset = load_dataset("weaviate/agents", "personalization-agent-movies", split="train", streaming=True) - -movies_collection = client.collections.use("Movies") - -with movies_collection.batch.dynamic() as batch: - for item in dataset: - batch.add_object(properties=item["properties"]) -``` - -## Create a Personalization Agent - -Below, we create a `PersonalizationAgent` for the `"Movies"` collection. If an agent for this collection already exists, we can simply connect to it. - -When creating a new `PeresonalizationAgent`, we can also optioanlly define `user_properties`. - -User properties can be anything that may be useful iformation about users that will be added to the agent. In this case, since we are creating a Movie recommender service, we may ask each persona to be added with ther `age`, `favorite_genres` and `languages`. - -```python -from weaviate.agents.personalization import PersonalizationAgent - -if PersonalizationAgent.exists(client, "Movies"): - agent = PersonalizationAgent.connect( - client=client, - reference_collection="Movies", - ) -else: - agent = PersonalizationAgent.create( - client=client, - reference_collection="Movies", - user_properties={ - "age": DataType.NUMBER, - "favorite_genres": DataType.TEXT_ARRAY, - "languages": DataType.TEXT_ARRAY, - }, - ) - -``` - -### Adding New Personas - -We can add new users with `add_persona`, listing the requested user properties when adding them. Try changing the code block below to represent yourself if you like 👇 - -```python -from uuid import uuid4 -from weaviate.agents.classes import Persona, PersonaInteraction - -persona_id = uuid4() -agent.add_persona( - Persona( - persona_id=persona_id, - properties={ - "age": 29, - "favorite_genres": ["RomCom", "Adventure", "Sci-Fi", "Fantasy"], - "languages": ["English", "French"], - }, - ) -) -``` - -### Adding Interactions - -Once we have at least one persona for our agent, we can start adding interactions for that persona. For example, in this movie recommender service, it makes sense to add a personas movie reviews. - -Each interaction can have a weight between -1.0 (negative) and 1.0 positive. So, we can add some reviews for a number or films below. - -It's a good idea to think about what kind of end application may be forwarding these interactions and have a rule around what each weight might represent. For example: -- 1.0: favorite movie -- 0.8: user liked the movie -- 0.5: user viewed and did not review the movie -- -0.5: user disliked the movie -- -1.0: user absolutely hated the movie 👎 - -```python -from uuid import UUID -from weaviate.collections.classes.filters import Filter - -reviewed_movies = [ - "Fantastic Beasts and Where to Find Them", - "The Emoji Movie", - "Titanic", - "The Shining", - "Jumanji", - "West Side Story", - "The Shape of Water", - "Morbius" -] - -reviews_dict = { - movie.properties["title"]: movie - for movie in movies_collection.query.fetch_objects( - filters=Filter.by_property("title").contains_any(reviewed_movies), limit=20 - ).objects -} - -interactions = [ - PersonaInteraction( - persona_id=persona_id, item_id=reviews_dict["Fantastic Beasts and Where to Find Them"].uuid, weight=0.8 - ), - PersonaInteraction( - persona_id=persona_id, item_id=reviews_dict["The Emoji Movie"].uuid, weight=-0.5 - ), - PersonaInteraction( - persona_id=persona_id, item_id=reviews_dict["Titanic"].uuid, weight=0.5 - ), - PersonaInteraction( - persona_id=persona_id, item_id=reviews_dict["The Shining"].uuid, weight=0.5 - ), - PersonaInteraction( - persona_id=persona_id, item_id=reviews_dict["Jumanji"].uuid, weight=0.8 - ), - PersonaInteraction( - persona_id=persona_id, item_id=reviews_dict["West Side Story"].uuid, weight=-0.5 - ), - PersonaInteraction( - persona_id=persona_id, item_id=reviews_dict["The Shape of Water"].uuid, weight=-1.0 - ), - PersonaInteraction( - persona_id=persona_id, item_id=reviews_dict["Morbius"].uuid, weight=-1.0 - ), -] -``` - -```python -agent.add_interactions(interactions=interactions) -``` - -## Get Recommendations and Rationale - -Now that we have a persona and some interactions for that persona, we can start getting recommended objects from the agent with `get_objects`. We have two options here: we can set `use_agent_ranking` or not. - -When we do not use agent ranking, the returned objects are ranked by classic ML clustering, whereas when we do use it, it will go through an additional re-ranking with an LLM and an optioanl `instruction`. - -When we use agent ranking, we can also see the rationale behind the ranking in `ranking_rationale` as we've done below 👇 - -```python -response = agent.get_objects(persona_id, limit=25, use_agent_ranking=True) - -print(response.ranking_rationale) -for i, obj in enumerate(response.objects): - print(f"*****{i}*****") - print(obj.properties["title"]) - print(obj.properties["overview"]) - print(obj.properties["genres"]) - print(f"vote_average: {obj.properties['vote_average']}") - print(obj.properties['poster_url']) -``` - -Python output: -```text -We've placed a spotlight on fantasy and adventure titles given your love for these genres. Movies like 'The Chronicles of Narnia' and 'Jumanji' have been prioritized as they align with your past favorites and preferences. Holiday-themed family films were also considered due to their family-friendly and adventurous nature. -*****0***** -The Chronicles of Narnia: The Lion, the Witch and the Wardrobe -Siblings Lucy, Edmund, Susan and Peter step through a magical wardrobe and find the land of Narnia. There, they discover a charming, once peaceful kingdom that has been plunged into eternal winter by the evil White Witch, Jadis. Aided by the wise and magnificent lion, Aslan, the children lead Narnia into a spectacular, climactic battle to be free of the Witch's glacial powers forever. -['Adventure', 'Family', 'Fantasy'] -vote_average: 7.1 -https://image.tmdb.org/t/p/original/kzJip9vndXYSKQHCgekrgqbnUrA.jpg -*****1***** -The Ewok Adventure -The Towani family civilian shuttlecraft crashes on the forest moon of Endor. The four Towani's are separated. Jermitt and Catarine, the mother and father are captured by the giant Gorax, and Mace and Cindel, the son and daughter, are missing when they are captured. The next day, the Ewok Deej is looking for his two sons when they find Cindel all alone in the shuttle (Mace and Cindel were looking for the transmitter to send a distress call), when Mace appears with his emergency blaster. Eventually, the four-year old Cindel is able to convince the teenage Mace that the Ewoks are nice. Then, the Ewoks and the Towani's go on an adventure to find the elder Towanis. -['Adventure', 'Family', 'Fantasy', 'Science Fiction', 'TV Movie'] -vote_average: 6.0 -https://image.tmdb.org/t/p/original/lP7FIxojVrgWsam9efElk5ba3I5.jpg -*****2***** -The Chronicles of Narnia: Prince Caspian -One year after their incredible adventures in the Lion, the Witch and the Wardrobe, Peter, Edmund, Lucy and Susan Pevensie return to Narnia to aid a young prince whose life has been threatened by the evil King Miraz. Now, with the help of a colorful cast of new characters, including Trufflehunter the badger and Nikabrik the dwarf, the Pevensie clan embarks on an incredible quest to ensure that Narnia is returned to its rightful heir. -['Adventure', 'Family', 'Fantasy'] -vote_average: 6.6 -https://image.tmdb.org/t/p/original/qxz3WIyjZiSKUhaTIEJ3c1GcC9z.jpg -*****3***** -Pete's Dragon -For years, old wood carver Mr. Meacham has delighted local children with his tales of the fierce dragon that resides deep in the woods of the Pacific Northwest. To his daughter, Grace, who works as a forest ranger, these stories are little more than tall tales... until she meets Pete, a mysterious 10-year-old with no family and no home who claims to live in the woods with a giant, green dragon named Elliott. And from Pete's descriptions, Elliott seems remarkably similar to the dragon from Mr. Meacham's stories. With the help of Natalie, an 11-year-old girl whose father Jack owns the local lumber mill, Grace sets out to determine where Pete came from, where he belongs, and the truth about this dragon. -['Adventure', 'Family', 'Fantasy'] -vote_average: 6.4 -https://image.tmdb.org/t/p/original/6TwrPngfpbwtVH6UsDfVNUnn3ms.jpg -*****4***** -The Chronicles of Narnia: The Voyage of the Dawn Treader -This time around Edmund and Lucy Pevensie, along with their pesky cousin Eustace Scrubb find themselves swallowed into a painting and on to a fantastic Narnian ship headed for the very edges of the world. -['Adventure', 'Family', 'Fantasy'] -vote_average: 6.4 -https://image.tmdb.org/t/p/original/pP27zlm9yeKrCeDZLFLP2HKELot.jpg -*****5***** -One Piece: Clockwork Island Adventure -Relaxing on a cozy beach, the Straw Hat Pirates are taking a rest from their quest. Right until Luffy noticed the Going Merry has been hijacked and sailed off from the beach. This leads them to search the ship and find the thief who took it from them. They ran into a duo named the Theif Brothers, who informed them that their ship was stolen by a group of pirates called the Trump Kyoudai. When they encountered the Trump Pirates, Nami ended up getting kidnapped as well as Luffy's hat. They tracked down the pirates to their base on Clockwork Island. Now Luffy, Zoro, Sanji, Usopp, and the Theif Brothers must reclaim the Going Merry, Save Nami, and get back Shank's straw hat. -['Action', 'Animation', 'Adventure'] -vote_average: 6.8 -https://image.tmdb.org/t/p/original/mocek0mTd2dX2neCB691iU9le9k.jpg -*****6***** -Good Luck Charlie, It's Christmas! -Teddy Duncan's middle-class family embarks on a road trip from their home in Denver to visit Mrs. Duncans Parents, the Blankenhoopers, in Palm Springs. When they find themselves stranded between Denver and Utah, they try to hitch a ride to Las Vegas with a seemingly normal older couple in a station wagon from Roswell, New Mexico. It turns out that the couple believes they are the victims of alien abduction. The Duncan's must resort to purchasing a clunker Yugo to get to Utah, have their luggage stolen in Las Vegas, and survive a zany Christmas with Grandpa and Grandma Blankenhooper. -['TV Movie', 'Comedy', 'Family'] -vote_average: 6.6 -https://image.tmdb.org/t/p/original/ecuJMYZM3HQ96mnWtmyXoHb7s7T.jpg -*****7***** -Bedknobs and Broomsticks -Three children evacuated from London during World War II are forced to stay with an eccentric spinster (Eglantine Price). The children's initial fears disappear when they find out she is in fact a trainee witch. -['Adventure', 'Fantasy', 'Comedy', 'Family', 'Music'] -vote_average: 7.0 -https://image.tmdb.org/t/p/original/3V7UFCu1u8BJLnoCdvdEqPYVaxQ.jpg -*****8***** -Doraemon: Nobita's New Great Adventure Into the Underworld - The Seven Magic Users -Nobita has changed the real world to a world of magic using the "Moshimo Box" in admiration of magic. One day, Nobita meets Chaplain Mangetsu, a magic researcher, and his daughter Miyoko. Nobita learns from them that the Great Satan of the Devildom Star is scheming to invade the Earth. The Chaplain tries to find a way out using ancient books, however, the Devildom Star rapidly approaches the Earth by the minute, causing earthquakes and abnormal weather conditions. Nobita, along with his friends, Doraemon, Shizuka, Suneo, Gaian and Dorami, together with Miyoko, storm into the Devildom Star, just like the "Legendary Seven Heroes" in an ancient book in order to confront the Great Satan and peace returns to the world of magic. -['Family', 'Adventure', 'Animation'] -vote_average: 6.9 -https://image.tmdb.org/t/p/original/4E0qUqbevK4DAW2RRbvZmjjPsOd.jpg -*****9***** -Barbie: A Perfect Christmas -Join Barbie and her sisters Skipper, Stacie and Chelsea as their holiday vacation plans turn into a most unexpected adventure and heartwarming lesson. After a snowstorm diverts their plane, the girls find themselves far from their New York destination and their holiday dreams. Now stranded at a remote inn in the tiny town of Tannenbaum, the sisters are welcomed by new friends and magical experiences. In appreciation for the wonderful hospitality they receive, they use their musical talents to put on a performance for the whole town. Barbie and her sisters realize the joy of being together is what really makes A Perfect Christmas! -['Animation', 'Family'] -vote_average: 6.7 -https://image.tmdb.org/t/p/original/u14NrsyD9h505ZXs5Ofm7Tv3AuM.jpg -*****10***** -The Many Adventures of Winnie the Pooh -Whether we’re young or forever young at heart, the Hundred Acre Wood calls to that place in each of us that still believes in magic. Join pals Pooh, Piglet, Kanga, Roo, Owl, Rabbit, Tigger and Christopher Robin as they enjoy their days together and sing their way through adventures. -['Animation', 'Family'] -vote_average: 7.2 -https://image.tmdb.org/t/p/original/2xwaFVLv5geVrFd81eUttv7OutF.jpg -*****11***** -The Gruffalo's Child -A follow up to the 2009 animated feature and adapted from the childrens' book by Julia Donaldson and Alex Scheffler. The Gruffalo's child explores the deep dark wood in search of the big bad mouse and meets the Snake, Owl and Fox in the process. She eventually finds the mouse, who manages to outwit her like the Gruffalo before! -['Adventure', 'Animation', 'Family', 'Fantasy'] -vote_average: 7.0 -https://image.tmdb.org/t/p/original/n8fu0eATvUWtmR9CsDlL1gwqTcp.jpg -*****12***** -The Tigger Movie -Winnie the Pooh, Piglet, Owl, Kanga, Roo, and Rabbit are preparing a suitable winter home for Eeyore, the perennially dejected donkey, but Tigger's continual bouncing interrupts their efforts. Rabbit suggests that Tigger go find others of his kind to bounce with, but Tigger thinks "the most wonderful thing about tiggers is" he's "the only one!" Just in case though, the joyously jouncy feline sets out to see if he can find relatives. -['Family', 'Animation', 'Comedy'] -vote_average: 6.5 -https://image.tmdb.org/t/p/original/lxuiGvLHIL1ZyePP7bn6FcKj0Mr.jpg -*****13***** -Return to Never Land -In 1940, the world is besieged by World War II. Wendy, all grown up, has two children; including Jane, who does not believe Wendy's stories about Peter Pan. -['Adventure', 'Fantasy', 'Animation', 'Family'] -vote_average: 6.4 -https://image.tmdb.org/t/p/original/zfclCksB7vCLA5Rd9HKHMGSz40.jpg -*****14***** -Winnie the Pooh: A Very Merry Pooh Year -It's Christmastime in the Hundred Acre Wood and all of the gang is getting ready with presents and decorations. The gang makes a list of what they want for Christmas and send it to Santa Claus - except that Pooh forgot to ask for something. So he heads out to retrieve the letter and get it to Santa by Christmas...which happens to be tomorrow! -['Animation', 'Family'] -vote_average: 6.8 -https://image.tmdb.org/t/p/original/1NbobWwoX7kFd1if8aCyCtFRZpu.jpg -*****15***** -Alice in Wonderland -Alice follows a white rabbit down a rabbit-hole into a whimsical Wonderland, where she meets characters like the delightful Cheshire Cat, the clumsy White Knight, a rude caterpillar, and the hot-tempered Queen of Hearts and can grow ten feet tall or shrink to three inches. But will she ever be able to return home? -['Fantasy', 'Family'] -vote_average: 6.3 -https://image.tmdb.org/t/p/original/kpXmXjqeyuSYCtNuGMytWQLdKX.jpg -*****16***** -Tarzan the Ape Man -James Parker and Harry Holt are on an expedition in Africa in search of the elephant burial grounds that will provide enough ivory to make them rich. Parker's beautiful daughter Jane arrives unexpectedly to join them. Jane is terrified when Tarzan and his ape friends abduct her, but when she returns to her father's expedition she has second thoughts about leaving Tarzan. -['Action', 'Adventure'] -vote_average: 6.8 -https://image.tmdb.org/t/p/original/sqtdNAktAI3p1iXmaEooaHjMmWd.jpg -*****17***** -Doraemon: Nobita and the Tin Labyrinth -Nobita's dad stumbled upon a strange advertisement of a fantastic resort on television at midnight. Sleepy as he was, he made a reservation even though he didn't even realize he was talking to the advertisement. The next day he discussed with the family their holiday plans, only to realize he could not find the place anywhere on earth. All of a sudden though there was a suitcase in Nobita's room and intrigued as he was, he opened it only to find a portal to a beautiful resort managed by tin robots. Better still, it's absolutely free. It seems that there is a hidden agenda behind the person who invites them there. -['Adventure', 'Animation'] -vote_average: 7.3 -https://image.tmdb.org/t/p/original/bkIR641RQyqk7hBlk0hui70dkz9.jpg -*****18***** -Casper's Haunted Christmas -Kibosh, supreme ruler of all ghosts, decrees that casper must scare at least one person before Christmas Day so Casper visits Kriss, Massachusetts where he meets the Jollimore family and sets out to complete his mission. As usual, kindhearted Casper has a ghastky time trying to scare anyone; so The Ghostly Trio, fed up with his goody-boo-shoes behavior, secretly hires Casper's look-alike cousin Spooky to do the job-with hilarious results. -['Animation', 'Family', 'Fantasy'] -vote_average: 5.4 -https://image.tmdb.org/t/p/original/3BFR30kh0O3NKR1Sfea3HXCG6hw.jpg -*****19***** -Home Alone: The Holiday Heist -8-year-old Finn is terrified to learn his family is relocating from sunny California to Maine in the scariest house he has ever seen! Convinced that his new house is haunted, Finn sets up a series of elaborate traps to catch the “ghost” in action. Left home alone with his sister while their parents are stranded across town, Finn’s traps catch a new target – a group of thieves who have targeted Finn’s house. -['Comedy', 'Family', 'TV Movie'] -vote_average: 5.3 -https://image.tmdb.org/t/p/original/6JPrRC0JPM06y17pUXD6w1xMvKi.jpg -*****20***** -The Three Caballeros -For Donald's birthday he receives a box with three gifts inside. The gifts, a movie projector, a pop-up book, and a pinata, each take Donald on wild adventures through Mexico and South America. -['Animation', 'Family', 'Music'] -vote_average: 6.4 -https://image.tmdb.org/t/p/original/nMfScRxw9wVLoO7LiEjziFAKLSK.jpg -*****21***** -The Madagascar Penguins in a Christmas Caper -During the holiday season, when the animals of the Central Park Zoo are preparing for Christmas, Private, the youngest of the penguins notices that the Polar Bear is all alone. Assured that nobody should have to spend Christmas alone, Private goes into the city for some last-minute Christmas shopping. Along the way, he gets stuffed into a stocking -['Animation', 'Comedy', 'Family'] -vote_average: 6.7 -https://image.tmdb.org/t/p/original/gOVdfrRfzQjYwezOxIap13j05d8.jpg -*****22***** -Jumanji: Welcome to the Jungle -The tables are turned as four teenagers are sucked into Jumanji's world - pitted against rhinos, black mambas and an endless variety of jungle traps and puzzles. To survive, they'll play as characters from the game. -['Adventure', 'Action', 'Comedy', 'Fantasy'] -vote_average: 6.8 -https://image.tmdb.org/t/p/original/pSgXKPU5h6U89ipF7HBYajvYt7j.jpg -*****23***** -Poltergeist -Steve Freeling lives with his wife, Diane, and their three children, Dana, Robbie, and Carol Anne, in Southern California where he sells houses for the company that built the neighborhood. It starts with just a few odd occurrences, such as broken dishes and furniture moving around by itself. However, when he realizes that something truly evil haunts his home, Steve calls in a team of parapsychologists led by Dr. Lesh to help before it's too late. -['Horror'] -vote_average: 7.1 -https://image.tmdb.org/t/p/original/xPazCcKp62IshnLVf9BLAjf9vgC.jpg -*****24***** -Up and Away -Hodja is a dreamer. He wants to experience the world, but his father insists he stays home and takes over the family's tailor shop. Fortunately, Hodja meets the old rug merchant El Faza, who gives him a flying carpet. In exchange he has to bring the old man's little granddaughter, Diamond, back to Pjort. El Faza can’t travel to the Sultan city himself, as the mighty ruler has imposed a death sentence on El Faza, on the grounds that he has stolen the Sultan's carpet. However, city life isn't quite what Hodja expected, and he only survives because of Emerald, a poor but street smart girl, who teaches him how to manage in the big world. But when Hodja loses his carpet to the power-hungry sultan, his luck seems to run out. Will he complete his mission, find El Faza's granddaughter and return safely back to Pjort? -['Animation', 'Family', 'Comedy'] -vote_average: 6.2 -https://image.tmdb.org/t/p/original/1WRK69soLEfVFRW1WwE0vWGz1mq.jpg -``` -### Get Recommendations with an Instruction - -Optionally, you can also provide the agent with an instruction too. This allows the agent LLM to have more context as to what kind of recommendations it could make. - -It may also make sense to set a higher limit for the initial ranking, and then filter down to a smaller group after the agent ranking as we've done below 👇 - -```python -response = agent.get_objects(persona_id, - limit=100, - use_agent_ranking=True, - instruction="""Your task is to recommend a diverse set of movies that the user may - like based on their fave genres and past interactions. Try to avoid recommending multiple films from within - the same cinematic universe.""", -) - -print(response.ranking_rationale) -for i, obj in enumerate(response.objects[:20]): - print(f"*****{i}*****") - print(obj.properties["title"]) - print(obj.properties["overview"]) - print(obj.properties["genres"]) - print(f"vote_average: {obj.properties['vote_average']}") - print(obj.properties['poster_url']) -``` - -Python output: -```text -We've highlighted a mix of movies from the user's favorite genres — RomCom, Adventure, Sci-Fi, and Fantasy — ensuring a diverse selection. We've also included some lesser-known gems to provide variety while avoiding multiple entries from the same cinematic universe. -*****0***** -Jumanji: Welcome to the Jungle -The tables are turned as four teenagers are sucked into Jumanji's world - pitted against rhinos, black mambas and an endless variety of jungle traps and puzzles. To survive, they'll play as characters from the game. -['Adventure', 'Action', 'Comedy', 'Fantasy'] -vote_average: 6.8 -https://image.tmdb.org/t/p/original/pSgXKPU5h6U89ipF7HBYajvYt7j.jpg -*****1***** -The Chronicles of Narnia: The Lion, the Witch and the Wardrobe -Siblings Lucy, Edmund, Susan and Peter step through a magical wardrobe and find the land of Narnia. There, they discover a charming, once peaceful kingdom that has been plunged into eternal winter by the evil White Witch, Jadis. Aided by the wise and magnificent lion, Aslan, the children lead Narnia into a spectacular, climactic battle to be free of the Witch's glacial powers forever. -['Adventure', 'Family', 'Fantasy'] -vote_average: 7.1 -https://image.tmdb.org/t/p/original/kzJip9vndXYSKQHCgekrgqbnUrA.jpg -*****2***** -Alice Through the Looking Glass -Alice Kingsleigh returns to Underland and faces a new adventure in saving the Mad Hatter. -['Adventure', 'Family', 'Fantasy'] -vote_average: 6.5 -https://image.tmdb.org/t/p/original/kbGamUkYfgKIYIrU8kW5oc0NatZ.jpg -*****3***** -Madagascar -Alex the lion is the king of the urban jungle, the main attraction at New York's Central Park Zoo. He and his best friends—Marty the zebra, Melman the giraffe and Gloria the hippo—have spent their whole lives in blissful captivity before an admiring public and with regular meals provided for them. Not content to leave well enough alone, Marty lets his curiosity get the better of him and makes his escape—with the help of some prodigious penguins—to explore the world. -['Family', 'Animation', 'Adventure', 'Comedy'] -vote_average: 6.9 -https://image.tmdb.org/t/p/original/uHkmbxb70IQhV4q94MiBe9dqVqv.jpg -*****4***** -Rio -Captured by smugglers when he was just a hatchling, a macaw named Blu never learned to fly and lives a happily domesticated life in Minnesota with his human friend, Linda. Blu is thought to be the last of his kind, but when word comes that Jewel, a lone female, lives in Rio de Janeiro, Blu and Linda go to meet her. Animal smugglers kidnap Blu and Jewel, but the pair soon escape and begin a perilous adventure back to freedom -- and Linda. -['Animation', 'Adventure', 'Comedy', 'Family'] -vote_average: 6.7 -https://image.tmdb.org/t/p/original/oo7M77GXEyyqDGOhzNNZTzEuDSF.jpg -*****5***** -Alice in Wonderland -Alice, now 19 years old, returns to the whimsical world she first entered as a child and embarks on a journey to discover her true destiny. -['Family', 'Fantasy', 'Adventure'] -vote_average: 6.6 -https://image.tmdb.org/t/p/original/o0kre9wRCZz3jjSjaru7QU0UtFz.jpg -*****6***** -Peter Pan -Leaving the safety of their nursery behind, Wendy, Michael and John follow Peter Pan to a magical world where childhood lasts forever. But while in Neverland, the kids must face Captain Hook and foil his attempts to get rid of Peter for good. -['Animation', 'Family', 'Adventure', 'Fantasy'] -vote_average: 7.2 -https://image.tmdb.org/t/p/original/fJJOs1iyrhKfZceANxoPxPwNGF1.jpg -*****7***** -Titanic -101-year-old Rose DeWitt Bukater tells the story of her life aboard the Titanic, 84 years later. A young Rose boards the ship with her mother and fiancé. Meanwhile, Jack Dawson and Fabrizio De Rossi win third-class tickets aboard the ship. Rose tells the whole story from Titanic's departure through to its death—on its first and last voyage—on April 15, 1912. -['Drama', 'Romance'] -vote_average: 7.9 -https://image.tmdb.org/t/p/original/9xjZS2rlVxm8SFx8kPC3aIGCOYQ.jpg -*****8***** -The Nutcracker and the Four Realms -When Clara’s mother leaves her a mysterious gift, she embarks on a journey to four secret realms—where she discovers her greatest strength could change the world. -['Fantasy', 'Adventure', 'Family'] -vote_average: 6.1 -https://image.tmdb.org/t/p/original/9vPDY8e7YxLwgVum7YZIUJbr4qc.jpg -*****9***** -Pete's Dragon -For years, old wood carver Mr. Meacham has delighted local children with his tales of the fierce dragon that resides deep in the woods of the Pacific Northwest. To his daughter, Grace, who works as a forest ranger, these stories are little more than tall tales... until she meets Pete, a mysterious 10-year-old with no family and no home who claims to live in the woods with a giant, green dragon named Elliott. And from Pete's descriptions, Elliott seems remarkably similar to the dragon from Mr. Meacham's stories. With the help of Natalie, an 11-year-old girl whose father Jack owns the local lumber mill, Grace sets out to determine where Pete came from, where he belongs, and the truth about this dragon. -['Adventure', 'Family', 'Fantasy'] -vote_average: 6.4 -https://image.tmdb.org/t/p/original/6TwrPngfpbwtVH6UsDfVNUnn3ms.jpg -*****10***** -The Chronicles of Narnia: Prince Caspian -One year after their incredible adventures in the Lion, the Witch and the Wardrobe, Peter, Edmund, Lucy and Susan Pevensie return to Narnia to aid a young prince whose life has been threatened by the evil King Miraz. Now, with the help of a colorful cast of new characters, including Trufflehunter the badger and Nikabrik the dwarf, the Pevensie clan embarks on an incredible quest to ensure that Narnia is returned to its rightful heir. -['Adventure', 'Family', 'Fantasy'] -vote_average: 6.6 -https://image.tmdb.org/t/p/original/qxz3WIyjZiSKUhaTIEJ3c1GcC9z.jpg -*****11***** -One Piece: Chopper's Kingdom on the Island of Strange Animals -As the Straw Hat Pirates sail through the Grand Line.A line of geysers erupted from under the Going Merry. And the whole crew find themselves flying over the island. Unfortunatly, Chopper fell off the ship and was separated from his friends. Luffy and the others landed on the other side of the island. Chopper meanwhile finds himself being worshiped as the island's new king by the animals. To make matters worse, a trio of human "horn" hunters are on the island. The leader, Count Butler is a violin playing/horn eating human who wants to eat the island's treasure to inherit immense power. Will Luffy & the rest be able to prevent the count from terrorizing the island? And will they be able to convince Momambi that not all pirates are bad? -['Action', 'Animation', 'Adventure'] -vote_average: 6.6 -https://image.tmdb.org/t/p/original/8uzFccR8F3h7tC9zfIOT063r91N.jpg -*****12***** -The Ewok Adventure -The Towani family civilian shuttlecraft crashes on the forest moon of Endor. The four Towani's are separated. Jermitt and Catarine, the mother and father are captured by the giant Gorax, and Mace and Cindel, the son and daughter, are missing when they are captured. The next day, the Ewok Deej is looking for his two sons when they find Cindel all alone in the shuttle (Mace and Cindel were looking for the transmitter to send a distress call), when Mace appears with his emergency blaster. Eventually, the four-year old Cindel is able to convince the teenage Mace that the Ewoks are nice. Then, the Ewoks and the Towani's go on an adventure to find the elder Towanis. -['Adventure', 'Family', 'Fantasy', 'Science Fiction', 'TV Movie'] -vote_average: 6.0 -https://image.tmdb.org/t/p/original/lP7FIxojVrgWsam9efElk5ba3I5.jpg -*****13***** -Doraemon: Nobita and the Tin Labyrinth -Nobita's dad stumbled upon a strange advertisement of a fantastic resort on television at midnight. Sleepy as he was, he made a reservation even though he didn't even realize he was talking to the advertisement. The next day he discussed with the family their holiday plans, only to realize he could not find the place anywhere on earth. All of a sudden though there was a suitcase in Nobita's room and intrigued as he was, he opened it only to find a portal to a beautiful resort managed by tin robots. Better still, it's absolutely free. It seems that there is a hidden agenda behind the person who invites them there. -['Adventure', 'Animation'] -vote_average: 7.3 -https://image.tmdb.org/t/p/original/bkIR641RQyqk7hBlk0hui70dkz9.jpg -*****14***** -Barbie & Her Sisters in the Great Puppy Adventure -Barbie and her sisters, Skipper, Stacie and Chelsea, and their adorable new puppy friends find unexpected mystery and adventure when they return to their hometown of Willows. While going through mementos in Grandma's attic, the sisters discover an old map, believed to lead to a long-lost treasure buried somewhere in the town. With their puppy pals in tow, the four girls go on an exciting treasure hunt, along the way discovering that the greatest treasure of all is the love and laughter they share as sisters! -['Family', 'Animation', 'Adventure'] -vote_average: 7.3 -https://image.tmdb.org/t/p/original/3ybjPWweUjPXXqIXFERgPnOQ5O3.jpg -*****15***** -Tinker Bell and the Lost Treasure -A blue harvest moon will rise, allowing the fairies to use a precious moonstone to restore the Pixie Dust Tree, the source of all their magic. But when Tinker Bell accidentally puts all of Pixie Hollow in jeopardy, she must venture out across the sea on a secret quest to set things right. -['Animation', 'Family', 'Adventure', 'Fantasy'] -vote_average: 6.7 -https://image.tmdb.org/t/p/original/hg1959yuBkHb4BKbIvETQSfxGCT.jpg -*****16***** -Barbie and the Diamond Castle -Liana and Alexa (Barbie and Teresa) are best friends who share everything, including their love of singing. One day while walking through the forest home from the village, the girls meet an old beggar who gives them a magical mirror. As they clean the mirror and sing, a musical apprentice muse named Melody appears in the mirror's surface, and tells the girls about the secret of the Diamond Castle. -['Animation', 'Family'] -vote_average: 7.4 -https://image.tmdb.org/t/p/original/dvjFM3GgYm3gDZ6Ulw0JurDYs4r.jpg -*****17***** -Doraemon: New Nobita's Great Demon – Peko and the Exploration Party of Five -The film starts with Gian seeing some like spirit and it asks him to accomplish a task. The story starts when a stray dogs are searching some foods in the can. Then a dirty white dog comes out of nowhere. Just then, the dog creates a close stare to the stray dogs and forces to run away. But the dog is disappointed that he doesn't know what to do after searching the garbage, under the pouring rain. After that, Suneo starts saying about the discoverable places on Earth and him and Gian are totally disappointed about that. That then, they are asking favor to Nobita to take them to an undiscovered place to be seen by their naked eyes. Nobita refuses but tells he will try his best. He comes to upstairs to explain Doraemon what the problem is now. -['Family', 'Animation', 'Adventure'] -vote_average: 7.0 -https://image.tmdb.org/t/p/original/1XxnaUvLuAlfSWEqravAfSiCaFj.jpg -*****18***** -The Wolf and the Lion -After her grandfather's death, 20-year-old Alma decides to go back to her childhood home - a little island in the heart of the majestic Canadian forest. Whilst there, she rescues two helpless cubs: a wolf and a lion. They forge an inseparable bond, but their world soon collapses as the forest ranger discovers the animals and takes them away. The two cub brothers must now embark on a treacherous journey across Canada to be reunited with one another and Alma once more. -['Adventure', 'Family'] -vote_average: 7.2 -https://image.tmdb.org/t/p/original/aSRvK4kLJORBrVdlFn2wrGx8XPv.jpg -*****19***** -Tinker Bell and the Legend of the NeverBeast -An ancient myth of a massive creature sparks the curiosity of Tinker Bell and her good friend Fawn, an animal fairy who’s not afraid to break the rules to help an animal in need. But this creature is not welcome in Pixie Hollow — and the scout fairies are determined to capture the mysterious beast, who they fear will destroy their home. Fawn must convince her fairy friends to risk everything to rescue the NeverBeast. -['Adventure', 'Animation', 'Family'] -vote_average: 7.1 -https://image.tmdb.org/t/p/original/bUGX7duQWSm04yAA1rBBfNRe4kY.jpg -``` diff --git a/docs/agents/recipes/personalization-agent-get-started-recipes.md b/docs/agents/recipes/personalization-agent-get-started-recipes.md deleted file mode 100644 index 1598c02b8..000000000 --- a/docs/agents/recipes/personalization-agent-get-started-recipes.md +++ /dev/null @@ -1,416 +0,0 @@ ---- -layout: recipe -colab: https://colab.research.google.com/github/weaviate/recipes/blob/main/weaviate-services/agents/personalization-agent-get-started-recipes.ipynb -toc: True -title: "Build a Weaviate Personalization Agent - Food Recommender" -featured: False -integration: False -agent: True -tags: ['Personalization Agent'] ---- - - Open In Google Colab - - -In this recipe, we will use the new Weaviate `PersonalizationAgent` to fetch personalized objects from a Weaviate collection, in a user personalized way. This new agentic way of retrieving objects is based on a users persona profile and past interactions with your collection. - -> 📚 You can learn more about how to use the `PersonalizationAgent`, in our ["Introducing the Weaviate Personalization Agent"](https://weaviate.io/blog/personalization-agent?utm_source=recipe&utm_campaign=agents) blog and [documentation](https://docs.weaviate.io/agents/personalization). - -To help you get started, we're providing a few demo datasets, available on Hugging Face datasets 🤗: -- [Recipes](https://huggingface.co/datasets/weaviate/agents/viewer/personalization-agent-recipes): A dataset that lists the name, short description and cuisine of a dish. -- [Movies](https://huggingface.co/datasets/weaviate/agents/viewer/personalization-agent-movies): A dataset that lists movies, their ratings, original language etc. - -For this example, we will be using the recipes dataset to create a food recommender service - -```python -!pip install 'weaviate-client[agents]' datasets -``` - -## Setting Up Weaviate & Importing Data - -To use the Weaviate Personalization Agent, first, create a [Weaviate Cloud](tps://weaviate.io/deployment/serverless?utm_source=recipe&utm_campaign=agents) account👇 -1. [Create Serverless Weaviate Cloud account](https://weaviate.io/deployment/serverless?utm_source=recipe&utm_campaign=agents) and setup a free [Sandbox](https://docs.weaviate.io/cloud/manage-clusters/create#sandbox-clusters?utm_source=recipe&utm_campaign=agents) -2. Go to 'Embedding' and enable it, by default, this will make it so that we use `Snowflake/snowflake-arctic-embed-l-v2.0` as the embedding model -3. Take note of the `WEAVIATE_URL` and `WEAVIATE_API_KEY` to connect to your cluster below - -> Info: We recommend using [Weaviate Embeddings](https://docs.weaviate.io/weaviate/model-providers/weaviate) so you do not have to provide any extra keys for external embedding providers. - -```python -import os - -import weaviate -from weaviate.auth import Auth -from getpass import getpass - -if "WEAVIATE_API_KEY" not in os.environ: - os.environ["WEAVIATE_API_KEY"] = getpass("Weaviate API Key") -if "WEAVIATE_URL" not in os.environ: - os.environ["WEAVIATE_URL"] = getpass("Weaviate URL") - -client = weaviate.connect_to_weaviate_cloud( - cluster_url=os.environ.get("WEAVIATE_URL"), - auth_credentials=Auth.api_key(os.environ.get("WEAVIATE_API_KEY")), -) -``` - -### Create a New Collection - -Next, we create a new collection in Weaviate called "Recipes". For the agentic services in Weaviate, it's a good idea to include descriptions of the properties in your collection. These descriptions can then be used by the agent. - -```python -from weaviate.classes.config import Configure, DataType, Property - -# if client.collections.exists("Recipes"): -# client.collections.delete("Recipes") - -client.collections.create( - "Recipes", - description="A dataset that lists recipes with titles, desctiptions, and labels indicating cuisine", - vector_config=Configure.Vectors.text2vec_weaviate(), - properties=[ - Property( - name="title", data_type=DataType.TEXT, description="title of the recipe" - ), - Property( - name="labels", - data_type=DataType.TEXT, - description="the cuisine the recipe belongs to", - ), - Property( - name="description", - data_type=DataType.TEXT, - description="short description of the recipe", - ), - ], -) -``` - -```python -from datasets import load_dataset - -dataset = load_dataset("weaviate/agents", "personalization-agent-recipes", split="train", streaming=True) - -recipes_collection = client.collections.use("Recipes") - -with recipes_collection.batch.dynamic() as batch: - for item in dataset: - batch.add_object(properties=item["properties"]) - -``` - -## Create a Personalization Agent - -Below, we create a `PersonalizationAgent` for the `"Recipes"` collection. If an agent for this collection already exists, we can simply connect to it. - -When creating a new `PeresonalizationAgent`, we can also optioanlly define `user_properties`. - -User properties can be anything that may be useful iformation about users that will be added to the agent. In this case, since we are creating a food recommender service, we may ask each persona to be added with ther `favorite_cuisines`, `likes` and `dislikes`. - -```python -from weaviate.agents.personalization import PersonalizationAgent - -if PersonalizationAgent.exists(client, "Recipes"): - agent = PersonalizationAgent.connect( - client=client, - reference_collection="Recipes", - ) -else: - agent = PersonalizationAgent.create( - client=client, - reference_collection="Recipes", - user_properties={ - "favorite_cuisines": DataType.TEXT_ARRAY, - "likes": DataType.TEXT_ARRAY, - "dislikes": DataType.TEXT_ARRAY - }, - ) - -``` - -### Adding New Personas - -We can add new users with `add_persona`, listing the requested user properties when adding them. Try changing the code block below to represent yourself if you like 👇 - -```python -from uuid import uuid4 -from weaviate.agents.classes import Persona, PersonaInteraction - -persona_id = uuid4() -agent.add_persona( - Persona( - persona_id=persona_id, - properties={ - "favorite_cuisines": ["Italian", "Thai"], - "likes": ["chocolate", "salmon", "pasta", "most veggies"], - "dislikes": ["okra", "mushroom"], - }, - ) -) -``` - -```python -agent.get_persona(persona_id) - -``` - -Python output: -```text -Persona(persona_id=UUID('df987437-4d10-44d6-b613-dfff31f715fb'), properties={'favorite_cuisines': ['Italian', 'Thai'], 'dislikes': ['okra', 'mushroom'], 'allergies': None, 'likes': ['chocolate', 'salmon', 'pasta', 'most veggies']}) -``` -### Adding Interactions - -Once we have at least one persona for our agent, we can start adding interactions for that persona. For example, in this food recommender service, it makes sense to add a personas food reviews. - -Each interaction can have a weight between -1.0 (negative) and 1.0 positive. So, we can add some reviews for a number or dishes below. - -It's a good idea to think about what kind of end application may be forwarding these interactions and have a rule around what each weight might represent. For example, let's imagine a recipes website -- 1.0: favorite meal -- 0.8: user liked the dish -- 0.5: user viewed the recipe page -- -0.5: user disliked the dish -- -1.0: user absolutely hated the dish 👎 - -```python -from uuid import UUID -from weaviate.collections.classes.filters import Filter - -reviewed_foods = [ - "Coq au Vin", - "Chicken Tikka Masala", - "Gnocchi alla Sorrentina", - "Matcha Ice Cream", - "Fiorentina Steak", - "Nabe", - "Duck Confit", - "Pappardelle with Porcini" -] - -reviews_dict = { - recipe.properties["title"]: recipe - for recipe in recipes_collection.query.fetch_objects( - filters=Filter.by_property("title").contains_any(reviewed_foods), limit=20 - ).objects -} - -interactions = [ - PersonaInteraction( - persona_id=persona_id, item_id=reviews_dict["Coq au Vin"].uuid, weight=0.8 - ), - PersonaInteraction( - persona_id=persona_id, item_id=reviews_dict["Chicken Tikka Masala"].uuid, weight=0.8 - ), - PersonaInteraction( - persona_id=persona_id, item_id=reviews_dict["Matcha Ice Cream"].uuid, weight=0.8 - ), - PersonaInteraction( - persona_id=persona_id, item_id=reviews_dict["Gnocchi alla Sorrentina"].uuid, weight=0.5 - ), - PersonaInteraction( - persona_id=persona_id, item_id=reviews_dict["Fiorentina Steak"].uuid, weight=0.8 - ), - PersonaInteraction( - persona_id=persona_id, item_id=reviews_dict["Nabe"].uuid, weight=0.5 - ), - PersonaInteraction( - persona_id=persona_id, item_id=reviews_dict["Duck Confit"].uuid, weight=1.0 - ), - PersonaInteraction( - persona_id=persona_id, item_id=reviews_dict["Pappardelle with Porcini"].uuid, weight=-1.0 - ), - -] -``` - -```python -agent.add_interactions(interactions=interactions) -``` - -## Get Recommendations and Rationale - -Now that we have a persona and some interactions for that persona, we can start getting recommended objects from the agent with `get_objects`. We have two options here: we can set `use_agent_ranking` or not. - -When we do not use agent ranking, the returned objects are ranked by classic ML clustering, whereas when we do use it, it will go through an additional re-ranking with an LLM and an optioanl `instruction`. - -When we use agent ranking, we can also see the rationale behind the ranking in `ranking_rationale` as we've done below 👇 - -```python -response = agent.get_objects(persona_id, limit=25, use_agent_ranking=True) - -print(response.ranking_rationale) -for i, obj in enumerate(response.objects): - print(f"*****{i}*****") - print(obj.properties["title"]) - print(obj.properties["description"]) - print(obj.properties["labels"]) -``` - -Python output: -```text -Based on your love for Italian cuisine and positive interactions with dishes like Gnocchi alla Sorrentina and Fiorentina Steak, Italian dishes like Frittata di Zucca e Pancetta and Classic Italian Margherita Pizza are highlighted. Your fondness for Chicken Tikka Masala also brought Indian dishes such as Spicy Indian Tikka Masala forward. Although you enjoyed Coq au Vin, the included mushrooms might not be to your liking, which is reflected in a balanced way within French dishes. -*****0***** -Frittata di Zucca e Pancetta -A fluffy egg omelette with sweet potatoes and pancetta, seasoned with herbs and grated cheese, a beloved dish from the heart of Italy. -Italian -*****1***** -Pizza Margherita -A simple yet iconic pizza with San Marzano tomatoes, mozzarella di bufala, fresh basil, and extra-virgin olive oil, encapsulating the Neapolitan pizza tradition. -Italian -*****2***** -Lasagna alla Bolognese -Layers of pasta sheets, Bolognese sauce, and béchamel, all baked to golden perfection, embodying the comforting flavors of Emilia-Romagna. -Italian -*****3***** -Lasagna alla Bolognese -Layers of flat pasta sheets, rich Bolognese sauce, and béchamel, baked to perfection. -Italian -*****4***** -Spicy Indian Tikka Masala -A rich tomato and cream sauce with chunks of chicken, covered in a fiery blend of spices and charred chunks of chicken. -Indian -*****5***** -Classic Italian Margherita Pizza -Thin crust pizza topped with San Marzano tomatoes, fresh mozzarella, basil, and extra-virgin olive oil, representing the simplicity of Italian cuisine. -Italian -*****6***** -Chicken Tikka Masala -Marinated chicken drumsticks grilled on a spit and then simmered in a spicy tomato sauce with cream, a popular dish in Indian cuisine. -Indian -*****7***** -Butter Chicken -A creamy and aromatic tomato sauce with tender chunks of chicken, marinated in a blend of spices and cooked with yogurt and cream, often served with rice or naan bread. -Indian -*****8***** -French Coq au Vin -A hearty stew of chicken braised with wine, mushrooms, and garlic, capturing the essence of French country cooking. -French -*****9***** -Sicilian Arancini -Deep-fried balls of risotto mixed with cheese and peas, coated with breadcrumbs and Parmesan cheese. -Italian -*****10***** -Ramen -A noodle soup dish with Chinese influences, typically containing Chinese-style noodles served in a meat or fish-based broth, often flavored with soy sauce or miso, and uses toppings such as sliced pork, green onions, and nori. -Japanese -*****11***** -Oden -A hearty Japanese hotpot dish made with simmered fish cakes, tofu, konnyaku, and vegetables, in a dashi-based broth. -Japanese -*****12***** -Shabu-Shabu -A Japanese hot pot dish where thinly sliced meat and vegetables are cooked in boiling water at the table. -Japanese -*****13***** -Tempura -A Japanese dish usually made with seafood, vegetables, and sometimes meat, battered and deep-fried until crisp. -Japanese -*****14***** -Oden -A Japanese stew containing fish cakes, daikon radish, konnyaku, tofu, and boiled eggs, typically flavored with miso or dashi broth. -Japanese -*****15***** -Tandoori Chicken -Marinated in yogurt and spices, then cooked in a tandoor (clay oven), resulting in a tangy and spicy chicken dish. -Indian -*****16***** -Beef Bourguignon -A flavorful beef stew cooked slowly in red wine, beef broth, and a bouquet garni, with carrots, onions, and mushrooms, typically served with potatoes or noodles. -French -*****17***** -Pizza Margherita -Simple pizza with San Marzano tomatoes, fresh mozzarella, basil, and extra-virgin olive oil, reflecting the colors of the Italian flag. -Italian -*****18***** -Butter Chicken -Soft and tender pieces of chicken in a rich and creamy sauce made with butter, tomatoes, and a blend of Indian spices. -Indian -*****19***** -Chicken Biryani -A flavorful rice dish cooked with basmati rice, chicken, and a mix of aromatic spices such as cardamom, cinnamon, and cloves, layered with meat and vegetables. -Indian -*****20***** -Milanesa a la Napolitana -A breaded cutlet, typically veal, topped with melted cheese and tomato sauce, a popular street food item. -Argentinian -*****21***** -Tempura Udon -Thick udon noodles served with crispy tempura shrimp and vegetables, lightly coated in a dashi-based sauce for a delicate taste. -Japanese -*****22***** -Miso Soup -A traditional Japanese soup consisting of a stock called dashi into which softened miso paste is mixed, often with pieces of tofu and seaweed. -Japanese -*****23***** -Udon Noodles -A type of thick wheat flour noodle common in Japanese cuisine, served hot or cold with a dipping sauce. -Japanese -*****24***** -Pappardelle with Porcini -Thick wide ribbons of pasta served with a creamy porcini mushroom sauce and grated Parmesan cheese. -Italian -``` -### Get Recommendations with an Instruction - -Optionally, you can also provide the agent with an instruction too. This allows the agent LLM to have more context as to what kind of recommendations it could make. - -It may also make sense to set a higher limit for the initial ranking, and then filter down to a smaller group after the agent ranking as we've done below 👇 - -```python -response = agent.get_objects(persona_id, - limit=50, - use_agent_ranking=True, - instruction="""Your task is to recommend a diverse set of dishes to the user - taking into account their likes and dislikes. It's especially important to avoid their dislikes.""", -) - -print(response.ranking_rationale) -for i, obj in enumerate(response.objects[:10]): - print(f"*****{i}*****") - print(obj.properties["title"]) - print(obj.properties["description"]) - print(obj.properties["labels"]) -``` - -Python output: -```text -As you love Italian cuisine and have a special liking for foods like pasta and salmon, while disliking mushrooms, we've focused on offering you a variety of Italian and other delightful dishes without mushroom content. We've also incorporated a touch of diversity with dishes from other cuisines you enjoy, while carefully avoiding those with ingredients you dislike. -*****0***** -Chicken Tikka Masala -Marinated chicken drumsticks grilled on a spit and then simmered in a spicy tomato sauce with cream, a popular dish in Indian cuisine. -Indian -*****1***** -Pasta alla Norma -Pasta served with fried eggplant, tomato sauce, and ricotta salata, a flavorful dish that showcases the vibrant flavors of Sicilian cuisine. -Italian -*****2***** -Classic Italian Margherita Pizza -Thin crust pizza topped with San Marzano tomatoes, fresh mozzarella, basil, and extra-virgin olive oil, representing the simplicity of Italian cuisine. -Italian -*****3***** -Pizza Margherita -Simple pizza with San Marzano tomatoes, fresh mozzarella, basil, and extra-virgin olive oil, reflecting the colors of the Italian flag. -Italian -*****4***** -Spicy Indian Tikka Masala -A rich tomato and cream sauce with chunks of chicken, covered in a fiery blend of spices and charred chunks of chicken. -Indian -*****5***** -Lasagna alla Bolognese -Layers of flat pasta sheets, rich Bolognese sauce, and béchamel, baked to perfection. -Italian -*****6***** -Fettuccine Alfredo -Creamy pasta dish made with fettuccine pasta tossed in a rich sauce of butter, heavy cream, and Parmesan cheese. -Italian -*****7***** -Sicilian Arancini -Deep-fried balls of risotto mixed with cheese and peas, coated with breadcrumbs and Parmesan cheese. -Italian -*****8***** -Frittata di Zucca e Pancetta -A fluffy egg omelette with sweet potatoes and pancetta, seasoned with herbs and grated cheese, a beloved dish from the heart of Italy. -Italian -*****9***** -Paneer Tikka -Small cubes of paneer marinated in spices and yogurt, then grilled and served in a spicy tomato sauce. -Indian -``` diff --git a/docs/agents/recipes/query-agent-get-started.md b/docs/agents/recipes/query-agent-get-started.md deleted file mode 100644 index 80e87a08b..000000000 --- a/docs/agents/recipes/query-agent-get-started.md +++ /dev/null @@ -1,579 +0,0 @@ ---- -layout: recipe -colab: https://colab.research.google.com/github/weaviate/recipes/blob/main/weaviate-services/agents/query-agent-get-started.ipynb -toc: True -title: "Build A Weaviate Query Agent - The E-Commerce Assistant" -featured: True -integration: False -agent: True -tags: ['Query Agent'] ---- - - Open In Google Colab - - -In this recipe, we will be building a simple e-commerce assistant agent with the [Weaviate Query Agent](https://docs.weaviate.io/agents). This agent will have access to a number of Weaviate collections, and will be capable of answering complex queries about brands and clothing items, accessing information from each collection. - -> 📚 You can read and learn more about this service in our ["Introducing the Weaviate Query Agent"](https://weaviate.io/blog/query-agent) blog. - -To get started, we've prepared a few open datasets, available on Hugging Face. The first step will be walking through how to populate your Weaviate Cloud collections. - -- [**E-commerce:**](https://huggingface.co/datasets/weaviate/agents/viewer/query-agent-ecommerce) A dataset that lists clothing items, prices, brands, reviews etc. -- [**Brands:**](https://huggingface.co/datasets/weaviate/agents/viewer/query-agent-brands) A dataset that lists clothing brands and information about them such as their parent brand, child brands, average customer rating etc. - -Additionally, we also have access to some other unrelated datasets which you can use to add more capabilities and variety to other agents later on in the recipe: - -- [**Financial Contracts**:](https://huggingface.co/datasets/weaviate/agents/viewer/query-agent-financial-contracts) A dataset of financial contracts between indivicuals and/or companies, as well as information on the type of contract and who has authored them. -- [**Weather**:](https://huggingface.co/datasets/weaviate/agents/viewer/query-agent-weather) Daily weather information including temperature, wind speed, percipitation, pressure etc. - -## 1. Setting Up Weaviate & Importing Data - -To use the Weaviate Query Agent, first, create a [Weaviate Cloud](https://weaviate.io/deployment/serverless) account👇 -1. [Create Serverless Weaviate Cloud account](https://weaviate.io/deployment/serverless) and setup a free [Sandbox](https://docs.weaviate.io/cloud/manage-clusters/create#sandbox-clusters) -2. Go to 'Embedding' and enable it, by default, this will make it so that we use `Snowflake/snowflake-arctic-embed-l-v2.0` as the embedding model -3. Take note of the `WEAVIATE_URL` and `WEAVIATE_API_KEY` to connect to your cluster below - -> Info: We recommend using [Weaviate Embeddings](https://docs.weaviate.io/weaviate/model-providers/weaviate) so you do not have to provide any extra keys for external embedding providers. - -```python -!pip install "weaviate-client[agents]" datasets -``` - -```python -import os -from getpass import getpass - -if "WEAVIATE_API_KEY" not in os.environ: - os.environ["WEAVIATE_API_KEY"] = getpass("Weaviate API Key") -if "WEAVIATE_URL" not in os.environ: - os.environ["WEAVIATE_URL"] = getpass("Weaviate URL") -``` - -```python -import weaviate -from weaviate.auth import Auth - -client = weaviate.connect_to_weaviate_cloud( - cluster_url=os.environ.get("WEAVIATE_URL"), - auth_credentials=Auth.api_key(os.environ.get("WEAVIATE_API_KEY")), -) -``` - -### Prepare the Collections - -In the following code blocks, we are pulling our demo datasets from Hugging Face and writing them to new collections in our Weaviate Serverless cluster. - -> ❗️ The `QueryAgent` uses the descriptions of collections and properties to decide which ones to use when solving queries, and to access more information about properties. You can experiment with changing these descriptions, providing more detail, and more. It's good practice to provide property descriptions too. For example, below we make sure that the `QueryAgent` knows that prices are all in USD, which is information that would otherwise be unavailable. - -```python -from weaviate.classes.config import Configure, Property, DataType - -# To re-run cell you may have to delete collections -# client.collections.delete("Brands") -client.collections.create( - "Brands", - description="A dataset that lists information about clothing brands, their parent companies, average rating and more.", - vector_config=Configure.Vectors.text2vec_weaviate() -) - -# client.collections.delete("Ecommerce") -client.collections.create( - "Ecommerce", - description="A dataset that lists clothing items, their brands, prices, and more.", - vector_config=Configure.Vectors.text2vec_weaviate(), - properties=[ - Property(name="collection", data_type=DataType.TEXT), - Property(name="category", data_type=DataType.TEXT), - Property(name="tags", data_type=DataType.TEXT_ARRAY), - Property(name="subcategory", data_type=DataType.TEXT), - Property(name="name", data_type=DataType.TEXT), - Property(name="description", data_type=DataType.TEXT), - Property(name="brand", data_type=DataType.TEXT), - Property(name="product_id", data_type=DataType.UUID), - Property(name="colors", data_type=DataType.TEXT_ARRAY), - Property(name="reviews", data_type=DataType.TEXT_ARRAY), - Property(name="image_url", data_type=DataType.TEXT), - Property(name="price", data_type=DataType.NUMBER, description="price of item in USD"), - ] -) - -# client.collections.delete("Weather") -client.collections.create( - "Weather", - description="Daily weather information including temperature, wind speed, percipitation, pressure etc.", - vector_config=Configure.Vectors.text2vec_weaviate(), - properties=[ - Property(name="date", data_type=DataType.DATE), - Property(name="humidity", data_type=DataType.NUMBER), - Property(name="precipitation", data_type=DataType.NUMBER), - Property(name="wind_speed", data_type=DataType.NUMBER), - Property(name="visibility", data_type=DataType.NUMBER), - Property(name="pressure", data_type=DataType.NUMBER), - Property(name="temperature", data_type=DataType.NUMBER, description="temperature value in Celsius") - ] -) - -# client.collections.delete("Financial_contracts") -client.collections.create( - "Financial_contracts", - description="A dataset of financial contracts between indivicuals and/or companies, as well as information on the type of contract and who has authored them.", - vector_config=Configure.Vectors.text2vec_weaviate(), -) -``` - -```python -from datasets import load_dataset - -brands_dataset = load_dataset("weaviate/agents", "query-agent-brands", split="train", streaming=True) -ecommerce_dataset = load_dataset("weaviate/agents", "query-agent-ecommerce", split="train", streaming=True) -weather_dataset = load_dataset("weaviate/agents", "query-agent-weather", split="train", streaming=True) -financial_dataset = load_dataset("weaviate/agents", "query-agent-financial-contracts", split="train", streaming=True) - -brands_collection = client.collections.use("Brands") -ecommerce_collection = client.collections.use("Ecommerce") -weather_collection = client.collections.use("Weather") -financial_collection = client.collections.use("Financial_contracts") - -with brands_collection.batch.dynamic() as batch: - for item in brands_dataset: - batch.add_object(properties=item["properties"]) - -with ecommerce_collection.batch.dynamic() as batch: - for item in ecommerce_dataset: - batch.add_object(properties=item["properties"]) - -with weather_collection.batch.dynamic() as batch: - for item in weather_dataset: - batch.add_object(properties=item["properties"]) - -with financial_collection.batch.dynamic() as batch: - for item in financial_dataset: - batch.add_object(properties=item["properties"]) -``` - -## 2. Set Up the Query Agent - -When setting up the query agent, we have to provide it a few things: -- The `client` -- The `collection` which we want the agent to have access to. -- (Optionally) A `system_prompt` that describes how our agent should behave -- (Optionally) Timeout - which for now defaults to 60s. - -Let's start with a simple agent. Here, we're creating an `agent` that has access to our `Brands` & `Ecommerce` datasets. - -```python -from weaviate.agents.query import QueryAgent - -agent = QueryAgent( - client=client, collections=["Ecommerce", "Brands"], -) -``` - -## 3. Run the Query Agent - -When we run the agent, it will first make a few decisions, depending on the query: - -1. The agent will decide which collection or collections to look up an answer in. -2. The agent will also decide whether to perform a regular ***search query***, what ***filters*** to use, whether to do an ***aggregation query***, or all of them together! -3. It will then provide a reponse within **`QueryAgentResponse`**. We will use the `print_query_agent_response` function for a nice display of various information provided in the response object. - -### Ask a Question -**Let's start with a simple question: "I like the vintage clothes, can you list me some options that are less than $200?"** - -We can then also inspect how the agent responded, what kind of searches it performed on which collections, whether it has identified if the final answer is missing information or not, as well as the final answer 👇 - -```python -from weaviate.agents.utils import print_query_agent_response - -response = agent.run("I like the vintage clothes, can you list me some options that are less than $200?") -print_query_agent_response(response) -``` - -
╭─────────────────────────────────────────────── 🔍 Original Query ───────────────────────────────────────────────╮
-│                                                                                                                 │
-│ I like the vintage clothes, can you list me some options that are less than $200?                               │
-│                                                                                                                 │
-╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
- -
╭──────────────────────────────────────────────── 📝 Final Answer ────────────────────────────────────────────────╮
-│                                                                                                                 │
-│ If you are looking for vintage clothing options under $200, here are some great choices:                        │
-│                                                                                                                 │
-│ 1. **Vintage Philosopher Midi Dress** - Priced at $125, this dress from Echo & Stitch embraces a classic        │
-│ scholarly look with its deep green velvet fabric and antique gold detailing. It's tailored for elegance and is  │
-│ ideal for sophisticated occasions.                                                                              │
-│                                                                                                                 │
-│ 2. **Vintage Gale Pleated Dress** - This $120 dress from Solemn Chic features deep burgundy pleats and          │
-│ vintage-inspired sleeve details, perfect for a timeless scholarly appearance.                                   │
-│                                                                                                                 │
-│ 3. **Retro Groove Flared Pants** - For $59, these electric blue flared pants from Vivid Verse bring back the    │
-│ playful spirit of the early 2000s with a modern touch.                                                          │
-│                                                                                                                 │
-│ 4. **Vintage Scholar Tote** - At $90, this tote from Echo & Stitch combines functionality and elegance, ideal   │
-│ for everyday use, especially if you enjoy a scholarly aesthetic.                                                │
-│                                                                                                                 │
-│ 5. **Electric Velvet Trousers** - Priced at $60, these neon green velvet trousers from Vivid Verse offer a fun, │
-│ throwback vibe to early Y2K fashion.                                                                            │
-│                                                                                                                 │
-│ 6. **Victorian Velvet Jumpsuit** - For $120, this jumpsuit from Solemn Chic offers an elegant blend of romance  │
-│ and scholarly charm, suited for library visits or cultured gatherings.                                          │
-│                                                                                                                 │
-│ 7. **Vintage Scholar Turtleneck** - This $55 turtleneck from Echo & Stitch suits the Dark Academia vibe,        │
-│ perfect for layering or wearing alone.                                                                          │
-│                                                                                                                 │
-│ 8. **Vintage Ivy Loafers** - These $120 loafers from Solemn Chic offer timeless sophistication, with a deep     │
-│ burgundy finish that complements any vintage wardrobe.                                                          │
-│                                                                                                                 │
-│ These options cater to various preferences, from dresses and jumpsuits to pants and accessories, all capturing  │
-│ the vintage essence at an affordable price.                                                                     │
-│                                                                                                                 │
-╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
- -
╭─────────────────────────────────────────── 🔭 Searches Executed 1/1 ────────────────────────────────────────────╮
-│                                                                                                                 │
-│ QueryResultWithCollection(                                                                                      │
-│     queries=['vintage clothes'],                                                                                │
-│     filters=[                                                                                                   │
-│         [                                                                                                       │
-│             IntegerPropertyFilter(                                                                              │
-│                 property_name='price',                                                                          │
-│                 operator=<ComparisonOperator.LESS_THAN: '<'>,                                                   │
-│                 value=200.0                                                                                     │
-│             )                                                                                                   │
-│         ]                                                                                                       │
-│     ],                                                                                                          │
-│     filter_operators='AND',                                                                                     │
-│     collection='Ecommerce'                                                                                      │
-│ )                                                                                                               │
-│                                                                                                                 │
-╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
- -
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
-│                                                                                                                 │
-│ 📊 No Aggregations Run                                                                                          │
-│                                                                                                                 │
-╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
- -
╭────────────────────────────────────────────────── 📚 Sources ───────────────────────────────────────────────────╮
-│                                                                                                                 │
-│  - object_id='5e9c5298-5b3a-4d80-b226-64b2ff6689b7' collection='Ecommerce'                                      │
-│  - object_id='48896222-d098-42e6-80df-ad4b03723c19' collection='Ecommerce'                                      │
-│  - object_id='00b383ca-262f-4251-b513-dafd4862c021' collection='Ecommerce'                                      │
-│  - object_id='cbe8f8be-304b-409d-a2a1-bafa0bbf249c' collection='Ecommerce'                                      │
-│  - object_id='c18d3c5b-8fbe-4816-bc60-174f336a982f' collection='Ecommerce'                                      │
-│  - object_id='1811da1b-6930-4bd1-832e-f8fa2119d4df' collection='Ecommerce'                                      │
-│  - object_id='2edd1bc5-777e-4376-95cd-42a141ffb71e' collection='Ecommerce'                                      │
-│  - object_id='9819907c-1015-4b4c-ac75-3b3848e7c247' collection='Ecommerce'                                      │
-│                                                                                                                 │
-╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
- - - - -
   📊 Usage Statistics
-┌────────────────┬──────┐
-│ LLM Requests:  │ 3    │
-│ Input Tokens:  │ 7774 │
-│ Output Tokens: │ 512  │
-│ Total Tokens:  │ 8286 │
-└────────────────┴──────┘
- -
Total Time Taken: 16.93s
- -### Ask a follow up question - -The agent can also be provided with additional context. For example, we can provide the previous response as context and get a `new_response` - -```python -new_response = agent.run("What about some nice shoes, same budget as before?", context=response) -print_query_agent_response(new_response) -``` - -
╭─────────────────────────────────────────────── 🔍 Original Query ───────────────────────────────────────────────╮
-│                                                                                                                 │
-│ What about some nice shoes, same budget as before?                                                              │
-│                                                                                                                 │
-╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
- -
╭──────────────────────────────────────────────── 📝 Final Answer ────────────────────────────────────────────────╮
-│                                                                                                                 │
-│ Here are some great shoe options under $200 that you might like:                                                │
-│                                                                                                                 │
-│ 1. **Vintage Noir Loafers** - Priced at $125, these loafers are part of the Dark Academia collection by Solemn  │
-│ Chic. They come in black and grey, featuring a classic design with a modern twist. Reviews highlight their      │
-│ comfort and stylish appearance, making them suitable for both casual and formal settings.                       │
-│                                                                                                                 │
-│ 2. **Parchment Boots** - At $145, these boots from Nova Nest's Light Academia collection are noted for their    │
-│ elegant ivory leather and classical detail stitching. They are praised for their comfort and versatile style.   │
-│                                                                                                                 │
-│ 3. **Bramble Berry Loafers** - These loafers, priced at $75, come in pink and green and are marked by their     │
-│ eco-friendly material and countryside aesthetic. Produced by Eko & Stitch, they are loved for their comfort and │
-│ sustainability.                                                                                                 │
-│                                                                                                                 │
-│ 4. **Glide Platforms** - Available for $90 from the Y2K collection by Vivid Verse, these platform sneakers are  │
-│ both comfortable and stylish with a high-shine pink finish.                                                     │
-│                                                                                                                 │
-│ 5. **Sky Shimmer Sneaks** - Costing $69, these sneakers are from the Y2K collection by Nova Nest and offer a    │
-│ comfortable fit with a touch of sparkle for style.                                                              │
-│                                                                                                                 │
-│ These selections offer a mix of formal and casual styles, ensuring you can find a perfect pair under your       │
-│ budget of $200.                                                                                                 │
-│                                                                                                                 │
-╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
- -
╭─────────────────────────────────────────── 🔭 Searches Executed 1/1 ────────────────────────────────────────────╮
-│                                                                                                                 │
-│ QueryResultWithCollection(                                                                                      │
-│     queries=['nice shoes'],                                                                                     │
-│     filters=[                                                                                                   │
-│         [                                                                                                       │
-│             IntegerPropertyFilter(                                                                              │
-│                 property_name='price',                                                                          │
-│                 operator=<ComparisonOperator.LESS_THAN: '<'>,                                                   │
-│                 value=200.0                                                                                     │
-│             )                                                                                                   │
-│         ]                                                                                                       │
-│     ],                                                                                                          │
-│     filter_operators='AND',                                                                                     │
-│     collection='Ecommerce'                                                                                      │
-│ )                                                                                                               │
-│                                                                                                                 │
-╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
- -
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
-│                                                                                                                 │
-│ 📊 No Aggregations Run                                                                                          │
-│                                                                                                                 │
-╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
- -
╭────────────────────────────────────────────────── 📚 Sources ───────────────────────────────────────────────────╮
-│                                                                                                                 │
-│  - object_id='96b30047-8ce1-4096-9bcf-009733cf8613' collection='Ecommerce'                                      │
-│  - object_id='61e4fcd7-d2bc-4861-beb6-4c16948d9921' collection='Ecommerce'                                      │
-│  - object_id='6e533f7d-eba1-4e74-953c-9d43008278e7' collection='Ecommerce'                                      │
-│  - object_id='f873ac48-1311-462a-86b2-a28b15fdda7a' collection='Ecommerce'                                      │
-│  - object_id='93b8b13e-a417-4be2-9cce-fda8c767f35e' collection='Ecommerce'                                      │
-│                                                                                                                 │
-╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
- - - - -
   📊 Usage Statistics
-┌────────────────┬───────┐
-│ LLM Requests:  │ 4     │
-│ Input Tokens:  │ 9783  │
-│ Output Tokens: │ 574   │
-│ Total Tokens:  │ 10357 │
-└────────────────┴───────┘
- -
Total Time Taken: 18.02s
- -Now let's try a question that sholud require an aggregation. Let's see which brand lists the most shoes. - -```python -response = agent.run("What is the the name of the brand that lists the most shoes?") -print_query_agent_response(response) -``` - -
╭─────────────────────────────────────────────── 🔍 Original Query ───────────────────────────────────────────────╮
-│                                                                                                                 │
-│ What is the the name of the brand that lists the most shoes?                                                    │
-│                                                                                                                 │
-╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
- -
╭──────────────────────────────────────────────── 📝 Final Answer ────────────────────────────────────────────────╮
-│                                                                                                                 │
-│ The brand that lists the most shoes is Loom & Aura with a total of 118 shoe listings.                           │
-│                                                                                                                 │
-╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
- -
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
-│                                                                                                                 │
-│ 🔭 No Searches Run                                                                                              │
-│                                                                                                                 │
-╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
- -
╭──────────────────────────────────────────── 📊 Aggregations Run 1/1 ────────────────────────────────────────────╮
-│                                                                                                                 │
-│ AggregationResultWithCollection(                                                                                │
-│     search_query=None,                                                                                          │
-│     groupby_property='brand',                                                                                   │
-│     aggregations=[                                                                                              │
-│         IntegerPropertyAggregation(property_name='collection', metrics=<NumericMetrics.COUNT: 'COUNT'>)         │
-│     ],                                                                                                          │
-│     filters=[],                                                                                                 │
-│     collection='Ecommerce'                                                                                      │
-│ )                                                                                                               │
-│                                                                                                                 │
-╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
- - - - -
   📊 Usage Statistics
-┌────────────────┬──────┐
-│ LLM Requests:  │ 3    │
-│ Input Tokens:  │ 3976 │
-│ Output Tokens: │ 159  │
-│ Total Tokens:  │ 4135 │
-└────────────────┴──────┘
- -
Total Time Taken: 5.33s
- -### Search over multiple collections - -In some cases, we need to combine the results of searches across multiple collections. From the result above, we can see that "Loom & Aura" lists the most shoes. - -Let's imagine a scenario where the user would now want to find out more about this company, _as well_ as the items that they sell. - -```python -response = agent.run("Does the brand 'Loom & Aura' have a parent brand or child brands and what countries do they operate from? " - "Also, what's the average price of a item from 'Loom & Aura'?") - -print_query_agent_response(response) -``` - -
╭─────────────────────────────────────────────── 🔍 Original Query ───────────────────────────────────────────────╮
-│                                                                                                                 │
-│ Does the brand 'Loom & Aura' have a parent brand or child brands and what countries do they operate from? Also, │
-│ what's the average price of a item from 'Loom & Aura'?                                                          │
-│                                                                                                                 │
-╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
- -
╭──────────────────────────────────────────────── 📝 Final Answer ────────────────────────────────────────────────╮
-│                                                                                                                 │
-│ Loom & Aura is itself a well-established brand based in Italy and operates as the parent brand to several child │
-│ brands. These child brands include 'Loom & Aura Active', 'Loom & Aura Kids', 'Nova Nest', 'Vivid Verse', 'Loom  │
-│ Luxe', 'Saffron Sage', 'Stellar Stitch', 'Nova Nectar', 'Canvas Core', and 'Loom Lure'. The countries           │
-│ associated with the operations or origins of these child brands include Italy, USA, UK, Spain, South Korea,     │
-│ Japan, and some extend beyond Italy as suggested by the presence of these brands in different countries.        │
-│                                                                                                                 │
-│ The average price of an item from Loom & Aura is approximately $87.11. This reflects the brand's positioning as │
-│ offering items of timeless elegance and quality craftsmanship.                                                  │
-│                                                                                                                 │
-╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
- -
╭─────────────────────────────────────────── 🔭 Searches Executed 1/2 ────────────────────────────────────────────╮
-│                                                                                                                 │
-│ QueryResultWithCollection(                                                                                      │
-│     queries=['parent brand of Loom & Aura', 'child brands of Loom & Aura'],                                     │
-│     filters=[[], []],                                                                                           │
-│     filter_operators='AND',                                                                                     │
-│     collection='Brands'                                                                                         │
-│ )                                                                                                               │
-│                                                                                                                 │
-╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
- -
╭─────────────────────────────────────────── 🔭 Searches Executed 2/2 ────────────────────────────────────────────╮
-│                                                                                                                 │
-│ QueryResultWithCollection(                                                                                      │
-│     queries=['Loom & Aura'],                                                                                    │
-│     filters=[                                                                                                   │
-│         [                                                                                                       │
-│             TextPropertyFilter(                                                                                 │
-│                 property_name='name',                                                                           │
-│                 operator=<ComparisonOperator.LIKE: 'LIKE'>,                                                     │
-│                 value='Loom & Aura'                                                                             │
-│             )                                                                                                   │
-│         ]                                                                                                       │
-│     ],                                                                                                          │
-│     filter_operators='AND',                                                                                     │
-│     collection='Brands'                                                                                         │
-│ )                                                                                                               │
-│                                                                                                                 │
-╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
- -
╭──────────────────────────────────────────── 📊 Aggregations Run 1/1 ────────────────────────────────────────────╮
-│                                                                                                                 │
-│ AggregationResultWithCollection(                                                                                │
-│     search_query=None,                                                                                          │
-│     groupby_property=None,                                                                                      │
-│     aggregations=[IntegerPropertyAggregation(property_name='price', metrics=<NumericMetrics.MEAN: 'MEAN'>)],    │
-│     filters=[                                                                                                   │
-│         TextPropertyFilter(                                                                                     │
-│             property_name='brand',                                                                              │
-│             operator=<ComparisonOperator.EQUALS: '='>,                                                          │
-│             value='Loom & Aura'                                                                                 │
-│         )                                                                                                       │
-│     ],                                                                                                          │
-│     collection='Ecommerce'                                                                                      │
-│ )                                                                                                               │
-│                                                                                                                 │
-╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
- -
╭────────────────────────────────────────────────── 📚 Sources ───────────────────────────────────────────────────╮
-│                                                                                                                 │
-│  - object_id='88433e18-216d-489a-8719-81a29b0ae915' collection='Brands'                                         │
-│  - object_id='99f42d07-51e9-4388-9c4b-63eb8f79f5fd' collection='Brands'                                         │
-│  - object_id='0852c2a4-0c5a-4c69-9762-1be10bc44f2b' collection='Brands'                                         │
-│  - object_id='d172a342-da41-45c3-876e-d08db843b8b3' collection='Brands'                                         │
-│  - object_id='a7ad0ed7-812e-4106-a29f-40442c3a106e' collection='Brands'                                         │
-│  - object_id='b6abfa02-18e5-44cf-a002-ba140e3623ad' collection='Brands'                                         │
-│                                                                                                                 │
-╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
- - - - -
   📊 Usage Statistics
-┌────────────────┬───────┐
-│ LLM Requests:  │ 5     │
-│ Input Tokens:  │ 9728  │
-│ Output Tokens: │ 479   │
-│ Total Tokens:  │ 10207 │
-└────────────────┴───────┘
- -
Total Time Taken: 11.38s
- -### Changing the System Prompt - -In some cases, you may want to define a custom `system_prompt` for your agent. This can help you provide the agent with some default instructions as to how to behave. For example, let's create an agent that will always answer the query in the users language. - -Let's also create a `QueryAgent` that has access to two more collections, `Financial_contracts` and `Weather`. Next, you can try out more queries yourself! - -```python -multi_lingual_agent = QueryAgent( - client=client, collections=["Ecommerce", "Brands", "Financial_contracts", "Weather"], - system_prompt="You are a helpful assistant that always generated the final response in the users language." - " You may have to translate the user query to perform searches. But you must always respond to the user in their own language." -) -``` - -For example, this time lets ask something that is about weather! - -```python -response = multi_lingual_agent.run("Quelles sont les vitesses minimales, maximales et moyennes du vent?") -print(response.final_answer) -``` - -Python output: -```text -Les vitesses de vent minimales, maximales et moyennes sont respectivement de 8,40 km/h, 94,88 km/h et 49,37 km/h. Ces données offrent une vue d'ensemble des conditions de vent typiques mesurées dans une période ou un lieu donné. -``` -### Try More Questions - -For example Let's try to find out more about the brans "Eko & Stitch" - -```python -response = multi_lingual_agent.run("Does Eko & Stitch have a branch in the UK? Or if not, does it have parent or child company in the UK?") - -print(response.final_answer) -``` - -Python output: -```text -Yes, Eko & Stitch has a branch in the UK. The brand is part of the broader company Nova Nest, which serves as Eko & Stitch's parent brand. Eko & Stitch itself operates in the UK and has its child brands, Eko & Stitch Active and Eko & Stitch Kids, also within the UK. -``` -Our `multi_lingual_agent` also has access to a collection called "Financial_contracts". Let's try to find out some more information about this dataser. - -```python -response = multi_lingual_agent.run("What kinds of contracts are listed? What's the most common type of contract?") - -print(response.final_answer) -``` - -Python output: -```text -The query seeks to identify the types of contracts listed and determine the most common type. Among the types of contracts provided in the results, the following were identified: employment contracts, sales agreements, invoice contracts, service agreements, and lease agreements. The most common type of contract found in the search results is the employment contract. However, when considering data from both search and aggregation results, the aggregation reveals that the invoice contract is the most common, followed by service agreements and lease agreements. While employment contracts appear frequently in the search results, they rank fourth in the aggregation data in terms of overall occurrences. -``` diff --git a/docs/agents/recipes/transformation-agent-get-started.md b/docs/agents/recipes/transformation-agent-get-started.md deleted file mode 100644 index a0cde7e00..000000000 --- a/docs/agents/recipes/transformation-agent-get-started.md +++ /dev/null @@ -1,345 +0,0 @@ ---- -layout: recipe -colab: https://colab.research.google.com/github/weaviate/recipes/blob/main/weaviate-services/agents/transformation-agent-get-started.ipynb -toc: True -title: "Build A Weaviate Transformation Agent" -featured: True -integration: False -agent: True -tags: ['Transformation Agent'] ---- - - Open In Google Colab - - -In this recipe, we will use a Weaviate [`TransformationAgent`](https://docs.weaviate.io/agents/transformation) to enhance our data in Weaviate. We will build an agent that has access to a collection containing a bunch or research papers, their abstracts and titles. We will then use the agent to create additional properties for eaach of our objects in the collection. - -> ⚠️ The Weaviate Transformation Agent is designed to modify data in Weaviate in place. **While the Agent is in technical preview, do not use it in a production environment.** The Agent may not work as expected, and the data in your Weaviate instance may be affected in unexpected ways. - -The `TransformationAgent` is able to access a Weaviate collection of your chosing, and perform operations on the objects within it. However, each operation for the agent can be defined in natural language. The agent will then use an LLM to complete the instructions in the operation. - -> 📚 You can learn more about the new `TransformationAgent`, you can read our accompanyin ["Introducing the Weaviate Transformation Agent"](https://weaviate.io/blog/transformation-agent) blog - -To get started, we've prepared an open datasets, available on Hugging Face. The first step will be walking through how to populate your Weaviate Cloud collections. - -- [**ArxivPapers:**](https://huggingface.co/datasets/weaviate/agents/viewer/query-agent-ecommerce) A dataset that lists titles and abstracts of research papers. - -If you'd like to try out building more agents with different datasets, check out the list of demo datasets we have available on [Hugging Face Weaviate agents dataset](https://huggingface.co/datasets/weaviate/agents) - -## Setting Up Weaviate & Importing Data - -To use the Weaviate Transformation Agent, first, create a [Weaviate Cloud](https://weaviate.io/deployment/serverless) account👇 -1. [Create Serverless Weaviate Cloud account](https://weaviate.io/deployment/serverless) and setup a free [Sandbox](https://docs.weaviate.io/cloud/manage-clusters/create#sandbox-clusters) -2. Go to 'Embedding' and enable it, by default, this will make it so that we use `Snowflake/snowflake-arctic-embed-l-v2.0` as the embedding model -3. Take note of the `WEAVIATE_URL` and `WEAVIATE_API_KEY` to connect to your cluster below - -> Info: We recommend using [Weaviate Embeddings](https://docs.weaviate.io/weaviate/model-providers/weaviate) so you do not have to provide any extra keys for external embedding providers. - -```python -!pip install "weaviate-client[agents]" datasets -!pip install -U weaviate-agents -``` - -Python output: -```text -/Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/pty.py:95: DeprecationWarning: This process (pid=93073) is multi-threaded, use of forkpty() may lead to deadlocks in the child. - pid, fd = os.forkpty() - -Collecting datasets - Using cached datasets-3.3.2-py3-none-any.whl.metadata (19 kB) -Requirement already satisfied: weaviate-client[agents] in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (4.11.1) -Requirement already satisfied: httpx<0.29.0,>=0.26.0 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from weaviate-client[agents]) (0.27.0) -Requirement already satisfied: validators==0.34.0 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from weaviate-client[agents]) (0.34.0) -Requirement already satisfied: authlib<1.3.2,>=1.2.1 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from weaviate-client[agents]) (1.3.1) -Requirement already satisfied: pydantic<3.0.0,>=2.8.0 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from weaviate-client[agents]) (2.10.5) -Requirement already satisfied: grpcio<2.0.0,>=1.66.2 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from weaviate-client[agents]) (1.69.0) -Requirement already satisfied: grpcio-tools<2.0.0,>=1.66.2 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from weaviate-client[agents]) (1.69.0) -Requirement already satisfied: grpcio-health-checking<2.0.0,>=1.66.2 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from weaviate-client[agents]) (1.69.0) -Requirement already satisfied: weaviate-agents<1.0.0,>=0.3.0 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from weaviate-client[agents]) (0.4.0) -Requirement already satisfied: filelock in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from datasets) (3.17.0) -Requirement already satisfied: numpy>=1.17 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from datasets) (2.2.2) -Collecting pyarrow>=15.0.0 (from datasets) - Using cached pyarrow-19.0.1-cp313-cp313-macosx_12_0_arm64.whl.metadata (3.3 kB) -Collecting dill<0.3.9,>=0.3.0 (from datasets) - Using cached dill-0.3.8-py3-none-any.whl.metadata (10 kB) -Requirement already satisfied: pandas in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from datasets) (2.2.3) -Requirement already satisfied: requests>=2.32.2 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from datasets) (2.32.3) -Requirement already satisfied: tqdm>=4.66.3 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from datasets) (4.67.1) -Collecting xxhash (from datasets) - Using cached xxhash-3.5.0-cp313-cp313-macosx_11_0_arm64.whl.metadata (12 kB) -Collecting multiprocess<0.70.17 (from datasets) - Using cached multiprocess-0.70.16-py312-none-any.whl.metadata (7.2 kB) -Requirement already satisfied: fsspec<=2024.12.0,>=2023.1.0 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from fsspec[http]<=2024.12.0,>=2023.1.0->datasets) (2024.12.0) -Requirement already satisfied: aiohttp in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from datasets) (3.11.11) -Requirement already satisfied: huggingface-hub>=0.24.0 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from datasets) (0.27.1) -Requirement already satisfied: packaging in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from datasets) (24.2) -Requirement already satisfied: pyyaml>=5.1 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from datasets) (6.0.2) -Requirement already satisfied: cryptography in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from authlib<1.3.2,>=1.2.1->weaviate-client[agents]) (44.0.0) -Requirement already satisfied: aiohappyeyeballs>=2.3.0 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from aiohttp->datasets) (2.4.4) -Requirement already satisfied: aiosignal>=1.1.2 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from aiohttp->datasets) (1.3.2) -Requirement already satisfied: attrs>=17.3.0 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from aiohttp->datasets) (24.3.0) -Requirement already satisfied: frozenlist>=1.1.1 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from aiohttp->datasets) (1.5.0) -Requirement already satisfied: multidict<7.0,>=4.5 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from aiohttp->datasets) (6.1.0) -Requirement already satisfied: propcache>=0.2.0 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from aiohttp->datasets) (0.2.1) -Requirement already satisfied: yarl<2.0,>=1.17.0 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from aiohttp->datasets) (1.18.3) -Requirement already satisfied: protobuf<6.0dev,>=5.26.1 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from grpcio-health-checking<2.0.0,>=1.66.2->weaviate-client[agents]) (5.29.3) -Requirement already satisfied: setuptools in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from grpcio-tools<2.0.0,>=1.66.2->weaviate-client[agents]) (75.1.0) -Requirement already satisfied: anyio in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from httpx<0.29.0,>=0.26.0->weaviate-client[agents]) (4.8.0) -Requirement already satisfied: certifi in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from httpx<0.29.0,>=0.26.0->weaviate-client[agents]) (2024.12.14) -Requirement already satisfied: httpcore==1.* in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from httpx<0.29.0,>=0.26.0->weaviate-client[agents]) (1.0.7) -Requirement already satisfied: idna in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from httpx<0.29.0,>=0.26.0->weaviate-client[agents]) (3.10) -Requirement already satisfied: sniffio in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from httpx<0.29.0,>=0.26.0->weaviate-client[agents]) (1.3.1) -Requirement already satisfied: h11<0.15,>=0.13 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from httpcore==1.*->httpx<0.29.0,>=0.26.0->weaviate-client[agents]) (0.14.0) -Requirement already satisfied: typing-extensions>=3.7.4.3 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from huggingface-hub>=0.24.0->datasets) (4.12.2) -Requirement already satisfied: annotated-types>=0.6.0 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from pydantic<3.0.0,>=2.8.0->weaviate-client[agents]) (0.7.0) -Requirement already satisfied: pydantic-core==2.27.2 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from pydantic<3.0.0,>=2.8.0->weaviate-client[agents]) (2.27.2) -Requirement already satisfied: charset-normalizer<4,>=2 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from requests>=2.32.2->datasets) (3.4.1) -Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from requests>=2.32.2->datasets) (2.3.0) -Requirement already satisfied: rich>=13.9.4 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from weaviate-agents<1.0.0,>=0.3.0->weaviate-client[agents]) (13.9.4) -Requirement already satisfied: python-dateutil>=2.8.2 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from pandas->datasets) (2.9.0.post0) -Requirement already satisfied: pytz>=2020.1 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from pandas->datasets) (2024.2) -Requirement already satisfied: tzdata>=2022.7 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from pandas->datasets) (2025.1) -Requirement already satisfied: six>=1.5 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from python-dateutil>=2.8.2->pandas->datasets) (1.17.0) -Requirement already satisfied: markdown-it-py>=2.2.0 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from rich>=13.9.4->weaviate-agents<1.0.0,>=0.3.0->weaviate-client[agents]) (3.0.0) -Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from rich>=13.9.4->weaviate-agents<1.0.0,>=0.3.0->weaviate-client[agents]) (2.19.1) -Requirement already satisfied: cffi>=1.12 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from cryptography->authlib<1.3.2,>=1.2.1->weaviate-client[agents]) (1.17.1) -Requirement already satisfied: pycparser in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from cffi>=1.12->cryptography->authlib<1.3.2,>=1.2.1->weaviate-client[agents]) (2.22) -Requirement already satisfied: mdurl~=0.1 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from markdown-it-py>=2.2.0->rich>=13.9.4->weaviate-agents<1.0.0,>=0.3.0->weaviate-client[agents]) (0.1.2) -Using cached datasets-3.3.2-py3-none-any.whl (485 kB) -Using cached dill-0.3.8-py3-none-any.whl (116 kB) -Using cached multiprocess-0.70.16-py312-none-any.whl (146 kB) -Using cached pyarrow-19.0.1-cp313-cp313-macosx_12_0_arm64.whl (30.7 MB) -Using cached xxhash-3.5.0-cp313-cp313-macosx_11_0_arm64.whl (30 kB) -Installing collected packages: xxhash, pyarrow, dill, multiprocess, datasets -Successfully installed datasets-3.3.2 dill-0.3.8 multiprocess-0.70.16 pyarrow-19.0.1 xxhash-3.5.0 -Requirement already satisfied: weaviate-agents in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (0.4.0) -Requirement already satisfied: rich>=13.9.4 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from weaviate-agents) (13.9.4) -Requirement already satisfied: weaviate-client>=4.11.0 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from weaviate-agents) (4.11.1) -Requirement already satisfied: markdown-it-py>=2.2.0 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from rich>=13.9.4->weaviate-agents) (3.0.0) -Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from rich>=13.9.4->weaviate-agents) (2.19.1) -Requirement already satisfied: httpx<0.29.0,>=0.26.0 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from weaviate-client>=4.11.0->weaviate-agents) (0.27.0) -Requirement already satisfied: validators==0.34.0 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from weaviate-client>=4.11.0->weaviate-agents) (0.34.0) -Requirement already satisfied: authlib<1.3.2,>=1.2.1 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from weaviate-client>=4.11.0->weaviate-agents) (1.3.1) -Requirement already satisfied: pydantic<3.0.0,>=2.8.0 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from weaviate-client>=4.11.0->weaviate-agents) (2.10.5) -Requirement already satisfied: grpcio<2.0.0,>=1.66.2 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from weaviate-client>=4.11.0->weaviate-agents) (1.69.0) -Requirement already satisfied: grpcio-tools<2.0.0,>=1.66.2 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from weaviate-client>=4.11.0->weaviate-agents) (1.69.0) -Requirement already satisfied: grpcio-health-checking<2.0.0,>=1.66.2 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from weaviate-client>=4.11.0->weaviate-agents) (1.69.0) -Requirement already satisfied: cryptography in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from authlib<1.3.2,>=1.2.1->weaviate-client>=4.11.0->weaviate-agents) (44.0.0) -Requirement already satisfied: protobuf<6.0dev,>=5.26.1 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from grpcio-health-checking<2.0.0,>=1.66.2->weaviate-client>=4.11.0->weaviate-agents) (5.29.3) -Requirement already satisfied: setuptools in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from grpcio-tools<2.0.0,>=1.66.2->weaviate-client>=4.11.0->weaviate-agents) (75.1.0) -Requirement already satisfied: anyio in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from httpx<0.29.0,>=0.26.0->weaviate-client>=4.11.0->weaviate-agents) (4.8.0) -Requirement already satisfied: certifi in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from httpx<0.29.0,>=0.26.0->weaviate-client>=4.11.0->weaviate-agents) (2024.12.14) -Requirement already satisfied: httpcore==1.* in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from httpx<0.29.0,>=0.26.0->weaviate-client>=4.11.0->weaviate-agents) (1.0.7) -Requirement already satisfied: idna in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from httpx<0.29.0,>=0.26.0->weaviate-client>=4.11.0->weaviate-agents) (3.10) -Requirement already satisfied: sniffio in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from httpx<0.29.0,>=0.26.0->weaviate-client>=4.11.0->weaviate-agents) (1.3.1) -Requirement already satisfied: h11<0.15,>=0.13 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from httpcore==1.*->httpx<0.29.0,>=0.26.0->weaviate-client>=4.11.0->weaviate-agents) (0.14.0) -Requirement already satisfied: mdurl~=0.1 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from markdown-it-py>=2.2.0->rich>=13.9.4->weaviate-agents) (0.1.2) -Requirement already satisfied: annotated-types>=0.6.0 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from pydantic<3.0.0,>=2.8.0->weaviate-client>=4.11.0->weaviate-agents) (0.7.0) -Requirement already satisfied: pydantic-core==2.27.2 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from pydantic<3.0.0,>=2.8.0->weaviate-client>=4.11.0->weaviate-agents) (2.27.2) -Requirement already satisfied: typing-extensions>=4.12.2 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from pydantic<3.0.0,>=2.8.0->weaviate-client>=4.11.0->weaviate-agents) (4.12.2) -Requirement already satisfied: cffi>=1.12 in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from cryptography->authlib<1.3.2,>=1.2.1->weaviate-client>=4.11.0->weaviate-agents) (1.17.1) -Requirement already satisfied: pycparser in /Users/tuanacelik/miniconda3/envs/agent/lib/python3.13/site-packages (from cffi>=1.12->cryptography->authlib<1.3.2,>=1.2.1->weaviate-client>=4.11.0->weaviate-agents) (2.22) -``` -```python -import os -from getpass import getpass - -if "WEAVIATE_API_KEY" not in os.environ: - os.environ["WEAVIATE_API_KEY"] = getpass("Weaviate API Key") -if "WEAVIATE_URL" not in os.environ: - os.environ["WEAVIATE_URL"] = getpass("Weaviate URL") -``` - -```python -import weaviate -from weaviate.auth import Auth - -client = weaviate.connect_to_weaviate_cloud( - cluster_url=os.environ.get("WEAVIATE_URL"), - auth_credentials=Auth.api_key(os.environ.get("WEAVIATE_API_KEY")), -) -``` - -### Prepare the Collections - -In the following code block, we are pulling our demo "papers" datasets from Hugging Face and writing them to a new collection in our Weaviate Serverless cluster. - -**Important:** Please enable 'Embeddings' in the Weavaite Cloud console. This way, you can use the `text2vec_weaviate` vectorizer, which will create vectors for each object using `Snowflake/snowflake-arctic-embed-l-v2.0` by default. - -```python -from weaviate.classes.config import Configure - -# To re-run cell you may have to delete collections -# client.collections.delete("ArxivPapers") -client.collections.create( - "ArxivPapers", - description="A dataset that lists research paper titles and abstracts", - vector_config=Configure.Vectors.text2vec_weaviate() -) - -``` - -Python output: -```text - -``` -```python -from datasets import load_dataset - -dataset = load_dataset("weaviate/agents", "transformation-agent-papers", split="train", streaming=True) - -papers_collection = client.collections.use("ArxivPapers") - -with papers_collection.batch.dynamic() as batch: - for i, item in enumerate(dataset): - if i < 200: - batch.add_object(properties=item["properties"]) -``` - -### Inspect the Collection in Explorer - -The `TransformationAgent` will modify the collection as we go along. This is a good time to take a look at the contents of your "ArxivPapers" collection. You can inspect the data in the Explorer tool in the Weaviate Cloud Console. If all goes well, you should be seeing 2 properties listed for each object: -- `title`: the title of the paper. -- `abstract`: the abstract of the paper. - -As well as the `vectors` for each object. - -## Define Transformation Operations - -The star of the show for the `TransformationAgent` are the operations. - -We can now define transformation operations which we want to perform on our collection. An operation can be: - -- Appending a new property -- Updating an existing property - -Currently, the `TransformationAgent` supports operations that update existing objects in Weaviate. - -### Append New Properties - -To append a new property, we define an operation with: -- **`instrcution`**: This is where you can describe, in natural language, what you want this new property to be. -- **`property_name`**: The name you want the property to have -- **`data_type`**: The specific datatype the property should be. E.g.: `DataType.TEXT`, `DataType.TEXT_ARRAY`, `DataType.BOOL`, `DataType.INT` etc. -- **`view_properties`**: Sometimes, you may want to create properties that are based on information provided in other properties, this is where you can list out which properties the instruction should view. - -#### Create a List of Topics - -First, let's append a new property called "topics", which should be a `TEXT_ARRAY`. Based on the "abstract" and "title", let's ask for the LLM to extract a list of topic tags. We can be specific here. Let's ask for no more than 5 - -```python -from weaviate.agents.classes import Operations -from weaviate.classes.config import DataType - -add_topics = Operations.append_property( - property_name="topics", - data_type=DataType.TEXT_ARRAY, - view_properties=["abstract"], - instruction="""Create a list of topic tags based on the abstract. - Topics should be distinct from eachother. Provide a maximum of 5 topics. - Group similar topics under one topic tag.""", -) - -``` - -#### Add a French Translation - -Next, let's add a new "french_abstract" property which is simply a translation of the "abstract" - -```python -add_french_abstract = Operations.append_property( - property_name="french_abstract", - data_type=DataType.TEXT, - view_properties=["abstract"], - instruction="Translate the abstract to French", -) -``` - -#### Update the Title - -This time, we are updating the `title` property to include the French translation of itself in parantheses. - -```python -update_title = Operations.update_property( - property_name="title", - view_properties=["title"], - instruction="""Update the title to ensure that it contains the French translation of itself in parantheses, after the original title.""", -) -``` - -#### Determine If It's a Survey Paper - -Finally, let's ask for a `BOOL` property which indicates whether the paper is a survey or not. I.e., we'll ask the LLM to determine if the paper presents novel techniques, or whether it's a survey of existing ones. - -```python -is_survey_paper = Operations.append_property( - property_name="is_survey_paper", - data_type=DataType.BOOL, - view_properties=["abstract"], - instruction="""Determine if the paper is a "survey". - A paper is considered survey it's a surveys existing techniques, and not if it presents novel techniques""", -) -``` - -## Create & Run the Transformation Agent - -Once we have all of our operations defined, we can initialize a `TransformationAgent`. - -When initializing the agent, we have to decide which `collection` it may have accesss to modify. In this case, we want it to have access to the "ArxivPapers" collection we previously created. - -Next, we need to provide a list of `operations` which the agent should run. Here, we provide all the operations we defined above. - -> Note: We are working on resolving a known issue which can result in data consistency issues when multiple operations act on the same object at once. - -```python -from weaviate.agents.transformation import TransformationAgent - -agent = TransformationAgent( - client=client, - collection="ArxivPapers", - operations=[ - add_topics, - add_french_abstract, - is_survey_paper, - update_title, - ], -) -``` - -### Running the Transformations - -By calling `update_all()`, we get the agent to spin up individual workflows for each operation. Each operation will then run on each object in our collectoion. - -```python -response = agent.update_all() -``` - -### Inspect the Operation Workflows - -To inspect the status of our operations, we can take a look at the `workflow_id` in the returned `TransformationResponse`, and get their status with `agent.get_status(workflow_id)`. These operations are asynchronous. - -```python -response -``` - -Python output: -```text -[TransformationResponse(operation_name='topics', workflow_id='TransformationWorkflow-1766a450c35039c2a44e1fa33dc49dd4'), - TransformationResponse(operation_name='french_abstract', workflow_id='TransformationWorkflow-67e90d88830347a5581d3ee1aa10b867'), - TransformationResponse(operation_name='is_survey_paper', workflow_id='TransformationWorkflow-6294dd575fad55c318ee7b0e8a38a8ff'), - TransformationResponse(operation_name='title', workflow_id='TransformationWorkflow-bba64a5bf204b00c3572310de715d1e2')] -``` -```python -agent.get_status(workflow_id=response.workflow_id) -``` - -Python output: -```text -{'workflow_id': 'TransformationWorkflow-1766a450c35039c2a44e1fa33dc49dd4', - 'status': {'batch_count': 1, - 'end_time': '2025-03-11 14:58:57', - 'start_time': '2025-03-11 14:57:55', - 'state': 'completed', - 'total_duration': 62.56732, - 'total_items': 200}} -``` diff --git a/docs/agents/recipes/transformation-agent-retrieval-benchmark.md b/docs/agents/recipes/transformation-agent-retrieval-benchmark.md deleted file mode 100644 index bdbe74b13..000000000 --- a/docs/agents/recipes/transformation-agent-retrieval-benchmark.md +++ /dev/null @@ -1,507 +0,0 @@ ---- -layout: recipe -colab: https://colab.research.google.com/github/weaviate/recipes/blob/main/weaviate-services/agents/transformation-agent-retrieval-benchmark.ipynb -toc: True -title: "Benchmarking Arctic 2.0 vs. Arctic 1.5 with Synthetic RAG Evals" -featured: True -integration: False -agent: True -tags: ['Transformation Agent'] ---- - - Open In Google Colab - - -Traditionally, AI system evaluation has relied heavily on human-written evaluation sets. Most notably, this process demands substantial time and resource investment, preventing most developers from creating and properly evaluating their AI systems. - -The Weaviate Transformation Agent offers a breakthrough in AI evaluation by enabling the rapid generation of synthetic evaluation datasets! - -In this notebook, we generate **2,100 synthetic questions for the Weaviate Blogs (1 for each) in 63 seconds!** - -We then use this dataset to report embedding recall (finding the source document in the haystack) between the Snowflake [Arctic 2.0](https://arxiv.org/abs/2412.04506) and [Arctic 1.5](https://arxiv.org/abs/2405.05374) embedding models. We find the following result: - -| Model | Recall@1 | Recall@5 | Recall@100 | -|------------|----------|----------|------------| -| Arctic 1.5 | 0.7995 | 0.9245 | 0.9995 | -| Arctic 2.0 | 0.8412 | 0.9546 | 0.9995 | - -The Arctic 2.0 model demonstrates superior performance, with particularly notable improvements in Recall @ 1 (4.17% increase) and Recall @ 5 (3.01% increase). - -## Here is an overview of what this notebook illustrates: - -![Embedding Benchmark with the Transformation Agent](https://raw.githubusercontent.com/weaviate/recipes/refs/heads/main/weaviate-services/agents/images/synthetic-query-overview-new.png "Embedding Benchmark with the Transformation Agent") - -```python -import weaviate -import os -from weaviate.classes.init import Auth -import weaviate.classes.config as wvcc -import re -from weaviate.util import get_valid_uuid -from uuid import uuid4 -``` - -```python -# Connect to Weaviate Client - -WEAVIATE_URL = os.getenv("WEAVIATE_URL") -WEAVIATE_API_KEY = os.getenv("WEAVIATE_API_KEY") - -weaviate_client = weaviate.connect_to_weaviate_cloud( - cluster_url=WEAVIATE_URL, - auth_credentials=Auth.api_key(WEAVIATE_API_KEY) -) - -print(weaviate_client.is_ready()) -``` - -Python output: -```text -True -``` -## Weaviate Named Vectors - -Create 2 HSNW indexes from the *same* property in Weaviate!! - -On top of that, you can set different embedding models for each! - -You can learn more about Weaviate Named Vectors [here](https://docs.weaviate.io/weaviate/config-refs/collections) and the Weaviate Embedding Service [here](https://docs.weaviate.io/cloud/embeddings)! - -```python -blogs_collection = weaviate_client.collections.create( - name="WeaviateBlogChunks", - vectorizer_config=[ - wvcc.Configure.NamedVectors.text2vec_weaviate( - name="content_arctic_1_5", - model="Snowflake/snowflake-arctic-embed-m-v1.5", - source_properties=["content"], - ), - wvcc.Configure.NamedVectors.text2vec_weaviate( - name="content_arctic_2_0", - model="Snowflake/snowflake-arctic-embed-l-v2.0", - source_properties=["content"], - ) - ], - properties=[ - wvcc.Property(name="content", data_type=wvcc.DataType.TEXT), - ] -) -``` - -## Simple Directory Parser to Load Weaviate's Blogs stored in Markdown Files into Memory - -```python -def chunk_list(lst, chunk_size): - """Break a list into chunks of the specified size.""" - return [lst[i:i + chunk_size] for i in range(0, len(lst), chunk_size)] - -def split_into_sentences(text): - """Split text into sentences using regular expressions.""" - sentences = re.split(r'(? -• [Arctic Embed 2.0 Research Report](https://arxiv.org/abs/2412.04506)
-• [Arctic Embed Research Report](https://arxiv.org/abs/2405.05374)
-• [Weaviate Podcast #110 with Luke Merrick, Puxuan Yu, and Charles Pierse!](https://www.youtube.com/watch?v=Kjqv4uk3RCs) - -## Massive thanks to Luke and Puxuan for reviewing this notebook! - -![Arctic Embed on the Weaviate Podcast](https://raw.githubusercontent.com/weaviate/recipes/refs/heads/main/weaviate-services/agents/images/pod-110-thumbnail.png "Arctic Embed on the Weaviate Podcast!") diff --git a/docs/agents/transformation/index.md b/docs/agents/transformation/index.md deleted file mode 100644 index 2ba0538df..000000000 --- a/docs/agents/transformation/index.md +++ /dev/null @@ -1,120 +0,0 @@ ---- -title: Transformation Agent -sidebar_position: 30 -description: "Overview of the AI agent that enhances, enriches and transforms existing data in Weaviate collections." -image: og/docs/agents.jpg -# tags: ['agents', 'getting started', 'transformation agent'] ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; -import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; -import PyCode from '!!raw-loader!/docs/agents/_includes/transformation_agent.py'; - -# Weaviate Transformation Agent - - - -:::caution Technical Preview - -![This Weaviate Agent is in technical preview.](../_includes/agents_tech_preview_light.png#gh-light-mode-only "This Weaviate Agent is in technical preview.") -![This Weaviate Agent is in technical preview.](../_includes/agents_tech_preview_dark.png#gh-dark-mode-only "This Weaviate Agent is in technical preview.") - -[Sign up here](https://events.weaviate.io/weaviate-agents) for notifications on Weaviate Agents, or visit [this page](https://weaviateagents.featurebase.app/) to see the latest updates and provide feedback. - -::: - -:::warning Do not use in production -The Weaviate Transformation Agent is designed to modify data in Weaviate in place. **While the Agent is in technical preview, do not use it in a production environment.** The Agent may not work as expected, and the data in your Weaviate instance may be affected in unexpected ways. -::: - -The Weaviate Transformation Agent is an agentic service designed to augment and transform data using generative models. Use the Transformation Agent to append new properties and/or update existing properties of data on existing objects in Weaviate. - -![Weaviate Transformation Agent example - append](../_includes/transformation_agent_append_example_light.png#gh-light-mode-only "Weaviate Transformation Agent example - append") -![Weaviate Transformation Agent example - append](../_includes/transformation_agent_append_example_dark.png#gh-dark-mode-only "Weaviate Transformation Agent example - append") - -This can help you to improve the quality of your objects in your Weaviate collections, ready for further use in your applications. - -## Architecture - -The Transformation Agent is provided as a service on Weaviate Cloud. It updates existing Weaviate objects by either appending new properties or updating existing properties. - -![Weaviate Transformation Agent overview](../_includes/transformation_agent_overview_light.png#gh-light-mode-only "Weaviate Transformation Agent overview") -![Weaviate Transformation Agent overview](../_includes/transformation_agent_overview_dark.png#gh-dark-mode-only "Weaviate Transformation Agent overview") - -Provide a set of instructions to the Transformation Agent, such as the collection to update and existing properties to review and the instructions. The Transformation Agent will then perform the specified operations on the specified objects in Weaviate. - -:::note Total object count unaffected -This would not change the number of objects in Weaviate, but would update the properties of the specified objects. -::: - -## Transformation Agent: visualized workflow - -To transform existing objects, the Transformation Agent follows the workflows shown below. - -- The Transformation Agent retrieves the existing objects from Weaviate, based on the specified criteria (steps 1-2). -- The Transformation Agent works with a generative model to create the property value, based on the instructions provided and the context of the specified existing properties (steps 3-4). -- Update the transformed objects in Weaviate. Weaviate vectorizes the data as needed using the specified vectorizer integration. (Steps 5-7) -- Receive the job status from Weaviate, which is returned to the user (Step 8). - -### Update properties on existing objects - -When updating properties on existing objects, the Transformation Agent replaces the existing property values with the new values. The workflow for this operation is shown below. - -![Weaviate Transformation Agent: Update properties on existing objects](../_includes/transformation_agent_existing_update_light.png#gh-light-mode-only "Weaviate Transformation Agent: Update properties on existing objects") -![Weaviate Transformation Agent: Update properties on existing objects](../_includes/transformation_agent_existing_update_dark.png#gh-dark-mode-only "Weaviate Transformation Agent: Update properties on existing objects") - -### Append new properties to existing objects - -When appending properties to existing objects, the Transformation Agent adds the new values to the objects as new properties. The workflow for this operation is shown below. - -![Weaviate Transformation Agent: Append news properties to existing objects](../_includes/transformation_agent_existing_append_light.png#gh-light-mode-only "Weaviate Transformation Agent: Append news properties to existing objects") -![Weaviate Transformation Agent: Append news properties to existing objects](../_includes/transformation_agent_existing_append_dark.png#gh-dark-mode-only "Weaviate Transformation Agent: Append news properties to existing objects") - -## Basic Usage - -Here is an overview of how to use the this Weaviate Agent. For more detailed information, refer to the [Usage](./usage.md) page. - -### Prerequisites - -This Agent is available exclusively for use with a Weaviate Cloud instance, and a supported version of the Weaviate client library. - -### Example Usage - -To use the Transformation Agent, instantiate it with the following inputs: - -- An instance of the Weaviate client (e.g. the `WeaviateClient` object in Python), connected to a Weaviate Cloud instance. -- Name of the target collection to be transformed. -- A list of the transformation operations to be performed. - -And then start the operations. - -Transformation operations are asynchronous. Each operation will return a workflow ID to the user. The user can then use this ID to check its status. - - - - - - - - -The transformed attributes will become available on each object as the transformation progresses. - -### Further Documentation - -For more detailed information on how to use this Agent, refer to the [Usage](./usage.md) page. - -## Questions and feedback - -:::info Changelog and feedback -The official changelog for Weaviate Agents can be [found here](https://weaviateagents.featurebase.app/changelog). If you have feedback, such as feature requests, bug reports or questions, please [submit them here](https://weaviateagents.featurebase.app/), where you will be able to see the status of your feedback and vote on others' feedback. -::: - -import DocsFeedback from '/_includes/docs-feedback.mdx'; - - diff --git a/docs/agents/transformation/tutorial-enrich-dataset.mdx b/docs/agents/transformation/tutorial-enrich-dataset.mdx deleted file mode 100644 index 90ee7e0e3..000000000 --- a/docs/agents/transformation/tutorial-enrich-dataset.mdx +++ /dev/null @@ -1,407 +0,0 @@ ---- -title: Enrich your dataset with a Transformation Agent -sidebar_label: "Tutorial: Enrich your dataset" -description: "Tutorial showing how to add new and update existing properties in Weaviate collections using the Transformation Agent." -sidebar_position: 40 -image: og/docs/tutorials.jpg -# tags: ['basics'] ---- - -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; -import FilteredTextBlock from "@site/src/components/Documentation/FilteredTextBlock"; -import PyCode from "!!raw-loader!/docs/agents/_includes/transformation_agent_tutorial_enrich_dataset.py"; - - - -:::caution Technical Preview - -![This Weaviate Agent is in technical preview.](../_includes/agents_tech_preview_light.png#gh-light-mode-only "This Weaviate Agent is in technical preview.") -![This Weaviate Agent is in technical preview.](../_includes/agents_tech_preview_dark.png#gh-dark-mode-only "This Weaviate Agent is in technical preview.") - -[Sign up here](https://events.weaviate.io/weaviate-agents) for notifications on Weaviate Agents, or visit [this page](https://weaviateagents.featurebase.app/) to see the latest updates and provide feedback. - -::: - -:::warning Do not use in production -The Weaviate Transformation Agent is designed to modify data in Weaviate in place. **While the Agent is in technical preview, do not use it in a production environment.** The Agent may not work as expected, and the data in your Weaviate instance may be affected in unexpected ways. -::: - -In this tutorial, we will use the **[Transformation Agent](./index.md)** to enrich data stored in Weaviate. We will build an agent that has access to a collection containing a bunch of research papers, their abstracts, and titles. We will then use the agent to create additional properties for each of our objects in the collection. - -We've prepared a public dataset that you can use to explore the Transformation Agent, and it's available on Hugging Face: - -- [**ArxivPapers:**](https://huggingface.co/datasets/weaviate/agents/viewer/transformation-agent-papers) A dataset that lists titles and abstracts of research papers. - -## Introduction: What are Transformation Agents? - -The Transformation Agent is able to access a Weaviate collection of your choosing and perform operations on the objects within it. However, each operation for the agent can be defined in natural language. The agent will then use an LLM to complete the instructions in the operation. - -import WeaviateAgentsArxivFlowchart from "/docs/agents/_includes/transformation_agent_tutorial_arxiv_flowchart.png"; - -
-
-
- Weaviate Query Agent flowchart -
-
-
-
- -The Transformation Agent: - -1. **Receives a task** to create new properties or update existing ones. -2. **Retrieves the needed data from Weaviate**, which will be updated or used to create the new properties. -3. **Uses an appropriate foundation model** (e.g. large language model) to perform the transformation of the data. -4. **Stores the transformed data in Weaviate** by creating new properties or updating existing ones. - -
- -## Prerequisites - -To use the Weaviate Agents and Weaviate Embedding service, you need to have a **[Weaviate Cloud](/go/console?utm_content=agents)** account. - -## Step 1: Set up Weaviate - -Now, let's get started by setting up a Weaviate Cloud instance that we will use for this tutorial and connecting it to the Python client. - -### 1.1 Create a Weaviate Cloud cluster - -1. Create a [free Sandbox cluster](/cloud/manage-clusters/create#sandbox-clusters) in Weaviate Cloud. -1. Take note of the `REST Endpoint` and `Admin` API key to connect to your cluster. (for more info, check out the [quickstart](/cloud/manage-clusters/connect.mdx)) - -:::tip -In this tutorial, we are using the [Weaviate Embeddings](../../weaviate/model-providers/weaviate/index.md) service as the vectorizer, so you do not have to provide any extra keys for external embedding providers. Weaviate Embeddings uses the `Snowflake/snowflake-arctic-embed-l-v2.0` as the default embedding model.

-If you want to use another vectorizer, check out the list of supported [model providers](../../weaviate/model-providers/index.md). -::: - -### 1.2 Install the Python libraries - -In order to install the Weaviate Python client together with the `agents` component, run: - - - - -``` -pip install "weaviate-client[agents]" -``` - - - - -You will also need `datasets`, a lightweight library providing access to the publicly hosted datasets on HuggingFace. - - - - -``` -pip install datasets -``` - - - - -import ForcePipInstall from "../_includes/_force_pip_install.mdx"; - - - -### 1.3 Connect to your instance - -Now, you can finally connect to your Weaviate Cloud instance with the parameters from the first step: - - - - - - - -After running this snippet, you should see the message `True` printed out, which means that you have successfully connected to your instance. - -## Step 2: Prepare the Collections - -In the following code blocks, we are pulling our demo datasets from Hugging Face and writing them to new collections in our Weaviate Sandbox cluster. Before we can start importing the data into Weaviate, we need to **define the collections**, which means setting up the data schema and choosing the vectorizer/embedding service. - -### 2.1 Define the Collections - -import WeaviateAgentsArxivDataset from "/docs/agents/_includes/transformation_agent_tutorial_arxiv_dataset.png"; - -
-
-
-

- In this image, you can see what the objects in the dataset{" "} - ArxivPapers look like. -

-
-
-
-
- The arXiv.org paper dataset -
-
The arXiv.org paper dataset
-
-
-
-
- -For the collection `ArxivPapers`, we are going to use the [`auto-schema`](../../weaviate/config-refs/collections.mdx#auto-schema) option, which creates properties automatically based on the imported data. - - - - - - - -### 2.2 Populate the database - -Now, we can import the pre-vectorized data [ArxivPapers](https://huggingface.co/datasets/weaviate/agents/viewer/transformation-agent-papers) into our Weaviate Cloud instance: - - - - - - - -By calling `len()` on our collections, we can check that the import has successfully concluded and see what the size of our collections is. - -``` -Size of the ArxivPapers dataset: 200 -``` - -### 2.3 Inspect the collection in the Explorer tool - -The Transformation Agent will modify the collection as we go along. This is a good time to take a look at the contents of your "ArxivPapers" collection. If all goes well, you should be seeing 2 properties listed for each object: - -- `title`: the title of the paper. -- `abstract`: the abstract of the paper. - -As well as the `vectors` for each object. - -## Step 3: Set up the Transformation Agent - -The star of the show for the Transformation Agent are the "operations". - -We can now define the transformation operations that we want to perform on our collection. An operation can be: - -- **[Appending a new property](#31-append-new-properties)** -- **[Updating an existing property](#32-update-an-existing-property)** - -### 3.1 Append new properties - -To append a new property, we define an operation with: - -- **`instruction`**: This is where you can describe, in natural language, what you want this new property to be. -- **`property_name`**: The name you want the property to have. -- **`data_type`**: The specific datatype the property should be (`DataType.TEXT`, `DataType.TEXT_ARRAY`, `DataType.BOOL`, `DataType.INT`, etc.) -- **`view_properties`**: Sometimes, you may want to create properties that are based on information provided in other properties and this is where you can list out which properties the instruction should access. - -#### 3.1.1 Create a list of topics - -First, let's append a new property called `topics`, which should be a `TEXT_ARRAY`. Based on the `abstract`, let's ask for the LLM to extract a list of topic tags. Let's ask for no more than 5. - - - - - - - -#### 3.1.2 Add a French translation - -Next, let's add a new `french_abstract` property, which is simply a translation of the `abstract` property: - - - - - - - -#### 3.1.3 Add NLP Relevance Score - -This time, we can add a property that is an `INT`. Here, we ask the LLM to give a score from `0` to `10` based on how relevant the paper is to Natural Language Processing. - - - - - - - -#### 3.1.4 Determine if it's a survey paper - -Finally, let's ask for a `BOOL` property, which indicates whether the paper is a survey or not. The LLM will determine if the paper presents novel techniques or if it's a survey of existing ones. - - - - - - - -### 3.2 Update an existing property - -:::caution - -Don't perform updates on properties that are part of other agent operations. This will result in unpredictable behavior. - -::: - -Now, let's update the `title` property as we haven't used it in any previous operations: - - - - - - - -## Step 4: Create and run the Transformation Agent - -Once we have defined all of our operations, we can initialize the `TransformationAgent`. - -When initializing the agent, we have to let it know which collection to modify. In this case, we want it to have access to the "ArxivPapers" collection we previously created. - -Next, we need to provide a list of `operations` that the agent should run. Here, we provide all the operations we defined above. - - - - - - - -### 4.1 Running the transformations - -By calling `update_all()`, we get the agent to spin up individual workflows for each operation. Each operation will then run on each object in our collection. - - - - - - - -import WeaviateAgentsExplorerTool from "/docs/agents/_includes/transformation_agent_tutorial_explorer_tool.png"; - -
-
-

- Now, you can open the{" "} - Explorer tool to - check the results of the transformation. -

-
-
-
-
- Explorer tool in Weaviate Cloud -
-
Explorer tool in Weaviate Cloud
-
-
-
-
- -The output is: - -``` -[TransformationResponse(operation_name='topics', workflow_id='TransformationWorkflow-7006854bd90f949b59bb8d88c816bdd6'), -TransformationResponse(operation_name='french_abstract', workflow_id='TransformationWorkflow-7a025ef11ef8e681adb0c273755d0a2a'), -TransformationResponse(operation_name='nlp_relevance', workflow_id='TransformationWorkflow-e6db777629ae7b38ca2f8f64df35c305'), -TransformationResponse(operation_name='is_survey_paper', workflow_id='TransformationWorkflow-e70d29827271f462f2a911ec29c6cb0c'), -TransformationResponse(operation_name='title', workflow_id='TransformationWorkflow-6b2ff75370e1f80ff537037fde02cb26')] -``` - -### 4.2 Inspect the operation workflows - -To inspect the status of the asynchronous transformation operations, we can use the `agent.get_status(workflow_id)` function: - - - - - - - -The output is: - -``` -{'workflow_id': 'TransformationWorkflow-f408a4a0211940525c0e2d45cf46a6c2', 'status': {'batch_count': 1, 'end_time': None, 'start_time': '2025-03-10 13:17:31', 'state': 'running', 'total_duration': None, 'total_items': 200}} -``` - -## Summary - -This guide shows you how to build an end-to-end Transformation Agent using Weaviate's agentic services — from setting up your Weaviate Cloud instance and importing a research papers dataset to configuring a Transformation Agent that intelligently enriches your data. - -The Transformation Agent automatically interprets natural language instructions to create or update properties in your dataset. It processes your collection by appending new properties like topic tags, translations and relevance scores, ensuring your data is enhanced and ready for further analysis. - -## Further resources - -- [Weaviate Agents - Transformation Agent](./index.md) - -## Questions and feedback - -:::info Changelog and feedback -The official changelog for Weaviate Agents can be [found here](https://weaviateagents.featurebase.app/changelog). If you have feedback, such as feature requests, bug reports or questions, please [submit them here](https://weaviateagents.featurebase.app/), where you will be able to see the status of your feedback and vote on others' feedback. -::: - -import DocsFeedback from "/_includes/docs-feedback.mdx"; - - diff --git a/docs/agents/transformation/usage.md b/docs/agents/transformation/usage.md deleted file mode 100644 index d38bb5a9f..000000000 --- a/docs/agents/transformation/usage.md +++ /dev/null @@ -1,237 +0,0 @@ ---- -title: Usage -sidebar_position: 30 -description: "Technical documentation and usage examples for implementing the Transformation Agent." -image: og/docs/agents.jpg -# tags: ['agents', 'getting started', 'transformation agent'] ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; -import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; -import PyCode from '!!raw-loader!/docs/agents/\_includes/transformation_agent.py'; - -# Weaviate Transformation Agent: Usage - - - -:::caution Technical Preview - -![This Weaviate Agent is in technical preview.](../_includes/agents_tech_preview_light.png#gh-light-mode-only "This Weaviate Agent is in technical preview.") -![This Weaviate Agent is in technical preview.](../_includes/agents_tech_preview_dark.png#gh-dark-mode-only "This Weaviate Agent is in technical preview.") - -[Sign up here](https://events.weaviate.io/weaviate-agents) for notifications on Weaviate Agents, or visit [this page](https://weaviateagents.featurebase.app/) to see the latest updates and provide feedback. - -::: - -:::warning Do not use in production -The Weaviate Transformation Agent is designed to modify data in Weaviate in place. **While the Agent is in technical preview, do not use it in a production environment.** The Agent may not work as expected, and the data in your Weaviate instance may be affected in unexpected ways. -::: - -The Weaviate Transformation Agent is an agentic service designed to augment and transform data using generative models. Use the Transformation Agent to append new properties and/or update existing properties of data on existing objects in Weaviate. - -This can help you to improve the quality of your objects in your Weaviate collections, ready for further use in your applications. - -![Weaviate Transformation Agent overview](../_includes/transformation_agent_overview_light.png#gh-light-mode-only "Weaviate Transformation Agent overview") -![Weaviate Transformation Agent overview](../_includes/transformation_agent_overview_dark.png#gh-dark-mode-only "Weaviate Transformation Agent overview") - -This page describes how to use the Weaviate Transformation Agent to transform and augment your data in Weaviate. - -:::info Changelog and feedback -The official changelog for Weaviate Agents can be [found here](https://weaviateagents.featurebase.app/changelog). If you have feedback, such as feature requests, bug reports or questions, please [submit them here](https://weaviateagents.featurebase.app/), where you will be able to see the status of your feedback and vote on others' feedback. -::: - -## Prerequisites - -### Weaviate instance - -This Agent is available exclusively for use with a Weaviate Cloud instance. - -Refer to the [Weaviate Cloud documentation](/cloud/index.mdx) for more information on how to set up a Weaviate Cloud instance. - -You can try this Weaviate Agent with a free Sandbox instance on [Weaviate Cloud](/go/console?utm_content=agents). - -### Client library - -:::note Supported languages -At this time, this Agent is available only for Python. Support for other languages will be added in the future. -::: - -You can install the Weaviate client library with the optional `agents` extras to use Weaviate Agents. This will install the `weaviate-agents` package along with the `weaviate-client` package. - -Install the client library using the following command: - - - - -```shell -pip install -U "weaviate-client[agents]" -``` - -#### Troubleshooting: Force `pip` to install the latest version - -For existing installations, even `pip install -U "weaviate-client[agents]"` may not upgrade `weaviate-agents` to the [latest version](https://pypi.org/project/weaviate-agents/). If this occurs, additionally try to explicitly upgrade the `weaviate-agents` package: - -```shell -pip install -U weaviate-agents -``` - -Or install a [specific version](https://github.com/weaviate/weaviate-agents-python-client/tags): - -```shell -pip install -U weaviate-agents==||site.weaviate_agents_version|| -``` - - - - - -## Usage - -To use the Transformation Agent, instantiate it with the required inputs and start the operations. - -Transformation operations are asynchronous. Each operation will return a workflow ID to the user. Use this ID to check its status. - -Example usage is shown below. - -### Prerequisites - -The Transformation Agent is tightly integrated with Weaviate Cloud. As a result, the Transformation Agent is available exclusively for use with a Weaviate Cloud instance, and a supported version of the client library. - -### Connect to Weaviate - -You must connect to the Weaviate Cloud instance to use the Transformation Agent. Connect to the Weaviate Cloud instance using the Weaviate client library. - - - - - - - -### Define transformation operations - -You must define transformation operations before starting the Transformation Agent. Define operations with the following information: - -- Operation type -- Target property name -- The properties to be used as context -- Instructions -- (For new properties) The data type of the new property - -Example operations are shown below. - -#### Append new properties to data - -New properties can be appended to objects based on existing property values and user instructions. - - - - - - - - -#### Update existing properties - -Values of existing properties can be updated on objects based on existing property values and user instructions. - - - - - - - - -### Start the transformation operations - -To start the transformation operations, instantiate the Transformation Agent with the required inputs and start the operations. - -Instantiate the Transformation Agent with the Weaviate client, the target collection name, and the list of transformation operations. - - - - - - - - -### Monitor job status - -You can use the workflow ID to monitor the status of each transformation operation. - - - - - - - - -## Limitations & Troubleshooting - -:::caution Technical Preview - -![This Weaviate Agent is in technical preview.](../_includes/agents_tech_preview_light.png#gh-light-mode-only "This Weaviate Agent is in technical preview.") -![This Weaviate Agent is in technical preview.](../_includes/agents_tech_preview_dark.png#gh-dark-mode-only "This Weaviate Agent is in technical preview.") - -[Sign up here](https://events.weaviate.io/weaviate-agents) for notifications on Weaviate Agents, or visit [this page](https://weaviateagents.featurebase.app/) to see the latest updates and provide feedback. - -::: - -### Usage limits - -At this stage, there is a limit of 50,000 Transformation Agent operations per day per Weaviate Cloud [organization](/cloud/platform/users-and-organizations.mdx#organizations). - -Note that this limit is per individual operations. In other words, running a Transformation Agent with 4 operations on a collection of 2,500 objects would max out the limit for that day. - -This limit may change in future versions of the Transformation Agent. - -### Model input context length - -Due to the limitations of the underlying models, the input context length for a transformation operation is limited. We recommend that the input context length is kept below ~25000 characters. - -In other words, the total length of the input context (the properties used as context) and the instructions should be kept below this limit. If the model input context length is exceeded, the transformation operation will fail. - -### Race condition on multiple operations - -When multiple transformation operations are initiated on the same collection, it is possible for a race condition to occur, overwriting the results of one operation with the results of another. - -This can be avoided by ensuring that only one operation is performed on a collection at a time. If you need to perform multiple operations on the same collection, ensure that the operations are performed sequentially. - -You can do this by using the workflow ID of the previous operation to monitor its status before starting the next operation. - -This will be addressed in future versions of the Transformation Agent. - -## Questions and feedback - -:::info Changelog and feedback -The official changelog for Weaviate Agents can be [found here](https://weaviateagents.featurebase.app/changelog). If you have feedback, such as feature requests, bug reports or questions, please [submit them here](https://weaviateagents.featurebase.app/), where you will be able to see the status of your feedback and vote on others' feedback. -::: - -import DocsFeedback from '/\_includes/docs-feedback.mdx'; - - diff --git a/docs/cloud/faq.mdx b/docs/cloud/faq.mdx index a3632b671..b38d24ec8 100644 --- a/docs/cloud/faq.mdx +++ b/docs/cloud/faq.mdx @@ -14,7 +14,7 @@ Frequently asked questions (FAQs) about [Weaviate Cloud (WCD)](/go/console?utm_c
Answer -Using Weaviate Cloud gives you access to a 14-day free sandbox for testing. You also get access to advanced features like [Weaviate Embeddings](docs/cloud/embeddings/index.md) and [Weaviate Agents](docs/agents/index.md), which are not available in all deployment methods. +Using Weaviate Cloud gives you access to a 14-day free sandbox for testing. You also get access to advanced features like [Weaviate Embeddings](/cloud/embeddings/index.md) and the [Query Agent](/query-agent/index.md), which are not available in all deployment methods.
@@ -27,6 +27,18 @@ Using Weaviate Cloud gives you access the option of importing [CVS/Excel](./tool
+#### Q: What happened to the Personalization Agent and Transformation Agent? {#deprecated-agents} + +
+ Answer + +Weaviate Agents now focus exclusively on the [Query Agent](/query-agent/index.md). The **Personalization Agent** and **Transformation Agent** have been deprecated and are no longer available. + +- For agentic search and retrieval over your data, use the [Query Agent](/query-agent/index.md). +- For personalization use cases previously served by the **Personalization Agent**, **[Engram](/engram/index.md)** is a good alternative. Engram is Weaviate's memory server for LLM and agent applications: it stores user interactions and preferences as persistent, semantically searchable memories that you can use to power personalized, context-aware experiences. + +
+ ## Account management #### Q: Can I reset or change my account password? {#reset-password} diff --git a/docs/cloud/tools/collections-tool.mdx b/docs/cloud/tools/collections-tool.mdx index 35b753344..aafecaebe 100644 --- a/docs/cloud/tools/collections-tool.mdx +++ b/docs/cloud/tools/collections-tool.mdx @@ -94,7 +94,7 @@ If you don't see any available clusters, select the `Clusters` option from the l The Weaviate Cloud (WCD) _Collection tool_ allows you to easily upload data from a PDF file into a new Weaviate collection. The tool guides you through selecting your cluster, configuring the collection, and then automatically imports the data and vectorizes the PDF pages. -For this guide, we will use the following file: [NASA's Plan for Sustainable Lunar Exploration (c. 2024)](https://ntrs.nasa.gov/citations/20240011013). +For this guide, we will use the following file: *NASA's Plan for Sustainable Lunar Exploration (c. 2024)*.
+ -[Weaviate Agents](../index.md) +[Query Agent](../index.md) ``` ### Absolute link paths @@ -67,11 +67,11 @@ Always fix any build errors before submitting changes, as broken builds will pre **Use absolute paths** for cross-section linking: ```markdown - + -[Weaviate Agents](/agents/index.md) +[Query Agent](/query-agent/index.md) - + [Weaviate Database](/weaviate/index.md) ``` @@ -81,9 +81,9 @@ Always fix any build errors before submitting changes, as broken builds will pre **Use absolute URLs** for reusable components: ```markdown - + -[Weaviate Agents](/agents/qeuery) +[Query Agent](/query-agent/quickstart) ``` This convention ensures links work correctly regardless of where the component is imported. diff --git a/docs/contributor-guide/weaviate-docs/style-guide.mdx b/docs/contributor-guide/weaviate-docs/style-guide.mdx index 4380f7bd5..d458f18fd 100644 --- a/docs/contributor-guide/weaviate-docs/style-guide.mdx +++ b/docs/contributor-guide/weaviate-docs/style-guide.mdx @@ -48,7 +48,7 @@ The documentation is organized into key sections. When contributing, understand - **Deployment docs - `/docs/deploy`:** Documentation for deploying and operating Weaviate instances. Covers installation methods including Docker and Kubernetes, configuration options for authentication and performance, production deployment patterns, scaling and high availability setups, cloud provider-specific guides, troubleshooting information, and version migration procedures. -- **Weaviate Agents - `/docs/agents`:** Documentation for Weaviate's agent framework. Includes setup instructions, usage examples, and implementation patterns for building AI agents that can interact with Weaviate databases. +- **Query Agent - `/docs/query-agent`:** Documentation for the Query Agent — Weaviate's pre-built agentic search service. Includes setup instructions, mode usage (Ask, Search, Suggest Queries), configuration references, client library guides, and recipes for common patterns. - **Weaviate Cloud - `/docs/cloud`:** Documentation for Weaviate's managed cloud service. Contains account setup procedures, Weaviate embeddings service documentation, billing and subscription management, service limitations, and cloud-specific configuration options. diff --git a/docs/agents/_includes/_force_pip_install.mdx b/docs/query-agent/_includes/_force_pip_install.mdx similarity index 82% rename from docs/agents/_includes/_force_pip_install.mdx rename to docs/query-agent/_includes/_force_pip_install.mdx index 0735aa0b3..cd006dc80 100644 --- a/docs/agents/_includes/_force_pip_install.mdx +++ b/docs/query-agent/_includes/_force_pip_install.mdx @@ -1,7 +1,7 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -#### Troubleshooting: Force `pip` to install the latest version +#### Troubleshooting: force `pip` to install the latest version For existing installations, even `pip install -U "weaviate-client[agents]"` may not upgrade `weaviate-agents` to the [latest version](https://pypi.org/project/weaviate-agents/). If this occurs, additionally try to explicitly upgrade the `weaviate-agents` package: @@ -15,7 +15,7 @@ pip install -U weaviate-agents Or install a [specific version](https://github.com/weaviate/weaviate-agents-python-client/tags): ```shell -pip install -U weaviate-agents==||site.weaviate_agents_version|| +pip install -U weaviate-agents==||site.agents_python_version|| ``` diff --git a/docs/query-agent/_includes/code/additional_filters.mts b/docs/query-agent/_includes/code/additional_filters.mts new file mode 100644 index 000000000..a802cf40a --- /dev/null +++ b/docs/query-agent/_includes/code/additional_filters.mts @@ -0,0 +1,85 @@ +import 'dotenv/config' +import weaviate from 'weaviate-client'; +const { loadClientInternally, populateWeaviate } = await import('./util.mjs').catch(() => import('../docs/query-agent/_includes/code/util.mjs')); +const client = await loadClientInternally(); +await populateWeaviate(client, false); + +const weatherCollection = client.collections.use('Weather'); +const financialCollection = client.collections.use('FinancialContracts'); +const ecommerceCollection = client.collections.use('ECommerce'); + +// START OverviewInInit +import { QueryAgent } from 'weaviate-agents'; + +const qa = new QueryAgent(client, { + collections: [ + { + name: 'Weather', + additionalFilters: weatherCollection.filter.byProperty('temperature').greaterThan(10), + }, + ], +}); +// END OverviewInInit + +// START OverviewInRuntime +const runtimeConfig = { + name: 'Weather', + additionalFilters: weatherCollection.filter.byProperty('humidity').equal(39), +}; + +const response = await qa.ask("Provide a summary of the weather patterns", { + collections: [runtimeConfig], +}); +// END OverviewInRuntime + +// START FilterExampleBad +const badResponse = await qa.ask( + `What type of contracts have been signed and who were the authors? + IMPORTANT: Only look at contracts from 2025.`, + { + collections: ['FinancialContracts'], + } +); +// END FilterExampleBad + + +// START FilterExampleGood +import { Filters } from 'weaviate-client'; +const goodResponse = await qa.ask( + `What products were sold last month?`, + { + collections: [ + { + name: 'FinancialContracts', + additionalFilters: Filters.and( + financialCollection.filter.byProperty('date').greaterThan(new Date(2025, 0, 1)), + financialCollection.filter.byProperty('date').lessThan(new Date(2026, 0, 1)), + ), + }, + ], + } +); +// END FilterExampleGood + +// START BasicFilter +const basicFilterConfig = { + name: 'ECommerce', + additionalFilters: ecommerceCollection.filter.byProperty('category').equal('Tops'), +}; +// END BasicFilter + + +// START NestedFilter +const nestedFilterConfig = { + name: 'ECommerce', + additionalFilters: Filters.or( + ecommerceCollection.filter.byProperty('category').equal('Shoes'), + Filters.and( + ecommerceCollection.filter.byProperty('price').greaterThan(50), + ecommerceCollection.filter.byProperty('price').lessThan(100), + ), + ), +}; +// END NestedFilter + +await client.close(); diff --git a/docs/query-agent/_includes/code/additional_filters.py b/docs/query-agent/_includes/code/additional_filters.py new file mode 100644 index 000000000..f81dc6d92 --- /dev/null +++ b/docs/query-agent/_includes/code/additional_filters.py @@ -0,0 +1,98 @@ +import sys +sys.path.insert(0, "docs/query-agent/_includes/code") +from util import load_client_internally, populate_weaviate +client = load_client_internally() +populate_weaviate(client, False) + +# START OverviewInInit +from weaviate.agents.query import QueryAgent +from weaviate.agents.classes import QueryAgentCollectionConfig +from weaviate.classes.query import Filter + +qa = QueryAgent( + client=client, + collections=[ + QueryAgentCollectionConfig( + name="Weather", + additional_filters=Filter.by_property("temperature").greater_than(10) + ), + ], + # END OverviewInInit + timeout=120, + # START OverviewInInit +) +# END OverviewInInit + +# START OverviewInRuntime +runtime_config = QueryAgentCollectionConfig( + name="Weather", + additional_filters=Filter.by_property("humidity").equal(39) +) + +response = qa.ask( + query="Provide a summary of the weather patterns", + collections=[runtime_config] +) +# END OverviewInRuntime + +# START FilterExampleBad +response = qa.ask( + query=( + "What type of contracts have been signed and who were the authors?" + "IMPORTANT: Only look at contracts from 2025." + ), + collections=["FinancialContracts"] +) +# END FilterExampleBad + + +# START FilterExampleGood +from datetime import datetime, timezone + +start_date = datetime(2025, 1, 1, tzinfo=timezone.utc) +end_date = datetime(2026, 1, 1, tzinfo=timezone.utc) + +response = qa.ask( + query="What type of contracts have been signed and who were the authors?", + collections=[ + QueryAgentCollectionConfig( + name="FinancialContracts", + additional_filters=( + Filter.all_of( + [ + Filter.by_property("date").greater_than(start_date), + Filter.by_property("date").less_than(end_date) + ] + ) + ) + ) + ] +) +# END FilterExampleGood + +# START BasicFilter +QueryAgentCollectionConfig( + name="ECommerce", + additional_filters=Filter.by_property("category").equal("Tops") +) +# END BasicFilter + + +# START NestedFilter +QueryAgentCollectionConfig( + name="ECommerce", + additional_filters=Filter.any_of( + [ + Filter.by_property("category").equal("Shoes"), + Filter.all_of( + [ + Filter.by_property("price").greater_than(50), + Filter.by_property("price").less_than(100) + ] + ) + ] + ) +) +# END NestedFilter + +client.close() \ No newline at end of file diff --git a/docs/query-agent/_includes/code/advanced_collections.mts b/docs/query-agent/_includes/code/advanced_collections.mts new file mode 100644 index 000000000..fcdf832d7 --- /dev/null +++ b/docs/query-agent/_includes/code/advanced_collections.mts @@ -0,0 +1,50 @@ +const { loadClientInternally, populateWeaviate } = await import('./util.mjs').catch(() => import('../docs/query-agent/_includes/code/util.mjs')); +const client = await loadClientInternally(); +await populateWeaviate(client, false); + +// START SimpleConfig +import { QueryAgent } from 'weaviate-agents'; + +const qaSimple = new QueryAgent(client, { + collections: ['ECommerce', 'FinancialContracts'], +}); +// END SimpleConfig + +// START AdvancedConfig +const qa = new QueryAgent(client, { + collections: [ + // Provide an object to specify further collection configuration + { + name: 'ECommerce', + targetVector: [ + 'name_description_brand_vector' + ], + viewProperties: [ + 'name', + 'description', + 'category', + 'brand', + ], + }, + { + name: 'FinancialContracts' + }, + ], +}); +// END AdvancedConfig + +// START RuntimeConfigAsk +const response = await qa.ask( + "Recommend some shoes below $60.", { + collections: [ + { + name: 'ECommerce', + targetVector: [ + 'name_description_brand_vector' + ], + } + ], +}); +// END RuntimeConfigAsk + +await client.close() diff --git a/docs/query-agent/_includes/code/advanced_collections.py b/docs/query-agent/_includes/code/advanced_collections.py new file mode 100644 index 000000000..7b093f1cf --- /dev/null +++ b/docs/query-agent/_includes/code/advanced_collections.py @@ -0,0 +1,63 @@ +import sys +sys.path.insert(0, "docs/query-agent/_includes/code") +from util import load_client_internally, populate_weaviate + +client = load_client_internally() +populate_weaviate(client, False) + +from weaviate.agents.query import QueryAgent +from weaviate.agents.classes import QueryAgentCollectionConfig + + +# START SimpleConfig +from weaviate.agents.query import QueryAgent + +qa = QueryAgent( + client=client, + collections=["ECommerce", "FinancialContracts"], +) +# END SimpleConfig + +# START AdvancedConfig +from weaviate.agents.classes import QueryAgentCollectionConfig + +qa = QueryAgent( + client=client, + collections=[ + # Use QueryAgentCollectionConfig class to provide further collection configuration + QueryAgentCollectionConfig( + name="ECommerce", + target_vector=[ + "name_description_brand_vector" + ], + view_properties=[ + "name", + "description", + "category", + "brand", + ], + ), + QueryAgentCollectionConfig( + name="FinancialContracts" + ), + ], +) + +# END AdvancedConfig + + +# START RuntimeConfigAsk +response = qa.ask( + "Recommend some shoes below $60.", + collections=[ + QueryAgentCollectionConfig( + name="ECommerce", + target_vector=[ + "name_description_brand_vector" + ], + ), + ], +) +# END RuntimeConfigAsk + +client.close() \ No newline at end of file diff --git a/docs/query-agent/_includes/code/ask_mode.mts b/docs/query-agent/_includes/code/ask_mode.mts new file mode 100644 index 000000000..d7ca786cf --- /dev/null +++ b/docs/query-agent/_includes/code/ask_mode.mts @@ -0,0 +1,67 @@ +import 'dotenv/config' +const { populateWeaviate } = await import('./util.mjs').catch(() => import('../docs/query-agent/_includes/code/util.mjs')); + + +// START BasicAskMode +import weaviate from 'weaviate-client'; +import { QueryAgent } from 'weaviate-agents'; + +// END BasicAskMode + +// START ImportAskResponse +import { AskModeResponse } from 'weaviate-agents'; +// END ImportAskResponse + +// START StreamingExample +import { ProgressMessage, StreamedTokens } from 'weaviate-agents'; +// END StreamingExample + +// START BasicAskMode +const client = await weaviate.connectToWeaviateCloud( + process.env.WEAVIATE_URL as string, { + authCredentials: new weaviate.ApiKey(process.env.WEAVIATE_API_KEY as string), +}); + +const qa = new QueryAgent(client, { + collections: ['Weather'], + systemPrompt: + "You are a helpful assistant. " + + "Write your response in short, 5 word sentences. " + + "Emphasize key insights." +}); + +// END BasicAskMode + +await populateWeaviate(client, false); + +// START BasicAskMode +const res = await qa.ask("What was the average temperature in the first week of May 2025?", { + resultEvaluation: "none", +}); + +// END BasicAskMode + +// START StreamingAskMode +for await (const output of qa.askStream("What was the average temperature in the first week of May 2025?")) { + // Do something with the output +} +// END StreamingAskMode + +// START StreamingExample +function printStreamOutput(output: ProgressMessage | StreamedTokens | AskModeResponse) { + if (output.outputType === "progressMessage") { + console.log(output.message); + } else if (output.outputType === "streamedTokens") { + process.stdout.write(output.delta); + } else { + output.display(); + } +} + +for await (const output of qa.askStream("What was the average temperature in the first week of May 2025?")) { + printStreamOutput(output); +} + +// END StreamingExample + +await client.close(); diff --git a/docs/query-agent/_includes/code/ask_mode.py b/docs/query-agent/_includes/code/ask_mode.py new file mode 100644 index 000000000..d226d07ae --- /dev/null +++ b/docs/query-agent/_includes/code/ask_mode.py @@ -0,0 +1,109 @@ +import sys +sys.path.insert(0, "docs/query-agent/_includes/code") +import asyncio +from weaviate.classes.config import Configure, Property, DataType +import os + +from util import populate_weaviate + +# START BasicAskMode +from weaviate.agents.query import QueryAgent +from weaviate.classes.init import Auth +import weaviate + +client = weaviate.connect_to_weaviate_cloud( + cluster_url=os.getenv("WEAVIATE_URL"), + auth_credentials=Auth.api_key(os.getenv("WEAVIATE_API_KEY")), +) + +qa = QueryAgent( + client=client, + collections=["Weather"] +) +# END BasicAskMode + +populate_weaviate(client, False) + +# START BasicAskMode + +res = qa.ask( + query = "What was the average temperature in the first week of May 2025?", + result_evaluation = "none" +) + +# END BasicAskMode + +# START StreamingAskMode +for output in qa.ask_stream("What was the average temperature in the first week of May 2025?"): + pass # Do something with the output +# END StreamingAskMode + +# START StreamingExample +from weaviate.agents.classes import ProgressMessage, StreamedTokens, AskModeResponse + +def print_stream_output(output): + if isinstance(output, ProgressMessage): + print(output.message) + elif isinstance(output, StreamedTokens): + print(output.delta, end='', flush=True) + elif isinstance(output, AskModeResponse): + output.display() + +for output in qa.ask_stream("What was the average temperature in the first week of May 2025?"): + print_stream_output(output) + +# END StreamingExample + +# -- Async examples below require await inside a function, for simplicity of code snippets we can wrap them in strings +# then define a function that runs this below (so tests run the same) +""" +# START AsyncInstantiation +from weaviate.agents.query import AsyncQueryAgent + +async_client = weaviate.use_async_with_weaviate_cloud( + cluster_url=os.environ.get("WEAVIATE_URL"), + auth_credentials=Auth.api_key(os.environ.get("WEAVIATE_API_KEY")), +) +await async_client.connect() + +async_qa = AsyncQueryAgent( + client=async_client, collections=["Weather"] +) +# END AsyncInstantiation +""" +""" +# START AsyncAsk +await async_qa.ask( + query = "What was the average temperature in the first week of May 2025?", +) +# END AsyncAsk +""" +""" +# START AsyncStreaming +async for output in async_qa.ask_stream("What was the average temperature in the first week of May 2025?"): + pass # Do something with the output +# END AsyncStreaming +""" + + +# --- Below for testing: +async def _async_run_for_testing(): + from weaviate.agents.query import AsyncQueryAgent + + async_client = weaviate.use_async_with_weaviate_cloud( + cluster_url=os.environ.get("WEAVIATE_URL"), + auth_credentials=Auth.api_key(os.environ.get("WEAVIATE_API_KEY")), + ) + await async_client.connect() + + async_qa = AsyncQueryAgent( + client=async_client, collections=["Weather"] + ) + await async_qa.ask( + query = "What was the average temperature in the first week of May 2025?", + ) + async for output in async_qa.ask_stream("What was the average temperature in the first week of May 2025?"): + pass # Do something with the output + await async_client.close() +asyncio.run(_async_run_for_testing()) +client.close() \ No newline at end of file diff --git a/docs/query-agent/_includes/code/conversations.mts b/docs/query-agent/_includes/code/conversations.mts new file mode 100644 index 000000000..23998e93a --- /dev/null +++ b/docs/query-agent/_includes/code/conversations.mts @@ -0,0 +1,62 @@ +import 'dotenv/config' +const { loadClientInternally, populateWeaviate } = await import('./util.mjs').catch(() => import('../docs/query-agent/_includes/code/util.mjs')); +import { QueryAgent } from 'weaviate-agents'; + +const client = await loadClientInternally(); +await populateWeaviate(client, false); +const qa = new QueryAgent(client, { + collections: ['Weather'], +}); + +// START BasicConversation +import { ChatMessage } from 'weaviate-agents'; + +const conversation: ChatMessage[] = [ + { + role: "user", + content: "Hi!" + }, + { + role: "assistant", + content: "Hello! How can I assist you today?" + }, + { + role: "user", + content: "I have some questions about the weather data. You can assume the temperature is in Fahrenheit and the wind speed is in mph.", + }, + { + role: "assistant", + content: "I can help with that. What specific information are you looking for?", + }, + { + role: "user", + content: "What's the average wind speed, the max wind speed, and the min wind speed", + } +] + +const response = await qa.ask(conversation) +// END BasicConversation + +// START ExampleMessageHistory +const messageHistory: ChatMessage[] = [] + +async function useQA(query: string): Promise { + messageHistory.push({ role: "user", content: query }) + const response = await qa.ask(messageHistory) + messageHistory.push({ role: "assistant", content: response.finalAnswer }) + return response.finalAnswer +} + +await useQA( + "I have some questions about the weather data. " + + "You can assume the temperature is in Fahrenheit " + + "and the wind speed is in mph." +) + +await useQA( + "What's the average wind speed, the max wind speed, " + + "and the min wind speed?" +) +// END ExampleMessageHistory + +await client.close(); \ No newline at end of file diff --git a/docs/query-agent/_includes/code/conversations.py b/docs/query-agent/_includes/code/conversations.py new file mode 100644 index 000000000..ad96f6c1f --- /dev/null +++ b/docs/query-agent/_includes/code/conversations.py @@ -0,0 +1,71 @@ +import sys +sys.path.insert(0, "docs/query-agent/_includes/code") +import os +from util import load_client_internally, populate_weaviate +client = load_client_internally() +populate_weaviate(client, False) + +from weaviate.agents.query import QueryAgent + +qa = QueryAgent( + client=client, + collections=["Weather"], +) + +# START BasicConversation +from weaviate.agents.classes import ChatMessage + +conversation = [ + ChatMessage( + role="user", + content=( + "I have some questions about the weather data. " + "You can assume the temperature is in Fahrenheit " + "and the wind speed is in mph." + ) + ), + ChatMessage( + role="assistant", + content=( + "I can help with that. " + "What specific information are you looking for?" + ) + ), + ChatMessage( + role="user", + content=( + "What's the average wind speed, the max wind speed, " + "and the min wind speed?" + ) + ) +] + +response = qa.ask(conversation) +# END BasicConversation + +# START ExampleMessageHistory +message_history: list[ChatMessage] = [] + +def use_qa(query: str) -> str: + message_history.append( + ChatMessage(role="user", content=query) + ) + response = qa.ask(message_history) + message_history.append( + ChatMessage(role="assistant", content=response.final_answer) + ) + return response.final_answer + +use_qa( + "I have some questions about the weather data. " + "You can assume the temperature is in Fahrenheit " + "and the wind speed is in mph." +) + +use_qa( + "What's the average wind speed, the max wind speed, " + "and the min wind speed?" +) +# END ExampleMessageHistory + +client.close() \ No newline at end of file diff --git a/docs/query-agent/_includes/code/instantiation.mts b/docs/query-agent/_includes/code/instantiation.mts new file mode 100644 index 000000000..19baaaf44 --- /dev/null +++ b/docs/query-agent/_includes/code/instantiation.mts @@ -0,0 +1,44 @@ +import 'dotenv/config' +const { populateWeaviate } = await import('./util.mjs').catch(() => import('../docs/query-agent/_includes/code/util.mjs')); +// START WeaviateSetup +import weaviate from 'weaviate-client'; +import { QueryAgent } from 'weaviate-agents'; + +const headers = { + // END WeaviateSetup + 'X-OpenAI-API-Key': process.env.OPENAI_API_KEY as string, + // START WeaviateSetup + // Provide your required API key(s), e.g. Cohere, OpenAI, etc. for the configured vectorizer(s) + 'X-INFERENCE-PROVIDER-API-KEY': process.env.YOUR_INFERENCE_PROVIDER_KEY as string, +}; + +const client = await weaviate.connectToWeaviateCloud(process.env.WEAVIATE_URL as string, { + authCredentials: new weaviate.ApiKey(process.env.WEAVIATE_API_KEY as string), + headers, +}); +// END WeaviateSetup + + +// START InstantiateQueryAgent +const qa = new QueryAgent(client); +// END InstantiateQueryAgent + + +// START InstantiateWithCollections +const qaWithCollections = new QueryAgent(client, { + collections: ['FinancialContracts', 'Weather'], +}); +// END InstantiateWithCollections + +await populateWeaviate(client, false); + +// START InstantiateWithoutCollections +const qaWithoutCollections = new QueryAgent(client); + +await qaWithoutCollections.ask( + "What type of contracts have been signed and who were the authors?", { + collections: ['FinancialContracts', 'Weather'], +}); +// END InstantiateWithoutCollections + +await client.close(); diff --git a/docs/query-agent/_includes/code/instantiation.py b/docs/query-agent/_includes/code/instantiation.py new file mode 100644 index 000000000..a81d13f4b --- /dev/null +++ b/docs/query-agent/_includes/code/instantiation.py @@ -0,0 +1,49 @@ +import sys +sys.path.insert(0, "docs/query-agent/_includes/code") +from util import populate_weaviate + +# START WeaviateSetup +import os +import weaviate +from weaviate.agents.query import QueryAgent +from weaviate.classes.init import Auth +headers = { + # END WeaviateSetup + "X-OpenAI-API-Key": os.environ.get("OPENAI_API_KEY"), + # START WeaviateSetup + # Provide your required API key(s), e.g. Cohere, OpenAI, etc. for the configured vectorizer(s) + "X-INFERENCE-PROVIDER-API-KEY": os.environ.get("YOUR_INFERENCE_PROVIDER_KEY", ""), +} + +client = weaviate.connect_to_weaviate_cloud( + cluster_url=os.environ.get("WEAVIATE_URL"), + auth_credentials=Auth.api_key(os.environ.get("WEAVIATE_API_KEY")), + headers=headers, +) +# END WeaviateSetup + + +# START InstantiateQueryAgent +qa = QueryAgent(client=client) +# END InstantiateQueryAgent + + +# START InstantiateWithCollections +qa = QueryAgent( + client=client, + collections=["FinancialContracts", "Weather"] +) +# END InstantiateWithCollections + +populate_weaviate(client, False) + +# START InstantiateWithoutCollections +qa = QueryAgent(client=client) + +qa.ask( + "What type of contracts have been signed and who were the authors?", + collections=["FinancialContracts", "Weather"] +) +# END InstantiateWithoutCollections + +client.close() \ No newline at end of file diff --git a/docs/query-agent/_includes/code/introduction.mts b/docs/query-agent/_includes/code/introduction.mts new file mode 100644 index 000000000..25254d665 --- /dev/null +++ b/docs/query-agent/_includes/code/introduction.mts @@ -0,0 +1,23 @@ +import 'dotenv/config' +const { loadClientInternally, populateWeaviate } = await import('./util.mjs').catch(() => import('../docs/query-agent/_includes/code/util.mjs')); +import weaviate from 'weaviate-client'; + +const client = await loadClientInternally(); +await populateWeaviate(client, false); + +// START FirstExample +import { QueryAgent } from 'weaviate-agents'; + +const qa = new QueryAgent( + client, // your Weaviate cloud client + { + collections: ['FinancialContracts'], + } +); + +const res = await qa.ask("Find all contracts signed in 2025"); + +res.display(); +// END FirstExample + +await client.close(); \ No newline at end of file diff --git a/docs/query-agent/_includes/code/introduction.py b/docs/query-agent/_includes/code/introduction.py new file mode 100644 index 000000000..349084ef3 --- /dev/null +++ b/docs/query-agent/_includes/code/introduction.py @@ -0,0 +1,21 @@ +import sys +sys.path.insert(0, "docs/query-agent/_includes/code") +from util import load_client_internally, populate_weaviate +client = load_client_internally() +populate_weaviate(client, False) + +# START FirstExample +from weaviate.agents.query import QueryAgent + +qa = QueryAgent( + client=client, # your Weaviate cloud client + collections=["FinancialContracts"] +) + +res = qa.ask("Find all contracts signed in 2025") + +res.display() + +# END FirstExample + +client.close() \ No newline at end of file diff --git a/docs/query-agent/_includes/code/query_agent.mts b/docs/query-agent/_includes/code/query_agent.mts new file mode 100644 index 000000000..baef9f49f --- /dev/null +++ b/docs/query-agent/_includes/code/query_agent.mts @@ -0,0 +1,367 @@ +import 'dotenv/config' +import weaviate from 'weaviate-client'; +import { ChatMessage } from 'weaviate-agents'; +const { loadClientInternally, populateWeaviate } = await import('./util.mjs').catch(() => import('../docs/query-agent/_includes/code/util.mjs')); +const client = await loadClientInternally(); +await populateWeaviate(client, false); + + +// START InstantiateQueryAgent +import { QueryAgent } from 'weaviate-agents'; + +// Instantiate a new agent object +const queryAgent = new QueryAgent( + client, // Your Weaviate client object + { + collections: ['ECommerce', 'FinancialContracts', 'Weather'], + + } +); +// END InstantiateQueryAgent + +// START SystemPromptExample +// Define a custom system prompt to guide the agent's behavior +const systemPrompt = `You are a helpful assistant that can answer questions about the products and + users in the database. When you write your response use standard markdown + formatting for lists, tables, and other structures. Emphasize key insights + and provide actionable recommendations when relevant.` + +const qaWithPrompt = new QueryAgent( + client, { + collections: [{ + name: 'ECommerce', + targetVector: ['name_description_brand_vector'], + viewProperties: ['description'] + // tenant: 'tenantA' // Optional for multi-tenancy + }, "FinancialContracts", "Weather"], + systemPrompt: systemPrompt +}) + +const responseWithPrompt = await qaWithPrompt.ask("What are the most expensive items in the store?") + +responseWithPrompt.display() +// END SystemPromptExample + +// START QueryAgentCollectionConfiguration +const qaWithConfig = new QueryAgent(client, { + collections: [ + { + name: 'ECommerce', + targetVector: ['name_description_brand_vector'], + viewProperties: ['description'] + // tenant: 'tenantA' // Optional for multi-tenancy + }, + { name: 'FinancialContracts' }, + { name: 'Weather' } + ] +}); +// END QueryAgentCollectionConfiguration + +// START UserDefinedFilters +// Apply persistent filters that will always be combined with agent-generated filters + +const eCommerceCollection = client.collections.use("ECommerce") + +const qaWithFilter = new QueryAgent( + client, { + collections: [{ + name: "ECommerce", + // This filter ensures only items above $50 are considered + additionalFilters: eCommerceCollection.filter.byProperty("price").greaterThan(50), + targetVector: [ + "name_description_brand_vector" + ], // Required target vector name(s) for collections with named vectors + }], +}) + +// The agent will automatically combine these filters with any it generates +const responseWithFilter = await qaWithFilter.ask("Find me some affordable clothing items") + +responseWithFilter.display() + +// You can also apply filters dynamically at runtime +const runtimeConfig = { + name: "ECommerce", + additionalFilters: eCommerceCollection.filter.byProperty("category").equal("Footwear"), + targetVector: ["name_description_brand_vector"] +} + +const responseWithRuntimeFilter = await queryAgent.ask("What products are available?", { + collections: [runtimeConfig] +}) + +responseWithRuntimeFilter.display() +// END UserDefinedFilters + + +// Reset qa to original configuration for following examples +const qa = new QueryAgent( + client, { + collections: [ + { + name: "ECommerce", + targetVector: ["name_description_brand_vector"], + viewProperties: ["name", "description", "price"], + }, + "FinancialContracts", + "Weather", + ], +}) + +// START QueryAgentAskBasicCollectionSelection +const contractResponse = await qa.ask( + "What kinds of contracts are listed? What's the most common type of contract?", { + collections: ['FinancialContracts'] +}); + +contractResponse.display(); +// END QueryAgentAskBasicCollectionSelection + +// START QueryAgentAskCollectionConfig +const clothingResponse = await qaWithConfig.ask( + "I like vintage clothes and nice shoes. Recommend some of each below $60.", { + collections: [ + { + name: 'ECommerce', + targetVector: ['name_description_brand_vector'], + viewProperties: ['name', 'description', 'category', 'brand'] + }, + { + name: 'FinancialContracts' + } + ] +}); + +clothingResponse.display(); +// END QueryAgentAskCollectionConfig + +// START BasicSearchQuery +// Perform a search using Search Mode (retrieval only, no answer generation) +const basicSearchResponse = await qa.search("Find me some vintage shoes under $70", { + limit: 10 +}) + +// Access the search results +for (const obj of basicSearchResponse.searchResults.objects) { + console.log(`Product: ${obj.properties['name']} - ${obj.properties['price']}`) +} +// END BasicSearchQuery + +// START DiversityRanking +// Diversity ranking needs a vectorizer it can resolve. Scope the call to a +// single collection with a target vector so the agent knows what to use. +const diversitySearchResponse = await qa.search("summer shoes", { + limit: 10, + diversityWeight: 0.5, + collections: [{ + name: "ECommerce", + targetVector: ["name_description_brand_vector"], + }], +}) + +// Access the search results +for (const obj of diversitySearchResponse.searchResults.objects) { + console.log(`Product: ${obj.properties['name']} - ${obj.properties['price']}`) +} +// END DiversityRanking + +// START BasicAskQuery +// Perform a query +const basicQuery = "I like vintage clothes and nice shoes. Recommend some of each below $60." +const basicResponse = await qaWithConfig.ask(basicQuery); + +basicResponse.display(); +// END BasicAskQuery + +// START SearchModeResponseStructure +// SearchModeResponse structure for TypeScript +const searchResponse = await qa.search("winter boots for under $100", { + limit: 5 +}) + +// Access different parts of the response +console.log("Original query:", basicQuery) +console.log("Total time:", searchResponse.totalTime) + +// Access usage statistics +console.log("Usage statistics:", searchResponse.usage) + +// Access the searches performed (if any) +if (searchResponse.searches) { + for (const search of searchResponse.searches) { + console.log("Search performed:", search) + } +} +// Access the search results (QueryReturn object) +for (const obj of searchResponse.searchResults.objects) { + console.log("Properties:", obj.properties) + console.log("Metadata:", obj.metadata) +} +// END SearchModeResponseStructure + +// START SearchPagination +// Search with pagination +const responsePage1 = await qa.search( + "Find summer shoes and accessories between $50 and $100 that have the tag 'sale'", { + limit: 3, +}) + +// Get the next page of results +const responsePage2 = await responsePage1.next({ + limit: 3, + offset: 3, +}) + +// Continue paginating +const responsePage3 = await responsePage2.next({ + limit: 3, + offset: 6, +}) + +const pages = [responsePage1, responsePage2, responsePage3]; + +pages.forEach((pageResponse, index) => { + const pageNum = index + 1; + console.log(`Page ${pageNum}:`); + + pageResponse.searchResults.objects.forEach(obj => { + // Safely access properties in case they don't exist + const name = obj.properties.name || "Unknown Product"; + const price = obj.properties.price || "Unknown Price"; + console.log(`${name} - $${price}`); + }); +}); +// END SearchPagination + + +// START FollowUpQuery +// Perform a follow-up query and include the answer from the previous query + +const basicConversation: ChatMessage[] = [ + { + role: "assistant", + content: basicResponse.finalAnswer + }, + { + role: "user", + content: "I like the vintage clothes options, can you do the same again but above $200?", + }, +] + +const followingResponse = await qaWithConfig.ask(basicConversation) + +// Print the response +followingResponse.display() +// END FollowUpQuery + +// START ConversationalQuery +// Create a conversation with multiple turns +const conversation: ChatMessage[] = [ + { + role: "user", + content: "Hi!" + }, + { + role: "assistant", + content: "Hello! How can I assist you today?" + }, + { + role: "user", + content: "I have some questions about the weather data. You can assume the temperature is in Fahrenheit and the wind speed is in mph.", + }, + { + role: "assistant", + content: "I can help with that. What specific information are you looking for?", + }, +] + +// Add the user's query +conversation.push( + { + role: "user", + content: "What's the average wind speed, the max wind speed, and the min wind speed", + } +) + +// Get the response +const response = await qaWithConfig.ask(conversation) +console.log(response.finalAnswer) + +// Continue the conversation +conversation.push({ role: "assistant", content: response.finalAnswer }) +conversation.push({ role: "user", content: "and for the temperature?" }) + +const followUpResponse = await qaWithConfig.ask(conversation) +console.log(followUpResponse.finalAnswer) +// END ConversationalQuery + +var query = "What is the weather like in San Francisco?"; + +// START StreamResponse +// Setting includeProgress to false will skip progressMessages, and only stream +// the streamedTokens / the final response. +for await (const event of qa.askStream(query, { + includeProgress: true, // Default: True + includeFinalState: true, // Default: True +})) { + if (event.outputType === "progressMessage") { + // The message is a human-readable string, structured info available in event.details + console.log(event.message); + } else if (event.outputType === "streamedTokens") { + // The delta is a string containing the next chunk of the final answer + process.stdout.write(event.delta); + } else { + // This is the final response, as returned by queryAgent.ask() + event.display(); + } +} +// END StreamResponse + +// START InspectResponseExample +console.log('\n=== Query Agent Response ==='); +console.log(`Original Query: ${basicQuery}\n`); // Pre-defined by user + +console.log('🔍 Final Answer Found:'); +console.log(`${basicResponse.finalAnswer}\n`); + +console.log('🔍 Searches Executed:'); +for (const collectionSearches of basicResponse.searches) { + console.log(`- ${collectionSearches.query}\n`); +} + +if (basicResponse.aggregations) { + console.log('📊 Aggregation Results:'); + for (const agg of basicResponse.aggregations) { + console.log(`- ${JSON.stringify(agg)}\n`); + } +} + +if (basicResponse.missingInformation && basicResponse.missingInformation.length > 0) { + if (basicResponse.isPartialAnswer) { + console.log('⚠️ Answer is Partial - Missing Information:'); + } else { + console.log('⚠️ Missing Information:'); + } + for (const missing of basicResponse.missingInformation) { + console.log(`- ${missing}`); + } +} +// END InspectResponseExample + +if (!basicResponse.finalAnswer || basicResponse.finalAnswer === '') { + throw new Error('Final answer is empty or null'); +} + +// START SuggestQueries +const suggestResponse = await qa.suggestQueries({ + collections: ["FinancialContracts"], + numQueries: 3, + instructions: "High-level themes and open-ended exploration", +}); + +for (const suggestedQuery of suggestResponse.queries) { + console.log(suggestedQuery.query); +} +// END SuggestQueries + +await client.close() diff --git a/docs/agents/_includes/query_agent.py b/docs/query-agent/_includes/code/query_agent.py similarity index 65% rename from docs/agents/_includes/query_agent.py rename to docs/query-agent/_includes/code/query_agent.py index d76ef6303..e8df3d9c7 100644 --- a/docs/agents/_includes/query_agent.py +++ b/docs/query-agent/_includes/code/query_agent.py @@ -1,212 +1,23 @@ -from weaviate.classes.config import Configure, Property, DataType +import sys +sys.path.insert(0, "docs/query-agent/_includes/code") +from util import populate_weaviate, load_client_internally - -def populate_weaviate(client, overwrite_existing=False): - - if overwrite_existing: - client.collections.delete("ECommerce") - client.collections.delete("Weather") - client.collections.delete("FinancialContracts") - - if not client.collections.exists("ECommerce"): - client.collections.create( - "ECommerce", - description="A dataset that lists clothing items, their brands, prices, and more.", - vector_config=[ - Configure.Vectors.text2vec_weaviate( - name="description_vector", - source_properties=[ - "description", - ], - ), - Configure.Vectors.text2vec_weaviate( - name="name_description_brand_vector", - source_properties=[ - "name", - "description", - "brand", - ], - ), - ], - properties=[ - Property(name="collection", data_type=DataType.TEXT), - Property( - name="category", - data_type=DataType.TEXT, - description="The category to which the clothing item belongs", - ), - Property( - name="tags", - data_type=DataType.TEXT_ARRAY, - description="The tags that are assocciated with the clothing item", - ), - Property(name="subcategory", data_type=DataType.TEXT), - Property(name="name", data_type=DataType.TEXT), - Property( - name="description", - data_type=DataType.TEXT, - description="A detailed description of the clothing item", - ), - Property( - name="brand", - data_type=DataType.TEXT, - description="The brand of the clothing item", - ), - Property(name="product_id", data_type=DataType.UUID), - Property( - name="colors", - data_type=DataType.TEXT_ARRAY, - description="The colors on the clothing item", - ), - Property(name="reviews", data_type=DataType.TEXT_ARRAY), - Property(name="image_url", data_type=DataType.TEXT), - Property( - name="price", - data_type=DataType.NUMBER, - description="The price of the clothing item in USD", - ), - ], - ) - overwrite_existing = True - - if not client.collections.exists("Weather"): - client.collections.create( - "Weather", - description="Daily weather information including temperature, wind speed, precipitation, pressure etc.", - # Use legacy single-vectorizer config so QueryAgent diversity - # ranking can resolve the collection's vectorizer. - vectorizer_config=Configure.Vectorizer.text2vec_weaviate(), - properties=[ - Property(name="date", data_type=DataType.DATE), - Property(name="humidity", data_type=DataType.NUMBER), - Property(name="precipitation", data_type=DataType.NUMBER), - Property(name="wind_speed", data_type=DataType.NUMBER), - Property(name="visibility", data_type=DataType.NUMBER), - Property(name="pressure", data_type=DataType.NUMBER), - Property( - name="temperature", - data_type=DataType.NUMBER, - description="temperature value in Celsius", - ), - ], - ) - overwrite_existing = True - - if not client.collections.exists("FinancialContracts"): - client.collections.create( - "FinancialContracts", - description="A dataset of financial contracts between individuals and/or companies, as well as information on the type of contract and who has authored them.", - # Use legacy single-vectorizer config so QueryAgent diversity - # ranking can resolve the collection's vectorizer. - vectorizer_config=Configure.Vectorizer.text2vec_weaviate(), - ) - overwrite_existing = True - - from datasets import load_dataset - - if not overwrite_existing: - print("Data already exists in Weaviate, skipping import.") - return - - ecommerce_dataset = load_dataset( - "weaviate/agents", "query-agent-ecommerce", split="train", streaming=True - ) - weather_dataset = load_dataset( - "weaviate/agents", "query-agent-weather", split="train", streaming=True - ) - financial_dataset = load_dataset( - "weaviate/agents", - "query-agent-financial-contracts", - split="train", - streaming=True, - ) - - ecommerce_collection = client.collections.use("ECommerce") - weather_collection = client.collections.use("Weather") - financial_collection = client.collections.use("FinancialContracts") - - print("\nImport `query-agent-ecommerce` dataset into Weaviate") - with ecommerce_collection.batch.fixed_size(batch_size=200) as batch: - for item in ecommerce_dataset: - batch.add_object(properties=item["properties"]) - if batch.number_errors > 0: - print("Batch import stopped due to excessive errors.") - break - - failed_objects = ecommerce_collection.batch.failed_objects - if failed_objects: - print(f"Number of failed imports: {len(failed_objects)}") - print(f"First failed object: {failed_objects[0]}") - - print("\nImport `query-agent-weather` dataset into Weaviate") - with weather_collection.batch.fixed_size(batch_size=200) as batch: - for item in weather_dataset: - batch.add_object(properties=item["properties"], vector=item["vector"]) - if batch.number_errors > 0: - print("Batch import stopped due to excessive errors.") - break - - failed_objects = weather_collection.batch.failed_objects - if failed_objects: - print(f"Number of failed imports: {len(failed_objects)}") - print(f"First failed object: {failed_objects[0]}") - - print("\nImport `query-agent-financial-contracts` dataset into Weaviate") - with financial_collection.batch.fixed_size(batch_size=200) as batch: - for item in financial_dataset: - batch.add_object(properties=item["properties"], vector=item["vector"]) - if batch.number_errors > 0: - print("Batch import stopped due to excessive errors.") - break - - failed_objects = financial_collection.batch.failed_objects - if failed_objects: - print(f"Number of failed imports: {len(failed_objects)}") - print(f"First failed object: {failed_objects[0]}") - - print("\nData import complete!") - print(f"Size of the ECommerce dataset: {len(ecommerce_collection)}") - print(f"Size of the Weather dataset: {len(weather_collection)}") - print(f"Size of the Financial dataset: {len(financial_collection)}") - - client.close() # Free up resources - - -# START InstantiateQueryAgent import os import weaviate -from weaviate.classes.init import Auth -from weaviate.agents.query import QueryAgent - -# END InstantiateQueryAgent - -# START InstantiateQueryAgent - -headers = { - # END InstantiateQueryAgent - "X-Cohere-API-Key": os.environ.get("COHERE_API_KEY"), - "X-OpenAI-API-Key": os.environ.get("OPENAI_API_KEY"), - # START InstantiateQueryAgent - # Provide your required API key(s), e.g. Cohere, OpenAI, etc. for the configured vectorizer(s) - "X-INFERENCE-PROVIDER-API-KEY": os.environ.get("YOUR_INFERENCE_PROVIDER_KEY", ""), -} -client = weaviate.connect_to_weaviate_cloud( - cluster_url=os.environ.get("WEAVIATE_URL"), - auth_credentials=Auth.api_key(os.environ.get("WEAVIATE_API_KEY")), - headers=headers, -) -# END InstantiateQueryAgent +client = load_client_internally() populate_weaviate( client, overwrite_existing=True -) # Populate the Weaviate instance with data +) # START InstantiateQueryAgent +from weaviate.agents.query import QueryAgent # Instantiate a new agent object qa = QueryAgent( - client=client, collections=["ECommerce", "FinancialContracts", "Weather"] + client=client, # Your Weaviate client object + collections=["ECommerce", "FinancialContracts", "Weather"] ) # END InstantiateQueryAgent @@ -379,15 +190,13 @@ def populate_weaviate(client, overwrite_existing=False): print(f"{response.final_answer}\n") print("🔍 Searches Executed:") -for collection_searches in response.searches: - for result in collection_searches: - print(f"- {result}\n") +for search in response.searches: + print(f"- {search}\n") if len(response.aggregations) > 0: print("📊 Aggregation Results:") - for collection_aggs in response.aggregations: - for agg in collection_aggs: - print(f"- {agg}\n") + for agg in response.aggregations: + print(f"- {agg}\n") if response.missing_information: if response.is_partial_answer: @@ -462,6 +271,12 @@ def populate_weaviate(client, overwrite_existing=False): "summer shoes", limit=10, diversity_weight=0.5, + collections=[ + QueryAgentCollectionConfig( + name="ECommerce", + target_vector=["name_description_brand_vector"], + ) + ], ) # Access the search results @@ -547,18 +362,22 @@ def populate_weaviate(client, overwrite_existing=False): output.display() # END StreamResponse -client.close() - # START UsageAsyncQueryAgent import asyncio import os import weaviate +from weaviate.classes.init import Auth from weaviate.agents.query import AsyncQueryAgent +# Provide any inference-provider keys your collections' vectorizers / generative +# models need; an empty dict is fine if the cluster uses Weaviate Embeddings. +headers = { + "X-OpenAI-API-Key": os.environ.get("OPENAI_API_KEY", ""), +} async_client = weaviate.use_async_with_weaviate_cloud( cluster_url=os.environ.get("WEAVIATE_URL"), - auth_credentials=os.environ.get("WEAVIATE_API_KEY"), + auth_credentials=Auth.api_key(os.environ.get("WEAVIATE_API_KEY")), headers=headers, ) @@ -681,7 +500,7 @@ async def run_streaming_query(): # START SuggestQueries response = qa.suggest_queries( - collections=["ArxivPapers"], + collections=["FinancialContracts"], num_queries=3, instructions="High-level themes and open-ended exploration", ) @@ -689,3 +508,5 @@ async def run_streaming_query(): for suggested_query in response.queries: print(suggested_query.query) # END SuggestQueries + +client.close() diff --git a/docs/query-agent/_includes/code/query_agent_as_a_tool.py b/docs/query-agent/_includes/code/query_agent_as_a_tool.py new file mode 100644 index 000000000..5050a230d --- /dev/null +++ b/docs/query-agent/_includes/code/query_agent_as_a_tool.py @@ -0,0 +1,211 @@ +# Reference snippets for the "Using the Query Agent as a tool" recipe. +# These examples integrate external providers (Gemini, Vertex AI, Ollama, +# LangChain, LlamaIndex) and are NOT executed by the test suite. The file +# exists so the documentation has a single source of truth for each snippet. + +# START DefineTool +import os +import weaviate +from weaviate.classes.init import Auth +from weaviate.agents.query import QueryAgent + +weaviate_client = weaviate.connect_to_weaviate_cloud( + cluster_url=os.getenv("WEAVIATE_URL"), + auth_credentials=Auth.api_key(os.getenv("WEAVIATE_API_KEY")), +) + +agent = QueryAgent( + client=weaviate_client, + collections=["WeaviateBlogChunks"], +) + +def ask_weaviate(query: str) -> str: + """ + Look up information in the Weaviate knowledge base by asking a question. + + Use this tool whenever the user asks something that may be answered by + content stored in the Weaviate database. The tool runs an agentic search + and returns a natural-language answer composed from the underlying data. + + Args: + query: The user's question, phrased in natural language. + + Returns: + A natural-language answer composed from the relevant content + in the database. + """ + return agent.ask(query).final_answer +# END DefineTool + +# START GeminiClient +from google import genai +from google.genai import types + +client = genai.Client() +config = types.GenerateContentConfig(tools=[ask_weaviate]) +# END GeminiClient + +# START GeminiAsk +prompt = """ +You are connected to a database that has Weaviate blog posts. +How do I deploy Weaviate with Docker? +""" + +chat = client.chats.create(model="gemini-2.0-flash", config=config) +response = chat.send_message(prompt) +print(response.text) +# END GeminiAsk + +# START VertexClient +from google import genai +from google.genai.types import GenerateContentConfig + +client = genai.Client( + vertexai=True, + project=os.getenv("GCP_PROJECT_ID"), + location=os.getenv("GOOGLE_CLOUD_REGION"), +) + +MODEL_ID = "gemini-2.0-flash-001" # any Model Garden model that supports function calling +# END VertexClient + +# START VertexAsk +prompt = """ +You are connected to a database that has Weaviate blog posts. +How do I deploy Weaviate with Docker? +""" + +response = client.models.generate_content( + model=MODEL_ID, + contents=prompt, + config=GenerateContentConfig(tools=[ask_weaviate], temperature=0), +) +print(response.text) +# END VertexAsk + +# START OllamaSchema +import json +import ollama + +query_agent_tool_schema = [{ + "type": "function", + "function": { + "name": "ask_weaviate", + "description": "Send a question to the Weaviate knowledge base and get a natural-language answer.", + "parameters": { + "type": "object", + "properties": { + "query": { + "type": "string", + "description": "The question to ask, in natural language.", + }, + }, + "required": ["query"], + }, + }, +}] + +tool_mapping = {"ask_weaviate": ask_weaviate} +# END OllamaSchema + +# START OllamaLoop +def chat_with_weaviate(user_message: str, model_name: str = "llama3.1") -> str: + messages = [{"role": "user", "content": user_message}] + + # First call: let the model decide whether to call a tool + response = ollama.chat( + model=model_name, + messages=messages, + tools=query_agent_tool_schema, + ) + messages.append(response["message"]) + + # If a tool was requested, execute it and append the result + if response["message"].get("tool_calls"): + for tool in response["message"]["tool_calls"]: + function_name = tool["function"]["name"] + args = tool["function"]["arguments"] + if isinstance(args, str): + args = json.loads(args) + query = args.get("query", "") + + print(f"Querying Weaviate with: {query}") + function_response = tool_mapping[function_name](query) + + messages.append({ + "role": "tool", + "content": function_response, + "name": function_name, + }) + + # Second call: let the model use the tool result to compose its answer + final_response = ollama.chat(model=model_name, messages=messages) + return final_response["message"]["content"] + + # No tool used — return the model's direct answer + return response["message"]["content"] +# END OllamaLoop + +# START OllamaAsk +response = chat_with_weaviate( + user_message="How do I deploy Weaviate with Docker?", + model_name="llama3.1", +) +print(response) +# END OllamaAsk + +# START LangchainTool +from langchain.tools import tool +from langchain.chat_models import init_chat_model + +@tool +def ask_weaviate_tool(query: str) -> str: + """ + Look up information in the Weaviate knowledge base by asking a question. + + Use this whenever the user asks something that may be answered by + content stored in the Weaviate database. + + Args: + query: The user's question in natural language. + + Returns: + A natural-language answer composed from the relevant content. + """ + return ask_weaviate(query) +# END LangchainTool + +# START LangchainBind +llm = init_chat_model("gpt-4o", model_provider="openai") +llm_with_tools = llm.bind_tools([ask_weaviate_tool]) +# END LangchainBind + +# START LangchainAsk +response = llm_with_tools.invoke("How do I run Weaviate with Docker?") +print(response.content) +# END LangchainAsk + +# START LlamaWorkflow +from llama_index.llms.openai import OpenAI +from llama_index.core.agent.workflow import AgentWorkflow + +llm = OpenAI(model="gpt-4o-mini") + +workflow = AgentWorkflow.from_tools_or_functions( + [ask_weaviate], + llm=llm, + system_prompt=( + "You are an agent that can search a Weaviate database " + "of blog content and answer questions about it." + ), +) +# END LlamaWorkflow + +# START LlamaAsk +response = await workflow.run(user_msg="How do I run Weaviate with Docker?") +print(response) +# END LlamaAsk + +# START Close +weaviate_client.close() +# END Close diff --git a/docs/query-agent/_includes/code/query_agent_ecommerce_assistant.py b/docs/query-agent/_includes/code/query_agent_ecommerce_assistant.py new file mode 100644 index 000000000..d6423692d --- /dev/null +++ b/docs/query-agent/_includes/code/query_agent_ecommerce_assistant.py @@ -0,0 +1,149 @@ +import sys + +sys.path.insert(0, "docs/query-agent/_includes/code") +import os +from util import populate_recipe_ecommerce, populate_brands + +# START Connect +import weaviate +from weaviate.classes.init import Auth + +client = weaviate.connect_to_weaviate_cloud( + cluster_url=os.environ.get("WEAVIATE_URL"), + auth_credentials=Auth.api_key(os.environ.get("WEAVIATE_API_KEY")), +) +# END Connect + +# Provision the demo collections + data for the test run. The doc shows the +# equivalent create/import code below, which is what a reader following along +# would run themselves. +populate_recipe_ecommerce(client) +populate_brands(client, overwrite_existing=False) + +# -- Shown in the docs but not executed in the test (data is provisioned above). +""" +# START CreateCollections +from weaviate.classes.config import Configure, Property, DataType + +client.collections.create( + "Brands", + description="A dataset that lists information about clothing brands, their parent companies, average rating and more.", + vector_config=Configure.Vectors.text2vec_weaviate() +) + +client.collections.create( + "ECommerce", + description="A dataset that lists clothing items, their brands, prices, and more.", + vector_config=Configure.Vectors.text2vec_weaviate(), + properties=[ + Property(name="collection", data_type=DataType.TEXT), + Property(name="category", data_type=DataType.TEXT), + Property(name="tags", data_type=DataType.TEXT_ARRAY), + Property(name="subcategory", data_type=DataType.TEXT), + Property(name="name", data_type=DataType.TEXT), + Property(name="description", data_type=DataType.TEXT), + Property(name="brand", data_type=DataType.TEXT), + Property(name="product_id", data_type=DataType.UUID), + Property(name="colors", data_type=DataType.TEXT_ARRAY), + Property(name="reviews", data_type=DataType.TEXT_ARRAY), + Property(name="image_url", data_type=DataType.TEXT), + Property(name="price", data_type=DataType.NUMBER, description="price of item in USD"), + ] +) +# END CreateCollections +""" + +""" +# START ImportData +from datasets import load_dataset + +brands_dataset = load_dataset("weaviate/agents", "query-agent-brands", split="train", streaming=True) +ecommerce_dataset = load_dataset("weaviate/agents", "query-agent-ecommerce", split="train", streaming=True) + +brands_collection = client.collections.use("Brands") +ecommerce_collection = client.collections.use("ECommerce") + +with brands_collection.batch.dynamic() as batch: + for item in brands_dataset: + batch.add_object(properties=item["properties"]) + +with ecommerce_collection.batch.dynamic() as batch: + for item in ecommerce_dataset: + batch.add_object(properties=item["properties"]) +# END ImportData +""" + +# START InstantiateAgent +from weaviate.agents.query import QueryAgent + +agent = QueryAgent( + client=client, + collections=["ECommerce", "Brands"], + system_prompt=( + "You are a friendly e-commerce shopping assistant. " + "Help the user find products from the catalog, compare options, and answer questions about brands. " + "Recommend specific items with their names, brands and prices, and explain why they match the user's request." + ), +) +# END InstantiateAgent + +# START AskVintage +response = agent.ask("I like the vintage clothes, can you list me some options that are less than $200?") +response.display() +# END AskVintage + +# START FollowUp +from weaviate.agents.classes import ChatMessage + +conversation = [ + ChatMessage(role="user", content="I like the vintage clothes, can you list me some options that are less than $200?"), + ChatMessage(role="assistant", content=response.final_answer), + ChatMessage(role="user", content="What about some nice shoes, same budget as before?"), +] + +new_response = agent.ask(conversation) +new_response.display() +# END FollowUp + +# START AskAggregation +response = agent.ask("What is the name of the brand that lists the most shoes?") +response.display() +# END AskAggregation + +# START AskMultiCollection +response = agent.ask( + "Does the brand 'Loom & Aura' have a parent brand or child brands and what countries do they operate from? " + "Also, what's the average price of a item from 'Loom & Aura'?" +) +response.display() +# END AskMultiCollection + +# START AssistantClass +from weaviate.agents.classes import ChatMessage + +class ECommerceAssistant: + def __init__(self, agent: QueryAgent): + self.agent = agent + self.history: list[ChatMessage] = [] + + def chat(self, user_message: str) -> str: + self.history.append(ChatMessage(role="user", content=user_message)) + response = self.agent.ask(self.history) + self.history.append(ChatMessage(role="assistant", content=response.final_answer)) + return response.final_answer + + def reset(self): + self.history = [] +# END AssistantClass + +# START DriveAssistant +assistant = ECommerceAssistant(agent) + +print(assistant.chat("I like the vintage clothes, can you list me some options that are less than $200?")) +print(assistant.chat("What about some nice shoes, same budget as before?")) +print(assistant.chat("Tell me more about the brand that makes the first pair you mentioned.")) +# END DriveAssistant + +# START Close +client.close() +# END Close diff --git a/docs/query-agent/_includes/code/query_agent_get_started.py b/docs/query-agent/_includes/code/query_agent_get_started.py new file mode 100644 index 000000000..2cf55a8dd --- /dev/null +++ b/docs/query-agent/_includes/code/query_agent_get_started.py @@ -0,0 +1,162 @@ +import sys + +sys.path.insert(0, "docs/query-agent/_includes/code") +import os +from util import populate_weaviate, populate_brands, populate_recipe_ecommerce + +# START Connect +import weaviate +from weaviate.classes.init import Auth + +client = weaviate.connect_to_weaviate_cloud( + cluster_url=os.environ.get("WEAVIATE_URL"), + auth_credentials=Auth.api_key(os.environ.get("WEAVIATE_API_KEY")), +) +# END Connect + +# Provision the demo collections + data for the test run. The doc shows the +# equivalent create/import code below (the CreateCollections / ImportData +# snippets), which is what a reader following along would run themselves. +populate_weaviate(client, overwrite_existing=False, include_ecommerce=False) +populate_recipe_ecommerce(client) +populate_brands(client, overwrite_existing=False) + +# -- The two snippets below are shown in the docs but not executed in the test +# (the collections + data are provisioned once via the helpers above). +""" +# START CreateCollections +from weaviate.classes.config import Configure, Property, DataType + +client.collections.create( + "Brands", + description="A dataset that lists information about clothing brands, their parent companies, average rating and more.", + vector_config=Configure.Vectors.text2vec_weaviate() +) + +client.collections.create( + "ECommerce", + description="A dataset that lists clothing items, their brands, prices, and more.", + vector_config=Configure.Vectors.text2vec_weaviate(), + properties=[ + Property(name="collection", data_type=DataType.TEXT), + Property(name="category", data_type=DataType.TEXT), + Property(name="tags", data_type=DataType.TEXT_ARRAY), + Property(name="subcategory", data_type=DataType.TEXT), + Property(name="name", data_type=DataType.TEXT), + Property(name="description", data_type=DataType.TEXT), + Property(name="brand", data_type=DataType.TEXT), + Property(name="product_id", data_type=DataType.UUID), + Property(name="colors", data_type=DataType.TEXT_ARRAY), + Property(name="reviews", data_type=DataType.TEXT_ARRAY), + Property(name="image_url", data_type=DataType.TEXT), + Property(name="price", data_type=DataType.NUMBER, description="price of item in USD"), + ] +) + +client.collections.create( + "Weather", + description="Daily weather information including temperature, wind speed, precipitation, pressure etc.", + vector_config=Configure.Vectors.text2vec_weaviate(), + properties=[ + Property(name="date", data_type=DataType.DATE), + Property(name="humidity", data_type=DataType.NUMBER), + Property(name="precipitation", data_type=DataType.NUMBER), + Property(name="wind_speed", data_type=DataType.NUMBER), + Property(name="visibility", data_type=DataType.NUMBER), + Property(name="pressure", data_type=DataType.NUMBER), + Property(name="temperature", data_type=DataType.NUMBER, description="temperature value in Celsius") + ] +) + +client.collections.create( + "FinancialContracts", + description="A dataset of financial contracts between individuals and/or companies, as well as information on the type of contract and who has authored them.", + vector_config=Configure.Vectors.text2vec_weaviate(), +) +# END CreateCollections +""" + +""" +# START ImportData +from datasets import load_dataset + +brands_dataset = load_dataset("weaviate/agents", "query-agent-brands", split="train", streaming=True) +ecommerce_dataset = load_dataset("weaviate/agents", "query-agent-ecommerce", split="train", streaming=True) +weather_dataset = load_dataset("weaviate/agents", "query-agent-weather", split="train", streaming=True) +financial_dataset = load_dataset("weaviate/agents", "query-agent-financial-contracts", split="train", streaming=True) + +brands_collection = client.collections.use("Brands") +ecommerce_collection = client.collections.use("ECommerce") +weather_collection = client.collections.use("Weather") +financial_collection = client.collections.use("FinancialContracts") + +with brands_collection.batch.dynamic() as batch: + for item in brands_dataset: + batch.add_object(properties=item["properties"]) + +with ecommerce_collection.batch.dynamic() as batch: + for item in ecommerce_dataset: + batch.add_object(properties=item["properties"]) + +with weather_collection.batch.dynamic() as batch: + for item in weather_dataset: + batch.add_object(properties=item["properties"]) + +with financial_collection.batch.dynamic() as batch: + for item in financial_dataset: + batch.add_object(properties=item["properties"]) +# END ImportData +""" + +# START InstantiateAgent +from weaviate.agents.query import QueryAgent + +agent = QueryAgent( + client=client, + collections=["ECommerce", "Brands", "Weather", "FinancialContracts"], +) +# END InstantiateAgent + +# START AskWeather +response = agent.ask("What was the average temperature in the first week of May 2025?") +response.display() +# END AskWeather + +# START AskAccessResponse +print(response.final_answer) +print(response.sources) +# END AskAccessResponse + +# START AskClothing +response = agent.ask("I like vintage clothes and nice shoes. Recommend some of each below $60.") +print(response.final_answer) +# END AskClothing + +# START SearchMode +search_response = agent.search( + "Find me some vintage shoes under $70", + limit=10, +) + +for obj in search_response.search_results.objects: + print(f"Product: {obj.properties['name']} - ${obj.properties['price']}") +# END SearchMode + +# START SuggestQueries +suggestions = agent.suggest_queries(num_queries=3) +for q in suggestions.queries: + print(q.query) +# END SuggestQueries + +# START SuggestQueriesInstructions +suggestions = agent.suggest_queries( + num_queries=3, + instructions="Focus on questions a customer would ask about the clothing items.", +) +for q in suggestions.queries: + print(q.query) +# END SuggestQueriesInstructions + +# START Close +client.close() +# END Close diff --git a/docs/query-agent/_includes/code/query_agent_streamlit_chat.py b/docs/query-agent/_includes/code/query_agent_streamlit_chat.py new file mode 100644 index 000000000..c0185bd46 --- /dev/null +++ b/docs/query-agent/_includes/code/query_agent_streamlit_chat.py @@ -0,0 +1,203 @@ +# Reference snippets for the "Build a streaming chat UI with Streamlit" recipe. +# This is a Streamlit application (`streamlit run app.py`) and is NOT executed by +# the test suite. The file exists so the documentation has a single source of +# truth for each snippet. + +# START LoadData +"""One-time data import for the Streamlit chat recipe.""" +import os +import weaviate +from weaviate.classes.init import Auth +from weaviate.classes.config import Configure, Property, DataType +from datasets import load_dataset + +client = weaviate.connect_to_weaviate_cloud( + cluster_url=os.environ["WEAVIATE_URL"], + auth_credentials=Auth.api_key(os.environ["WEAVIATE_API_KEY"]), +) + +# --- Create the collections -------------------------------------------------- +# The `description` fields below are what the Query Agent reads to decide +# which collection to search and how to interpret each property — providing +# them is what lets the agent route a question like "what's the cheapest +# vintage dress?" to the right place. + +client.collections.create( + "Brands", + description=( + "A dataset that lists information about clothing brands, their " + "parent companies, average rating and more." + ), + vector_config=Configure.Vectors.text2vec_weaviate(), +) + +client.collections.create( + "ECommerce", + description="A dataset that lists clothing items, their brands, prices, and more.", + vector_config=Configure.Vectors.text2vec_weaviate(), + properties=[ + Property(name="collection", data_type=DataType.TEXT), + Property(name="category", data_type=DataType.TEXT), + Property(name="tags", data_type=DataType.TEXT_ARRAY), + Property(name="subcategory", data_type=DataType.TEXT), + Property(name="name", data_type=DataType.TEXT), + Property(name="description", data_type=DataType.TEXT), + Property(name="brand", data_type=DataType.TEXT), + Property(name="product_id", data_type=DataType.UUID), + Property(name="colors", data_type=DataType.TEXT_ARRAY), + Property(name="reviews", data_type=DataType.TEXT_ARRAY), + Property(name="image_url", data_type=DataType.TEXT), + Property( + name="price", + data_type=DataType.NUMBER, + description="price of item in USD", + ), + ], +) + +# --- Pull the datasets from Hugging Face ------------------------------------ +brands_dataset = load_dataset( + "weaviate/agents", "query-agent-brands", split="train", streaming=True +) +ecommerce_dataset = load_dataset( + "weaviate/agents", "query-agent-ecommerce", split="train", streaming=True +) + +brands_collection = client.collections.use("Brands") +ecommerce_collection = client.collections.use("ECommerce") + +print("Importing Brands…") +with brands_collection.batch.dynamic() as batch: + for item in brands_dataset: + batch.add_object(properties=item["properties"]) + +print("Importing ECommerce…") +with ecommerce_collection.batch.dynamic() as batch: + for item in ecommerce_dataset: + batch.add_object(properties=item["properties"]) + +print(f"\nBrands collection: {len(brands_collection)} objects") +print(f"ECommerce collection: {len(ecommerce_collection)} objects") + +client.close() +# END LoadData + +# START AppFull +"""Streamlit chat UI for the Weaviate Query Agent.""" +import os + +import streamlit as st +import weaviate +from weaviate.classes.init import Auth +from weaviate.agents.query import QueryAgent +from weaviate.agents.classes import ( + ProgressMessage, + StreamedTokens, + AskModeResponse, + ChatMessage, +) + +st.set_page_config(page_title="E-Commerce Assistant", page_icon="🛍️") +st.title("🛍️ E-Commerce Assistant") +st.caption("Powered by the Weaviate Query Agent") + + +@st.cache_resource +def get_agent() -> QueryAgent: + client = weaviate.connect_to_weaviate_cloud( + cluster_url=os.environ["WEAVIATE_URL"], + auth_credentials=Auth.api_key(os.environ["WEAVIATE_API_KEY"]), + ) + return QueryAgent( + client=client, + collections=["ECommerce", "Brands"], + system_prompt=( + "You are a friendly e-commerce shopping assistant. " + "Help the user find products from the catalog, compare options, " + "and answer questions about brands. Recommend specific items with " + "their name, brand and price, and explain why they match." + ), + ) + + +agent = get_agent() + +# Chat history persists across script re-runs +if "messages" not in st.session_state: + st.session_state.messages = [] + +with st.sidebar: + st.header("Settings") + if st.button("Reset conversation", use_container_width=True): + st.session_state.messages = [] + st.rerun() + +# Render history so the user sees prior turns +for msg in st.session_state.messages: + with st.chat_message(msg["role"]): + st.markdown(msg["content"]) + +# Handle a new prompt +if prompt := st.chat_input("Ask about products, brands, prices…"): + st.session_state.messages.append({"role": "user", "content": prompt}) + with st.chat_message("user"): + st.markdown(prompt) + + # Build the full conversation for the agent + conversation = [ + ChatMessage(role=m["role"], content=m["content"]) + for m in st.session_state.messages + ] + + # Stream the agent's response + with st.chat_message("assistant"): + progress_box = st.empty() + answer_box = st.empty() + sources_to_show = [] + answer_so_far = "" + + for output in agent.ask_stream(conversation): + if isinstance(output, ProgressMessage): + progress_box.info(f"🔄 {output.message}") + elif isinstance(output, StreamedTokens): + answer_so_far += output.delta + answer_box.markdown(answer_so_far + "▌") + elif isinstance(output, AskModeResponse): + progress_box.empty() + answer_box.markdown(answer_so_far) + sources_to_show = output.sources or [] + + if sources_to_show: + with st.expander(f"Sources ({len(sources_to_show)})"): + for src in sources_to_show: + st.write(f"- `{src.object_id}` in **{src.collection}**") + + st.session_state.messages.append({"role": "assistant", "content": answer_so_far}) +# END AppFull + +# START GetAgentExcerpt +@st.cache_resource +def get_agent() -> QueryAgent: + client = weaviate.connect_to_weaviate_cloud(...) + return QueryAgent(client=client, collections=[...], system_prompt=...) +# END GetAgentExcerpt + +# START StreamingExcerpt +for output in agent.ask_stream(conversation): + if isinstance(output, ProgressMessage): + progress_box.info(f"🔄 {output.message}") + elif isinstance(output, StreamedTokens): + answer_so_far += output.delta + answer_box.markdown(answer_so_far + "▌") + elif isinstance(output, AskModeResponse): + progress_box.empty() + answer_box.markdown(answer_so_far) + sources_to_show = output.sources or [] +# END StreamingExcerpt + +# START SourcesExcerpt +if sources_to_show: + with st.expander(f"Sources ({len(sources_to_show)})"): + for src in sources_to_show: + st.write(f"- `{src.object_id}` in **{src.collection}**") +# END SourcesExcerpt diff --git a/docs/query-agent/_includes/code/query_agent_vs_diy.py b/docs/query-agent/_includes/code/query_agent_vs_diy.py new file mode 100644 index 000000000..b4fada08d --- /dev/null +++ b/docs/query-agent/_includes/code/query_agent_vs_diy.py @@ -0,0 +1,243 @@ +import sys + +sys.path.insert(0, "docs/query-agent/_includes/code") +import os +from util import populate_weaviate + +# This recipe requires an OpenAI API key (it builds a DIY LLM pipeline with the +# OpenAI SDK). The test that runs this file is skipped when OPENAI_API_KEY is unset. + +# -- Shown in the docs as a standalone `load_data.py`, but not executed here: +# the Weather collection + data are provisioned once via the helper below. +""" +# START LoadData +import os +import weaviate +from weaviate.classes.init import Auth +from weaviate.classes.config import Configure, Property, DataType +from datasets import load_dataset + +client = weaviate.connect_to_weaviate_cloud( + cluster_url=os.environ["WEAVIATE_URL"], + auth_credentials=Auth.api_key(os.environ["WEAVIATE_API_KEY"]), +) + +client.collections.create( + "Weather", + description=( + "Daily weather information including temperature, wind speed, " + "precipitation, pressure etc." + ), + vector_config=Configure.Vectors.text2vec_weaviate(), + properties=[ + Property(name="date", data_type=DataType.DATE), + Property(name="humidity", data_type=DataType.NUMBER), + Property(name="precipitation", data_type=DataType.NUMBER), + Property(name="wind_speed", data_type=DataType.NUMBER), + Property(name="visibility", data_type=DataType.NUMBER), + Property(name="pressure", data_type=DataType.NUMBER), + Property( + name="temperature", + data_type=DataType.NUMBER, + description="temperature value in Celsius", + ), + ], +) + +weather_dataset = load_dataset( + "weaviate/agents", "query-agent-weather", split="train", streaming=True +) +weather_collection = client.collections.use("Weather") + +print("Importing Weather…") +with weather_collection.batch.dynamic() as batch: + for item in weather_dataset: + batch.add_object(properties=item["properties"], vector=item["vector"]) + +print(f"Weather collection: {len(weather_collection)} objects") +client.close() +# END LoadData +""" + +# START SharedSetup +import os +import weaviate +from weaviate.classes.init import Auth + +weaviate_client = weaviate.connect_to_weaviate_cloud( + cluster_url=os.environ["WEAVIATE_URL"], + auth_credentials=Auth.api_key(os.environ["WEAVIATE_API_KEY"]), +) +weather = weaviate_client.collections.use("Weather") + +question = "Show me the top 5 windiest days where it rained more than 5mm." +# END SharedSetup + +populate_weaviate(weaviate_client, overwrite_existing=False, include_ecommerce=False) + +# START PydanticModels +from typing import Literal +from pydantic import BaseModel, Field + + +class SearchFilter(BaseModel): + field: str = Field(description="Property name to filter on.") + operator: Literal["=", "!=", ">", "<", ">=", "<="] = Field( + description="Comparison operator to apply between the property and the value." + ) + value: str | float | int | bool = Field( + description="Value to compare the property against." + ) + + +class SearchSort(BaseModel): + field: str = Field(description="Property name to sort by.") + direction: Literal["asc", "desc"] = Field(description="Sort direction.") + + +class Search(BaseModel): + query: str | None = Field( + default=None, + description=( + "Optional semantic search string. Set this only when the question has a " + "free-text or topical component (e.g. 'hot summer days'). Leave None for " + "purely structured queries that filter and sort numeric or date properties." + ), + ) + filters: list[SearchFilter] = Field( + default_factory=list, + description="Filters to apply, combined with AND.", + ) + sort: SearchSort | None = Field( + default=None, + description="Optional sort order. Use it for questions like 'windiest', 'coldest', 'most recent'.", + ) + limit: int = Field(default=10, description="Maximum number of results to return.") +# END PydanticModels + +# START GetSchema +def get_schema(collection) -> list[dict]: + """Read the collection schema so the LLM knows what properties exist.""" + config = collection.config.get() + return [ + {"name": p.name, "type": str(p.data_type)} + for p in config.properties + ] +# END GetSchema + +# START PlanQuery +import json +from openai import OpenAI + +openai_client = OpenAI() + + +def plan_query(question: str, schema: list[dict]) -> Search: + """Ask the LLM to turn a natural-language question into a structured Search.""" + prompt = ( + f"Collection schema:\n{json.dumps(schema, indent=2)}\n\n" + f'User question: "{question}"\n\n' + "Return a Search object with the filters, sort and limit needed to answer it." + ) + completion = openai_client.beta.chat.completions.parse( + model="gpt-4o-mini", + messages=[{"role": "user", "content": prompt}], + response_format=Search, + ) + return completion.choices[0].message.parsed +# END PlanQuery + +# START BuildQuery +from weaviate.classes.query import Filter, Sort + + +def build_filter(f: SearchFilter) -> Filter: + """Convert a single SearchFilter into a Weaviate Filter.""" + prop = Filter.by_property(f.field) + if f.operator == "=": + return prop.equal(f.value) + if f.operator == "!=": + return prop.not_equal(f.value) + if f.operator == ">": + return prop.greater_than(f.value) + if f.operator == "<": + return prop.less_than(f.value) + if f.operator == ">=": + return prop.greater_or_equal(f.value) + if f.operator == "<=": + return prop.less_or_equal(f.value) + raise ValueError(f"Unsupported operator: {f.operator}") + + +def build_filters(filters: list[SearchFilter]) -> Filter | None: + """Combine multiple SearchFilters with AND. Returns None if there are none.""" + if not filters: + return None + if len(filters) == 1: + return build_filter(filters[0]) + return Filter.all_of([build_filter(f) for f in filters]) + + +def build_sort(s: SearchSort | None) -> Sort | None: + """Convert a SearchSort into a Weaviate Sort, or None if not specified.""" + if s is None: + return None + return Sort.by_property(s.field, ascending=(s.direction == "asc")) +# END BuildQuery + +# START RunQuery +def run_query(collection, plan: Search): + """Execute the Search against Weaviate, picking the right query method.""" + filters = build_filters(plan.filters) + if plan.query: + return collection.query.near_text( + query=plan.query, + filters=filters, + limit=plan.limit, + ) + return collection.query.fetch_objects( + filters=filters, + sort=build_sort(plan.sort), + limit=plan.limit, + ) +# END RunQuery + +# START ComposeAnswer +def compose_answer(question: str, objects: list) -> str: + """Turn the matching rows into a natural-language answer.""" + rows = [obj.properties for obj in objects] + prompt = ( + f'User question: "{question}"\n\n' + f"Results:\n{json.dumps(rows, default=str, indent=2)}\n\n" + "Write a short, friendly answer using only the results above." + ) + completion = openai_client.chat.completions.create( + model="gpt-4o-mini", + messages=[{"role": "user", "content": prompt}], + ) + return completion.choices[0].message.content +# END ComposeAnswer + +# START AskDiy +def ask_diy(question: str, collection) -> str: + """End-to-end DIY pipeline: schema → plan → query → answer.""" + schema = get_schema(collection) + plan = plan_query(question, schema) + print(f"LLM plan: {plan}") + results = run_query(collection, plan) + return compose_answer(question, results.objects) + + +print(ask_diy(question, weather)) +# END AskDiy + +# START WithAgent +from weaviate.agents.query import QueryAgent + +agent = QueryAgent(client=weaviate_client, collections=["Weather"]) +print(agent.ask(question).final_answer) +# END WithAgent + +# START Close +weaviate_client.close() +# END Close diff --git a/docs/query-agent/_includes/code/quickstart.mts b/docs/query-agent/_includes/code/quickstart.mts new file mode 100644 index 000000000..727b5c932 --- /dev/null +++ b/docs/query-agent/_includes/code/quickstart.mts @@ -0,0 +1,76 @@ +import 'dotenv/config' +const { populateWeaviate } = await import('./util.mjs').catch(() => import('../docs/query-agent/_includes/code/util.mjs')); +// START InstantiateQueryAgent +import weaviate from 'weaviate-client'; +import { QueryAgent } from 'weaviate-agents'; + +// END InstantiateQueryAgent + +// START InstantiateQueryAgent +const headers = { + // END InstantiateQueryAgent + 'X-OpenAI-API-Key': process.env.OPENAI_API_KEY as string, + // START InstantiateQueryAgent + // Provide your required API key(s), e.g. Cohere, OpenAI, etc. for the configured vectorizer(s) + 'X-INFERENCE-PROVIDER-API-KEY': process.env.YOUR_INFERENCE_PROVIDER_KEY as string, +}; + +const client = await weaviate.connectToWeaviateCloud( + process.env.WEAVIATE_URL as string, + { + authCredentials: new weaviate.ApiKey(process.env.WEAVIATE_API_KEY as string), + headers, + } +); +// END InstantiateQueryAgent + +// Populate Weaviate with data +await populateWeaviate(client, true); + +// START InstantiateQueryAgent + +// Instantiate a new query agent object +let qa = new QueryAgent(client, { + collections: ['ECommerce', 'FinancialContracts', 'Weather'], +}); +// END InstantiateQueryAgent + +qa = new QueryAgent(client, { + collections: [ + { + name: 'ECommerce', + targetVector: [ + 'name_description_brand_vector' + ], + }, + 'FinancialContracts', + 'Weather', + ], +}); + +// START BasicSearchQuery +const searchResponse = await qa.search( + "Find me some vintage shoes under $70", { + limit: 10, +}); +// END BasicSearchQuery + +// START BasicSearchResponse +for (const obj of searchResponse.searchResults.objects) { + console.log(`Product: ${obj.properties['name']} - $${obj.properties['price']}`); +} +// END BasicSearchResponse + +// START BasicAskQuery +const askResponse = await qa.ask( + "I like vintage clothes and nice shoes. Recommend some of each below $60." +); +// END BasicAskQuery + +// START BasicAskResponse +askResponse.sources; // retrieved objects from initial search +askResponse.finalAnswer; // final answer to the question +askResponse.display(); +// END BasicAskResponse + +await client.close(); diff --git a/docs/query-agent/_includes/code/quickstart.py b/docs/query-agent/_includes/code/quickstart.py new file mode 100644 index 000000000..73af640cb --- /dev/null +++ b/docs/query-agent/_includes/code/quickstart.py @@ -0,0 +1,78 @@ +import sys +sys.path.insert(0, "docs/query-agent/_includes/code") +from util import populate_weaviate + +# START InstantiateQueryAgent +import os +import weaviate +from weaviate.classes.init import Auth +from weaviate.agents.query import QueryAgent + +headers = { + # END InstantiateQueryAgent + "X-OpenAI-API-Key": os.environ.get("OPENAI_API_KEY"), + # START InstantiateQueryAgent + # Provide your required API key(s), e.g. Cohere, OpenAI, etc. for the configured vectorizer(s) + "X-INFERENCE-PROVIDER-API-KEY": os.environ.get("YOUR_INFERENCE_PROVIDER_KEY", ""), +} + +client = weaviate.connect_to_weaviate_cloud( + cluster_url=os.environ.get("WEAVIATE_URL"), + auth_credentials=Auth.api_key(os.environ.get("WEAVIATE_API_KEY")), + headers=headers, +) +# END InstantiateQueryAgent + +populate_weaviate( + client, overwrite_existing=True +) # Populate the Weaviate instance with data + +# START InstantiateQueryAgent + +# Instantiate a new query agent object +qa = QueryAgent( + client=client, + collections=["ECommerce", "FinancialContracts", "Weather"] +) +# END InstantiateQueryAgent + +from weaviate.agents.classes import QueryAgentCollectionConfig +qa = QueryAgent( + client=client, + collections=[ + QueryAgentCollectionConfig( + name="ECommerce", + target_vector=[ + "name_description_brand_vector" + ], + ), + "FinancialContracts", + "Weather" + ] +) + +# START BasicSearchQuery +search_response = qa.search( + "Find me some vintage shoes under $70", + limit=10 +) +# END BasicSearchQuery + +# START BasicSearchResponse +for obj in search_response.search_results.objects: + print(f"Product: {obj.properties['name']} - ${obj.properties['price']}") +# END BasicSearchResponse + +# START BasicAskQuery +ask_response = qa.ask( + "I like vintage clothes and nice shoes. Recommend some of each below $60." +) +# END BasicAskQuery + +# START BasicAskResponse +ask_response.sources # retrieved objects from initial search +ask_response.final_answer # final answer to the question +ask_response.display() +# END BasicAskResponse + +client.close() \ No newline at end of file diff --git a/docs/query-agent/_includes/code/search_mode.mts b/docs/query-agent/_includes/code/search_mode.mts new file mode 100644 index 000000000..fc9f355b8 --- /dev/null +++ b/docs/query-agent/_includes/code/search_mode.mts @@ -0,0 +1,105 @@ +import 'dotenv/config' +const { loadClientInternally, populateWeaviate } = await import('./util.mjs').catch(() => import('../docs/query-agent/_includes/code/util.mjs')); +// START BasicSearchMode +import weaviate from 'weaviate-client'; +import { QueryAgent } from 'weaviate-agents'; + +// END BasicSearchMode + +// START ImportSearchResponse +import { SearchModeResponse } from 'weaviate-agents'; +// END ImportSearchResponse + +// START BasicSearchMode +const client = await weaviate.connectToWeaviateCloud( + process.env.WEAVIATE_URL as string, { + authCredentials: new weaviate.ApiKey(process.env.WEAVIATE_API_KEY as string), +}); + +// Instantiate a new query agent object +let qa = new QueryAgent(client, { + collections: ['ECommerce', 'FinancialContracts', 'Weather'], +}); +// END BasicSearchMode + +qa = new QueryAgent(client, { + collections: [ + { + name: 'ECommerce', + targetVector: [ + 'name_description_brand_vector' + ], + }, + 'FinancialContracts', + 'Weather', + ], +}); + +await populateWeaviate(client); + +// START BasicSearchMode +const searchResponse = await qa.search("Find me some vintage shoes under $70", { + limit: 10, +}); + +// Access the matching Weaviate objects +for (const obj of searchResponse.searchResults.objects) { + console.log(`Product: ${obj.properties['name']} - $${obj.properties['price']}`); +} +// END BasicSearchMode + +// START DiversityRanking +const diversitySearchResponse = await qa.search("summer shoes", { + limit: 10, + diversityWeight: 0.5, + collections: [{ + name: "ECommerce", + targetVector: ["name_description_brand_vector"], + }], +}); + +for (const obj of diversitySearchResponse.searchResults.objects) { + console.log(`Product: ${obj.properties['name']} - $${obj.properties['price']}`); +} +// END DiversityRanking + +// START SearchPagination +// Search with pagination +const responsePage1 = await qa.search( + "Find summer shoes and accessories between $50 and $100 that have the tag 'sale'", { + limit: 3, +}); + +// Get the next page of results +const responsePage2 = await responsePage1.next({ limit: 3, offset: 3 }); + +// Continue paginating +const responsePage3 = await responsePage2.next({ limit: 3, offset: 6 }); + +const pages = [responsePage1, responsePage2, responsePage3]; + +pages.forEach((pageResponse, index) => { + const pageNum = index + 1; + console.log(`Page ${pageNum}:`); + + pageResponse.searchResults.objects.forEach(obj => { + // Safely access properties in case they don't exist + const name = obj.properties.name || "Unknown Product"; + const price = obj.properties.price || "Unknown Price"; + console.log(` ${name} - $${price}`); + }); +}); +// END SearchPagination + +// START FilteringExample +const filteringResponse = await qa.search("Find me some vintage shoes under $70", { + filtering: "precision", + limit: 10, +}); + +for (const obj of filteringResponse.searchResults.objects) { + console.log(`Product: ${obj.properties['name']} - $${obj.properties['price']}`); +} +// END FilteringExample + +await client.close(); diff --git a/docs/query-agent/_includes/code/search_mode.py b/docs/query-agent/_includes/code/search_mode.py new file mode 100644 index 000000000..d1bab68d4 --- /dev/null +++ b/docs/query-agent/_includes/code/search_mode.py @@ -0,0 +1,169 @@ +import sys +import asyncio +sys.path.insert(0, "docs/query-agent/_includes/code") +from util import populate_weaviate, load_client_internally + + +client = load_client_internally() +populate_weaviate(client, False) +client.close() + +# START BasicSearchMode +import os +import weaviate +from weaviate.agents.query import QueryAgent +from weaviate.classes.init import Auth + +client = weaviate.connect_to_weaviate_cloud( + cluster_url=os.environ.get("WEAVIATE_URL"), + auth_credentials=Auth.api_key(os.environ.get("WEAVIATE_API_KEY")), +) + +qa = QueryAgent( + client=client, + collections=["ECommerce"], +) +# END BasicSearchMode + +from weaviate.agents.classes import QueryAgentCollectionConfig +qa = QueryAgent( + client=client, + collections=[ + QueryAgentCollectionConfig( + name="ECommerce", + target_vector=[ + "name_description_brand_vector" + ], + ) + ] +) + +# START BasicSearchMode +search_response = qa.search( + query="Find me some vintage shoes under $70", + limit=10, +) + +# Access the matching Weaviate objects +for obj in search_response.search_results.objects: + print(f"Product: {obj.properties['name']} - ${obj.properties['price']}") +# END BasicSearchMode + +# START DiversityRanking +qa = QueryAgent( + client=client, + collections=[ + QueryAgentCollectionConfig( + name="ECommerce", + target_vector=["name_description_brand_vector"], + ) + ] +) + +search_response = qa.search( + "summer shoes", + limit=10, + diversity_weight=0.5, +) + +for obj in search_response.search_results.objects: + print(f"Product: {obj.properties['name']} - ${obj.properties['price']}") +# END DiversityRanking + +# START SearchPagination +# Search with pagination +response_page_1 = qa.search( + "Find summer shoes and accessories between $50 and $100 that have the tag 'sale'", + limit=3, +) + +# Get the next page of results +response_page_2 = response_page_1.next(limit=3, offset=3) + +# Continue paginating +response_page_3 = response_page_2.next(limit=3, offset=6) + +# Access results from each page +for page_num, page_response in enumerate( + [response_page_1, response_page_2, response_page_3], 1 +): + print(f"Page {page_num}:") + for obj in page_response.search_results.objects: + # Safely access properties in case they don't exist + name = obj.properties.get("name", "Unknown Product") + price = obj.properties.get("price", "Unknown Price") + print(f" {name} - ${price}") + print() +# END SearchPagination + +# START FilteringExample +search_response = qa.search( + "Find me some vintage shoes under $70", + filtering="precision", + limit=10, +) + +for obj in search_response.search_results.objects: + print(f"Product: {obj.properties['name']} - ${obj.properties['price']}") +# END FilteringExample + +# --- Async code examples in string as top-level await doesn't work, full code will be executed in +# asyncio.run below + +""" +# START AsyncInstantiation +from weaviate.agents.query import AsyncQueryAgent + +async_client = weaviate.use_async_with_weaviate_cloud( + cluster_url=os.environ.get("WEAVIATE_URL"), + auth_credentials=Auth.api_key(os.environ.get("WEAVIATE_API_KEY")), +) +await async_client.connect() + +async_qa = AsyncQueryAgent( + client=async_client, + collections=[ + QueryAgentCollectionConfig( + name="ECommerce", + target_vector=["name_description_brand_vector"], + ) + ] +) +# END AsyncInstantiation +""" +""" +# START AsyncSearch +await async_qa.search( + query="Find me some vintage shoes under $70", + limit=10, +) +# END AsyncSearch +""" + +async def _async_run_for_testing(): + from weaviate.agents.query import AsyncQueryAgent + + async_client = weaviate.use_async_with_weaviate_cloud( + cluster_url=os.environ.get("WEAVIATE_URL"), + auth_credentials=Auth.api_key(os.environ.get("WEAVIATE_API_KEY")), + ) + await async_client.connect() + + async_qa = AsyncQueryAgent( + client=async_client, + collections=[ + QueryAgentCollectionConfig( + name="ECommerce", + target_vector=["name_description_brand_vector"], + ) + ] + ) + + await async_qa.search( + query="Find me some vintage shoes under $70", + limit=10, + ) + await async_client.close() + +asyncio.run(_async_run_for_testing()) +client.close() \ No newline at end of file diff --git a/docs/query-agent/_includes/code/suggest_queries.mts b/docs/query-agent/_includes/code/suggest_queries.mts new file mode 100644 index 000000000..eaec99af4 --- /dev/null +++ b/docs/query-agent/_includes/code/suggest_queries.mts @@ -0,0 +1,44 @@ +import 'dotenv/config' +const { populateWeaviate } = await import('./util.mjs').catch(() => import('../docs/query-agent/_includes/code/util.mjs')); + +// START SuggestQueries +import weaviate from 'weaviate-client'; +import { QueryAgent } from 'weaviate-agents'; + +// END SuggestQueries + +// START SuggestQueries +const client = await weaviate.connectToWeaviateCloud( + process.env.WEAVIATE_URL as string, { + authCredentials: new weaviate.ApiKey(process.env.WEAVIATE_API_KEY as string), +}); + +let qa = new QueryAgent(client); + +// END SuggestQueries + +await populateWeaviate(client, false); + +// START SuggestQueries +const response = await qa.suggestQueries({ + collections: ['FinancialContracts'], + numQueries: 3, + instructions: 'High-level themes and open-ended exploration', +}); +// END SuggestQueries + +// START IndividualCall +qa = new QueryAgent(client, { + collections: ['FinancialContracts'], +}); + +await qa.suggestQueries(); +// END IndividualCall + +// START AccessResponse +for (const suggestedQuery of response.queries) { + console.log(suggestedQuery.query); +} +// END AccessResponse + +await client.close(); diff --git a/docs/query-agent/_includes/code/suggest_queries.py b/docs/query-agent/_includes/code/suggest_queries.py new file mode 100644 index 000000000..518a33035 --- /dev/null +++ b/docs/query-agent/_includes/code/suggest_queries.py @@ -0,0 +1,90 @@ +import sys +import asyncio + +sys.path.insert(0, "docs/query-agent/_includes/code") +from util import load_client_internally, populate_weaviate +client = load_client_internally() +populate_weaviate(client, False) + +# START SuggestQueries +from weaviate.agents.query import QueryAgent +qa = QueryAgent(client=client) + +response = qa.suggest_queries( + collections=["FinancialContracts"], + num_queries=3, + instructions="High-level themes and open-ended exploration", +) +# END SuggestQueries + +# START IndividualCall +qa = QueryAgent(client=client, collections=["FinancialContracts"]) + +qa.suggest_queries() +# END IndividualCall + + +# START AccessResponse +for suggested_query in response.queries: + print(suggested_query.query) +# END AccessResponse + +""" +# START AsyncInstantiation +import os +import weaviate +from weaviate.classes.init import Auth +from weaviate.agents.query import AsyncQueryAgent + +async_client = weaviate.use_async_with_weaviate_cloud( + cluster_url=os.environ.get("WEAVIATE_URL"), + auth_credentials=Auth.api_key(os.environ.get("WEAVIATE_API_KEY")), +) +await async_client.connect() + +async_qa = AsyncQueryAgent(client=async_client) +# END AsyncInstantiation +""" + +""" +# START AsyncSuggest +await async_qa.suggest_queries( + collections=["FinancialContracts"], + num_queries=3, + instructions="High-level themes and open-ended exploration", +) +# END AsyncSuggest +""" + +async def _async_run_for_testing(): + import os + import weaviate + from weaviate.classes.init import Auth + from weaviate.agents.query import AsyncQueryAgent + from weaviate.agents.classes import QueryAgentCollectionConfig + + async_client = weaviate.use_async_with_weaviate_cloud( + cluster_url=os.environ.get("WEAVIATE_URL"), + auth_credentials=Auth.api_key(os.environ.get("WEAVIATE_API_KEY")), + ) + await async_client.connect() + + async_qa = AsyncQueryAgent( + client=async_client, + collections=[ + QueryAgentCollectionConfig( + name="ECommerce", + target_vector=["name_description_brand_vector"], + ) + ] + ) + await async_qa.suggest_queries( + collections=["FinancialContracts"], + num_queries=3, + instructions="High-level themes and open-ended exploration", + ) + + await async_client.close() + +asyncio.run(_async_run_for_testing()) +client.close() \ No newline at end of file diff --git a/docs/query-agent/_includes/code/system_prompt.mts b/docs/query-agent/_includes/code/system_prompt.mts new file mode 100644 index 000000000..11d135937 --- /dev/null +++ b/docs/query-agent/_includes/code/system_prompt.mts @@ -0,0 +1,33 @@ +import 'dotenv/config' +const { loadClientInternally, populateWeaviate } = await import('./util.mjs').catch(() => import('../docs/query-agent/_includes/code/util.mjs')); +const client = await loadClientInternally(); +await populateWeaviate(client, false); + +// START InstantiateWithSystemPrompt +import { QueryAgent } from 'weaviate-agents'; + +// Define a custom system prompt to guide the agent's behavior +const systemPrompt = ` +You are a helpful assistant that can answer questions about the products and users in the database. +When you write your response use standard markdown formatting for lists, tables, and other structures. +Emphasize key insights and provide actionable recommendations when relevant. +`; + +const qa = new QueryAgent(client, { + systemPrompt: systemPrompt, + collections: [ + { + name: 'ECommerce', + targetVector: [ + 'name_description_brand_vector' + ], + }, + ], +}); +// END InstantiateWithSystemPrompt + +// START AskWithSystemPrompt +const response = await qa.ask("What are the most expensive items in the store?"); +// END AskWithSystemPrompt + +await client.close(); diff --git a/docs/query-agent/_includes/code/system_prompt.py b/docs/query-agent/_includes/code/system_prompt.py new file mode 100644 index 000000000..87d9639a6 --- /dev/null +++ b/docs/query-agent/_includes/code/system_prompt.py @@ -0,0 +1,35 @@ +import sys +sys.path.insert(0, "docs/query-agent/_includes/code") +from util import load_client_internally + +client = load_client_internally() + +# START InstantiateWithSystemPrompt +from weaviate.agents.query import QueryAgent +from weaviate.agents.classes import QueryAgentCollectionConfig + +# Define a custom system prompt to guide the agent's behavior +system_prompt = """ +You are a helpful assistant that can answer questions about the products and users in the database. +When you write your response use standard markdown formatting for lists, tables, and other structures. +Emphasize key insights and provide actionable recommendations when relevant. +""" + +qa = QueryAgent( + client=client, + collections=[ + QueryAgentCollectionConfig( + name="ECommerce", + target_vector=["name_description_brand_vector"], + ) + ], + system_prompt=system_prompt, + # END InstantiateWithSystemPrompt + timeout=120, + # START InstantiateWithSystemPrompt +) +# END InstantiateWithSystemPrompt + +# START AskWithSystemPrompt +response = qa.ask("What are the most expensive items in the store?") +# END AskWithSystemPrompt \ No newline at end of file diff --git a/docs/query-agent/_includes/code/util.mts b/docs/query-agent/_includes/code/util.mts new file mode 100644 index 000000000..6b56599fd --- /dev/null +++ b/docs/query-agent/_includes/code/util.mts @@ -0,0 +1,153 @@ +import 'dotenv/config'; +import weaviate, { type WeaviateClient, vectors, dataType, configure } from 'weaviate-client'; + +interface DatasetItem { + properties: any; + vector?: number[]; +} + +export async function populateWeaviate(client: WeaviateClient, overwriteExisting: boolean = false): Promise { + if (overwriteExisting) { + try { + await client.collections.delete('ECommerce'); + await client.collections.delete('Weather'); + await client.collections.delete('FinancialContracts'); + } catch (error) { + // Collections may not exist, continue + } + } + + // Create ECommerce collection + if (!(await client.collections.exists('ECommerce'))) { + await client.collections.create({ + name: 'ECommerce', + description: 'A dataset that lists clothing items, their brands, prices, and more.', + vectorizers: [ + vectors.text2VecWeaviate({ + name: 'description_vector', + sourceProperties: ['description'], + vectorIndexConfig: configure.vectorIndex.hnsw() + }), + vectors.text2VecWeaviate({ + name: 'name_description_brand_vector', + sourceProperties: ['name', 'description', 'brand'], + vectorIndexConfig: configure.vectorIndex.hnsw() + }) + ], + properties: [ + { name: 'collection', dataType: dataType.TEXT }, + { name: 'category', dataType: dataType.TEXT, description: 'The category to which the clothing item belongs' }, + { name: 'tags', dataType: dataType.TEXT_ARRAY, description: 'The tags that are associated with the clothing item' }, + { name: 'subcategory', dataType: dataType.TEXT }, + { name: 'name', dataType: dataType.TEXT }, + { name: 'description', dataType: dataType.TEXT, description: 'A detailed description of the clothing item' }, + { name: 'brand', dataType: dataType.TEXT, description: 'The brand of the clothing item' }, + { name: 'product_id', dataType: dataType.UUID }, + { name: 'colors', dataType: dataType.TEXT_ARRAY, description: 'The colors on the clothing item' }, + { name: 'reviews', dataType: dataType.TEXT_ARRAY }, + { name: 'image_url', dataType: dataType.TEXT }, + { name: 'price', dataType: dataType.NUMBER, description: 'The price of the clothing item in USD' } + ] + }); + } + + // Create Weather collection + if (!(await client.collections.exists('Weather'))) { + await client.collections.create({ + name: 'Weather', + description: 'Daily weather information including temperature, wind speed, precipitation, pressure etc.', + vectorizers: vectors.text2VecWeaviate(), + properties: [ + { name: 'date', dataType: dataType.DATE }, + { name: 'humidity', dataType: dataType.NUMBER }, + { name: 'precipitation', dataType: dataType.NUMBER }, + { name: 'wind_speed', dataType: dataType.NUMBER }, + { name: 'visibility', dataType: dataType.NUMBER }, + { name: 'pressure', dataType: dataType.NUMBER }, + { name: 'temperature', dataType: dataType.NUMBER, description: 'temperature value in Celsius' } + ] + }); + } + + // Create FinancialContracts collection + if (!(await client.collections.exists('FinancialContracts'))) { + await client.collections.create({ + name: 'FinancialContracts', + description: 'A dataset of financial contracts between individuals and/or companies, as well as information on the type of contract and who has authored them.', + vectorizers: vectors.text2VecWeaviate() + }); + } + + // Helper function to load dataset from HF Datasets Viewer API + async function loadHFDataset(repo: string, config: string, split: string = 'train'): Promise { + const url = `https://datasets-server.huggingface.co/rows?dataset=${repo}&config=${config}&split=${split}&limit=1000`; + + try { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`Failed to fetch dataset: ${response.statusText}`); + } + + const data = await response.json(); + return data.rows.map((row: any) => row.row); + } catch (error) { + console.error(`Error loading dataset ${repo}/${config}:`, error); + return []; + } + } + + const ecommerceCollection = client.collections.use('ECommerce'); + const weatherCollection = client.collections.use('Weather'); + const financialCollection = client.collections.use('FinancialContracts'); + + try { + const [ecommerceData, weatherData, financialData] = await Promise.all([ + loadHFDataset('weaviate/agents', 'query-agent-ecommerce', 'train'), + loadHFDataset('weaviate/agents', 'query-agent-weather', 'train'), + loadHFDataset('weaviate/agents', 'query-agent-financial-contracts', 'train') + ]); + + if (ecommerceData.length > 0) { + await ecommerceCollection.data.insertMany( + ecommerceData.map(item => ({ properties: item.properties || item })) + ); + } + + if (weatherData.length > 0) { + await weatherCollection.data.insertMany( + weatherData.map(item => ({ + properties: item.properties || item, + vectors: item.vector ? { default: item.vector } : undefined + })) + ); + } + + if (financialData.length > 0) { + await financialCollection.data.insertMany( + financialData.map(item => ({ + properties: item.properties || item, + vectors: item.vector ? { default: item.vector } : undefined + })) + ); + } + } catch (error) { + console.error('Error loading or inserting data:', error); + } +} + +export async function loadClientInternally(): Promise { + const headers = { + 'X-Cohere-API-Key': process.env.COHERE_API_KEY as string, + 'X-OpenAI-API-Key': process.env.OPENAI_API_KEY as string, + 'X-INFERENCE-PROVIDER-API-KEY': process.env.YOUR_INFERENCE_PROVIDER_KEY ?? '', + }; + + const client = await weaviate.connectToWeaviateCloud( + process.env.WEAVIATE_URL as string, + { + authCredentials: new weaviate.ApiKey(process.env.WEAVIATE_API_KEY as string), + headers, + } + ); + return client; +} diff --git a/docs/query-agent/_includes/code/util.py b/docs/query-agent/_includes/code/util.py new file mode 100644 index 000000000..0968cbc33 --- /dev/null +++ b/docs/query-agent/_includes/code/util.py @@ -0,0 +1,287 @@ +import os +import weaviate +from weaviate.classes.init import Auth +from weaviate.classes.config import Configure, Property, DataType + +def populate_weaviate(client, overwrite_existing=False, include_ecommerce=True): + + if overwrite_existing: + if include_ecommerce: + client.collections.delete("ECommerce") + client.collections.delete("Weather") + client.collections.delete("FinancialContracts") + + if include_ecommerce and not client.collections.exists("ECommerce"): + client.collections.create( + "ECommerce", + description="A dataset that lists clothing items, their brands, prices, and more.", + vector_config=[ + Configure.Vectors.text2vec_weaviate( + name="description_vector", + source_properties=[ + "description", + ], + ), + Configure.Vectors.text2vec_weaviate( + name="name_description_brand_vector", + source_properties=[ + "name", + "description", + "brand", + ], + ), + ], + properties=[ + Property(name="collection", data_type=DataType.TEXT), + Property( + name="category", + data_type=DataType.TEXT, + description="The category to which the clothing item belongs", + ), + Property( + name="tags", + data_type=DataType.TEXT_ARRAY, + description="The tags that are associated with the clothing item", + ), + Property(name="subcategory", data_type=DataType.TEXT), + Property(name="name", data_type=DataType.TEXT), + Property( + name="description", + data_type=DataType.TEXT, + description="A detailed description of the clothing item", + ), + Property( + name="brand", + data_type=DataType.TEXT, + description="The brand of the clothing item", + ), + Property(name="product_id", data_type=DataType.UUID), + Property( + name="colors", + data_type=DataType.TEXT_ARRAY, + description="The colors on the clothing item", + ), + Property(name="reviews", data_type=DataType.TEXT_ARRAY), + Property(name="image_url", data_type=DataType.TEXT), + Property( + name="price", + data_type=DataType.NUMBER, + description="The price of the clothing item in USD", + ), + ], + ) + overwrite_existing = True + + if not client.collections.exists("Weather"): + client.collections.create( + "Weather", + description="Daily weather information including temperature, wind speed, precipitation, pressure etc.", + vector_config=Configure.Vectors.text2vec_weaviate(), + properties=[ + Property(name="date", data_type=DataType.DATE), + Property(name="humidity", data_type=DataType.NUMBER), + Property(name="precipitation", data_type=DataType.NUMBER), + Property(name="wind_speed", data_type=DataType.NUMBER), + Property(name="visibility", data_type=DataType.NUMBER), + Property(name="pressure", data_type=DataType.NUMBER), + Property( + name="temperature", + data_type=DataType.NUMBER, + description="temperature value in Celsius", + ), + ], + ) + overwrite_existing = True + + if not client.collections.exists("FinancialContracts"): + client.collections.create( + "FinancialContracts", + description="A dataset of financial contracts between individuals and/or companies, as well as information on the type of contract and who has authored them.", + vector_config=Configure.Vectors.text2vec_weaviate(), + ) + overwrite_existing = True + + from datasets import load_dataset + + if not overwrite_existing: + print("Data already exists in Weaviate, skipping import.") + return + + weather_dataset = load_dataset( + "weaviate/agents", "query-agent-weather", split="train", streaming=True + ) + financial_dataset = load_dataset( + "weaviate/agents", + "query-agent-financial-contracts", + split="train", + streaming=True, + ) + + weather_collection = client.collections.use("Weather") + financial_collection = client.collections.use("FinancialContracts") + + if include_ecommerce: + ecommerce_dataset = load_dataset( + "weaviate/agents", "query-agent-ecommerce", split="train", streaming=True + ) + ecommerce_collection = client.collections.use("ECommerce") + + print("\nImport `query-agent-ecommerce` dataset into Weaviate") + with ecommerce_collection.batch.fixed_size(batch_size=200) as batch: + for item in ecommerce_dataset: + batch.add_object(properties=item["properties"]) + if batch.number_errors > 0: + print("Batch import stopped due to excessive errors.") + break + + failed_objects = ecommerce_collection.batch.failed_objects + if failed_objects: + print(f"Number of failed imports: {len(failed_objects)}") + print(f"First failed object: {failed_objects[0]}") + + print("\nImport `query-agent-weather` dataset into Weaviate") + with weather_collection.batch.fixed_size(batch_size=200) as batch: + for item in weather_dataset: + batch.add_object(properties=item["properties"], vector=item["vector"]) + if batch.number_errors > 0: + print("Batch import stopped due to excessive errors.") + break + + failed_objects = weather_collection.batch.failed_objects + if failed_objects: + print(f"Number of failed imports: {len(failed_objects)}") + print(f"First failed object: {failed_objects[0]}") + + print("\nImport `query-agent-financial-contracts` dataset into Weaviate") + with financial_collection.batch.fixed_size(batch_size=200) as batch: + for item in financial_dataset: + batch.add_object(properties=item["properties"], vector=item["vector"]) + if batch.number_errors > 0: + print("Batch import stopped due to excessive errors.") + break + + failed_objects = financial_collection.batch.failed_objects + if failed_objects: + print(f"Number of failed imports: {len(failed_objects)}") + print(f"First failed object: {failed_objects[0]}") + + print("\nData import complete!") + if include_ecommerce: + print(f"Size of the ECommerce dataset: {len(ecommerce_collection)}") + print(f"Size of the Weather dataset: {len(weather_collection)}") + print(f"Size of the Financial dataset: {len(financial_collection)}") + +def populate_brands(client, overwrite_existing=False): + """Create and populate the `Brands` collection used by the recipe walkthroughs. + + Idempotent: skips creation/import when the collection already has data, unless + `overwrite_existing=True`. + """ + if overwrite_existing: + client.collections.delete("Brands") + + needs_import = overwrite_existing + if not client.collections.exists("Brands"): + client.collections.create( + "Brands", + description=( + "A dataset that lists information about clothing brands, their " + "parent companies, average rating and more." + ), + vector_config=Configure.Vectors.text2vec_weaviate(), + ) + needs_import = True + + if not needs_import: + print("Brands data already exists in Weaviate, skipping import.") + return + + from datasets import load_dataset + + brands_dataset = load_dataset( + "weaviate/agents", "query-agent-brands", split="train", streaming=True + ) + brands_collection = client.collections.use("Brands") + + print("\nImport `query-agent-brands` dataset into Weaviate") + with brands_collection.batch.fixed_size(batch_size=200) as batch: + for item in brands_dataset: + batch.add_object(properties=item["properties"]) + if batch.number_errors > 0: + print("Batch import stopped due to excessive errors.") + break + + failed_objects = brands_collection.batch.failed_objects + if failed_objects: + print(f"Number of failed imports: {len(failed_objects)}") + print(f"First failed object: {failed_objects[0]}") + + print(f"Size of the Brands dataset: {len(brands_collection)}") + + +def populate_recipe_ecommerce(client): + """Create and populate `ECommerce` with a single default vector, matching the + recipe walkthroughs (so the agent can target it by name without specifying a + vector). Force-recreates the collection so the schema is deterministic even if + a multi-vector `ECommerce` was left behind by another test. + """ + client.collections.delete("ECommerce") + client.collections.create( + "ECommerce", + description="A dataset that lists clothing items, their brands, prices, and more.", + vector_config=Configure.Vectors.text2vec_weaviate(), + properties=[ + Property(name="collection", data_type=DataType.TEXT), + Property(name="category", data_type=DataType.TEXT), + Property(name="tags", data_type=DataType.TEXT_ARRAY), + Property(name="subcategory", data_type=DataType.TEXT), + Property(name="name", data_type=DataType.TEXT), + Property(name="description", data_type=DataType.TEXT), + Property(name="brand", data_type=DataType.TEXT), + Property(name="product_id", data_type=DataType.UUID), + Property(name="colors", data_type=DataType.TEXT_ARRAY), + Property(name="reviews", data_type=DataType.TEXT_ARRAY), + Property(name="image_url", data_type=DataType.TEXT), + Property( + name="price", + data_type=DataType.NUMBER, + description="price of item in USD", + ), + ], + ) + + from datasets import load_dataset + + ecommerce_dataset = load_dataset( + "weaviate/agents", "query-agent-ecommerce", split="train", streaming=True + ) + ecommerce_collection = client.collections.use("ECommerce") + + print("\nImport `query-agent-ecommerce` dataset into Weaviate (single vector)") + with ecommerce_collection.batch.fixed_size(batch_size=200) as batch: + for item in ecommerce_dataset: + batch.add_object(properties=item["properties"]) + if batch.number_errors > 0: + print("Batch import stopped due to excessive errors.") + break + + failed_objects = ecommerce_collection.batch.failed_objects + if failed_objects: + print(f"Number of failed imports: {len(failed_objects)}") + print(f"First failed object: {failed_objects[0]}") + + print(f"Size of the ECommerce dataset: {len(ecommerce_collection)}") + + +def load_client_internally(): + headers = { + "X-OpenAI-API-Key": os.environ.get("OPENAI_API_KEY"), + "X-INFERENCE-PROVIDER-API-KEY": os.environ.get("YOUR_INFERENCE_PROVIDER_KEY", ""), + } + + client = weaviate.connect_to_weaviate_cloud( + cluster_url=os.environ.get("WEAVIATE_URL"), + auth_credentials=Auth.api_key(os.environ.get("WEAVIATE_API_KEY")), + headers=headers, + ) + return client \ No newline at end of file diff --git a/docs/agents/_includes/query_agent.excalidraw.zip b/docs/query-agent/_includes/query_agent.excalidraw.zip similarity index 100% rename from docs/agents/_includes/query_agent.excalidraw.zip rename to docs/query-agent/_includes/query_agent.excalidraw.zip diff --git a/docs/agents/_includes/query_agent_architecture_dark.png b/docs/query-agent/_includes/query_agent_architecture_dark.png similarity index 100% rename from docs/agents/_includes/query_agent_architecture_dark.png rename to docs/query-agent/_includes/query_agent_architecture_dark.png diff --git a/docs/agents/_includes/query_agent_architecture_light.png b/docs/query-agent/_includes/query_agent_architecture_light.png similarity index 100% rename from docs/agents/_includes/query_agent_architecture_light.png rename to docs/query-agent/_includes/query_agent_architecture_light.png diff --git a/docs/agents/_includes/query_agent_tutorial_ecommerce.py b/docs/query-agent/_includes/query_agent_tutorial_ecommerce.py similarity index 100% rename from docs/agents/_includes/query_agent_tutorial_ecommerce.py rename to docs/query-agent/_includes/query_agent_tutorial_ecommerce.py diff --git a/docs/agents/_includes/query_agent_tutorial_ecommerce_dataset.png b/docs/query-agent/_includes/query_agent_tutorial_ecommerce_dataset.png similarity index 100% rename from docs/agents/_includes/query_agent_tutorial_ecommerce_dataset.png rename to docs/query-agent/_includes/query_agent_tutorial_ecommerce_dataset.png diff --git a/docs/agents/_includes/query_agent_tutorial_ecommerce_flowchart.png b/docs/query-agent/_includes/query_agent_tutorial_ecommerce_flowchart.png similarity index 100% rename from docs/agents/_includes/query_agent_tutorial_ecommerce_flowchart.png rename to docs/query-agent/_includes/query_agent_tutorial_ecommerce_flowchart.png diff --git a/docs/query-agent/clients/index.md b/docs/query-agent/clients/index.md new file mode 100644 index 000000000..6f1912c36 --- /dev/null +++ b/docs/query-agent/clients/index.md @@ -0,0 +1,43 @@ +--- +title: Client libraries +description: "Use the Python or TypeScript client to interact with the Query Agent." +image: og/query-agent.jpg +# tags: ['agents', 'query-agent', 'clients'] +--- + +You can interact with the Query Agent through official client libraries, currently supporting either Python or JavaScript/TypeScript: + + +import CardsSection from "/src/components/CardsSection"; + +export const agentsClientLibrariesData = [ + { + title: "Python Client", + description: + "Install and use the official Query Agent Python client.", + link: "/query-agent/clients/python/", + icon: "fab fa-python", + }, + { + title: "JavaScript / TypeScript Client", + description: "Use the official Query Agent TypeScript/JavaScript client.", + link: "/query-agent/clients/typescript/", + icon: "fab fa-js", + } +]; + +
+ +
+ +:::info Don't see your preferred language? + +If you want to contribute a client, or to request a particular client, let us know in [the community forum](https://forum.weaviate.io/) + +::: + +## Questions and feedback + +import DocsFeedback from '/\_includes/docs-feedback.mdx'; + + diff --git a/docs/query-agent/clients/python.md b/docs/query-agent/clients/python.md new file mode 100644 index 000000000..024fc3754 --- /dev/null +++ b/docs/query-agent/clients/python.md @@ -0,0 +1,96 @@ +--- +title: Python client +description: "Use the Python client to interact with the Query Agent." +image: og/query-agent.jpg +# tags: ['agents', 'query-agent', 'clients'] +--- + +import QuickLinks from "/src/components/QuickLinks"; + +export const pythonCardsData = [ + { + title: "weaviate/weaviate-agents-python-client", + link: "https://github.com/weaviate/weaviate-agents-python-client", + icon: "fa-brands fa-github", + }, + { + title: "Reference manual (docstrings)", + link: "https://weaviate-python-client.readthedocs.io/en/latest/weaviate-agents-python-client/docs/modules.html", + icon: "fa-solid fa-book", + }, +]; + +The Python client allows you to easily interact with the Query Agent API from your Python applications. + +It relies on the [Weaviate Client package](../../weaviate/client-libraries/python/index.mdx), and handles authentication and connection to your Weaviate instance from there. + + +:::note Python client (SDK) + +The latest Query Agent Python client is version `v||site.agents_python_version||`. + + + +::: + +## Installation + +The Query Agent Python client is distributed as the [`weaviate-agents`](https://pypi.org/project/weaviate-agents/) package on PyPI, and depends on the [`weaviate-client`](https://pypi.org/project/weaviate-client/) package. You can install it in one of two equivalent ways. + +**Recommended: Install via the `weaviate-client` extra** + +```shell +pip install -U "weaviate-client[agents]" +``` + +This installs `weaviate-client` together with its `agents` extra, which pulls in a compatible version of `weaviate-agents`. This is the recommended form because it makes the relationship explicit — `weaviate-agents` is a sub-package designed to be used alongside `weaviate-client`. + +**Alternative: Install `weaviate-agents` directly** + +```shell +pip install -U weaviate-agents +``` + +`weaviate-agents` declares `weaviate-client` as a hard dependency, so this command also installs both packages. The end result is the same set of installed packages as the recommended form. + +### Imports + +Both install commands install the same two packages (`weaviate-client` and `weaviate-agents`), so the following two import styles both work and are equivalent in practice — pick whichever you prefer: + +```python +# Style A — import directly from the agents package +from weaviate_agents.query import QueryAgent +``` + +```python +# Style B — import via the weaviate.agents namespace +from weaviate.agents.query import QueryAgent +``` + +:::info Importing without Agents +If you try to import a Weaviate agent from the Weaviate Python Client without the agents package being installed, i.e. +```python +from weaviate.agents import ... +``` +it will raise a `WeaviateAgentsNotInstalledError`. Simply install the agents package via the above installation options to fix. +::: + +#### Troubleshooting: Force `pip` to install the latest version + +For existing installations, even `pip install -U "weaviate-client[agents]"` may not upgrade `weaviate-agents` to the [latest version](https://pypi.org/project/weaviate-agents/). If this occurs, additionally try to explicitly upgrade the `weaviate-agents` package: + +```shell +pip install -U weaviate-agents +``` + +Or install a [specific version](https://github.com/weaviate/weaviate-agents-python-client/tags): + +```shell +pip install -U weaviate-agents==||site.agents_python_version|| +``` + +## Questions and feedback + +import DocsFeedback from '/\_includes/docs-feedback.mdx'; + + diff --git a/docs/query-agent/clients/typescript.md b/docs/query-agent/clients/typescript.md new file mode 100644 index 000000000..4ca9adef4 --- /dev/null +++ b/docs/query-agent/clients/typescript.md @@ -0,0 +1,74 @@ +--- +title: JavaScript/TypeScript client +description: "Use the TypeScript client to interact with the Query Agent." +image: og/query-agent.jpg +# tags: ['agents', 'query-agent', 'clients'] +--- + +import QuickLinks from "/src/components/QuickLinks"; + +export const typescriptCardsData = [ + { + title: "weaviate/agents-typescript-client", + link: "https://github.com/weaviate/agents-typescript-client", + icon: "fa-brands fa-github", + }, + { + title: "Reference manual (docstrings)", + link: "https://weaviate.github.io/agents-typescript-client/index.html", + icon: "fa-solid fa-book", + }, +]; + +The TypeScript client supports code that is written in TypeScript or JavaScript. It allows you to easily interact with the Query Agent API from your JavaScript or TypeScript applications. + +It relies on the [Weaviate Client package](../../weaviate/client-libraries/typescript/index.mdx), and handles authentication and connection to your Weaviate instance from there. + +:::note JavaScript/TypeScript client (SDK) + +The latest Query Agent TypeScript client is version `v||site.agents_typescript_version||`. + + + +::: + +## Installation + +The Query Agent TypeScript client is distributed as the [`weaviate-agents`](https://www.npmjs.com/package/weaviate-agents) package on npm, and depends on the [`weaviate-client`](https://www.npmjs.com/package/weaviate-client) package, which it declares as a peer dependency. You should install both packages together: + +```shell +npm install weaviate-client weaviate-agents +``` + +Or with `yarn` / `pnpm`: + +```shell +yarn add weaviate-client weaviate-agents +``` + +```shell +pnpm add weaviate-client weaviate-agents +``` + +### Imports + +Import the agent class directly from the `weaviate-agents` package, alongside your usual `weaviate-client` imports: + +```typescript +import weaviate from "weaviate-client"; +import { QueryAgent } from "weaviate-agents"; +``` + +#### Troubleshooting: Force `npm` to install the latest version + +For existing installations, `npm install` may not upgrade `weaviate-agents` to the [latest version](https://www.npmjs.com/package/weaviate-agents). If this occurs, explicitly upgrade the package: + +```shell +npm install weaviate-agents@latest +``` + +## Questions and feedback + +import DocsFeedback from '/\_includes/docs-feedback.mdx'; + + diff --git a/docs/query-agent/guides/ask_mode.md b/docs/query-agent/guides/ask_mode.md new file mode 100644 index 000000000..190e66753 --- /dev/null +++ b/docs/query-agent/guides/ask_mode.md @@ -0,0 +1,281 @@ +--- +title: Ask Mode +description: "Use Ask Mode to retrieve data from Weaviate and get a generated answer." +image: og/query-agent.jpg +# tags: ['agents', 'query-agent', 'modes'] +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; +import PyCode from '!!raw-loader!/docs/query-agent/_includes/code/ask_mode.py'; +import TSCode from '!!raw-loader!/docs/query-agent/_includes/code/ask_mode.mts'; + + + +Ask Mode transforms your query into actionable searches or aggregations, and then provides a final answer to the question. + +For example, you could ask: + +> "How many orders related to books were placed last week?" + +And the agent will filter for `orders`, perform semantic search for `books` and sort or filter for timestamps from the last week. Then, the agent will provide a response, answering this question exactly based on the data retrieved. + +For more details, see the page for [the Python client](https://weaviate-python-client.readthedocs.io/en/stable/weaviate-agents-python-client/docs/weaviate_agents.query.html#weaviate_agents.query.QueryAgent.ask) or [the Typescript Client](https://weaviate.github.io/agents-typescript-client/classes/QueryAgent.html#ask). + + +## Usage + +Like all features of the Query Agent, it requires instantiation of the `QueryAgent` class, which is connected to your Weaviate `client`. [See the class instantiation page for more detail](../reference/instantiation.md). + +Note, locally running Weaviate instances do not support the Query Agent. + + + + + + + + + + + +Make sure to include your API keys in your environment, and specify whichever collection you want to search over. + +:::note Async +In Python, the Query Agent supports both synchronous and asynchronous usage. The Python examples on this page use the synchronous client, but can be easily replaced with the async equivalents — see the [async section](#async) for details. In JavaScript/TypeScript, all calls are asynchronous by default and use `await`. +::: + +### Parameters + +The `.ask()` method accepts several arguments: + + + +| Parameter | Type | Description | +| --- | --- | --- | +| `query` | `str \| list[ChatMessage]` | The user query you want the agent to answer. This can be a simple string (`"What is the highest-grossing product?"`) or a list of chat messages (for conversational context). [See the page on multi-turn conversations for more detail](../reference/multi_turn_conversations.md). | +| `collections` | `list[str \| QueryAgentCollectionConfig] \| None` | The name(s) of the collections to search. You can pass one or many collection names as a list of strings (e.g., `["ECommerce", "BookSales"]`), or provide collection configuration objects for more control. If specified in the `ask` method, it will overwrite those defined in the instantiation of `QueryAgent`. [See the page on collection configuration for more detail](../reference/advanced_collections.md). | +| `result_evaluation` | `Literal["llm", "none"]` | Controls whether the agent will ask an LLM to "evaluate" (i.e., rewrite or rephrase) the result based on all retrieved context. Accepts either:
• `"none"` (default): faster and cheaper; where the final answer is the last LLM call and no further analysis is completed.
• `"llm"`: higher cost/latency - enables a final step where an LLM subsets the sources retrieved to only those used in the answer, as well as enabling the optional fields `is_partial_answer` and `missing_information`. See [the response class](#response) for more details. | + +
+ +| Parameter | Type | Description | +| --- | --- | --- | +| `query` | `string \| ChatMessage[]` | The user query you want the agent to answer. This can be a simple string (`"What is the highest-grossing product?"`) or a list of chat messages (for conversational context). [See the page on multi-turn conversations for more detail](../reference/multi_turn_conversations.md). | +| `collections` | `(string \| QueryAgentCollectionConfig)[]` | The name(s) of the collections to search. You can pass one or many collection names as a list of strings (e.g., `["ECommerce", "BookSales"]`), or provide collection configuration objects for more control. [See the page on collection configuration for more detail](../reference/advanced_collections.md). If specified in the `ask` method, it will overwrite those defined in the instantiation of `QueryAgent`. | +| `resultEvaluation` | `"llm" \| "none"` | Controls whether the agent will ask an LLM to "evaluate" (i.e., rewrite or rephrase) the result based on all retrieved context. Accepts either:
• `"none"`: faster and cheaper; default setting where the final answer is the last LLM call.
• `"llm"`: higher cost/latency - enables a final step where an LLM subsets the sources retrieved to only those used in the answer, as well as enabling the optional fields `is_partial_answer` and `missing_information`. See [the response class](#response) for more details. | + +
+
+ +For more advanced searches, you can also specify _additional filters_ within the collection configuration. [See the page on additional filters for more detail](../reference/additional_filters.md). + +These arguments allow you to customize agent behavior, data access, and the type of answer you receive. + +## Response +The `AskModeResponse` class has the following properties: + + + +| Field | Type | Description | +| --- | --- | --- | +| `searches` | `list[QueryResultWithCollectionNormalized]` | A list of `QueryResultWithCollectionNormalized`. Each contains full details on the searches carried out during the run. This gives explicit information on the search query, filters, UUID values and sorts that were used, as well as the collection searched on. | +| `aggregations` | `list[AggregationResultWithCollectionNormalized]` | A list of `AggregationResultWithCollectionNormalized`. Each contains full details on the aggregations carried out during the run. This gives explicit information on the group-by property, filters, and aggregation metrics that were used, as well as the collection aggregated on. | +| `usage` | `ModelUnitUsage` | A `ModelUnitUsage` instance providing detail on the model units that were used during the run. The `model_units` are effectively token usage measurements normalized by cost. | +| `total_time` | `float` | Total time taken (seconds). | +| `is_partial_answer` | `bool \| None` | A boolean or null value indicating whether the answer is incomplete or not. Only available if `result_evaluation` is `"llm"`. | +| `missing_information` | `list[str] \| None` | A list of strings detailing what information is missing from the answer that makes it incomplete. Only available if `result_evaluation` is `"llm"`. | +| `final_answer` | `str` | A string comprising the LLM's final answer to the user query. | +| `sources` | `list[Source] \| None` | A list of `Source` objects, which have an `object_id` property correlating to the UUID of the Weaviate object that was retrieved during the run. If `result_evaluation` is `"llm"`, these are subset to only those that are relevant to the `final_answer`. | + +[See the client documentation for more detail.](https://weaviate-python-client.readthedocs.io/en/latest/weaviate-agents-python-client/docs/weaviate_agents.classes.html#weaviate_agents.classes.AskModeResponse) + + + + +| Field | Type | Description | +| --- | --- | --- | +| `searches` | `Search[]` | A list of `Search` objects. Each contains full details on the searches carried out during the run. This gives explicit information on the search query, filters, UUID values and sorts that were used, as well as the collection searched on. | +| `aggregations` | `Aggregation[]` | A list of `Aggregation` objects. Each contains full details on the aggregations carried out during the run. This gives explicit information on the group-by property, filters, and aggregation metrics that were used, as well as the collection aggregated on. | +| `usage` | `ModelUnitUsage` | A `ModelUnitUsage` object providing detail on the model units that were used during the run. The `modelUnits` are effectively token usage measurements normalized by cost. | +| `totalTime` | `number` | Total time taken (seconds). | +| `isPartialAnswer` | `boolean` | A boolean indicating whether the answer is incomplete. Only available if `resultEvaluation` is `"llm"`. | +| `missingInformation` | `string[]` | A list of strings detailing what information is missing from the answer that makes it incomplete. Only available if `resultEvaluation` is `"llm"`. | +| `finalAnswer` | `string` | A string comprising the LLM's final answer to the user query. | +| `sources` | `Source[]` | A list of `Source` objects, which have an `objectId` property correlating to the UUID of the Weaviate object that was retrieved during the run. If `resultEvaluation` is `"llm"`, these are subset to only those that are relevant to the `finalAnswer`. | + +[See the client documentation for more detail.](https://weaviate.github.io/agents-typescript-client/types/AskModeResponse.html) + + + + + +## Streaming + +While regular Ask Mode returns a single object, you can choose to stream updates and tokens from the workflow of Ask Mode instead. + + + + + + + + + + +Since the Query Agent is a multi-layered agentic system, there are different types of streaming payloads you will receive. Each one always has a field that identifies which payload it is, [see below](#responses). + +### Request + +In addition to the standard Ask Mode arguments ([above](#parameters)), the streaming method accepts two extra flags that control which payload types are emitted: + + + + +| Parameter | Type | Description | +| --- | --- | --- | +| `include_progress` | `bool` | Optional. If `True` (default), the agent will stream `ProgressMessage` updates as it processes the query. | +| `include_final_state` | `bool` | Optional. If `True` (default), the agent will emit a final `AskModeResponse` payload at the end of the stream. | + +If both `include_progress` and `include_final_state` are set to `false`, the stream will only emit `StreamedTokens` payloads as the final answer is generated. + + + +| Parameter | Type | Description | +| --- | --- | --- | +| `includeProgress` | `boolean` | Optional. If `true` (default), the agent will stream `ProgressMessage` updates as it processes the query. | +| `includeFinalState` | `boolean` | Optional. If `true` (default), the agent will emit a final `AskModeResponse` payload at the end of the stream. | + +If both `includeProgress` and `includeFinalState` are set to `false`, the stream will only emit `StreamedTokens` payloads as the final answer is generated. + + + + +### Responses + + + + +**`ProgressMessage`** — an update on what part of the system has most recently been completed. A class with four fields: + +| Field | Type | Description | +| --- | --- | --- | +| `output_type` | `Literal["progress_message"]` | Always `progress_message`. | +| `stage` | `str` | One of `query_analysis`, `search`, `aggregation`, or `final_answer`. Identifies the stage at which the agentic service is running. | +| `message` | `str` | A human-readable message describing what the agent is doing. For example, during `query_analysis` this is `"Analyzing query..."`. | +| `details` | `ProgressDetails` | A dictionary providing additional context about each stage.

During the `search` and `aggregation` stages, this typically includes a `"queries"` key — a list of dictionaries, each with:
• `query` — the specific search term used.
• `collection` — the collection the search was run against.

This lets you see exactly which queries were issued, and against which collections, at each stage. | + +[See the client documentation for more detail.](https://weaviate-python-client.readthedocs.io/en/latest/weaviate-agents-python-client/docs/weaviate_agents.classes.html#weaviate_agents.classes.ProgressMessage) + +**`StreamedTokens`** — incremental chunks of the final answer as it is generated, letting you render the response token-by-token rather than waiting for it to complete. Each instance has two fields: `output_type` (always `"streamed_tokens"`) and `delta` (the newly generated tokens to append to what you have received so far). [See the client documentation for more detail.](https://weaviate-python-client.readthedocs.io/en/latest/weaviate-agents-python-client/docs/weaviate_agents.classes.html#weaviate_agents.classes.StreamedTokens) + +**`AskModeResponse`** — the full response model, [as defined above](#response), with `output_type` always `final_state`. This is always the final result in the stream and indicates the system has completed. [See the client documentation for more detail.](https://weaviate-python-client.readthedocs.io/en/latest/weaviate-agents-python-client/docs/weaviate_agents.classes.html#weaviate_agents.classes.AskModeResponse) + +
+ + +**`ProgressMessage`** — an update on what part of the system has most recently been completed. A class with four fields: + +| Field | Type | Description | +| --- | --- | --- | +| `outputType` | `"progressMessage"` | Always `progressMessage`. | +| `stage` | `string` | One of `query_analysis`, `search`, `aggregation`, or `final_answer`. Identifies the stage at which the agentic service is running. | +| `message` | `string` | A human-readable message describing what the agent is doing. For example, during `query_analysis` this is `"Analyzing query..."`. | +| `details` | `ProgressDetails` | An object providing additional context about each stage.

During the `search` and `aggregation` stages, this typically includes a `"queries"` key — a list of objects, each with:
• `query` — the specific search term used.
• `collection` — the collection the search was run against.

This lets you see exactly which queries were issued, and against which collections, at each stage. | + +[See the client documentation for more detail.](https://weaviate.github.io/agents-typescript-client/types/ProgressMessage.html) + +**`StreamedTokens`** — incremental chunks of the final answer as it is generated, letting you render the response token-by-token rather than waiting for it to complete. Each instance has two fields: `outputType` (always `"streamedTokens"`) and `delta` (the newly generated tokens to append to what you have received so far). [See the client documentation for more detail.](https://weaviate.github.io/agents-typescript-client/types/StreamedTokens.html) + +**`AskModeResponse`** — the full response model, [as defined above](#response), with `outputType` always `finalState`. This is always the final result in the stream and indicates the system has completed. [See the client documentation for more detail.](https://weaviate.github.io/agents-typescript-client/types/AskModeResponse.html) + +
+
+ +### Example: Handling different streamed responses + +You can handle each streamed payload differently depending on their class, or their output-type property. For example, you may want to display the progress message differently than building the tokens for the final answer. + + + + + + + + + + +## Async + + + + +In Python, the above examples use the synchronous client, but Ask Mode can also be called asynchronously. This requires the `AsyncQueryAgent` class (instantiated the same way as its sync counterpart) together with an async Weaviate client. + + + +The `.ask()` method must be awaited: + + +And the `.ask_stream()` method must be used in an `async for` loop: + + + + +In JavaScript/TypeScript, the `QueryAgent` is asynchronous by default — the examples in the previous sections already are asynchronous, and no separate async setup is needed. + + + + + +## Questions and feedback + +import DocsFeedback from '/\_includes/docs-feedback.mdx'; + + diff --git a/docs/query-agent/guides/index.md b/docs/query-agent/guides/index.md new file mode 100644 index 000000000..15dccd75d --- /dev/null +++ b/docs/query-agent/guides/index.md @@ -0,0 +1,20 @@ +--- +title: Modes +description: "Compare the different modes the Weaviate Query Agent supports." +image: og/query-agent.jpg +# tags: ['agents', 'query-agent', 'modes'] +--- + +The Query Agent is capable of various tasks: + +* **[Ask Mode](./ask_mode.md)**: Search using natural language, and retrieve a natural language answer back. The user query is transformed into one or many different searches or aggregations, whose results are used by an LLM to answer the original question. +* **[Search Mode](./search_mode.md)**: Search using natural language, and return a list of raw Weaviate objects, no final answer generation. +* **[Suggest Queries Mode](./suggest_queries.md)**: Suggest queries based on data in your collections and custom instructions. + + + +## Questions and feedback + +import DocsFeedback from '/\_includes/docs-feedback.mdx'; + + diff --git a/docs/query-agent/guides/research_mode.md b/docs/query-agent/guides/research_mode.md new file mode 100644 index 000000000..aa1d18b00 --- /dev/null +++ b/docs/query-agent/guides/research_mode.md @@ -0,0 +1,14 @@ +--- +title: Research Mode +description: "Use Research Mode to perform deep, multi-step research across your collections." +image: og/query-agent.jpg +# tags: ['agents', 'query-agent', 'modes'] +--- + +TBD + +## Questions and feedback + +import DocsFeedback from '/\_includes/docs-feedback.mdx'; + + diff --git a/docs/query-agent/guides/search_mode.md b/docs/query-agent/guides/search_mode.md new file mode 100644 index 000000000..1dc8d1ac7 --- /dev/null +++ b/docs/query-agent/guides/search_mode.md @@ -0,0 +1,243 @@ +--- +title: Search Mode +description: "Use Search Mode to retrieve raw results from Weaviate without generating an answer." +image: og/query-agent.jpg +# tags: ['agents', 'query-agent', 'modes'] +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; +import PyCode from '!!raw-loader!/docs/query-agent/_includes/code/search_mode.py'; +import TSCode from '!!raw-loader!/docs/query-agent/_includes/code/search_mode.mts'; + + + +Search Mode transforms your query into actionable searches and returns the matching Weaviate objects directly — without generating an LLM-authored answer. + +For example, you could ask: + +> "Find me some vintage shoes under $70" + +And the agent will perform semantic search for `vintage shoes`, apply a filter for `price < 70`, and return the matching objects from your collections, ready for you to render or post-process. + +For more details, see the page for [the Python client](https://weaviate-python-client.readthedocs.io/en/stable/weaviate-agents-python-client/docs/weaviate_agents.query.html#weaviate_agents.query.QueryAgent.search) or [the Typescript Client](https://weaviate.github.io/agents-typescript-client/classes/QueryAgent.html#search). + +## Usage + +Like all features of the Query Agent, it requires instantiation of the `QueryAgent` class, which is connected to your Weaviate `client`. [See the class instantiation page for more detail](../reference/instantiation.md). + + +Note, locally running Weaviate instances do not support the Query Agent. + + + + + + + + + + + +Make sure to include your API keys in your environment, and specify whichever collection you want to search over. + +:::note Async +In Python, the Query Agent supports both synchronous and asynchronous usage. The Python examples on this page use the synchronous client, but can be easily replaced with the async equivalents — see the [async section](#async) for details. In JavaScript/TypeScript, all calls are asynchronous by default and use `await`. +::: + +### Parameters + +The `.search()` method accepts several arguments: + + + +| Parameter | Type | Description | +| --- | --- | --- | +| `query` | `str \| list[ChatMessage]` | The user query you want the agent to search with. This can be a simple string (`"Find me some vintage shoes under $70"`) or a list of chat messages (for conversational context). [See the page on multi-turn conversations for more detail](../reference/multi_turn_conversations.md). | +| `collections` | `list[str \| QueryAgentCollectionConfig] \| None` | The name(s) of the collections to search. You can pass one or many collection names as a list of strings (e.g., `["ECommerce", "BookSales"]`), or provide collection configuration objects for more control. If specified in the `ask` method, it will overwrite those defined in the instantiation of `QueryAgent`. [See the page on collection configuration for more detail](../reference/advanced_collections.md). | +| `limit` | `int` | The maximum number of results returned in this page of results. Defaults to `20`. Use [`.next()`](#pagination) to fetch additional pages. | +| `filtering` | `Literal["recall", "precision"]` | Either `"recall"` or `"precision"` to control filter generation. `"recall"` favors more results across filter interpretations; `"precision"` favors strict intent match. See [Customized filtering](#customized-filtering) below. | +| `diversity_weight` | `float \| None` | A value between `0.0` and `1.0` that biases the result ranking towards diversity using Maximal Marginal Relevance (MMR). See [Diversity ranking](#diversity-ranking) below. | + + + +| Parameter | Type | Description | +| --- | --- | --- | +| `query` | `string \| ChatMessage[]` | The user query you want the agent to search with. This can be a simple string (`"Find me some vintage shoes under $70"`) or a list of chat messages (for conversational context). [See the page on multi-turn conversations for more detail](../reference/multi_turn_conversations.md). | +| `collections` | `(string \| QueryAgentCollectionConfig)[]` | The name(s) of the collections to search. You can pass one or many collection names as a list of strings (e.g., `["ECommerce", "BookSales"]`), or provide collection configuration objects for more control. If specified in the `ask` method, it will overwrite those defined in the instantiation of `QueryAgent`. [See the page on collection configuration for more detail](../reference/advanced_collections.md). | +| `limit` | `number` | The maximum number of results returned in this page of results. Defaults to `20`. Use [`.next()`](#pagination) to fetch additional pages. | +| `filtering` | `"recall" \| "precision"` | Either `"recall"` or `"precision"` to control filter generation. `"recall"` favors more results across filter interpretations; `"precision"` favors strict intent match. See [Customized filtering](#customized-filtering) below. | +| `diversityWeight` | `number` | A value between `0.0` and `1.0` that biases the result ranking towards diversity using Maximal Marginal Relevance (MMR). See [Diversity ranking](#diversity-ranking) below. | + + + + +For more advanced searches, you can also specify _additional filters_ within the collection configuration. [See the page on additional filters for more detail](../reference/additional_filters.md). + +### Customized filtering + +Search Mode uses query rewriting to transform your original query into one or multiple Weaviate queries, each with either a search query, metadata filters, or both. The `filtering` parameter controls how many Weaviate queries are generated. + +- **`"recall"`** (default): Generates multiple Weaviate queries spanning different filters and interpretations of the user query. You should use these when you prefer to get results, even if they don't match every criteria in your query. + +- **`"precision"`**: Generates a single Weaviate query targeting the most likely interpretation of the user query. You should use this when you want the results to follow your query intent closely, even if that means potentially receiving no results. + + + + + + + + + + + +### Diversity ranking + +`Search` supports adding diversity weighting to result rankings using Maximal Marginal Relevance (MMR). This is enabled by passing a `diversity_weight` parameter in the range of `0.0` to `1.0` — higher values favor more varied results over the most relevant ones. + +To use diversity ranking with target vectors, set the single target vector you want to use in the Query Agent's constructor. Diversity ranking is not yet supported with collections using multi-vector embeddings, and will only work across multiple collections if they share the same embedding model. + + + + + + + + + + +## Response +The Search Mode response has the following properties: + + + + +| Field | Type | Description | +| --- | --- | --- | +| `searches` | `list[QueryResultWithCollectionNormalized]` | A list of searches the agent carried out. Each contains the search query, filters, and the collection the search was run against. | +| `usage` | `ModelUnitUsage` | A `ModelUnitUsage` instance providing detail on the model units used during the run. The `model_units` are effectively token usage measurements normalized by cost. | +| `total_time` | `float` | Total time taken (seconds). | +| `search_results` | `QueryReturn` | A `QueryReturn` object whose `.objects` field is the list of matching Weaviate objects, each with `properties` and `metadata` (including the relevance `score`). | +| `next(limit, offset)` | `SearchModeResponse` | A method that returns the next page of results, reusing the same underlying searches for consistency. See [Pagination](#pagination) below. | + +[See the client documentation for more detail.](https://weaviate-python-client.readthedocs.io/en/latest/weaviate-agents-python-client/docs/weaviate_agents.classes.html#weaviate_agents.classes.SearchModeResponse) + + + + + +| Field | Type | Description | +| --- | --- | --- | +| `searches` | `Search[]` | A list of searches the agent carried out. Each contains the search query, filters, and the collection the search was run against. | +| `usage` | `ModelUnitUsage` | A `ModelUnitUsage` object providing detail on the model units used during the run. The `modelUnits` are effectively token usage measurements normalized by cost. | +| `totalTime` | `number` | Total time taken (seconds). | +| `searchResults` | `WeaviateReturnWithCollection` | A `WeaviateReturnWithCollection` object whose `.objects` field is the list of matching Weaviate objects, each with `properties` and `metadata` (including the relevance `score`). | +| `next({ limit, offset })` | `Promise` | A method that returns the next page of results, reusing the same underlying searches for consistency. See [Pagination](#pagination) below. | + +[See the client documentation for more detail.](https://weaviate.github.io/agents-typescript-client/types/SearchModeResponse.html) + + + + + +:::note Result scores +The `search_results` / `searchResults` field reuses Weaviate's native `QueryReturn` / `WeaviateReturnWithCollection` type, so results have the same shape as a standard Weaviate query. However, the `score` in each object's metadata is replaced with Search Mode's own ranking score rather than the original Weaviate search score. +::: + + +### Pagination + +Search returns results one page at a time. To fetch additional pages, call `.next()` on the previous response — the underlying searches are reused so results stay consistent across pages. + + + + + + + + + + +## Async + + + + + +In Python, the above examples use the synchronous client, but Search Mode can also be called asynchronously. This requires the `AsyncQueryAgent` class (instantiated the same way as its sync counterpart) together with an async Weaviate client. + + + +The `.search()` method must be awaited: + + + + +In JavaScript/TypeScript, the `QueryAgent` is asynchronous by default — the examples in the previous sections already are asynchronous, and no separate async setup is needed. + + + + + +## Questions and feedback + +import DocsFeedback from '/\_includes/docs-feedback.mdx'; + + diff --git a/docs/query-agent/guides/suggest_queries.md b/docs/query-agent/guides/suggest_queries.md new file mode 100644 index 000000000..0c4ecb2a4 --- /dev/null +++ b/docs/query-agent/guides/suggest_queries.md @@ -0,0 +1,147 @@ +--- +title: Suggest Queries Mode +description: "Generate suggested follow-up queries to help users explore Weaviate data." +image: og/query-agent.jpg +# tags: ['agents', 'query-agent', 'modes'] +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; +import PyCode from '!!raw-loader!/docs/query-agent/_includes/code/suggest_queries.py'; +import TSCode from '!!raw-loader!/docs/query-agent/_includes/code/suggest_queries.mts'; + + + +The Query Agent can suggest queries based on the data in your collections. This is useful for helping users discover what kinds of questions they can ask, or for generating example queries for a new dataset. + +## Usage + +The method can be called with a set of instructions and/or specifications: + + + + + + + + + + +Or can be called without any additional arguments, to use the defaults. + + + + + + + + + +### Parameters + +Suggest Queries can be called with the following arguments: + + + + +| Parameter | Type | Description | +| --- | --- | --- | +| `collections` | `list[str \| QueryAgentCollectionConfig] \| None` | Override the collections configured at instantiation. [See the page on collection configuration for more detail](../reference/advanced_collections.md). | +| `num_queries` | `int` | The number of queries to suggest (default: `3`). | +| `instructions` | `str \| None` | Guide the style or focus of the suggested queries. This is provided in addition to any system instructions. Useful for e.g. specifying language. | + + + +| Parameter | Type | Description | +| --- | --- | --- | +| `collections` | `(string \| QueryAgentCollectionConfig)[]` | Override the collections configured at instantiation. [See the page on collection configuration for more detail](../reference/advanced_collections.md). | +| `numQueries` | `number` | The number of queries to suggest (default: `3`). | +| `instructions` | `string` | Guide the style or focus of the suggested queries. This is provided in addition to any system instructions. Useful for e.g. specifying language. | + + + +## Response + +The `SuggestQueryResponse` class has the following properties: + + + + +| Field | Type | Description | +| --- | --- | --- | +| `queries` | `list[SuggestedQuery]` | A list of `SuggestedQuery` objects, each with a single property `query`, a suggested query that the user could run against their data. | +| `collection_count` | `int` | The number of collections that were considered when generating the suggested queries. | +| `usage` | `ModelUnitUsage` | A `ModelUnitUsage` instance providing detail on the model units used during the run. The `model_units` are effectively token usage measurements normalized by cost. | +| `total_time` | `float` | Total time taken (seconds). | + +[See the client documentation for more detail.](https://weaviate-python-client.readthedocs.io/en/latest/weaviate-agents-python-client/docs/weaviate_agents.classes.html#weaviate_agents.classes.SuggestQueryResponse) + + + +| Field | Type | Description | +| --- | --- | --- | +| `queries` | `SuggestedQuery[]` | A list of `SuggestedQuery` objects, each with a single property `query`, a suggested query that the user could run against their data. | +| `collectionCount` | `number` | The number of collections that were considered when generating the suggested queries. | +| `usage` | `ModelUnitUsage` | A `ModelUnitUsage` object providing detail on the model units used during the run. The `modelUnits` are effectively token usage measurements normalized by cost. | +| `totalTime` | `number` | Total time taken (seconds). | + +[See the client documentation for more detail.](https://weaviate.github.io/agents-typescript-client/types/SuggestQueryResponse.html) + + + +## Async + + + + + +In Python, the above examples use the synchronous client, but Suggest Queries can also be called asynchronously. This requires the `AsyncQueryAgent` class (instantiated the same way as its sync counterpart) together with an async Weaviate client. + + + +The `.suggest_queries()` method must be awaited: + + + + +In JavaScript/TypeScript, the `QueryAgent` is asynchronous by default — the examples in the previous sections already are asynchronous, and no separate async setup is needed. + + + + +## Questions and feedback + +import DocsFeedback from '/\_includes/docs-feedback.mdx'; + + diff --git a/docs/query-agent/index.md b/docs/query-agent/index.md new file mode 100644 index 000000000..05273baa2 --- /dev/null +++ b/docs/query-agent/index.md @@ -0,0 +1,165 @@ +--- +title: Introduction +description: "Get an overview of the Weaviate Query Agent and what it can do." +image: og/query-agent.jpg +# tags: ['agents', 'query-agent', 'getting-started'] +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; +import PyCode from "!!raw-loader!./_includes/code/introduction.py"; +import TSCode from '!!raw-loader!./_includes/code/introduction.mts'; + + + +The Query Agent runs agentic search over your Weaviate Cloud database. Ask a question in natural language and the agent automatically decides which collections to search, which filters and sorts to apply, and which search types to use — all in a single call. + +:::info Free tier +Up to 250 ask queries or 1000 search queries per month, no credit card required. [Get started →](quickstart.md) +::: + + + + + + + + + + +:::tip Looking for agent memory? +[Engram](/engram/) is a managed memory service that gives your agents persistent, searchable memory across conversations and users. +::: + +## How Weaviate Agents work + +
+Example output + +``` +╭───────────────────────────────────────────── 💬 Ask Mode Response ──────────────────────────────────────────────╮ +│ │ +│ The most expensive blue t-shirt is **Neotech Noir Tee** by **Vivid Verse**, priced at **$46.00**. │ +│ │ +│ Details: │ +│ - **Product ID:** 9f9fe575-be97-46d9-a5ca-ff41ae57bef4 │ +│ - **Colors:** black, blue │ +│ - **Category:** Tops │ +│ - **Subcategory:** T-Shirts │ +│ │ +╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ +╭───────────────────────────────────────────────── 🔭 Search 1/1 ─────────────────────────────────────────────────╮ +│ │ +│ QueryResultWithCollectionNormalized( │ +│ query=None, │ +│ filters=FilterAndOr( │ +│ combine='AND', │ +│ filters=[ │ +│ TextPropertyFilter( │ +│ property_name='subcategory', │ +│ operator=, │ +│ value=['blue'] │ +│ ) │ +│ ] │ +│ ), │ +│ collection='ECommerce', │ +│ sort_property=QuerySort(property_name='price', order='descending', tie_break=None), │ +│ uuid_value=None │ +│ ) │ +│ │ +╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ +╭────────────────────────────────────────────── 📊 Aggregation 1/1 ───────────────────────────────────────────────╮ +│ │ +│ AggregationResultWithCollectionNormalized( │ +│ groupby_property=None, │ +│ aggregation=IntegerPropertyAggregation(property_name='price', metrics=), │ +│ filters=FilterAndOr( │ +│ combine='AND', │ +│ filters=[ │ +│ TextPropertyFilter( │ +│ property_name='category', │ +│ operator=, │ +│ value=['blue'] │ +│ ) │ +│ ] │ +│ ), │ +│ collection='ECommerce' │ +│ ) │ +│ │ +╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ +``` + +
+ +## What is the Query Agent? + +![Weaviate Query Agent from a user perspective](./_includes/query_agent_architecture_light.png#gh-light-mode-only "Weaviate Query Agent from a user perspective") +![Weaviate Query Agent from a user perspective](./_includes/query_agent_architecture_dark.png#gh-dark-mode-only "Weaviate Query Agent from a user perspective") + +The Weaviate Query Agent connects to your pre-existing Weaviate database and transforms natural language queries into actionable searches using an LLM. It can perform multiple searches and aggregations across one or more collections, dynamically deciding which collection(s) to search on, creating custom filters, group bys, sorts, and search types, all depending on a single natural language question. + +It is designed as a pre-built agentic service for your data, with two main modes: + +* [**Ask Mode**](guides/ask_mode.md): Return a natural language answer after searching your data. Chat-like; best for end-user-facing apps where the user wants a written response instead of raw data. +* [**Search Mode**](guides/search_mode.md): Return the raw matching objects directly from your collection(s), with filters, sorts, and search types chosen for you. Lookup-like; best for internal search, dashboards, or the retrieval step in a larger pipeline. + +### Example use cases + +- **Customer-facing chat assistant** (Ask Mode) — Answer questions like *"Recommend me vintage shoes under $70 in size 9"* with a written response, sourced from your product catalog. +- **Natural-language filter on an internal dashboard** (Search Mode) — Turn *"orders flagged last week from EU customers"* into a filtered Weaviate query and render the rows in your UI. +- **Retrieval step inside your own RAG or agent stack** (Search Mode) — Fetch the most relevant objects via the agent, then pass them to a downstream generative step you control. + +## Get started + +:::info Query Agent in cloud +[You can try the Query Agent without any setup on Weaviate Cloud. Simply go to the 'Agents' tab to start asking questions about data in your collections.](/go/console?utm_content=agents) +::: + +You need a Weaviate Cloud cluster — [a 14-day sandbox is free](https://weaviate.io/deployment/serverless). With a cluster and some data, install [the Python or TypeScript client](./installation.md) and you can run your first query in minutes. + +Already have a cluster but no data? Upload via CSV in the cloud console, or [via the Weaviate APIs](/weaviate/manage-objects/create). + +## Further resources + +- [**Quickstart**](quickstart.md) — Set up the client and run your first ask and search calls. +- [**Modes**](guides/index.md) — Detailed pages on Ask Mode, Search Mode, and other modes. +- [**Configuration**](reference/instantiation.md) — Constructor options, collection configuration, additional filters, system prompts, and conversational inputs. +- [**Recipes**](recipes/index.mdx) — End-to-end example notebooks. + + +## Questions and feedback + + + + +import DocsFeedback from '/_includes/docs-feedback.mdx'; + + diff --git a/docs/query-agent/installation.md b/docs/query-agent/installation.md new file mode 100644 index 000000000..be1746dac --- /dev/null +++ b/docs/query-agent/installation.md @@ -0,0 +1,68 @@ +--- +title: Installation +description: "Install the Weaviate client with the agents extra to use the Query Agent." +image: og/query-agent.jpg +# tags: ['agents', 'query-agent', 'getting-started'] +--- + + + +Install the Query Agent client package alongside the regular Weaviate client. Below are the prerequisites and the install commands for Python and JavaScript/TypeScript. + +## Prerequisites + +:::info What does the Query Agent have access to? + +The Query Agent derives its access credentials from the Weaviate client object passed to it. This can be further restricted by the collection names provided to the Query Agent. + +For example, if the associated Weaviate credentials' user has access to only a subset of collections, the Query Agent will only be able to access those collections. + +::: + +The Query Agent is available exclusively for use with a Weaviate Cloud instance. [See the page on Weaviate Cloud for more detail](/cloud/index.mdx). + +You can try this Weaviate Agent with a free Sandbox instance on [Weaviate Cloud](/go/console?utm_content=agents). + +:::note Supported languages +At this time, the Query Agent clients are available only for Python and JavaScript/TypeScript. Support for other languages will be added in the future. +::: + +## Python client + +For Python, you can install the Weaviate client library with the optional `agents` extras to use the Query Agent. This will install the `weaviate-agents` package along with the `weaviate-client` package. For JavaScript/TypeScript, you can install the `weaviate-agents` package alongside the `weaviate-client` package. + +Install the client library using the following command: + +```shell +pip install -U "weaviate-client[agents]" +``` + +[See the Python Client installation page for more detail](./clients/python.md#installation). + +#### Troubleshooting: Force `pip` to install the latest version + +For existing installations, even `pip install -U "weaviate-client[agents]"` may not upgrade `weaviate-agents` to the [latest version](https://pypi.org/project/weaviate-agents/). If this occurs, additionally try to explicitly upgrade the `weaviate-agents` package: + +```shell +pip install -U weaviate-agents +``` + +Or install a [specific version](https://github.com/weaviate/weaviate-agents-python-client/tags): + +```shell +pip install -U weaviate-agents==||site.agents_python_version|| +``` + +## JavaScript/TypeScript client + +You can install for TypeScript or JavaScript via `npm`: + +```shell +npm install weaviate-agents@latest +``` + +## Questions and feedback + +import DocsFeedback from '/\_includes/docs-feedback.mdx'; + + diff --git a/docs/query-agent/quickstart.md b/docs/query-agent/quickstart.md new file mode 100644 index 000000000..5a858d312 --- /dev/null +++ b/docs/query-agent/quickstart.md @@ -0,0 +1,260 @@ +--- +title: Quickstart +description: "Get started with the Weaviate Query Agent through a runnable example." +image: og/query-agent.jpg +# tags: ['agents', 'query-agent', 'getting-started'] +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; +import PyCode from '!!raw-loader!/docs/query-agent/_includes/code/quickstart.py'; +import TSCode from '!!raw-loader!/docs/query-agent/_includes/code/quickstart.mts'; + + + +This quickstart walks through connecting to a Weaviate Cloud cluster, pointing the Query Agent at one or more existing collections, and running your first natural-language queries in both Search Mode and Ask Mode. + +## Prerequisites + +Ensure you have access to: +* A **Weaviate Cloud Instance**, such as a [free sandbox instance](/go/console?utm_content=agents). +* Either the **[Python Client](./installation.md#python-client)** or the **[TypeScript Client](./installation.md#javascripttypescript-client)**. + +## Step 1: Start the Query Agent + +You only need to provide: +- Your Weaviate client object, which points to a target [Weaviate Cloud instance](/cloud/manage-clusters/connect.mdx) +- The collections you want to make possible to be searched. + + + + + + + + + + + +## Step 2: Search with the Query Agent + +Perform a search using Search Mode (retrieval only, no answer generation). The LLM decides dynamic search options (such as filters, sorts, etc.) and returns the search results. + + + + + + + + + + +Search Mode returns the raw Weaviate objects, as if you had performed the search in Weaviate directly. + + + + + + + + + + +
+ Example output +``` +Product: Sky Shimmer Sneaks - $69.0 +Product: Garden Serenade Sandals - $56.0 +Product: Forest Murmur Sandals - $59.0 +Product: Mystic Garden Strappy Flats - $59.0 +``` +
+ +## Step 3: Ask the Query Agent + +Perform a query using Ask Mode (with answer generation). The LLM creates a search with dynamic filters and other search settings, and then answers the question using the search results to inform the answer. + + + + + + + + + + + +You can access specific search results via `ask_response.sources`, the final response via `ask_response.final_answer`, or view all outputs via `ask_response.display()`. + + + + + + + + + +
+ Example output +``` +╭───────────────────────────────────────────── 💬 Ask Mode Response ──────────────────────────────────────────────╮ +│ │ +│ Here are some vintage-leaning clothes and nice shoes under $60: │ +│ │ +│ **Clothes** │ +│ - Vintage Scholar Turtleneck — $55 │ +│ - Victorian Noir Turtleneck — $58 │ +│ - Retro Glitz Halter Top — $29.98 │ +│ - RetroFuturist Tee — $29.98 │ +│ - Retro Pop Glitz Blouse — $46 │ +│ - Futurist Flashback Blouse — $59 │ +│ - Space-Age Sequin Top — $46 │ +│ - Pop Glitz Button-Up — $46 │ +│ - Shimmering Pastel Crop Tee — $29.98 │ +│ - Retro Groove Flared Pants — $59 │ +│ - Pastel Dawn Jeans — $59 │ +│ - Twilight Spark Mini Dress — $59 │ +│ │ +│ **Shoes** │ +│ - Mystic Garden Strappy Flats — $59 │ +│ - Forest Murmur Sandals — $59 │ +│ - Garden Serenade Sandals — $56 │ +│ │ +│ If you want, I can also narrow these down by style, like more **true vintage**, **Y2K**, or **dark academia**. │ +│ │ +╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ +╭───────────────────────────────────────────────── 🔭 Search 1/2 ─────────────────────────────────────────────────╮ +│ │ +│ QueryResultWithCollectionNormalized( │ +│ query='vintage style clothes retro apparel old-fashioned garments dresses tops bottoms outerwear │ +│ accessories', │ +│ filters=IntegerPropertyFilter( │ +│ property_name='price', │ +│ operator=, │ +│ value=60.0 │ +│ ), │ +│ collection='ECommerce', │ +│ sort_property=None, │ +│ uuid_value=None │ +│ ) │ +│ │ +╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ +╭───────────────────────────────────────────────── 🔭 Search 2/2 ─────────────────────────────────────────────────╮ +│ │ +│ QueryResultWithCollectionNormalized( │ +│ query='stylish shoes footwear boots sneakers heels flats loafers', │ +│ filters=IntegerPropertyFilter( │ +│ property_name='price', │ +│ operator=, │ +│ value=60.0 │ +│ ), │ +│ collection='ECommerce', │ +│ sort_property=None, │ +│ uuid_value=None │ +│ ) │ +│ │ +╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ +╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ │ +│ 📊 No Aggregations Run │ +│ │ +╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ +╭────────────────────────────────────────────────── 📚 Sources ───────────────────────────────────────────────────╮ +│ │ +│ - object_id='7a0730cc-b5ef-477c-af49-3f48812717d5' collection='ECommerce' │ +│ - object_id='60faa7af-ecb2-48f4-a496-74807b8e1856' collection='ECommerce' │ +│ - object_id='00d9638a-8ded-4bfe-8a36-fcf5b067a1b4' collection='ECommerce' │ +│ - object_id='c45bed45-aa7a-40c3-a7b3-2d59b9f43e1f' collection='ECommerce' │ +│ - object_id='d85a4802-45c4-4563-9d5e-b24db2a1bf75' collection='ECommerce' │ +│ - object_id='7550957b-b68e-41cd-aa5e-8ad9df1160b7' collection='ECommerce' │ +│ - object_id='afe828a6-a6de-4484-b7cb-933ec705a751' collection='ECommerce' │ +│ - object_id='ca2858c7-c303-43e1-baf6-f85c4e8cf0e7' collection='ECommerce' │ +│ - object_id='7fe657e7-d496-4302-8e77-3cca8f336a7c' collection='ECommerce' │ +│ - object_id='6188d087-ccde-416c-bb60-819db860280a' collection='ECommerce' │ +│ - object_id='7a75acf7-9cdd-46c1-9d3c-b033f92783f8' collection='ECommerce' │ +│ - object_id='84d6cba0-397b-4b55-9e51-b4c2fde2480b' collection='ECommerce' │ +│ - object_id='f8e4ac67-79e0-489b-a30c-c2af788ad4f6' collection='ECommerce' │ +│ - object_id='296ed34e-a0c8-4d1a-9259-abff65dcad0a' collection='ECommerce' │ +│ - object_id='cd1330f3-5e1e-47c3-85ef-7af92ab5bf52' collection='ECommerce' │ +│ - object_id='80d2d7f6-915e-4750-a27a-f6ae33735859' collection='ECommerce' │ +│ - object_id='5ac48f1f-204c-4498-9ed7-356418ef9f93' collection='ECommerce' │ +│ - object_id='e08017a4-8444-4eae-bd2e-7dd6abc21be6' collection='ECommerce' │ +│ - object_id='d1bfbcfe-08a7-4eec-bebd-33b35f771e32' collection='ECommerce' │ +│ - object_id='5f2d1c2c-51ce-478b-b4a5-d700f041110e' collection='ECommerce' │ +│ - object_id='2880c69e-fa19-4ecc-9f4c-7816db3302e5' collection='ECommerce' │ +│ - object_id='3822e271-a9b8-46d2-9402-1da2a605c970' collection='ECommerce' │ +│ - object_id='66eef8a1-f72f-44fe-86fb-ccbe928d3c1d' collection='ECommerce' │ +│ - object_id='56d4e9cf-27a6-4120-be5a-52ba70df9ad6' collection='ECommerce' │ +│ - object_id='a7a4577d-087b-466b-b99c-b7db5e1f2855' collection='ECommerce' │ +│ - object_id='423392a3-10db-4009-8f1e-d2ee0fe04257' collection='ECommerce' │ +│ - object_id='1185d4e0-013b-4ad2-9d08-9fb75c953417' collection='ECommerce' │ +│ - object_id='91b09adb-2903-4b4b-a750-18db6db8a787' collection='ECommerce' │ +│ │ +╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ + 📊 Usage Statistics +┌──────────────────────────┬──────┐ +│ Model Units: │ 662 │ +│ Usage in Plan: │ True │ +│ Remaining Plan Requests: │ -1 │ +└──────────────────────────┴──────┘ +Total Time Taken: 6.69s +``` +
+ + +## Questions and feedback + +import DocsFeedback from '/\_includes/docs-feedback.mdx'; + + diff --git a/docs/query-agent/recipes/index.mdx b/docs/query-agent/recipes/index.mdx new file mode 100644 index 000000000..e33a99a63 --- /dev/null +++ b/docs/query-agent/recipes/index.mdx @@ -0,0 +1,12 @@ +--- +title: Tutorials and guides +description: "Examples of using the Query Agent in different use cases." +image: og/query-agent.jpg +# tags: ['agents', 'query-agent', 'recipes'] +--- + +import RecipesCards from "@site/src/components/RecipesCards"; + +Self-contained examples that show how to apply the Query Agent to specific problems — from getting started against a single collection to wiring it into a Streamlit chat UI or exposing it as a tool to another LLM. + + diff --git a/docs/query-agent/recipes/query-agent-as-a-tool.md b/docs/query-agent/recipes/query-agent-as-a-tool.md new file mode 100644 index 000000000..c788905f3 --- /dev/null +++ b/docs/query-agent/recipes/query-agent-as-a-tool.md @@ -0,0 +1,462 @@ +--- +layout: recipe +toc: True +title: "Using the Query Agent as a tool" +featured: True +integration: True +agent: True +sidebar_position: 40 +# tags: ['Query Agent', 'Integration', 'Function Calling'] +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; +import PyCode from '!!raw-loader!/docs/query-agent/_includes/code/query_agent_as_a_tool.py'; + +In this recipe, we'll show how to expose the [Weaviate Query Agent](https://docs.weaviate.io/query-agent) as a **tool** to other LLMs and agent frameworks. The Query Agent already handles search, filtering, aggregation, and writing a natural-language answer — wrapping it as a tool lets a higher-level model decide *when* to consult your Weaviate data as part of a larger reasoning flow. + +We'll cover five integrations: + +- **Google Gemini API** (via `google-genai`) +- **Google Vertex AI** (via `google-genai` with a GCP project) +- **Ollama** (local LLMs with function calling) +- **LangChain** +- **LlamaIndex** + +Because the Query Agent is just a Python call (`agent.ask(query).final_answer`), the same pattern works in any framework that supports tools or function calling — see [the closing section](#using-the-query-agent-as-a-tool-anywhere) for how to adapt this to anything else. + +> 💡 New to the Query Agent itself? Start with the [**Get Started**](./query-agent-get-started.md) recipe first — it walks through the agent's own Ask Mode, Search Mode and Suggest Queries features before treating it as a building block. + +## What you'll need + +This recipe assumes: + +- A **Weaviate Cloud** cluster — [create a free sandbox here](https://console.weaviate.cloud/). +- A populated collection. The examples below use `WeaviateBlogChunks` (the Weaviate blog content), but you can substitute your own collection name throughout. +- The Weaviate client with the `agents` extras: + +```python +!pip install -U "weaviate-client[agents]" +``` + +Each framework section adds its own additional installs. + +## Connect to Weaviate and define the tool + +The trick to using the Query Agent as a tool is simple: it's a Python function that takes a string in and returns a string out. Most modern agent frameworks can consume a regular Python function directly — the function's name and docstring become the tool's name and description, which is what the calling LLM uses to decide whether to invoke it. + +We'll create the Weaviate client and the `QueryAgent` **once**, and wrap a thin function around them. Reusing a single client across calls avoids reopening a connection on every invocation, which is what you want in any real application. + + + + + + + + + +A few things to notice: + +- The **docstring matters**. Tool-calling LLMs read it to decide when to invoke the function and what argument to pass. Be specific about what the tool is for and when to use it. +- The function returns a plain `str` (the agent's `final_answer`). Some frameworks can also pass through structured objects, but a single string is the most portable form. +- The `agent` is captured in a closure. In a long-running application you'd put this inside a class or module so you can close the client cleanly on shutdown. + +The rest of this recipe is just five different ways to hand `ask_weaviate` to a calling LLM. + +## Google Gemini API + +The [Google Gen AI SDK](https://googleapis.github.io/python-genai/) lets you pass a regular Python function directly as a tool — it inspects the signature and docstring to build the function declaration. + +### Setup + +You'll need a Gemini API key, which you can generate in [Google AI Studio](https://aistudio.google.com/). + +```python +!pip install -U google-genai +``` + +```python +import os +os.environ["GOOGLE_API_KEY"] = "" # your Gemini API key +``` + +### Create the client and register the tool + + + + + + + + + +`ask_weaviate` goes in the `tools` list and Gemini will call it when its response logic decides the user's question requires looking something up. The SDK reads the function's signature and docstring to build the tool declaration for you. + +### Ask a question + + + + + + + + + +```text +To deploy Weaviate with Docker, you need to: + +1. Install Docker and Docker Compose. +2. Obtain the Weaviate Docker image using: + docker pull cr.weaviate.io/semitechnologies/weaviate:latest +3. Prepare a docker-compose.yml file, which you can generate using the + Weaviate configuration tool or example files from the documentation. +4. Start Weaviate using either: + - docker run -p 8080:8080 -p 50051:50051 cr.weaviate.io/semitechnologies/weaviate:latest + - docker-compose up -d +5. Access Weaviate at http://localhost:8080 and configure as needed. +6. Check if Weaviate is ready by hitting the readiness endpoint: + curl localhost:8080/v1/.well-known/ready +``` + +Because we're using `client.chats.create(...)`, follow-up questions in the same chat preserve context — Gemini will only re-call `ask_weaviate` if it needs more information. + +## Google Vertex AI + +Vertex AI uses the `google-genai` SDK and authenticates against your GCP project. This is the path to take if you're already deploying on Google Cloud — you get IAM-controlled access and can call any model in the Vertex AI Model Garden. The SDK reads your Python function's signature and docstring to build the tool declaration automatically. + +### Setup + +You need an existing GCP project with the [Vertex AI API enabled](https://console.cloud.google.com/apis/), and the [`gcloud` CLI](https://cloud.google.com/sdk/docs/install) installed and initialized (`gcloud init`). + +```python +!pip install -U google-genai +``` + +```python +import os +os.environ["GCP_PROJECT_ID"] = "" +os.environ["GOOGLE_CLOUD_REGION"] = "" # e.g. "us-central1" +``` + +### Create the Vertex client + + + + + + + + + +### Ask a question + + + + + + + + + +```text +To deploy Weaviate on Docker, you need Docker and Docker Compose CLI. +Download a 'docker-compose.yml' file using Weaviate's configuration tool to +customize it. Then, navigate to the directory containing the file and run +`docker compose up -d` in the terminal. This will start the setup in detached +mode. Ensure the file is correctly named and located before starting. +``` + +`ask_weaviate` goes in the `tools` list on `GenerateContentConfig`, and Vertex will invoke it whenever the model decides the user's question needs a lookup against your Weaviate data. + +## Ollama + +[Ollama](https://ollama.com/) runs open models locally and supports function calling for models that have been trained for it (Llama 3.1, Llama 3.2, etc.). It requires you to declare the tool schema explicitly and drive the function-calling loop yourself — there's no automatic introspection of Python signatures. + +### Setup + +[Install Ollama](https://ollama.com/download) and pull a model that supports tool use: + +```bash +ollama pull llama3.1 +``` + +```python +!pip install ollama +``` + +### Declare the tool schema + + + + + + + + + +### Drive the function-calling loop + +With Ollama you make a first call to let the model decide whether to invoke a tool, execute the tool yourself if it does, then make a second call with the tool's output appended to the message history. + + + + + + + + + +### Ask a question + + + + + + + + + +```text +Querying Weaviate with: docker deployment +To deploy Weaviate with Docker, you'll need to follow these steps: + +1. Pull the Weaviate Docker image: + docker pull weaviate/weaviate:latest + +2. Run Weaviate in a container: + docker run -p 8080:8080 -v /path/to/your/data:/data weaviate/weaviate:latest + +3. Verify Weaviate is running by visiting http://localhost:8080 + +4. Stop or remove containers as needed. +``` + +The loop above makes the tool-calling contract very explicit: the model proposes a tool call, your code decides whether to honor it, and you control what gets fed back in. The same pattern works against any provider that exposes raw OpenAI-style function calling. + +## LangChain + +[LangChain](https://www.langchain.com/) wraps tool-using LLMs behind a uniform interface, so once you've declared your tool you can switch model providers with a one-line change. + +### Setup + +```python +!pip install -U langchain langchain-openai +``` + +```python +import os +os.environ["OPENAI_API_KEY"] = "" +``` + +### Declare the tool + +LangChain's `@tool` decorator turns a regular Python function into a `BaseTool`, using the docstring as the tool description. You can pass `ask_weaviate` as-is by decorating a wrapper, or apply `@tool` directly: + + + + + + + + + +### Bind the tool to a model + + + + + + + + + +`bind_tools` is the swap-friendly part — change the `init_chat_model` call to point at Anthropic, Vertex, or any other supported provider and the rest stays the same. + +### Ask a question + + + + + + + + + +```text +To run Weaviate with Docker, you can follow these steps: + +1. Install Docker on your machine. +2. Pull the Weaviate image: + docker pull semitechnologies/weaviate +3. Run the container: + docker run -d -p 8080:8080 semitechnologies/weaviate +4. Verify by visiting http://localhost:8080/v1 +... +``` + +For a full agent loop (multiple tool calls, reasoning between them) wire `llm_with_tools` into a LangGraph agent or use `AgentExecutor`. The single `invoke` call above is enough to demonstrate the tool wiring. + +## LlamaIndex + +[LlamaIndex](https://docs.llamaindex.ai/) has a high-level `AgentWorkflow` that accepts plain Python functions directly — pass `ask_weaviate` in and the workflow handles the tool-calling protocol for you. + +### Setup + +```python +!pip install -U llama-index llama-index-llms-openai +``` + +```python +import os +os.environ["OPENAI_API_KEY"] = "" +``` + +### Build the agent workflow + + + + + + + + + +The `system_prompt` here is the *outer* agent's prompt — it shapes how the LlamaIndex agent decides when and how to call the tool. The Query Agent itself has its own (separate) system prompt, which you can configure on the `QueryAgent` constructor; see [Customizing the System Prompt](../reference/system_prompt.md). + +### Ask a question + + + + + + + + + +```text +To run Weaviate with Docker, follow these steps: + +1. Install Docker and Docker Compose. +2. Download the Weaviate Docker image: + docker pull cr.weaviate.io/semitechnologies/weaviate:latest +3. Run Weaviate: + docker run -p 8080:8080 -p 50051:50051 cr.weaviate.io/semitechnologies/weaviate:latest +4. Or use Docker Compose with a docker-compose.yml file. +5. Verify it's ready: + curl --fail -s localhost:8080/v1/.well-known/ready +``` + +Because `workflow.run` is async, call it with `await` inside an async function (or wrap it with `asyncio.run(...)` in a script). + +## Using the Query Agent as a tool anywhere + +The pattern is the same regardless of framework: + +1. You have a Python function — `ask_weaviate(query: str) -> str` — that takes a question and returns the Query Agent's `final_answer`. +2. You hand that function to a calling LLM, either as a Python callable (when the framework can introspect signatures) or with a thin schema or decorator wrapper around it. +3. The LLM decides when the user's request needs to consult your Weaviate data and routes a question through the tool. + +This means you can plug the Query Agent into **anything** that supports function calling or tools: + +- **OpenAI Assistants / Responses API** — declare the tool schema (same shape as the Ollama example) and hand it to the API. +- **Anthropic tool use** — pass a tool definition with name `ask_weaviate` and the description from the docstring. +- **MCP servers** — wrap the function as an MCP tool so any MCP-aware client (Claude Desktop, Cursor, custom IDE plugins) can call into your Weaviate data. +- **Custom agent frameworks** — anything that can execute a Python callable can use this directly. + +### Production tips + +A few things worth knowing once you take this past a notebook: + +- **Reuse a single client and agent.** Opening a Weaviate client per call is slow and creates more connections than you need. Create them once on startup and close them on shutdown. +- **Close the client cleanly.** When your process exits, call `weaviate_client.close()`. If you're using a framework with a lifecycle hook (FastAPI's `lifespan`, Django's `appconfig`, etc.), tie it in there. +- **Watch your usage.** Each tool invocation runs a Query Agent call, which uses model units from your Weaviate Cloud plan. The calling LLM may call the tool multiple times per turn — guard against runaway loops if cost matters. +- **Consider returning more than the final answer.** For some apps, the calling agent benefits from seeing the `sources` or executed `searches`, not just the natural-language answer. You can change `ask_weaviate` to return a structured object (JSON) and update the docstring to tell the LLM what to do with each field. +- **Constrain the collections.** If you have many collections, instantiate separate agents over different subsets (e.g. `ask_products`, `ask_docs`) and expose each as its own tool. The calling LLM will pick the right one based on the docstrings. + +## Further resources + +- [**Get Started with the Weaviate Query Agent**](./query-agent-get-started.md) — Walkthrough of the Query Agent's own Ask Mode, Search Mode and Suggest Queries features. +- [**Build a Query Agent E-Commerce Assistant**](./query-agent-ecommerce-assistant.md) — Use-case-focused tutorial that wraps the Query Agent into a reusable customer-facing assistant. +- [**Ask Mode**](../guides/ask_mode.md) — Streaming, system prompts, multi-turn conversations, result evaluation. +- [**Customizing the System Prompt**](../reference/system_prompt.md) — Tune the Query Agent's own behavior independent of the outer agent's prompt. + +Close the Weaviate client when your application shuts down: + + + + + + + + diff --git a/docs/query-agent/recipes/query-agent-ecommerce-assistant.md b/docs/query-agent/recipes/query-agent-ecommerce-assistant.md new file mode 100644 index 000000000..e3d4873af --- /dev/null +++ b/docs/query-agent/recipes/query-agent-ecommerce-assistant.md @@ -0,0 +1,379 @@ +--- +layout: recipe +toc: True +title: "Build a Query Agent e-commerce assistant" +featured: True +integration: False +agent: True +sidebar_position: 20 +# tags: ['Query Agent'] +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; +import PyCode from '!!raw-loader!/docs/query-agent/_includes/code/query_agent_ecommerce_assistant.py'; + +In this recipe, we will be building a simple e-commerce assistant agent with the [Weaviate Query Agent](https://docs.weaviate.io/query-agent). This agent will have access to a number of Weaviate collections, and will be capable of answering complex queries about brands and clothing items, accessing information from each collection. By the end, we'll wrap the agent in a small reusable class that's ready to plug into a chatbot, CLI, or any larger application. + +![Weaviate Query Agent flowchart for the Ecommerce example](../_includes/query_agent_tutorial_ecommerce_flowchart.png#gh-light-mode-only "Weaviate Query Agent flowchart for the Ecommerce example") +![Weaviate Query Agent flowchart for the Ecommerce example](../_includes/query_agent_tutorial_ecommerce_flowchart.png#gh-dark-mode-only "Weaviate Query Agent flowchart for the Ecommerce example") + +> 📚 You can read and learn more about this service in our ["Introducing the Weaviate Query Agent"](https://weaviate.io/blog/query-agent) blog. + +To get started, we've prepared two open datasets, available on Hugging Face. The first step will be walking through how to populate your Weaviate Cloud collections. + +- [**E-commerce:**](https://huggingface.co/datasets/weaviate/agents/viewer/query-agent-ecommerce) A dataset that lists clothing items, prices, brands, reviews, etc. +- [**Brands:**](https://huggingface.co/datasets/weaviate/agents/viewer/query-agent-brands) A dataset that lists clothing brands and information about them such as their parent brand, child brands, average customer rating, etc. + +> 💡 New to the Query Agent? Start with the [**Get Started**](./query-agent-get-started.md) recipe — it walks through Ask Mode, Search Mode and Suggest Queries at a higher level before diving into this use-case-focused tutorial. + +## 1. Setting up Weaviate & importing data + +To use the Weaviate Query Agent, first, create a [Weaviate Cloud](https://weaviate.io/deployment/serverless) account👇 +1. [Create Serverless Weaviate Cloud account](https://weaviate.io/deployment/serverless) and setup a free [Sandbox](https://docs.weaviate.io/cloud/manage-clusters/create#sandbox-clusters) +2. Go to 'Embedding' and enable it, by default, this will make it so that we use `Snowflake/snowflake-arctic-embed-l-v2.0` as the embedding model +3. Take note of the `WEAVIATE_URL` and `WEAVIATE_API_KEY` to connect to your cluster below + +> Info: We recommend using [Weaviate Embeddings](https://docs.weaviate.io/weaviate/model-providers/weaviate) so you do not have to provide any extra keys for external embedding providers. + +```python +!pip install "weaviate-client[agents]" datasets +``` + +```python +import os +from getpass import getpass + +if "WEAVIATE_API_KEY" not in os.environ: + os.environ["WEAVIATE_API_KEY"] = getpass("Weaviate API Key") +if "WEAVIATE_URL" not in os.environ: + os.environ["WEAVIATE_URL"] = getpass("Weaviate URL") +``` + + + + + + + + + +### Prepare the collections + +In the following code blocks, we are pulling our demo datasets from Hugging Face and writing them to new collections in our Weaviate Serverless cluster. + +> ❗️ The `QueryAgent` uses the descriptions of collections and properties to decide which ones to use when solving queries, and to access more information about properties. You can experiment with changing these descriptions, providing more detail, and more. It's good practice to provide property descriptions too. For example, below we make sure that the `QueryAgent` knows that prices are all in USD, which is information that would otherwise be unavailable. + +![Ecommerce and Brands collection example data](../_includes/query_agent_tutorial_ecommerce_dataset.png#gh-light-mode-only "Ecommerce and Brands collection example data") +![Ecommerce and Brands collection example data](../_includes/query_agent_tutorial_ecommerce_dataset.png#gh-dark-mode-only "Ecommerce and Brands collection example data") + + + + + + + + + + + + + + + + + + +## 2. Set up the Query Agent + +When setting up the Query Agent, we have to provide it a few things: +- The `client` +- The `collections` which we want the agent to have access to. +- (Optionally) A `system_prompt` that describes how our agent should behave +- (Optionally) Timeout - which for now defaults to 60s. + +Let's start with a simple agent. Here, we're creating an `agent` that has access to our `Brands` & `ECommerce` datasets, and frame it as a helpful shopping assistant via the system prompt. + + + + + + + + + +## 3. Run the Query Agent + +When we run the agent, it will first make a few decisions, depending on the query: + +1. The agent will decide which collection or collections to look up an answer in. +2. The agent will also decide whether to perform a regular ***search query***, what ***filters*** to use, whether to do an ***aggregation query***, or all of them together! +3. It will then provide a response, accessible via `response.final_answer`, `response.sources`, or by calling `response.display()` for a rich formatted view. + +### Ask a question +**Let's start with a simple question: "I like the vintage clothes, can you list me some options that are less than $200?"** + +We can then also inspect how the agent responded, what kind of searches it performed on which collections, whether it has identified if the final answer is missing information or not, as well as the final answer 👇 + + + + + + + + + +
╭─────────────────────────────────────────────── 🔍 Original Query ───────────────────────────────────────────────╮
+│                                                                                                                 │
+│ I like the vintage clothes, can you list me some options that are less than $200?                               │
+│                                                                                                                 │
+╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+ +
╭──────────────────────────────────────────────── 📝 Final Answer ────────────────────────────────────────────────╮
+│                                                                                                                 │
+│ If you are looking for vintage clothing options under $200, here are some great choices:                        │
+│                                                                                                                 │
+│ 1. **Vintage Philosopher Midi Dress** - Priced at $125, this dress from Echo & Stitch embraces a classic        │
+│ scholarly look with its deep green velvet fabric and antique gold detailing. It's tailored for elegance and is  │
+│ ideal for sophisticated occasions.                                                                              │
+│                                                                                                                 │
+│ 2. **Vintage Gale Pleated Dress** - This $120 dress from Solemn Chic features deep burgundy pleats and          │
+│ vintage-inspired sleeve details, perfect for a timeless scholarly appearance.                                   │
+│                                                                                                                 │
+│ 3. **Retro Groove Flared Pants** - For $59, these electric blue flared pants from Vivid Verse bring back the    │
+│ playful spirit of the early 2000s with a modern touch.                                                          │
+│                                                                                                                 │
+│ 4. **Vintage Scholar Tote** - At $90, this tote from Echo & Stitch combines functionality and elegance, ideal   │
+│ for everyday use, especially if you enjoy a scholarly aesthetic.                                                │
+│                                                                                                                 │
+│ 5. **Electric Velvet Trousers** - Priced at $60, these neon green velvet trousers from Vivid Verse offer a fun, │
+│ throwback vibe to early Y2K fashion.                                                                            │
+│                                                                                                                 │
+│ 6. **Victorian Velvet Jumpsuit** - For $120, this jumpsuit from Solemn Chic offers an elegant blend of romance  │
+│ and scholarly charm, suited for library visits or cultured gatherings.                                          │
+│                                                                                                                 │
+│ 7. **Vintage Scholar Turtleneck** - This $55 turtleneck from Echo & Stitch suits the Dark Academia vibe,        │
+│ perfect for layering or wearing alone.                                                                          │
+│                                                                                                                 │
+│ 8. **Vintage Ivy Loafers** - These $120 loafers from Solemn Chic offer timeless sophistication, with a deep     │
+│ burgundy finish that complements any vintage wardrobe.                                                          │
+│                                                                                                                 │
+│ These options cater to various preferences, from dresses and jumpsuits to pants and accessories, all capturing  │
+│ the vintage essence at an affordable price.                                                                     │
+│                                                                                                                 │
+╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+ +
╭─────────────────────────────────────────── 🔭 Searches Executed 1/1 ────────────────────────────────────────────╮
+│                                                                                                                 │
+│ QueryResultWithCollectionNormalized(                                                                            │
+│     query='vintage clothes',                                                                                    │
+│     filters=IntegerPropertyFilter(                                                                              │
+│         property_name='price',                                                                                  │
+│         operator=<ComparisonOperator.LESS_THAN: '<'>,                                                           │
+│         value=200.0                                                                                             │
+│     ),                                                                                                          │
+│     collection='ECommerce'                                                                                      │
+│ )                                                                                                               │
+│                                                                                                                 │
+╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+ +### Ask a follow-up question + +Customers rarely ask one question and stop — they have a conversation. To give the agent the prior turns, pass a list of `ChatMessage` objects to `.ask()` instead of a single string. The agent will then use the full message history as context. + + + + + + + + + +
╭──────────────────────────────────────────────── 📝 Final Answer ────────────────────────────────────────────────╮
+│                                                                                                                 │
+│ Here are some great shoe options under $200 that you might like:                                                │
+│                                                                                                                 │
+│ 1. **Vintage Noir Loafers** - Priced at $125, these loafers are part of the Dark Academia collection by Solemn  │
+│ Chic. They come in black and grey, featuring a classic design with a modern twist. Reviews highlight their      │
+│ comfort and stylish appearance, making them suitable for both casual and formal settings.                       │
+│                                                                                                                 │
+│ 2. **Parchment Boots** - At $145, these boots from Nova Nest's Light Academia collection are noted for their    │
+│ elegant ivory leather and classical detail stitching. They are praised for their comfort and versatile style.   │
+│                                                                                                                 │
+│ 3. **Bramble Berry Loafers** - These loafers, priced at $75, come in pink and green and are marked by their     │
+│ eco-friendly material and countryside aesthetic. Produced by Eko & Stitch, they are loved for their comfort and │
+│ sustainability.                                                                                                 │
+│                                                                                                                 │
+│ 4. **Glide Platforms** - Available for $90 from the Y2K collection by Vivid Verse, these platform sneakers are  │
+│ both comfortable and stylish with a high-shine pink finish.                                                     │
+│                                                                                                                 │
+│ 5. **Sky Shimmer Sneaks** - Costing $69, these sneakers are from the Y2K collection by Nova Nest and offer a    │
+│ comfortable fit with a touch of sparkle for style.                                                              │
+│                                                                                                                 │
+│ These selections offer a mix of formal and casual styles, ensuring you can find a perfect pair under your       │
+│ budget of $200.                                                                                                 │
+│                                                                                                                 │
+╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+ +Now let's try a question that should require an aggregation. Let's see which brand lists the most shoes. + + + + + + + + + +
╭──────────────────────────────────────────────── 📝 Final Answer ────────────────────────────────────────────────╮
+│                                                                                                                 │
+│ The brand that lists the most shoes is Loom & Aura with a total of 118 shoe listings.                           │
+│                                                                                                                 │
+╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+ +
╭──────────────────────────────────────────── 📊 Aggregations Run 1/1 ────────────────────────────────────────────╮
+│                                                                                                                 │
+│ AggregationResultWithCollectionNormalized(                                                                      │
+│     groupby_property='brand',                                                                                   │
+│     aggregation=IntegerPropertyAggregation(property_name='collection', metrics=<NumericMetrics.COUNT: 'COUNT'>), │
+│     filters=None,                                                                                               │
+│     collection='ECommerce'                                                                                      │
+│ )                                                                                                               │
+│                                                                                                                 │
+╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+ +### Search across multiple collections + +In some cases, we need to combine the results of searches across multiple collections. From the result above, we can see that "Loom & Aura" lists the most shoes. + +Let's imagine a scenario where the user would now want to find out more about this company, _as well_ as the items that they sell. + + + + + + + + + +
╭──────────────────────────────────────────────── 📝 Final Answer ────────────────────────────────────────────────╮
+│                                                                                                                 │
+│ Loom & Aura is itself a well-established brand based in Italy and operates as the parent brand to several child │
+│ brands. These child brands include 'Loom & Aura Active', 'Loom & Aura Kids', 'Nova Nest', 'Vivid Verse', 'Loom  │
+│ Luxe', 'Saffron Sage', 'Stellar Stitch', 'Nova Nectar', 'Canvas Core', and 'Loom Lure'. The countries           │
+│ associated with the operations or origins of these child brands include Italy, USA, UK, Spain, South Korea,     │
+│ Japan, and some extend beyond Italy as suggested by the presence of these brands in different countries.        │
+│                                                                                                                 │
+│ The average price of an item from Loom & Aura is approximately $87.11. This reflects the brand's positioning as │
+│ offering items of timeless elegance and quality craftsmanship.                                                  │
+│                                                                                                                 │
+╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+ +You can see in `response.display()` that the agent issued two searches against the `Brands` collection (to find the parent/child relationships) plus one aggregation against the `ECommerce` collection (to compute the average price) — all from a single natural-language call. + +## 4. Wrap the agent as a reusable assistant + +So far we've been calling `agent.ask()` ad hoc and rebuilding the conversation list ourselves. To plug this into a real app, we want a small wrapper that: +- Keeps a running conversation history across calls. +- Returns just the final answer to the caller. +- Lets us reset between sessions. + + + + + + + + + +We can now drive a multi-turn session with a single object: + + + + + + + + + +From here, the `ECommerceAssistant` is a self-contained component you can drop into a web app, Slack bot, CLI, or any flow where a customer needs to talk to your catalog in natural language. Because all of the search and aggregation work is delegated to the Query Agent, your application code stays small. + +### Extending the assistant + +A few directions you can take this from here: +- **Switch to Search Mode for product grids.** When you want to render a list of products rather than a written answer, call `agent.search(...)` and pass `response.search_results.objects` to your UI. See the [Search Mode](../guides/search_mode.md) page. +- **Tune the assistant's voice with a richer system prompt.** Add brand-voice guidelines, response formatting (markdown, JSON), or language requirements. See [Customizing the System Prompt](../reference/system_prompt.md). +- **Restrict to a single user's data.** If your catalog is multi-tenant, set `tenant` on a `QueryAgentCollectionConfig`. To enforce a hard filter (e.g. `region = "EU"`) regardless of what the LLM decides, use `additional_filters`. See [Additional Filters](../reference/additional_filters.md) and [Collection Configuration](../reference/advanced_collections.md). + +## Further resources + +- [**Build a Streaming Chat UI with Streamlit**](./query-agent-streamlit-chat.md) — A direct continuation of this recipe: wrap the same `ECommerce + Brands` agent in a Streamlit app with token-by-token streaming, live progress updates, and persisted multi-turn history. +- [**Ask Mode**](../guides/ask_mode.md) — Streaming, system prompts, result evaluation. +- [**Multi-turn Conversations**](../reference/multi_turn_conversations.md) — More detail on the conversation pattern used above. +- [**Search Mode**](../guides/search_mode.md) — Use Search Mode if you want raw results instead of a written answer (for example to render a product grid). + +Close the client when you're done: + + + + + + + + diff --git a/docs/query-agent/recipes/query-agent-get-started.md b/docs/query-agent/recipes/query-agent-get-started.md new file mode 100644 index 000000000..23c3b89f5 --- /dev/null +++ b/docs/query-agent/recipes/query-agent-get-started.md @@ -0,0 +1,241 @@ +--- +layout: recipe +colab: https://colab.research.google.com/github/weaviate/recipes/blob/main/weaviate-services/agents/query-agent-get-started.ipynb +toc: True +title: "Get started with the Weaviate Query Agent" +featured: True +integration: False +agent: True +sidebar_position: 10 +# tags: ['Query Agent'] +--- + + Open In Google Colab + + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; +import PyCode from '!!raw-loader!/docs/query-agent/_includes/code/query_agent_get_started.py'; + +In this recipe, we will get started with the [Weaviate Query Agent](https://docs.weaviate.io/query-agent). We'll set up Weaviate Cloud, import a handful of open datasets, and run a few queries across them using **Ask Mode**, **Search Mode**, and the **Suggest Queries** feature. + +> 📚 You can read and learn more about this service in our ["Introducing the Weaviate Query Agent"](https://weaviate.io/blog/query-agent) blog. + +To follow along, we've prepared four open datasets, available on Hugging Face. We'll load all of them so the same agent can answer questions across very different kinds of data. + +- [**E-commerce:**](https://huggingface.co/datasets/weaviate/agents/viewer/query-agent-ecommerce) A dataset that lists clothing items, prices, brands, reviews, etc. +- [**Brands:**](https://huggingface.co/datasets/weaviate/agents/viewer/query-agent-brands) A dataset that lists clothing brands and information about them such as their parent brand, child brands, average customer rating, etc. +- [**Financial Contracts**:](https://huggingface.co/datasets/weaviate/agents/viewer/query-agent-financial-contracts) A dataset of financial contracts between individuals and/or companies, as well as information on the type of contract and who has authored them. +- [**Weather**:](https://huggingface.co/datasets/weaviate/agents/viewer/query-agent-weather) Daily weather information including temperature, wind speed, precipitation, pressure, etc. + +## 1. Setting up Weaviate & importing data + +To use the Weaviate Query Agent, first, create a [Weaviate Cloud](https://weaviate.io/deployment/serverless) account👇 +1. [Create Serverless Weaviate Cloud account](https://weaviate.io/deployment/serverless) and setup a free [Sandbox](https://docs.weaviate.io/cloud/manage-clusters/create#sandbox-clusters) +2. Go to 'Embedding' and enable it, by default, this will make it so that we use `Snowflake/snowflake-arctic-embed-l-v2.0` as the embedding model +3. Take note of the `WEAVIATE_URL` and `WEAVIATE_API_KEY` to connect to your cluster below + +> Info: We recommend using [Weaviate Embeddings](https://docs.weaviate.io/weaviate/model-providers/weaviate) so you do not have to provide any extra keys for external embedding providers. + +```python +!pip install "weaviate-client[agents]" datasets +``` + +```python +import os +from getpass import getpass + +if "WEAVIATE_API_KEY" not in os.environ: + os.environ["WEAVIATE_API_KEY"] = getpass("Weaviate API Key") +if "WEAVIATE_URL" not in os.environ: + os.environ["WEAVIATE_URL"] = getpass("Weaviate URL") +``` + + + + + + + + + +### Prepare the collections + +In the following code blocks, we are pulling our demo datasets from Hugging Face and writing them to new collections in our Weaviate Serverless cluster. + +> ❗️ The `QueryAgent` uses the descriptions of collections and properties to decide which ones to use when solving queries, and to access more information about properties. You can experiment with changing these descriptions, providing more detail, and more. It's good practice to provide property descriptions too. For example, below we make sure that the `QueryAgent` knows that prices are all in USD, which is information that would otherwise be unavailable. + + + + + + + + + + + + + + + + + +## 2. Set up the Query Agent + +When setting up the Query Agent, we have to provide it a few things: +- The `client` +- The `collections` which we want the agent to have access to. +- (Optionally) A `system_prompt` that describes how our agent should behave +- (Optionally) Timeout - which for now defaults to 60s. + +Here we'll give it access to all four collections so it can route any question to the right place. + + + + + + + + + +## 3. Ask Mode + +Ask Mode returns a natural-language answer composed from the underlying data. The agent decides which collection(s) to search, which filters to apply, and how to phrase the response. + + + + + + + + + +The `display()` method prints a rich view of the original query, the searches and aggregations that were executed, the sources used, and the final answer. You can also access individual pieces of the response directly: + + + + + + + + + +Because our agent has access to all four collections, it can route the query to the right one without us specifying. The same agent can also answer questions about clothing: + + + + + + + + + +## 4. Search Mode + +Search Mode skips the final answer-generation step and returns the raw matching objects from your collection(s). This is what you want when you need rows, not a written response — for example as the retrieval step in your own pipeline, or to render results in a UI. + + + + + + + + + +You can inspect the agent's chosen filters and target collection through `search_response.searches`, just like in Ask Mode. + +## 5. Suggest Queries + +If you're not sure what to ask, the Query Agent can suggest queries based on the data in your collections. This is useful for surfacing what's available in a new dataset, or for populating example prompts in a UI. + + + + + + + + + +You can also constrain the style or focus of the suggestions with the `instructions` argument: + + + + + + + + + +## Further resources + +- [**Build a Query Agent E-Commerce Assistant**](./query-agent-ecommerce-assistant.md) — A use-case-focused tutorial that wraps the Query Agent into a reusable customer-facing assistant. +- [**Ask Mode**](../guides/ask_mode.md) — Streaming, system prompts, result evaluation, multi-turn conversations. +- [**Search Mode**](../guides/search_mode.md) — Pagination, diversity ranking. +- [**Collection Configuration**](../reference/advanced_collections.md) — Target vectors, view properties, multi-tenancy, additional filters. + +Finally, free up resources by closing the client: + + + + + + + + diff --git a/docs/query-agent/recipes/query-agent-streamlit-chat.md b/docs/query-agent/recipes/query-agent-streamlit-chat.md new file mode 100644 index 000000000..14f737c4e --- /dev/null +++ b/docs/query-agent/recipes/query-agent-streamlit-chat.md @@ -0,0 +1,205 @@ +--- +layout: recipe +toc: True +title: "Build a streaming chat UI with Streamlit" +featured: True +integration: True +agent: True +sidebar_position: 30 +# tags: ['Query Agent', 'Streamlit', 'Streaming', 'UI'] +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; +import PyCode from '!!raw-loader!/docs/query-agent/_includes/code/query_agent_streamlit_chat.py'; + +In this recipe, we'll build a chat UI for the Weaviate Query Agent using [Streamlit](https://streamlit.io). The UI streams the agent's progress (which collection it's searching, what query it's running) *and* the final answer token by token, so the user sees something happen the moment they hit enter — instead of waiting silently for the full response. + +We'll use the **ECommerce + Brands** datasets and give the agent a system prompt that frames it as a shopping assistant. The result is a working chat app you can run locally with `streamlit run app.py`. + +This recipe focuses on three things: + +- **Streaming responses** via the Query Agent's `ask_stream` API. +- **Multi-turn conversations** with persisted chat history. +- **Surfacing the agent's reasoning** so the user can see *what* it's doing, not just the final answer. + +> 💡 New to the Query Agent? Start with the [**Get Started**](./query-agent-get-started.md) recipe — it covers Ask Mode, Search Mode and Suggest Queries at a higher level. + +## What you'll build + +When you run the app, the user types a question like *"recommend me some vintage shoes under $80"* and immediately sees a sequence of progress lines — *"Analyzing query…"*, *"Searching ECommerce…"*, *"Generating answer…"* — appear above an empty assistant bubble. As soon as the agent starts composing its response, the answer streams in token by token. When the run completes, a *Sources* expander appears underneath with the UUIDs of the products the agent referenced. The whole experience feels alive instead of stuck. + +## What you'll need + +- A **Weaviate Cloud** cluster — [create a free sandbox here](https://console.weaviate.cloud/). When you create the cluster, enable **Embeddings** so you don't need to provide an external embedding provider's API key. +- The Weaviate client with the `agents` extras, plus Streamlit and `datasets` (for the one-time data import): + +```bash +pip install -U "weaviate-client[agents]" streamlit datasets +``` + +- Two environment variables in the shell you'll run from: + +```bash +export WEAVIATE_URL="https://your-cluster.weaviate.network" +export WEAVIATE_API_KEY="your-api-key" +``` + +## Setting up the data + +The chat app reads from two collections: **ECommerce** (clothing items with brands, prices, reviews, tags) and **Brands** (brand metadata including parent/child relationships). We'll load both from open datasets on Hugging Face. + +This is a **one-time setup** — once the collections exist and have data you can re-run the Streamlit app as many times as you like without re-importing. + +Save the following as `load_data.py` and run it once: + + + + + + + + + +Run it: + +```bash +python load_data.py +``` + +The import takes a couple of minutes — Hugging Face streams the data, Weaviate Embeddings vectorizes it on the way in. If you re-run this script and the collections already exist, the `client.collections.create(...)` calls will error; uncomment the `client.collections.delete(...)` lines or delete the collections from the Weaviate Cloud console first. + +The two datasets used here are public on Hugging Face: + +- [**weaviate/agents · query-agent-ecommerce**](https://huggingface.co/datasets/weaviate/agents/viewer/query-agent-ecommerce) — clothing items with brands, prices, reviews and tags. +- [**weaviate/agents · query-agent-brands**](https://huggingface.co/datasets/weaviate/agents/viewer/query-agent-brands) — clothing brand metadata including parent/child brand relationships. + +## The app + +Save the following as `app.py`. We'll walk through what each part does in the next section. + + + + + + + + + +Run it with: + +```bash +streamlit run app.py +``` + +This will open a browser at `http://localhost:8501` with the chat UI. + +## How it works + +### Connecting once with `@st.cache_resource` + +Streamlit re-runs the entire script on every interaction — every chat submission, every button click. Without caching, that would mean opening a fresh Weaviate connection and instantiating a new `QueryAgent` for every message the user sends. + + + + + + + + + +`@st.cache_resource` marks a function whose return value is a long-lived resource. The agent and its underlying Weaviate client are created exactly once per session, no matter how many turns the user takes. + +### Chat history in `st.session_state` + +`st.session_state.messages` is a list of `{role, content}` dicts that survives across script re-runs. On every new prompt we: + +1. Append the user message to history. +2. Build a `list[ChatMessage]` from the full history and pass it to `ask_stream`. +3. Append the agent's final answer to history once the stream completes. + +Passing the *entire* history on every call is what gives the agent full context for follow-up questions like *"what about under $50?"* or *"tell me more about the second one."* See [Multi-turn Conversations](../reference/multi_turn_conversations.md) for more on this pattern. + +### Streaming three kinds of output + +`agent.ask_stream(conversation)` is a generator that yields three different payload types as the agent works through your question. The UI handles each one differently: + + + + + + + + + +- **`ProgressMessage`** — Updates like *"Analyzing query…"*, *"Running search…"*, *"Generating answer…"*. We show only the latest in `progress_box`. This is the part that makes the app feel responsive — within a second of the user hitting enter, they see *something* describing what the agent is doing. +- **`StreamedTokens`** — Incremental chunks of the final answer. We append `output.delta` to a running string and re-render. The trailing `▌` is a fake cursor that visually communicates *still generating*. +- **`AskModeResponse`** — The final payload, emitted once when the run completes. We clear the progress indicator, render the answer one last time without the cursor, and grab the `sources` list to display in an expander below. + +The two `st.empty()` placeholders are the trick that makes this work. Calling `.info(...)` or `.markdown(...)` on an `empty()` placeholder *replaces* its contents, so the UI updates in place instead of appending a new line for every chunk. + +### Sources expander + +When the run is done, we render an expander with the UUIDs of the source objects the agent used: + + + + + + + + + +For a real storefront app you'd likely fetch each object and render its full properties (name, brand, image, price) — see [Extending the App](#extending-the-app) below. + +## Try it out + +Some questions to throw at the assistant once it's running: + +- *"Recommend me some vintage shoes under $80."* +- *"Which brand has the most products under $50?"* +- *"Tell me more about the parent brand of Loom & Aura."* +- *"What about something more colorful in the same price range?"* — a follow-up to test multi-turn context. + +## Extending the app + +A few directions you can take this from here: + +- **Render product cards from sources.** Instead of showing UUIDs, fetch each source object via `client.collections.use("ECommerce").query.fetch_object_by_id(src.object_id)` and render its name, price, and image in `st.columns`. This is what a real storefront chat would do. +- **Toggle between Ask and Search Modes.** Add a sidebar radio to pick *"answer me"* (Ask Mode) versus *"show me the products"* (Search Mode). In Search Mode, call `agent.search(...)` and render `search_results.objects` as a product grid. See the [Search Mode](../guides/search_mode.md) page. +- **Show suggested follow-ups.** After each turn, call `agent.suggest_queries(num_queries=3, instructions="Based on the conversation, suggest follow-up questions a shopper might ask.")` and render the suggestions as buttons that re-submit when clicked. See [Suggest Queries](../guides/suggest_queries.md). +- **Surface partial-answer warnings.** Pass `result_evaluation="llm"` to enable `is_partial_answer` and `missing_information`. Display a small warning above the answer when the agent flags the response as incomplete. See [Ask Mode](../guides/ask_mode.md#response). +- **Deploy it.** Streamlit apps run on [Streamlit Community Cloud](https://streamlit.io/cloud), Hugging Face Spaces, or your own server. For deployment, move the env vars into [Streamlit secrets](https://docs.streamlit.io/develop/concepts/connections/secrets-management) (`st.secrets["WEAVIATE_URL"]`) instead of `os.environ`. + +## Further resources + +- [**Ask Mode**](../guides/ask_mode.md) — Full details on `ask_stream`, the three streaming payload classes, and parameter reference. +- [**Get Started with the Weaviate Query Agent**](./query-agent-get-started.md) — Walkthrough of Ask Mode, Search Mode and Suggest Queries at a higher level. +- [**Build a Query Agent E-Commerce Assistant**](./query-agent-ecommerce-assistant.md) — Use-case-focused tutorial that wraps the Query Agent into a reusable assistant class. +- [**Using the Query Agent as a Tool**](./query-agent-as-a-tool.md) — Hand the agent to other frameworks (Gemini, Vertex AI, Ollama, LangChain, LlamaIndex) as a callable tool. diff --git a/docs/query-agent/recipes/query-agent-vs-diy.md b/docs/query-agent/recipes/query-agent-vs-diy.md new file mode 100644 index 000000000..a9c33defa --- /dev/null +++ b/docs/query-agent/recipes/query-agent-vs-diy.md @@ -0,0 +1,318 @@ +--- +layout: recipe +toc: True +title: "Query Agent vs. doing it yourself" +featured: True +integration: False +agent: True +sidebar_position: 50 +# tags: ['Query Agent', 'Comparison'] +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; +import PyCode from '!!raw-loader!/docs/query-agent/_includes/code/query_agent_vs_diy.py'; + +In this recipe, we'll answer the same natural-language question against the same Weaviate collection two ways: first by writing the LLM pipeline ourselves with Pydantic-typed plans and explicit filter/sort builders, then by calling `agent.ask(...)`. The goal is to show what scaffolding the DIY approach needs to support even a small slice of what the Query Agent handles. + +The DIY side of this recipe is **deliberately minimal**: six filter operators, basic sorting, no aggregations, no multi-turn context, one collection. We'll then list what you'd have to add to match the Query Agent feature-for-feature. + +> 💡 New to the Query Agent? Start with the [**Get Started**](./query-agent-get-started.md) recipe — it covers Ask Mode, Search Mode and Suggest Queries at a higher level. + +## What you'll need + +- A **Weaviate Cloud** cluster — [create a free sandbox here](https://console.weaviate.cloud/). When you create the cluster, enable **Embeddings** so you don't need to provide an external embedding provider's API key. +- The Weaviate client with the `agents` extras, the OpenAI SDK, and `datasets` (for the one-time data import): + +```bash +pip install -U "weaviate-client[agents]" openai datasets +``` + +- Three environment variables: + +```bash +export WEAVIATE_URL="https://your-cluster.weaviate.network" +export WEAVIATE_API_KEY="your-api-key" +export OPENAI_API_KEY="sk-..." +``` + +## Setting up the data + +We'll use the **Weather** dataset — daily weather records with date, temperature, wind speed, precipitation, humidity, visibility and pressure. The numeric properties are well-suited to showing filter and sort extraction: the DIY pipeline has to translate phrases like *"more than 5mm"* and *"windiest"* into operators and orderings. + +This is a **one-time setup** — once the `Weather` collection exists and has data, you can re-run the rest of the recipe freely. Save the following as `load_data.py` and run it once: + + + + + + + + + +Run it once: + +```bash +python load_data.py +``` + +The dataset is public on Hugging Face: [**weaviate/agents · query-agent-weather**](https://huggingface.co/datasets/weaviate/agents/viewer/query-agent-weather). + +## The question + +We'll use this single user question throughout the rest of the recipe: + +> *"Show me the top 5 windiest days where it rained more than 5mm."* + +It has all three of the structured pieces the DIY pipeline has to extract: a **filter** (`precipitation > 5`), a **sort** (`wind_speed` descending), and a **limit** (`5`). Anything simpler hides the work the agent does internally. + +Both sides of the comparison share a tiny bit of setup — connecting to Weaviate and grabbing the collection handle: + + + + + + + + + +## Without the Query Agent + +Building this yourself means breaking the question down into stages: tell an LLM what properties exist, ask it to produce a typed plan (filters, sort, limit, optional semantic query), translate that plan into Weaviate query objects, run the query, then ask the LLM to write a final answer using the rows. + +Each step below is a small Python function. At the end of this section we compose them all into a single `ask_diy(question, collection)` that matches the shape of `agent.ask(question)`. Read the steps as building blocks — they're meant to be assembled. + +### Step 1 — Type the plan with Pydantic + +The first job is to constrain what the LLM is allowed to emit. Pydantic gives us strong types we can pass straight to the OpenAI parser, and clear field descriptions the LLM will read to understand what to populate. + + + + + + + + + +The `query` field is what lets the planner choose between **semantic** search and **structured** retrieval depending on the question. For our example, the LLM should set `query=None` — *"top 5 windiest days where it rained more than 5mm"* has no free-text component — but the field exists so the same plumbing handles a question like *"hot summer days"* too. + +> **In production**, this schema grows to cover every shape of question. You'd add OR groupings inside `filters`, an `is_null` operator, date arithmetic, and array operators (`contains_any`) for properties like `tags` or `colors`. Each addition is a new field on `Search`, a new branch in the executor, and a new instruction line in the prompt. + +### Step 2 — Read the collection schema + +The LLM has no idea what's in your database, so before we ask it to plan a query we have to tell it which properties exist and what type each one is. The Weaviate client exposes this via `collection.config.get()`: + + + + + + + + + +> **In production**, the schema alone isn't enough — the LLM also needs realistic example values per property (so it knows `category` is one of a fixed set rather than free-form). You'd sample rows, fold them into the description, and budget a token cap. If you have many collections, a routing step has to run first to pick which one(s) to even describe. + +### Step 3 — Ask the LLM to plan the query + +With the schema and the question, the LLM emits a `Search`. We use OpenAI's typed-output API (`beta.chat.completions.parse`) so the response is already a `Search` instance — no JSON parsing, no validation glue. + + + + + + + + + +> **In production**, this prompt grows considerably: few-shot examples for each filter shape, instructions for ambiguous values (*"under $80"* → `< 80` vs `<= 80`?), and stricter validation that string values look reasonable for their declared types. Once `Search` has 10+ fields you'd also split prompts by question category — one for filter-only questions, one for semantic, one for aggregation — because a single prompt covering everything starts to lose accuracy. + +### Step 4 — Translate the plan into Weaviate query objects + +The LLM produces a `Search` of typed Python objects, but Weaviate's query API wants its own `Filter` and `Sort` objects. Two small helpers handle the mapping: + + + + + + + + + +> **In production**, this is where most of the long tail of work lives. Weaviate also supports `like`, `contains_any` / `contains_all` (for array properties like `tags`, `colors`), `is_null`, and per-tenant filtering — each needs a branch here and a matching entry in `SearchFilter.operator`. `Sort.by_property` also doesn't combine with `near_text`, so any time you sort while doing semantic search you have to pick a tradeoff the agent resolves automatically. + +### Step 5 — Run the query + +Now we hit Weaviate. The executor branches on whether the LLM set `query`: with a semantic query we use `near_text`, without one we fall through to `fetch_objects` (which is the path that supports `sort`). + + + + + + + + + +> **In production**, this branching expands. Real apps also need `hybrid` (with a tunable `alpha`) and `bm25` (keyword), plus rules for when each combines with `sort`. Aggregation questions go to `collection.aggregate.*` entirely — a separate API with its own planner schema and answer composer. + +### Step 6 — Compose the final answer + +Weaviate returns rows. The user wants a written answer, so a second LLM call turns the rows into prose: + + + + + + + + + +> **In production**, this prompt also has to handle the empty-result case (apologise, suggest a relaxed filter), the too-many-rows case (truncate intelligently, flag the answer as partial), and streaming (`stream=True` and propagate chunks). UI integrations want to surface which rows informed the answer so they can be rendered as sources. + +### Step 7 — Tie it all together + +All the building blocks compose into one function — the DIY equivalent of `agent.ask(question)`: + + + + + + + + + +
+Example output + +```text +LLM plan: query=None filters=[SearchFilter(field='precipitation', operator='>', value=5)] sort=SearchSort(field='wind_speed', direction='desc') limit=5 +Here are the top 5 windiest days with more than 5 mm of rain: + +1. 2023-05-02 — Wind: 93.5, Rain: 12.0 mm +2. 2023-05-02 — Wind: 93.5, Rain: 12.0 mm +3. 2023-08-18 — Wind: 74.1, Rain: 6.3 mm +4. 2023-08-18 — Wind: 74.1, Rain: 6.3 mm +5. 2023-08-18 — Wind: 74.1, Rain: 6.3 mm +``` + +Notice the duplicates. The DIY pipeline returns whatever `fetch_objects` gives it, so when the underlying data has near-identical rows the final answer reflects that — and the `limit=5` cap gets consumed by them, so only two distinct days surface and the next-windiest distinct days never make the cut. + +
+ +That's the minimum DIY pipeline. Roughly 90 lines once you count the Pydantic models, two LLM calls, six filter operators, sort, two search methods, one collection. + +## With the Query Agent + + + + + + + + + +
+Example output + +```text +Here are the top 5 windiest days with rainfall over 5 mm: + +1. 2023-05-02 — wind speed: 93.5, precipitation: 12.0 mm +2. 2023-08-18 — wind speed: 74.1, precipitation: 6.3 mm +3. 2023-11-08 — wind speed: 71.5, precipitation: 30.6 mm +4. 2023-12-13 — wind speed: 68.2, precipitation: 30.0 mm +5. 2023-09-04 — wind speed: 66.9, precipitation: 28.6 mm +``` + +Five distinct rainy days — including three the DIY pipeline never surfaced (the 71.5, 68.2 and 66.9 days) because its `limit=5` was consumed by duplicate rows. + +
+ +The agent runs the same stages internally — schema introspection, query planning, execution, answer composition — and also covers multi-collection routing, the full set of filter and aggregation types Weaviate supports, search-method selection across `near_text`, `hybrid`, `bm25` and `fetch_objects`, source attribution, streaming, and multi-turn context. None of which the DIY example handles. + +## What you'd have to add to match the Query Agent + +The DIY pipeline above is a starting point. Here's what you'd extend, roughly in order of how often you actually need each thing: + +| Feature | What's involved | +|---|---| +| **More filter operators** | Adds `Literal` variants to `SearchFilter.operator`, a branch in `build_filter`, and an instruction line in the planner prompt. Common ones: `like`, `contains_any`, `contains_all`, `is_null`. | +| **Aggregations** | A whole second pipeline. The planner first decides *aggregate or search?*, then aggregations have their own model (`group_by`, `metrics`) and a different Weaviate API entirely. | +| **Search-method selection** | The pipeline above covers `near_text` and `fetch_objects`. Real apps also need `hybrid` (with a tunable `alpha`) and `bm25`, plus rules for when each combines with `sort`. | +| **Multi-collection routing** | A planner step *before* `plan_query` that picks the right collection(s) from the available list. Adds an LLM call and another prompt to budget. | +| **Multi-turn conversations** | Track message history, decide what to carry forward, manage prompt size. | +| **Streaming** | Stream the answer composer's output (and ideally the planner's, for very fast first-token UX). Propagate the right structured payloads through your stack. | +| **Source attribution** | Track which row IDs informed the final answer. The Query Agent surfaces this in `response.sources` and, with `result_evaluation="llm"`, trims it down to only the rows actually used. | +| **Schema sampling** | Production LLMs need to see example values, not just types — otherwise filtering on enumerated string fields becomes unreliable. | + +## Further resources + +- [**Get Started with the Weaviate Query Agent**](./query-agent-get-started.md) — Walkthrough of the Query Agent's own Ask Mode, Search Mode and Suggest Queries. +- [**Ask Mode**](../guides/ask_mode.md) — Streaming, system prompts, result evaluation. +- [**Additional Filters**](../reference/additional_filters.md) — How to enforce fixed filters that always apply regardless of what the agent's planner decides. +- [**Collection Configuration**](../reference/advanced_collections.md) — Target vectors, view properties, multi-tenancy. + +Close the Weaviate client when you're done: + + + + + + + + diff --git a/docs/query-agent/reference/additional_filters.md b/docs/query-agent/reference/additional_filters.md new file mode 100644 index 000000000..9714aa0ba --- /dev/null +++ b/docs/query-agent/reference/additional_filters.md @@ -0,0 +1,184 @@ +--- +title: Additional filters +description: "Apply persistent filters that the Query Agent uses on every query." +image: og/query-agent.jpg +# tags: ['agents', 'query-agent', 'configuration'] +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; +import PyCode from '!!raw-loader!/docs/query-agent/_includes/code/additional_filters.py'; +import TSCode from '!!raw-loader!/docs/query-agent/_includes/code/additional_filters.mts'; + +Additional filters can be used to subset the data in a single collection manually in addition to whatever filters the Query Agent decides to use in a particular search. + +These persistent filters are defined at the specification of the collection, and combined with agent-generated filters using logical `AND` operations at search time. + +Additional filters are available in both [Ask Mode](../guides/ask_mode.md) and [Search Mode](../guides/search_mode.md). + +The syntax used is that of a standard Weaviate filter, [see more on filtering in Weaviate for details.](../../weaviate/search/filters.md) + +These can be specified at **instantiation of the Query Agent**. + + + + + + + + + + +Or at **runtime of Ask or Search Mode**. + + + + + + + + + + + + +The additional filters are an argument to `QueryAgentCollectionConfig`, and used as part of collection configuration. [See the page on collection configuration for more detail](./advanced_collections.md). + +You can add as many layers of complexity to the custom filter as you need - a single filter on one property, or multiple nested filters across multiple properties. + +## How is it used? + +The filters are applied in addition to any filters determined by any agent in a run of the Query Agent. The Query Agent could decide one or many filters, and these are combined with the additional filters specified when the final result set is being retrieved. + +In addition, a sample of data from the collection is provided to the agents to better understand the data they have access to. This data subset is also filtered using the additional filters provided. + +## Use cases + +Additional filters reduce the sample space of data to be retrieved. If you have a large data collection but only want to use the Query Agent across a subset of that data, specifying a filter enforces only a portion of the data can be used. + +Since the Query Agent is a non-deterministic process (via the usage of LLMs), if you want to enforce a particular property is always being filtered, you can do so here. + +For example, instead of directly trying to enforce the filter in the prompt, you could replace + + + + + + + + + +with + + + + + + + + + + +
+Additional Information + +You would expect both examples to provide the same (or similar) output. The directness in the first prompt is very likely to ensure that the agent provides an accurate filter based on the request. + +However, since the LLM agent is a non-deterministic process, it is never guaranteed. Directly passing the filter ensures it will always be used. + +
+ +Another example could be in a user-facing app, if you want to restrict search results to only a single user ID, you can directly pass the filter instead of relying on the agent to use the correct filter. + +## Basic filtering + +A single filter, such as limiting the search to only a single category, can be constructed simply. + + + + + + + + + + +## Nested filtering + +If you want to provide more than one filter, you can wrap it in either a logical `AND` or `OR` using Weaviate filter construction, such as: + + + + + + + + + + +## Questions and feedback + +import DocsFeedback from '/\_includes/docs-feedback.mdx'; + + diff --git a/docs/query-agent/reference/advanced_collections.md b/docs/query-agent/reference/advanced_collections.md new file mode 100644 index 000000000..0865d2c1d --- /dev/null +++ b/docs/query-agent/reference/advanced_collections.md @@ -0,0 +1,119 @@ +--- +title: Collection configuration +description: "Configure how Weaviate collections are exposed to the Query Agent." +image: og/query-agent.jpg +# tags: ['agents', 'query-agent', 'configuration'] +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; +import PyCode from '!!raw-loader!/docs/query-agent/_includes/code/advanced_collections.py'; +import TSCode from '!!raw-loader!/docs/query-agent/_includes/code/advanced_collections.mts'; + +The Query Agent, in Ask Mode or Search Mode, has the option to search one or more of any collections that are provided to it. + +These collections can either be specified by a string (the name of the collection) or via a more advanced configuration. + +### Simple configuration + +To give your collections without any advanced configuration, you can just pass strings of the collection names to the Query Agent. + + + + + + + + + + +### Advanced configuration + +You can provide a more detailed configuration on how you want the agents to interact with your collections to define the tenant names (for a multi-tenant collection), target vector(s), property names and any additional filters. + + + + +The `QueryAgentCollectionConfig` class accepts the following arguments: + +| Field | Type | Description | +| --- | --- | --- | +| `name` | `str` | The name of the collection to query. Required. | +| `target_vector` | `str \| list[str] \| None` | An optional list of target vector name(s) for collections with named vectors. Required when the collection has more than one named vector. | +| `view_properties` | `list[str] \| None` | An optional list of property names that the agent is allowed to view when reasoning about and querying the collection. If omitted, the agent can view all properties. | +| `tenant` | `str \| None` | An optional tenant name for collections with multi-tenancy enabled. | +| `additional_filters` | `Filter \| None` | An optional `Filter` object that is always combined with any agent-generated filters when querying this collection. [See the page on additional filters for more detail](./additional_filters.md). | + + + + + +A collection configuration object accepts the following fields: + +| Field | Type | Description | +| --- | --- | --- | +| `name` | `string` | The name of the collection to query. Required. | +| `targetVector` | `string \| string[]` | An optional list of target vector name(s) for collections with named vectors. Required when the collection has more than one named vector. | +| `viewProperties` | `string[]` | An optional list of property names that the agent is allowed to view when reasoning about and querying the collection. If omitted, the agent can view all properties. | +| `tenant` | `string` | An optional tenant name for collections with multi-tenancy enabled. | +| `additionalFilters` | `FilterValue` | An optional `Filter` object that is always combined with any agent-generated filters when querying this collection. [See the page on additional filters for more detail](./additional_filters.md). | + + + + +## Runtime configuration + +The examples above show configuring collections at instantiation of the Query Agent. This defines the _default_ collections which will be used automatically when running Ask Mode or Search Mode. + +You can instead or additionally provide collection information at runtime of the Query Agent, which will override any default collections set at instantiation. + + + + + + + + + + +Similarly to above, this collection can also be either string(s) of the collection name(s), or a set of configurations. + +This is possible in both Ask and Search Mode. + +## Questions and feedback + +import DocsFeedback from '/\_includes/docs-feedback.mdx'; + + + diff --git a/docs/query-agent/reference/index.md b/docs/query-agent/reference/index.md new file mode 100644 index 000000000..fd27c8aaf --- /dev/null +++ b/docs/query-agent/reference/index.md @@ -0,0 +1,22 @@ +--- +title: Configuration +description: "Configure the Query Agent's behavior across Ask Mode and Search Mode." +image: og/query-agent.jpg +# tags: ['agents', 'query-agent', 'configuration'] +--- + +See the different configuration options for the Query Agent and how you can customize it to your specific use case. + +* **[Class Instantiation](./instantiation.md)**: Learn how to instantiate the Query Agent class, as well as options to configure collections and a custom system prompt. +* **[Customize the System Prompt](./system_prompt.md)**: Learn how to define a system prompt and where it is used during the Query Agent process. +* **[Multi-turn Conversations](./multi_turn_conversations.md)**: Learn how to include multiple turns of conversations in a message history instead of a single user query. +* **[Additional Filters](./additional_filters.md)**: Define persistent filters that get added to every search the Query Agent performs. +* **[Collection Configuration](./advanced_collections.md)**: Setup your collections with more advanced configurations, such as named vectors, multi-tenancy and additional filters. + + + +## Questions and feedback + +import DocsFeedback from '/\_includes/docs-feedback.mdx'; + + diff --git a/docs/query-agent/reference/instantiation.md b/docs/query-agent/reference/instantiation.md new file mode 100644 index 000000000..d389b00a3 --- /dev/null +++ b/docs/query-agent/reference/instantiation.md @@ -0,0 +1,146 @@ +--- +title: Class instantiation +description: "Instantiate a Query Agent with a Weaviate client, collections, and options." +image: og/query-agent.jpg +# tags: ['agents', 'query-agent', 'configuration'] +--- + + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; +import PyCode from '!!raw-loader!/docs/query-agent/_includes/code/instantiation.py'; +import TSCode from '!!raw-loader!/docs/query-agent/_includes/code/instantiation.mts'; + +Instantiate the Query Agent against an authenticated Weaviate Cloud client. Configuration can be set at construction time (collections, system prompt, and — in Python — a request timeout) and most options can also be overridden per call to `ask()` or `search()`. + +## Basic instantiation + +The Query Agent requires only a target [Weaviate Cloud instance](/cloud/manage-clusters/connect.mdx) to be initialised. First, set up a Weaviate client: + + + + + + + + + + +Then pass that client to the Query Agent, and all Weaviate calls via agents will be routed through it. + + + + + + + + + + +:::note Async +In Python, to instantiate the async Query Agent (`AsyncQueryAgent`), you must also pass an async Weaviate Client via `weaviate.use_async_with_weaviate_cloud`. In JavaScript/TypeScript, the Query Agent is async by default. +::: + +## Additional configuration + +### Parameters + +The `QueryAgent` constructor accepts the following arguments: + + + + +| Parameter | Type | Description | +| --- | --- | --- | +| `client` | `WeaviateClient` | Required. The Weaviate client connected to a Weaviate Cloud cluster. | +| `collections` | `list[str \| QueryAgentCollectionConfig]` | Optional. The collections to query. Can be overridden per call to `ask()` or `search()`. | +| `system_prompt` | `str` | Optional. Prompt to provide extra instructions to the agents, as well as define the tone, format, and style of the agent's final response. [See the page on the system prompt for more detail](./system_prompt.md). | +| `timeout` | `int \| None` | Optional. The maximum time to wait for a response, in seconds. Defaults to 60 seconds. | + + + + +The first argument is the Weaviate client. All other options are passed in a `QueryAgentOptions` object as the second argument. + +| Parameter | Type | Description | +| --- | --- | --- | +| `client` | `WeaviateClient` | Required. The Weaviate client connected to a Weaviate Cloud cluster. | +| `collections` | `(string \| QueryAgentCollectionConfig)[]` | Optional. The collections to query. Can be overridden per call to `ask()` or `search()`. | +| `systemPrompt` | `string` | Optional. Prompt to provide extra instructions to the agents, as well as define the tone, format, and style of the agent's final response. [See the page on the system prompt for more detail](./system_prompt.md). | + +The TypeScript client does not currently expose a `timeout` option. + + + + +### Collections + +You can define which collections are available either +* at the instantiation of the Query Agent base class, + + + + + + + + +* or at runtime of the Query Agent's methods, either Ask Mode or Search Mode. + + + + + + + + + +If you provide both, then the collections specified at runtime will override those specified in the base class. [See the page on collection configuration for more detail](./advanced_collections.md). + + +## Questions and feedback + +import DocsFeedback from '/\_includes/docs-feedback.mdx'; + + diff --git a/docs/query-agent/reference/multi_turn_conversations.md b/docs/query-agent/reference/multi_turn_conversations.md new file mode 100644 index 000000000..7c47c44ec --- /dev/null +++ b/docs/query-agent/reference/multi_turn_conversations.md @@ -0,0 +1,69 @@ +--- +title: Multi-turn conversations +description: "Pass conversation history to the Query Agent for context-aware follow-up questions." +image: og/query-agent.jpg +# tags: ['agents', 'query-agent', 'configuration'] +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; +import PyCode from '!!raw-loader!/docs/query-agent/_includes/code/conversations.py'; +import TSCode from '!!raw-loader!/docs/query-agent/_includes/code/conversations.mts'; + +The Query Agent transforms a natural language query into actionable searches. You can either pass a single string for the query, or provide more context by including a full conversation with previous message turns. + + + + + + + + + + + +Each message in the conversation must have a `role`, being either `"user"` or `"assistant"`, and `content`, being the text of the message. + +The final message should be a user message, and it will be treated as the current user query to define the task. + +### Example: Iterative message history + +In a chat-style application, you typically want each new user message to build on top of everything said so far, rather than asking the agent in isolation. To do this, keep a running list of `ChatMessage` objects and append both the user's query and the agent's reply to it after every turn. Pass the full list back into `qa.ask()` on the next call so the agent has the complete context. + +The example below wraps this pattern in a simple way. + + + + + + + + + + +## Questions and feedback + +import DocsFeedback from '/\_includes/docs-feedback.mdx'; + + diff --git a/docs/query-agent/reference/system_prompt.md b/docs/query-agent/reference/system_prompt.md new file mode 100644 index 000000000..0caf4fe9e --- /dev/null +++ b/docs/query-agent/reference/system_prompt.md @@ -0,0 +1,57 @@ +--- +title: Customizing the system prompt +description: "Customize the Query Agent's system prompt to shape its behavior and output." +image: og/query-agent.jpg +# tags: ['agents', 'query-agent', 'configuration'] +--- + + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; +import PyCode from '!!raw-loader!/docs/query-agent/_includes/code/system_prompt.py'; +import TSCode from '!!raw-loader!/docs/query-agent/_includes/code/system_prompt.mts'; + + +You can provide a custom system prompt to guide the Query Agent's behavior, by passing it as part of the [instantiation](./instantiation.md). + + + + + + + + + + + +Then any run using the Query Agent will use this new set of instructions. + +A custom system prompt is supported in **both Ask Mode and Search Mode.** + +## How is it used? + +The system prompt is used in two places: + +1. During the query/aggregation writing - the system prompt is passed in addition to a general set of instructions to guide the construction of any queries. +2. During the writing of the final answer - the system prompt overrides a general prompt. + +Therefore it is most useful to use the system prompt in one of two ways: +* Instructions specific for your data, so that the query writing agent has additional information to write queries more effectively. +* A guide for style and tone in writing the final answer, such as specific formatting instructions. + +## Questions and feedback + +import DocsFeedback from '/\_includes/docs-feedback.mdx'; + + diff --git a/docs/query-agent/reference/troubleshooting.md b/docs/query-agent/reference/troubleshooting.md new file mode 100644 index 000000000..2a2a8e088 --- /dev/null +++ b/docs/query-agent/reference/troubleshooting.md @@ -0,0 +1,32 @@ +--- +title: Limitations & troubleshooting +description: "Diagnose common issues and understand the limitations of the Query Agent." +image: og/query-agent.jpg +# tags: ['agents', 'query-agent', 'troubleshooting'] +--- + +Things to check when the Query Agent isn't behaving as expected, plus the soft usage limits and typical execution timings to keep in mind. + +## Usage limits + +import UsageLimits from "/\_includes/agents/query-agent-usage-limits.mdx"; + + + +## Custom collection descriptions + +import CollectionDescriptions from "/\_includes/agents/query-agent-collection-descriptions.mdx"; + + + +## Execution times + +import ExecutionTimes from "/\_includes/agents/query-agent-execution-times.mdx"; + + + +## Questions and feedback + +import DocsFeedback from '/\_includes/docs-feedback.mdx'; + + diff --git a/docs/weaviate/best-practices/code-generation.md b/docs/weaviate/best-practices/code-generation.md index 0411a80bd..e15a344d0 100644 --- a/docs/weaviate/best-practices/code-generation.md +++ b/docs/weaviate/best-practices/code-generation.md @@ -98,11 +98,11 @@ Some AI-powered code generation tools such as Cursor allow you to index further Review the documentation of your specific IDE to see if it has this feature, and how to use it. -### Consider using Weaviate Agents +### Consider using the Query Agent -[Weaviate Agents](/agents) are pre-built agentic services designed for specific tasks, such as [querying](/agents/query), [transforming data](/agents/transformation/), and [personalizing content](/agents/personalization). +The [Query Agent](/query-agent) is a pre-built agentic search service that decides the search terms, filters, sorts, and other search parameters for you — the [modes overview](/query-agent/guides/index.md) covers what it can do. -Weaviate agents are available for Weaviate Cloud users to enable interacting with the Weaviate Cloud instance using natural language. For some use cases, this may be a better approach than using AI-powered code generation tools. +The Query Agent is available to Weaviate Cloud users for interacting with their Weaviate Cloud instance in natural language. For some use cases, this may be a better approach than using AI-powered code generation tools. ## Help us improve this page diff --git a/docs/weaviate/client-libraries/python/index.mdx b/docs/weaviate/client-libraries/python/index.mdx index 6db80f066..8b582365d 100644 --- a/docs/weaviate/client-libraries/python/index.mdx +++ b/docs/weaviate/client-libraries/python/index.mdx @@ -78,9 +78,9 @@ ports: -#### Weaviate Agents +#### Query Agent -You can install the Weaviate client library with the optional agents extras to use [Weaviate Agents](../../../agents/index.md). Install the client library using the following command: +You can install the Weaviate client library with the optional `agents` extras to use the [Query Agent](../../../query-agent/index.md). Install the client library using the following command: ```bash pip install -U "weaviate-client[agents]" diff --git a/docs/weaviate/config-refs/collections.mdx b/docs/weaviate/config-refs/collections.mdx index dad5f2226..86b89d34c 100644 --- a/docs/weaviate/config-refs/collections.mdx +++ b/docs/weaviate/config-refs/collections.mdx @@ -162,7 +162,7 @@ import InitialCaps from "/_includes/schemas/initial-capitalization.md"; #### `description` -A description of the collection. This is for your reference and can also provide additional information to [Weaviate Agents](/docs/agents/index.md). +A description of the collection. This is for your reference and can also provide additional information to the [Query Agent](/query-agent/index.md). --- diff --git a/docs/weaviate/connections/connect-query.mdx b/docs/weaviate/connections/connect-query.mdx index 80304b939..7e7852f0f 100644 --- a/docs/weaviate/connections/connect-query.mdx +++ b/docs/weaviate/connections/connect-query.mdx @@ -53,11 +53,11 @@ Beyond picking collections, you can also provide API keys for external model pro ### Generate client code -After running a query in the console, you can copy a Python or TypeScript snippet that reproduces the same call through the [`weaviate-agents`](/docs/agents/query/index.md) client libraries — useful for moving from exploration into application code. +After running a query in the console, you can copy a Python or TypeScript snippet that reproduces the same call through the [`weaviate-agents`](/query-agent/index.md) client libraries — useful for moving from exploration into application code. ### Limitations -- The Cloud-console Query Agent does **not** support multi-tenant collections. To use the Query Agent with multi-tenancy, call it from a [client library](/docs/agents/query/usage.md#configure-collections). +- The Cloud-console Query Agent does **not** support multi-tenant collections. To use the Query Agent with multi-tenancy, call it from a [client library](/query-agent/reference/advanced_collections.md). - Standard Query Agent [usage limits](/docs/cloud/tools/query-agent.mdx#usage-limits) apply. For a deeper walkthrough including additional screen recordings, see the [Query Agent tool docs](/docs/cloud/tools/query-agent.mdx). diff --git a/docs/weaviate/index.mdx b/docs/weaviate/index.mdx index 185bfc40e..e43048dd9 100644 --- a/docs/weaviate/index.mdx +++ b/docs/weaviate/index.mdx @@ -99,7 +99,7 @@ Weaviate is an **open-source vector database** designed to store and index both - **[Retrieval augmented generation (RAG)](./search/generative.md)** Weaviate can serve as a robust backend for RAG workflows, where vector search is used to retrieve context that enhances the output of generative models, making it easier to generate accurate, context-aware responses. -- **[Agent-driven workflows](../agents/index.md)** +- **[Agent-driven workflows](../query-agent/index.md)** Its flexible API and integration with modern AI models make Weaviate suitable for powering applications that rely on intelligent agents. These agents can leverage semantic insights to make decisions or trigger actions based on the data stored in Weaviate. import AcademyAdmonition from '@site/src/components/AcademyAdmonition'; @@ -125,7 +125,7 @@ As shown in the high-level overview above, the ecosystem consists of: - **[Weaviate Database](#what-is-weaviate)**: An open source vector database that stores both objects and vectors. - **[Weaviate Cloud](/cloud)**: A fully managed cloud deployment of the Weaviate vector database. -- **[Weaviate Agents](/agents)**: Pre-built agentic services for Weaviate Cloud users. +- **[Query Agent](/query-agent)**: A pre-built agentic search service for Weaviate Cloud users. - **[Weaviate Embeddings](/cloud/embeddings)**: A managed embedding inference service for Weaviate Cloud users. - **[External model providers](/weaviate/model-providers)**: Third-party models that integrate with Weaviate. diff --git a/docs/weaviate/quickstart/index.md b/docs/weaviate/quickstart/index.md index b1952ea1f..2c0db0fd3 100644 --- a/docs/weaviate/quickstart/index.md +++ b/docs/weaviate/quickstart/index.md @@ -280,7 +280,7 @@ Are you ready to see how deep the rabbit hole goes? 🔴🔵 #TheMatrix #WakeUp -The [Weaviate Query Agent](/agents/query/index.md) is a pre-built agentic service designed to answer natural language queries based on the data stored in Weaviate Cloud. The user simply provides a prompt/question in natural language, and the Query Agent takes care of all intervening steps to provide an answer. +The [Weaviate Query Agent](/query-agent/index.md) is a pre-built agentic service designed to answer natural language queries based on the data stored in Weaviate Cloud. The user simply provides a prompt/question in natural language, and the Query Agent takes care of all intervening steps to provide an answer. import QueryAgentQuickstart from "/\_includes/code/quickstart/quickstart.short.query-agent.mdx"; diff --git a/docs/weaviate/quickstart/local.md b/docs/weaviate/quickstart/local.md index 4680514a4..ea5cd21e1 100644 --- a/docs/weaviate/quickstart/local.md +++ b/docs/weaviate/quickstart/local.md @@ -194,9 +194,9 @@ import QueryNearVectorImportVectors from "/_includes/code/quickstart/quickstart. -:::tip Weaviate Agents +:::tip Query Agent -Try the [Query Agent](/agents/query/index.md) with a Weaviate Cloud instance. You simply provide a prompt/question in natural language, and the Query Agent takes care of all the needed steps to provide an answer. +Try the [Query Agent](/query-agent/index.md) with a Weaviate Cloud instance. You simply provide a prompt/question in natural language, and the Query Agent takes care of all the needed steps to provide an answer. ::: diff --git a/docs/weaviate/search/query-agent.md b/docs/weaviate/search/query-agent.md index 185cb2e8e..cd6046d45 100644 --- a/docs/weaviate/search/query-agent.md +++ b/docs/weaviate/search/query-agent.md @@ -8,17 +8,40 @@ image: og/docs/howto.jpg import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; -import PyCode from '!!raw-loader!/docs/agents/_includes/query_agent.py'; -import TSCode from '!!raw-loader!/docs/agents/_includes/query_agent.mts'; +import PyCode from '!!raw-loader!/docs/query-agent/_includes/code/query_agent.py'; +import TSCode from '!!raw-loader!/docs/query-agent/_includes/code/query_agent.mts'; -The Weaviate Query Agent enables users to perform Weaviate searches or ask questions about their data using natural language. +The Weaviate Query Agent enables users to perform Weaviate searches or ask questions about their data using natural language. -:::info First time using Weaviate Agents? -Weaviate Agents are only available for Weaviate Cloud instances. See the [full setup guide](../../agents/query/usage.md) for setup and instantiation details. +An agentic LLM will dynamically determine query terms and search strategies based on the natural language query. + +:::info First time using the Query Agent? +The Query Agent is only available for Weaviate Cloud instances. See the [full setup guide](../../query-agent/installation.md) for setup and instantiation details. ::: +First, you must define the Query Agent class, setup with a client pointing towards your Weaviate cloud cluster. + + + + + + + + + + ## Basic search Use `search` to retrieve relevant objects based on a natural language query: @@ -366,10 +389,10 @@ However, no shoes under $60 were found based on available information. ## Further resources -- [Query Agent full documentation](/agents/query/usage) - Complete guide with setup and advanced features +- [Query Agent full documentation](/query-agent/index.md) - Complete guide with setup and advanced features - [Connect to Weaviate Cloud](/cloud/manage-clusters/connect) - [Weaviate Cloud documentation](/cloud) -- [AI agents framework](/agents) +- [AI agents framework](/query-agent) ## Questions and feedback diff --git a/netlify.toml b/netlify.toml index 383bf5866..4aecc23e2 100644 --- a/netlify.toml +++ b/netlify.toml @@ -1154,3 +1154,75 @@ status = 301 from = "/weaviate/client-libraries/java/java-v5" to = "/weaviate/client-libraries/java" status = 301 + +# Agents rework (PR #410): Personalization and Transformation Agents removed, +# Query Agent restructured into /query-agent with guides/reference/recipes/clients. +# Specific paths first; splats below catch anything else under the removed roots. + +[[redirects]] +from = "/agents/query" +to = "/query-agent" +status = 301 + +[[redirects]] +from = "/agents/query/usage" +to = "/query-agent/guides/ask_mode" +status = 301 + +[[redirects]] +from = "/agents/query/tutorial-ecommerce" +to = "/query-agent/recipes/query-agent-ecommerce-assistant" +status = 301 + +[[redirects]] +from = "/agents/recipes/personalization-agent-get-started-movies" +to = "/query-agent/recipes" +status = 301 + +[[redirects]] +from = "/agents/recipes/personalization-agent-get-started-recipes" +to = "/query-agent/recipes" +status = 301 + +[[redirects]] +from = "/agents/recipes/transformation-agent-get-started" +to = "/query-agent/recipes" +status = 301 + +[[redirects]] +from = "/agents/recipes/transformation-agent-retrieval-benchmark" +to = "/query-agent/recipes" +status = 301 + +[[redirects]] +from = "/agents/personalization" +to = "/query-agent" +status = 301 + +[[redirects]] +from = "/agents/personalization/*" +to = "/query-agent" +status = 301 + +[[redirects]] +from = "/agents/transformation" +to = "/query-agent" +status = 301 + +[[redirects]] +from = "/agents/transformation/*" +to = "/query-agent" +status = 301 + +# /agents base renamed to /query-agent. Keep these LAST so the specific +# remaps above win; this splat catches the landing page and all other +# /agents/* pages (guides, reference, clients, recipes) 1:1. +[[redirects]] +from = "/agents" +to = "/query-agent" +status = 301 + +[[redirects]] +from = "/agents/*" +to = "/query-agent/:splat" +status = 301 diff --git a/package.json b/package.json index f8ba9acaf..e30d145a9 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "stream-chain": "^2.2.5", "stream-json": "^1.7.5", "uuid": "^13.0.0", - "weaviate-agents": "^1.4.0", + "weaviate-agents": "^1.4.1", "weaviate-client": "^3.12.1", "weaviate-ts-embedded": "^1.1.0" }, diff --git a/pytest.ini b/pytest.ini index f1769b205..3f173969d 100644 --- a/pytest.ini +++ b/pytest.ini @@ -3,7 +3,7 @@ python_files = test_*.py *_test.py norecursedirs = _* .github .idea* .pytest_cache .venv venv* blog developers downloads playbook src static markers = pyv4: groups tests by language for v4 client only (python) - agents: group tests for Weaviate Agents + agents: group tests for Query Agent engram: group tests for Weaviate Engram engram_curl: group tests for Weaviate Engram using cURL engram_python: group tests for Weaviate Engram using Python client diff --git a/secondaryNavbar.js b/secondaryNavbar.js index 8e450266a..2cffab4e0 100644 --- a/secondaryNavbar.js +++ b/secondaryNavbar.js @@ -64,28 +64,23 @@ const secondaryNavbarItems = { link: "/deploy", links: [ { label: "Get started", link: "/deploy", sidebar: "deploySidebar" }, - { label: "Configuration", link: "/deploy/configuration", sidebar: "deployConfigSidebar"}, + { label: "Configuration", link: "/deploy/configuration", sidebar: "deployConfigSidebar" }, /*{ label: "Kubernetes", link: "/deploy/k8s", sidebar: "deployK8sSidebar" },*/ - { label: "Production guides", link: "/deploy/production", sidebar: "deployProductionSidebar"}, + { label: "Production guides", link: "/deploy/production", sidebar: "deployProductionSidebar" }, /*{ label: "Scaling Strategies", link: "/deploy/scaling-strategies", sidebar: "deployScalingSidebar"},*/ /*{ label: "Monitoring and Observability", link: "/deploy/monitoring-obs", sidebar: "deployObservabilitySidebar"},*/ - { label: "FAQs", link: "/deploy/faqs", sidebar: "deployFaqsSidebar"}, - { label: "Migration", link: "/deploy/migration", sidebar: "deployMigrationSidebar"}, + { label: "FAQs", link: "/deploy/faqs", sidebar: "deployFaqsSidebar" }, + { label: "Migration", link: "/deploy/migration", sidebar: "deployMigrationSidebar" }, ] }, agents: { - title: "Weaviate Agents", + title: "Query Agent", icon: "fa fa-robot", - description: "Build and deploy intelligent agents with Weaviate", - link: "/agents", + description: "Run agentic search over your Weaviate Cloud collections", + link: "/query-agent", links: [ - { label: "Documentation", link: "/agents", sidebar: "agentsSidebar" }, - { - label: "Recipes", - link: "/agents/recipes", - sidebar: "agentsRecipesSidebar", - }, + { label: "Documentation", link: "/query-agent", sidebar: "agentsSidebar" } ], }, cloud: { diff --git a/sidebars.js b/sidebars.js index 560ce052b..15fe78558 100644 --- a/sidebars.js +++ b/sidebars.js @@ -1284,36 +1284,45 @@ const sidebars = { }, ], agentsSidebar: [ - { - type: "doc", - id: "agents/index", - }, + "query-agent/index", + "query-agent/installation", + "query-agent/quickstart", { type: "html", value: "", }, { type: "category", - label: "Query Agent", + label: "Modes", className: "sidebar-main-category", collapsible: false, collapsed: false, link: { type: "doc", - id: "agents/query/index", + id: "query-agent/guides/index", }, customProps: { - cloudOnly: true, + cloudOnly: false, }, items: [ { type: "doc", - id: "agents/query/usage", + id: "query-agent/guides/ask_mode", + className: "sidebar-item", + }, + { + type: "doc", + id: "query-agent/guides/search_mode", className: "sidebar-item", }, + // { + // type: "doc", + // id: "query-agent/guides/research_mode", + // className: "sidebar-item", + // }, { type: "doc", - id: "agents/query/tutorial-ecommerce", + id: "query-agent/guides/suggest_queries", className: "sidebar-item", }, ], @@ -1324,26 +1333,41 @@ const sidebars = { }, { type: "category", - label: "Transformation Agent", + label: "Configuration", className: "sidebar-main-category", collapsible: false, collapsed: false, link: { type: "doc", - id: "agents/transformation/index", + id: "query-agent/reference/index", }, customProps: { - cloudOnly: true, + cloudOnly: false, }, items: [ { type: "doc", - id: "agents/transformation/usage", + id: "query-agent/reference/instantiation", + className: "sidebar-item", + }, + { + type: "doc", + id: "query-agent/reference/system_prompt", className: "sidebar-item", }, { type: "doc", - id: "agents/transformation/tutorial-enrich-dataset", + id: "query-agent/reference/multi_turn_conversations", + className: "sidebar-item", + }, + { + type: "doc", + id: "query-agent/reference/additional_filters", + className: "sidebar-item", + }, + { + type: "doc", + id: "query-agent/reference/advanced_collections", className: "sidebar-item", }, ], @@ -1354,48 +1378,87 @@ const sidebars = { }, { type: "category", - label: "Personalization Agent", + label: "Clients", className: "sidebar-main-category", collapsible: false, collapsed: false, link: { type: "doc", - id: "agents/personalization/index", + id: "query-agent/clients/index", }, customProps: { - cloudOnly: true, + cloudOnly: false, }, items: [ { type: "doc", - id: "agents/personalization/usage", + id: "query-agent/clients/python", className: "sidebar-item", }, { type: "doc", - id: "agents/personalization/tutorial-recipe-recommender", + id: "query-agent/clients/typescript", className: "sidebar-item", }, ], }, - ], - agentsRecipesSidebar: [ + { + type: "html", + value: "", + }, { type: "category", - label: "Recipes", - collapsed: false, - collapsible: false, + label: "Tutorials and guides", + className: "sidebar-item", + collapsed: true, link: { type: "doc", - id: "agents/recipes", + id: "query-agent/recipes/index", + }, + customProps: { + cloudOnly: false, }, items: [ { - type: "autogenerated", - dirName: "agents/recipes", // Scans the folder docs/weaviate/recipes/ + type: "doc", + id: "query-agent/recipes/query-agent-get-started", + className: "sidebar-item", + }, + { + type: "doc", + id: "query-agent/recipes/query-agent-ecommerce-assistant", + className: "sidebar-item", + }, + { + type: "doc", + id: "query-agent/recipes/query-agent-streamlit-chat", + className: "sidebar-item", + }, + { + type: "doc", + id: "query-agent/recipes/query-agent-vs-diy", + className: "sidebar-item", + }, + { + type: "doc", + id: "query-agent/recipes/query-agent-as-a-tool", + className: "sidebar-item", }, ], }, + // { + // type: "html", + // value: "", + // }, + { + type: "doc", + id: "query-agent/reference/troubleshooting", + className: "sidebar-item", + }, + { + type: "html", + value: "", + }, ], contributorSidebar: [ { diff --git a/src/theme/DocItem/Footer/Footer.js b/src/theme/DocItem/Footer/Footer.js index 649abb794..6115a1920 100644 --- a/src/theme/DocItem/Footer/Footer.js +++ b/src/theme/DocItem/Footer/Footer.js @@ -118,7 +118,7 @@ function Footer() { Weaviate Cloud
  • - Weaviate Agents + Query Agent
  • Engram diff --git a/static/config/index.toml b/static/config/index.toml index d51961a14..2819bf859 100644 --- a/static/config/index.toml +++ b/static/config/index.toml @@ -23,28 +23,44 @@ featured = true description = "Learn how to utilize the Weaviate Embedding Service available on Weaviate Cloud for generating vector embeddings." [[recipe]] -title = "Build A Weaviate Query Agent - The E-Commerce Assistant" +title = "Get Started with the Weaviate Query Agent" notebook = "weaviate-services/agents/query-agent-get-started.ipynb" tags = ["Query Agent"] agent = true featured = true -description = "A getting-started guide to building a Weaviate Query Agent, demonstrated with an e-commerce assistant example." +description = "A high-level introduction to the Weaviate Query Agent across Ask Mode, Search Mode, and Suggest Queries." [[recipe]] -title = "Build A Weaviate Transformation Agent" -notebook = "weaviate-services/agents/transformation-agent-get-started.ipynb" -tags = ["Transformation Agent"] +title = "Build a Query Agent E-Commerce Assistant" +notebook = "weaviate-services/agents/query-agent-ecommerce-assistant.ipynb" +tags = ["Query Agent", "E-Commerce"] agent = true featured = true -description = "Learn the basics of creating and using a Weaviate Transformation Agent for data processing workflows." +description = "Wrap the Query Agent in a reusable customer-facing assistant for an e-commerce catalog." [[recipe]] -title = "Benchmarking Arctic 2.0 vs. Arctic 1.5 with Synthetic RAG Evals" -notebook = "weaviate-services/agents/transformation-agent-retrieval-benchmark.ipynb" -tags = ["Transformation Agent"] +title = "Build a Streaming Chat UI with Streamlit" +notebook = "weaviate-services/agents/query-agent-streamlit-chat.ipynb" +tags = ["Query Agent", "Streamlit", "Streaming", "UI"] agent = true featured = true -description = "Benchmarks Arctic 2.0 against Arctic 1.5 using synthetic RAG evaluations within a Weaviate Agent context." +description = "Build a Streamlit chat UI on top of the Query Agent with token-by-token streaming and multi-turn history." + +[[recipe]] +title = "Using the Query Agent as a Tool" +notebook = "weaviate-services/agents/query-agent-as-a-tool.ipynb" +tags = ["Query Agent", "Integration", "Function Calling"] +agent = true +featured = true +description = "Expose the Weaviate Query Agent as a callable tool inside your own agent framework." + +[[recipe]] +title = "Query Agent vs. Doing It Yourself" +notebook = "weaviate-services/agents/query-agent-vs-diy.ipynb" +tags = ["Query Agent", "Comparison"] +agent = true +featured = true +description = "Compare the Weaviate Query Agent against a hand-rolled retrieval and generation pipeline." [[recipe]] title = "Weaviate Query Agent with Crew AI" @@ -67,21 +83,6 @@ tags = ["Query Agent", "Integration"] integration = true description = "Illustrates how to incorporate the Weaviate Query Agent into agentic workflows built with LlamaIndex." -[[recipe]] -title = "Build a Weaviate Personalization Agent - Movie Recommender" -notebook = "weaviate-services/agents/personalization-agent-get-started-movies.ipynb" -tags = ["Personalization Agent"] -agent = true -featured = true -description = "Learn how to create a movie recommendation engine powered by an LLM and a vector database." - -[[recipe]] -title = "Build a Weaviate Personalization Agent - Food Recommender" -notebook = "weaviate-services/agents/personalization-agent-get-started-recipes.ipynb" -tags = ["Personalization Agent"] -agent = true -description = "Learn how to use the Weaviate Personalization Agent to create tailored food recommendations." - [[recipe]] title = "Generative search (RAG) with AWS Bedrock" notebook = "weaviate-features/model-providers/aws/rag_titan-text-express-v1_bedrock.ipynb" diff --git a/tests/README.md b/tests/README.md index 1317bda8f..b0847deb2 100644 --- a/tests/README.md +++ b/tests/README.md @@ -21,7 +21,7 @@ Each language runs in its own parallel job: | Job | Marker(s) | Description | | --- | --------- | ----------- | -| `test-agents` | `agents` | Weaviate Agents tests | +| `test-agents` | `agents` | Query Agent tests | | `test-python` | `(pyv4 or pyv3) and not agents` | Python client tests | | `test-typescript` | `ts and not agents` | TypeScript client tests | | `test-java` | `java` | Java client tests (with SNAPSHOT build) | @@ -83,7 +83,7 @@ Tests are organized by language, one file per language: | `test_typescript.py` | `ts` | TypeScript client tests | | `test_java.py` | `java` | Java client tests (JUnit via Maven) | | `test_csharp.py` | `csharp` | C# client tests (xUnit via dotnet) | -| `test_agents.py` | `agents` | Weaviate Agents tests | +| `test_agents.py` | `agents` | Query Agent tests | Supporting files: @@ -103,7 +103,7 @@ Tests are organized using pytest markers: | `ts` | TypeScript snippets | | `java` | Java client snippets | | `csharp` | C# client snippets | -| `agents` | Weaviate Agents snippets | +| `agents` | Query Agent snippets | | `wcd` | Tests requiring a Weaviate Cloud instance | ### Running tests by marker diff --git a/tests/test_agents.py b/tests/test_agents.py index 3675ddba0..13fe86825 100644 --- a/tests/test_agents.py +++ b/tests/test_agents.py @@ -1,3 +1,4 @@ +import os import pytest import utils from pathlib import Path @@ -8,12 +9,20 @@ @pytest.mark.parametrize( "script_loc", [ - "./docs/agents/_includes/query_agent_tutorial_ecommerce.py", - "./docs/agents/_includes/query_agent.py", - "./docs/agents/_includes/transformation_agent.py", - "./docs/agents/_includes/transformation_agent_tutorial_enrich_dataset.py", - "./docs/agents/_includes/personalization_agent.py", - "./docs/agents/_includes/personalization_agent_tutorial_food_recommender.py", + "./docs/query-agent/_includes/code/additional_filters.py", + "./docs/query-agent/_includes/code/advanced_collections.py", + "./docs/query-agent/_includes/code/ask_mode.py", + "./docs/query-agent/_includes/code/conversations.py", + "./docs/query-agent/_includes/code/instantiation.py", + "./docs/query-agent/_includes/code/introduction.py", + "./docs/query-agent/_includes/code/query_agent.py", + "./docs/query-agent/_includes/code/quickstart.py", + "./docs/query-agent/_includes/code/search_mode.py", + "./docs/query-agent/_includes/code/suggest_queries.py", + "./docs/query-agent/_includes/code/system_prompt.py", + # Recipe walkthroughs (Weaviate Cloud + Weaviate Embeddings only) + "./docs/query-agent/_includes/code/query_agent_get_started.py", + "./docs/query-agent/_includes/code/query_agent_ecommerce_assistant.py", ], ) def test_on_blank_instance_pyv4(script_loc): @@ -21,11 +30,40 @@ def test_on_blank_instance_pyv4(script_loc): utils.execute_py_script_as_module(proc_script, Path(script_loc).stem) +@pytest.mark.pyv4 +@pytest.mark.agents +@pytest.mark.skipif( + not os.environ.get("OPENAI_API_KEY"), + reason="Query-Agent-vs-DIY recipe builds a DIY OpenAI pipeline; needs OPENAI_API_KEY.", +) +@pytest.mark.parametrize( + "script_loc", + [ + "./docs/query-agent/_includes/code/query_agent_vs_diy.py", + ], +) +def test_recipes_requiring_openai_pyv4(script_loc): + proc_script = utils.load_and_prep_script(script_loc) + utils.execute_py_script_as_module(proc_script, Path(script_loc).stem) + + @pytest.mark.ts @pytest.mark.agents @pytest.mark.parametrize( "script_loc", - ["./docs/agents/_includes/query_agent.mts"], + [ + "./docs/query-agent/_includes/code/additional_filters.mts", + "./docs/query-agent/_includes/code/advanced_collections.mts", + "./docs/query-agent/_includes/code/ask_mode.mts", + "./docs/query-agent/_includes/code/conversations.mts", + "./docs/query-agent/_includes/code/instantiation.mts", + "./docs/query-agent/_includes/code/introduction.mts", + "./docs/query-agent/_includes/code/query_agent.mts", + "./docs/query-agent/_includes/code/quickstart.mts", + "./docs/query-agent/_includes/code/search_mode.mts", + "./docs/query-agent/_includes/code/suggest_queries.mts", + "./docs/query-agent/_includes/code/system_prompt.mts", + ], ) def test_ts(script_loc): temp_proc_script_loc = utils.load_and_prep_temp_file(script_loc, lang="ts") diff --git a/versions-config.json b/versions-config.json index 3afd0a68b..c711914fc 100644 --- a/versions-config.json +++ b/versions-config.json @@ -4,11 +4,12 @@ "weaviate_version": "1.37.2", "helm_version": "17.8.0", "weaviate_cli_version": "3.2.2", - "weaviate_agents_version": "1.4.0", + "agents_python_version": "1.5.0", + "agents_typescript_version": "1.4.1", "python_client_version": "4.21.0", "go_client_version": "5.7.2", "java_client_version": "6.2.0", "typescript_client_version": "3.13.0", "spark_connector_version": "1.4.0", "csharp_client_version": "1.0.0" -} +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index f2421c590..145bf53f1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2639,21 +2639,21 @@ integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== "@grpc/grpc-js@^1.14.0": - version "1.14.3" - resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.14.3.tgz#4c9b817a900ae4020ddc28515ae4b52c78cfb8da" - integrity sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA== + version "1.14.4" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.14.4.tgz#e73ff57d97802f063999545f43ebb2b1eca65d9d" + integrity sha512-k9Dj3DV/itK9D06Y8f190Qgop7/Ui+D0njFV3LHMPwPT75DpXLQohE9Wmz0QElrJnzsjB7KPWiKJbOl7IPDArQ== dependencies: "@grpc/proto-loader" "^0.8.0" "@js-sdsl/ordered-map" "^4.4.2" "@grpc/proto-loader@^0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.8.0.tgz#b6c324dd909c458a0e4aa9bfd3d69cf78a4b9bd8" - integrity sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ== + version "0.8.1" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.8.1.tgz#5a6b290ccbfb1ae2f6775afb74e9898bd8c5d4e8" + integrity sha512-wtF6h+DY6M3YaDBPAmvuuA6jV8Sif9MjtOI5euKFWRgCDl5PeDpPsHR9u2l6St5ceY8AZgoNDww5+HvEsXFsGg== dependencies: lodash.camelcase "^4.3.0" long "^5.0.0" - protobufjs "^7.5.3" + protobufjs "^7.5.5" yargs "^17.7.2" "@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0": @@ -3663,28 +3663,27 @@ resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.5.tgz#d9315ad7cf3f30aac70bda3c068443dc6f143659" integrity sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g== -"@protobufjs/eventemitter@^1.1.0": - version "1.1.0" - resolved "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz" - integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== +"@protobufjs/eventemitter@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz#d512cb26c0ae026091ee2c1167f1be6faf5c842a" + integrity sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg== -"@protobufjs/fetch@^1.1.0": - version "1.1.0" - resolved "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz" - integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== +"@protobufjs/fetch@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.1.tgz#4d6fc00c8fb64016a5c81b469d549046350f1065" + integrity sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw== dependencies: "@protobufjs/aspromise" "^1.1.1" - "@protobufjs/inquire" "^1.1.0" "@protobufjs/float@^1.0.2": version "1.0.2" resolved "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz" integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== -"@protobufjs/inquire@^1.1.0": - version "1.1.0" - resolved "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz" - integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== +"@protobufjs/inquire@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.2.tgz#ae64fbc014ff44c8bfad03dd4c93cd2d6a4c82db" + integrity sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw== "@protobufjs/inquire@^1.1.1": version "1.1.1" @@ -8626,9 +8625,9 @@ graphql-request@^6.1.0: cross-fetch "^3.1.5" graphql@^16.12.0: - version "16.13.2" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.13.2.tgz#4d2b73df5796b201f1bc2765f5d7067f689cb55f" - integrity sha512-5bJ+nf/UCpAjHM8i06fl7eLyVC9iuNAjm9qzkiu2ZGhM0VscSvS6WDPfAwkdkBuoXGM9FJSbKl6wylMwP9Ktig== + version "16.14.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.14.0.tgz#f1128a74b16a34d1245c8436bb07b488d87b83e1" + integrity sha512-BBvQ/406p+4CZbTpCbVPSxfzrZrbnuWSP1ELYgyS6B+hNeKzgrdB4JczCa5VZUBQrDa9hUngm0KnexY6pJRN5Q== gray-matter@^4.0.3: version "4.0.3" @@ -13247,23 +13246,23 @@ proto-list@~1.2.1: resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz" integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA== -protobufjs@^7.5.3: - version "7.5.6" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.5.6.tgz#11af832ebc4b4326f658a5b1308e6141eb57edfd" - integrity sha512-M71sTMB146U3u0di3yup8iM+zv8yPRNQVr1KK4tyBitl3qFvEGucq/rGDRShD2rsJhtN02RJaJ7j5X5hmy8SJg== +protobufjs@^7.5.5: + version "7.6.1" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.6.1.tgz#6320bb08c3be7dcfc6f9193ee03d3a4643f1eb37" + integrity sha512-4K0myLaWL5EteuSAro91EGFgcfVgxb64Jx+7oDAY6GOkXD4M69yuSEljNcInGVCA5sOPxmZ/EqDLj2x0Q0+Ygg== dependencies: "@protobufjs/aspromise" "^1.1.2" "@protobufjs/base64" "^1.1.2" "@protobufjs/codegen" "^2.0.5" - "@protobufjs/eventemitter" "^1.1.0" - "@protobufjs/fetch" "^1.1.0" + "@protobufjs/eventemitter" "^1.1.1" + "@protobufjs/fetch" "^1.1.1" "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.1" + "@protobufjs/inquire" "^1.1.2" "@protobufjs/path" "^1.1.2" "@protobufjs/pool" "^1.1.0" "@protobufjs/utf8" "^1.1.1" "@types/node" ">=13.7.0" - long "^5.0.0" + long "^5.3.2" proxy-addr@^2.0.7, proxy-addr@~2.0.7: version "2.0.7" @@ -15777,10 +15776,10 @@ wcwidth@^1.0.1: dependencies: defaults "^1.0.3" -weaviate-agents@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/weaviate-agents/-/weaviate-agents-1.4.0.tgz#6e74e750febb5fe104c99a662cda4e2268de1869" - integrity sha512-47X7oL5nuDG5zj4y5EcaAtwRQG7LxWbmi3TE2dPWeE+h4QwXsbJnkoh/hOab9PWjWy7EEbXS+xwsRzd5ArVV5Q== +weaviate-agents@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/weaviate-agents/-/weaviate-agents-1.4.1.tgz#9b813fc9da987bf99f6d812f5110cf3acb01efe0" + integrity sha512-YqNKp63VTdWLnQQl7JGAH0sFBp36j4TgYASK2aka0NrBAtnzwbdEh5Zg+Br/PSVgDplSleYkotE0vq0g012mBw== weaviate-client@^3.12.1: version "3.13.0" @@ -15797,15 +15796,6 @@ weaviate-client@^3.12.1: nice-grpc-common "^2.0.2" uuid "^14.0.0" -weaviate-ts-client@^1.3.3: - version "1.6.0" - resolved "https://registry.yarnpkg.com/weaviate-ts-client/-/weaviate-ts-client-1.6.0.tgz#83c516f2265dcfe6d0be30e234911a32115ba52b" - integrity sha512-1We0l8/uw6r8xnPsY8nSne1+/Ntd6o2JFq5LODqb63ac9v4QWDpT8dyPSRriUhif+IZ2Ttusw+w38361z72eaw== - dependencies: - graphql-request "^5.2.0" - isomorphic-fetch "^3.0.0" - uuid "^9.0.1" - weaviate-ts-embedded@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/weaviate-ts-embedded/-/weaviate-ts-embedded-1.2.0.tgz#08d0916cbf698e9ea12ef3ae9c6b96ab8f84a288"