Skip to main content

Build a recipe recommender with the Personalization Agent

Technical Preview

This Weaviate Agent is in technical preview. This Weaviate Agent is in technical preview.

Sign up here for notifications on Weaviate Agents, or visit this page to see the latest updates and provide feedback.

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. 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: 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.

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 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 in Weaviate Cloud.
  2. Take note of the REST Endpoint and Admin API key to connect to your cluster. (for more info, check out the quickstart)
tip

In this tutorial, we are using the Weaviate Embeddings 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.

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

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. If this occurs, additionally try to explicitly upgrade the weaviate-agents package:

pip install -U weaviate-agents

Or install a specific version:

pip install -U weaviate-agents==0.5.0

1.3 Connect to your instance

Now, you can finally connect to your Weaviate Cloud instance with the parameters from the first step:

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

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.

The Recipes dataset structure

For the collection Recipes, we will manually define the properties and include descriptions. While using 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.

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",
vectorizer_config=Configure.Vectorizer.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",
),
],
)

2.2 Populate the database

Now, we can import the recipe data (Recipes) into our Weaviate Cloud instance:

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.get("Recipes")

with recipes_collection.batch.dynamic() as batch:
for i, item in enumerate(dataset):
if i < 200:
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]}")

By calling len() on our collections, we can check that the import has successfully concluded and see what the size of our collections is:

print(f"Size of the Recipes dataset: {len(recipes_collection)}")
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.

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",
)
print("Connected to existing agent.")
else:
print("Creating new Personalization Agent for 'Recipes' collection...")
agent = PersonalizationAgent.create(
client=client,
reference_collection="Recipes",
user_properties={
"favorite_cuisines": DataType.TEXT_ARRAY,
"likes": DataType.TEXT_ARRAY,
"dislikes": DataType.TEXT_ARRAY,
},
)
print("New agent created.")

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!

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"],
},
)
)

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).

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().

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)

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.

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.")

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

Questions and feedback

Changelog and feedback

The official changelog for Weaviate Agents can be found here. If you have feedback, such as feature requests, bug reports or questions, please submit them here, where you will be able to see the status of your feedback and vote on others' feedback.

If you have any questions or feedback, let us know in the user forum.