Skip to main content
Weaviate Docs (migrated from docs.weaviate.io) Docs

Search documentation

Type to search this documentation.

On this pageOverview

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.

Python
from weaviate.agents.query import QueryAgent

# Instantiate a new agent object
qa = QueryAgent(
    client=client, # Your Weaviate client object
    collections=["ECommerce", "FinancialContracts", "Weather"]
)
JavaScript/TypeScript
import { QueryAgent } from 'weaviate-agents';

// Instantiate a new agent object
const queryAgent = new QueryAgent(
    client, // Your Weaviate client object
    {
        collections: ['ECommerce', 'FinancialContracts', 'Weather'],

    }
);

Use search to retrieve relevant objects based on a natural language query:

Python
# 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']}")
JavaScript/TypeScript
// 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:

Python
Product: Vintage Scholar Turtleneck - $55.0
Product: Glide Platforms - $69.0
Product: Sky Shimmer Sneaks - $69.0

Use ask to get a generated answer based on your data:

Python
# 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()
JavaScript/TypeScript
// 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:

text
📝 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.58s

Search supports pagination for large result sets:

Python
# 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()
JavaScript/TypeScript
// 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:

text
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

Build conversational flows by passing message history:

Python
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)
JavaScript/TypeScript
// 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:

text
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 to receive answers as they are generated:

Python
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()
JavaScript/TypeScript
// 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:

text
Searching... ⏳
Processing results... 🔍
For vintage... clothing... under $60... you might like... the Vintage...
Philosopher Midi Dress... by Echo & Stitch...
✓ Complete

Override the agent-configured collections for a specific query:

Python
response = qa.ask(
    "What kinds of contracts are listed? What's the most common type of contract?",
    collections=["FinancialContracts"],
)

response.display()
JavaScript/TypeScript
const contractResponse = await qa.ask(
    "What kinds of contracts are listed? What's the most common type of contract?", {
    collections: ['FinancialContracts']
});

contractResponse.display();

Specify additional collection options like target vectors, properties, tenants, and filters:

Python
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()
JavaScript/TypeScript
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 persistent filters that combine with agent-generated filters using logical AND:

Python
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
        ),
    ],
JavaScript/TypeScript
// 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:

Python
# Configuration: price < 100
# User query: "red shoes"
# Actual query: (semantic search for "red shoes") AND (price < 100) AND (color = "red")

Access detailed information about searches performed, aggregations, and token usage:

Python
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}")
JavaScript/TypeScript
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:

text
=== 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 $60

Have a question or feedback? Here's how to reach us.

Suggest an edit

Propose a replacement for this page. The site team reviews it before applying any changes.

Export
Documentation menu