Query Agent search
Weaviate Cloud only
The Weaviate Query Agent enables users to perform Weaviate searches or ask questions about their data using natural language.
An agentic LLM will dynamically determine query terms and search strategies based on the natural language query.
First, you must define the Query Agent class, setup with a client pointing towards your Weaviate cloud cluster.
from weaviate.agents.query import QueryAgent
# Instantiate a new agent object
qa = QueryAgent(
client=client, # Your Weaviate client object
collections=["ECommerce", "FinancialContracts", "Weather"]
)import { QueryAgent } from 'weaviate-agents';
// Instantiate a new agent object
const queryAgent = new QueryAgent(
client, // Your Weaviate client object
{
collections: ['ECommerce', 'FinancialContracts', 'Weather'],
}
);Basic search
Section titled “Basic search”Use search to retrieve relevant objects based on a natural language query:
# Perform a search using Search Mode (retrieval only, no answer generation)
search_response = qa.search("Find me some vintage shoes under $70", limit=10)
# Access the search results
for obj in search_response.search_results.objects:
print(f"Product: {obj.properties['name']} - ${obj.properties['price']}")// 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']}`)
}Example response
The response includes retrieved objects with their properties:
Product: Vintage Scholar Turtleneck - $55.0
Product: Glide Platforms - $69.0
Product: Sky Shimmer Sneaks - $69.0Ask with answer generation
Section titled “Ask with answer generation”Use ask to get a generated answer based on your data:
# Perform a query using Ask Mode (with answer generation)
response = qa.ask(
"I like vintage clothes and nice shoes. Recommend some of each below $60."
)
# Print the response
response.display()// 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();Example response
The response includes a generated answer plus supporting information:
📝 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.
For nice shoes under $60, consider the Glide Platforms by Vivid Verse.
These are high-shine pink platform sneakers with cushioned soles.
🔭 Searches Executed:
- queries=['vintage clothing'], filters=[[price < 60]], collection='ECommerce'
- queries=['nice shoes'], filters=[[price < 60]], collection='ECommerce'
📊 Usage Statistics:
- LLM Requests: 5
- Input Tokens: 288
- Output Tokens: 17
- Total Time: 7.58sPaginate search results
Section titled “Paginate search results”Search supports pagination for large result sets:
# 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=3)
# 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()// 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}`);
});
});Example response
Results are returned page by page:
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.0Multi-turn conversations
Section titled “Multi-turn conversations”Build conversational flows by passing message history:
from weaviate.agents.classes import ChatMessage
# Create a conversation with multiple turns
conversation = [
ChatMessage(role="user", content="Hi!"),
ChatMessage(role="assistant", content="Hello! How can I assist you today?"),
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?",
),
]
# Add the user's query
conversation.append(
ChatMessage(
role="user",
content="What's the average wind speed, the max wind speed, and the min wind speed",
)
)
# Get the response
response = qa.ask(conversation)
print(response.final_answer)
# Continue the conversation
conversation.append(ChatMessage(role="assistant", content=response.final_answer))
conversation.append(ChatMessage(role="user", content="and for the temperature?"))
response = qa.ask(conversation)
print(response.final_answer)// 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)Example response
The agent uses conversation history for context:
User: What's the weather like?
Assistant: The average temperature is 15°C with moderate humidity.
User: Is that good for outdoor activities?
Assistant: Yes, 15°C is comfortable for most outdoor activities.
The moderate humidity levels make it pleasant for hiking, cycling, or sports.Stream responses
Section titled “Stream responses”Stream responses to receive answers as they are generated:
from weaviate.agents.classes import ProgressMessage, StreamedTokens
for output in qa.ask_stream(
query,
# Setting this to false will skip ProgressMessages, and only stream
# the StreamedTokens / the final QueryAgentResponse
include_progress=True, # Default is True
include_final_state=True, # Default is True
):
if isinstance(output, ProgressMessage):
# The message is a human-readable string, structured info available in output.details
print(output.message)
elif isinstance(output, StreamedTokens):
# The delta is a string containing the next chunk of the final answer
print(output.delta, end="", flush=True)
else:
# This is the final response, as returned by QueryAgent.ask()
output.display()// 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();
}
}Example output
Responses are streamed as they're generated:
Searching... ⏳
Processing results... 🔍
For vintage... clothing... under $60... you might like... the Vintage...
Philosopher Midi Dress... by Echo & Stitch...
✓ CompleteOverride collections at query time
Section titled “Override collections at query time”Override the agent-configured collections for a specific query:
response = qa.ask(
"What kinds of contracts are listed? What's the most common type of contract?",
collections=["FinancialContracts"],
)
response.display()const contractResponse = await qa.ask(
"What kinds of contracts are listed? What's the most common type of contract?", {
collections: ['FinancialContracts']
});
contractResponse.display();Configure collections in detail
Section titled “Configure collections in detail”Specify additional collection options like target vectors, properties, tenants, and filters:
from weaviate.agents.classes import QueryAgentCollectionConfig
response = qa.ask(
"I like vintage clothes and nice shoes. Recommend some of each below $60.",
collections=[
# Use QueryAgentCollectionConfig class to provide further collection configuration
QueryAgentCollectionConfig(
name="ECommerce", # The name of the collection to query
target_vector=[
"name_description_brand_vector"
], # Required target vector name(s) for collections with named vectors
view_properties=[
"name",
"description",
"category",
"brand",
], # Optional list of property names the agent can view
),
QueryAgentCollectionConfig(
name="FinancialContracts", # The name of the collection to query
# Optional tenant name for collections with multi-tenancy enabled
# tenant="tenantA"
),
],
)
response.display()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();Apply user-defined filters
Section titled “Apply user-defined filters”Apply persistent filters that combine with agent-generated filters using logical AND:
from weaviate.agents.query import QueryAgent
from weaviate.agents.classes import QueryAgentCollectionConfig
from weaviate.classes.query import Filter
# Apply persistent filters that will always be combined with agent-generated filters
qa = QueryAgent(
client=client,
collections=[
QueryAgentCollectionConfig(
name="ECommerce",
# This filter ensures only items above $50 are considered
additional_filters=Filter.by_property("price").greater_than(50),
target_vector=[
"name_description_brand_vector"
], # Required target vector name(s) for collections with named vectors
),
],// 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()Example behavior
User-defined filters are always applied in addition to agent-generated filters:
# Configuration: price < 100
# User query: "red shoes"
# Actual query: (semantic search for "red shoes") AND (price < 100) AND (color = "red")Inspect response details
Section titled “Inspect response details”Access detailed information about searches performed, aggregations, and token usage:
print("\n=== Query Agent Response ===")
print(f"Original Query: {response.searches[0].query}\n")
print("🔍 Final Answer Found:")
print(f"{response.final_answer}\n")
print("🔍 Searches Executed:")
for search in response.searches:
print(f"- {search}\n")
if len(response.aggregations) > 0:
print("📊 Aggregation Results:")
for agg in response.aggregations:
print(f"- {agg}\n")
if response.missing_information:
if response.is_partial_answer:
print("⚠️ Answer is Partial - Missing Information:")
else:
print("⚠️ Missing Information:")
for missing in response.missing_information:
print(f"- {missing}")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}`);
}
}Example output
Response inspection reveals the agent's execution details:
=== 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 soft, stretchable fabric with
timeless pleated details, perfect for a Dark Academia-inspired look.
However, no shoes under $60 were found based on available information.
🔍 Searches Executed:
- query: 'vintage style clothing'
- filters: price < 60
- collection: 'ECommerce'
- query: 'nice shoes'
- filters: price < 60
- collection: 'ECommerce'
⚠️ Answer is Partial - Missing Information:
- No recommendations were provided for nice shoes under $60Further resources
Section titled “Further resources”- Query Agent full documentation - Complete guide with setup and advanced features
- Connect to Weaviate Cloud
- Weaviate Cloud documentation
Questions and feedback
Section titled “Questions and feedback”Have a question or feedback? Here's how to reach us.