# Generating Multi-Faceted Queries

> Build a system that generates multi-faceted queries to capture the full intent of a user's request.

<a target="_blank" href="https://colab.research.google.com/github/cohere-ai/cohere-developer-experience/blob/main/notebooks/guides/agentic-rag/agentic_rag_pt4_multi_faceted_queries.ipynb">
  Open in Colab
</a>

Consider a RAG system that needs to search through a large database of code examples and tutorials. A user might ask for "Python examples using the chat endpoint" or "JavaScript tutorials for text summarization".

In a basic RAG setup, these queries would be passed as-is to a search function, potentially missing important context or failing to leverage the structured nature of the data. For example, the code examples database might consist of metadata such as the programming language, the created time, the tech stack used, and so on.

It would be great if we could design a system that could leverage this metadata as a filter to retrieve only the relevant results.

We can achieve this using a tool use approach. Here, we can build a system that generates multi-faceted queries to capture the full intent of a user's request. This allows for more precise and relevant results by utilizing the semi-structured nature of the data.

Here are some examples of how this approach can be applied:

1. E-commerce product searches: Filtering by price range, category, brand, customer ratings, and availability.
2. Academic research databases: Narrowing results by publication year, field of study, citation count, and peer-review status.
3. Job search platforms: Refining job listings by location, experience level, salary range, and required skills.

In this tutorial, we'll cover:

* Defining the function for data querying
* Creating the tool for generating multi-faceted queries
* Building an agent for performing multi-faceted queries
* Running the agent

We'll build an agent that helps developers find relevant code examples and tutorials for using Cohere.

## Setup

To get started, first we need to install the `cohere` library and create a Cohere client.

```python PYTHON
! pip install cohere -qq
```

```python PYTHON
import json
import os
import cohere

co = cohere.ClientV2(
    "COHERE_API_KEY"
)  # Get your free API key: https://dashboard.cohere.com/api-keys
```

## Defining the function for data querying

We'll remove the other tools from Part 1 and just use one – `search_code_examples`.

Now, instead of just the `query` parameter, we'll add two more parameters: `programming_language` and `endpoints`:

* `programming_language`: The programming language of the code example or tutorial.
* `endpoints`: The Cohere endpoints used in the code example or tutorial.

We'll use these parameters as the metadata to filter the code examples and tutorials.

Let's rename the function to `search_code_examples_detailed` to reflect this change.

And as in Part 1, for simplicity, we create `query` as just a mock parameter and no actual search logic will be performed based on it.

**IMPORTANT:**

The source code for tool definitions can be [found here](https://github.com/cohere-ai/cohere-developer-experience/blob/main/notebooks/guides/agentic-rag/tool_def.py). Make sure to have the `tool_def.py` file in the same directory as this notebook for the imports to work correctly.

```python PYTHON
from tool_def import (
    search_code_examples_detailed,
    search_code_examples_detailed_tool,
)
```

```python PYTHON
functions_map = {
    "search_code_examples_detailed": search_code_examples_detailed,
}
```

## Creating the tool for generating multi-faceted queries

With the `search_code_examples` modified, we now need to modify the tool definition as well. Here, we are adding the two new properties to the tool definition:

* `programming_language`: This is a string property which we provide a list of options for the model to choose from. We do this by adding "Possible enum values" to the description, which in our case is `py, js`.
* `endpoints`: We want the model to be able to choose from more than one endpoint, and so here we define an array property. When defining an array property, we need to specify the type of the items in the array using the `items` key, which in our case is `string`. We also provide a list of endpoint options for the model to choose from, which is `chat, embed, rerank, classify`.

We make only the `query` parameter required, while the other two parameters are optional.

```python PYTHON
tools = [search_code_examples_detailed_tool]
```

## Building an agent for performing multi-faceted queries

Next, let's create a `run_agent` function to run the agentic RAG workflow, the same as in Part 1.

The only change we are making here is to make the system message simpler and more specific since the agent now only has one tool.

```python PYTHON
system_message = """## Task and Context
You are an assistant who helps developers find code examples and tutorials on using Cohere."""
```

```python PYTHON
model = "command-a-03-2025"


def run_agent(query, messages=None):
    if messages is None:
        messages = []

    if "system" not in {m.get("role") for m in messages}:
        messages.append({"role": "system", "content": system_message})

    # Step 1: get user message
    print(f"QUESTION:\n{query}")
    print("=" * 50)

    messages.append({"role": "user", "content": query})

    # Step 2: Generate tool calls (if any)
    response = co.chat(
        model=model, messages=messages, tools=tools, temperature=0.3
    )

    while response.message.tool_calls:

        print("TOOL PLAN:")
        print(response.message.tool_plan, "\n")
        print("TOOL CALLS:")
        for tc in response.message.tool_calls:
            print(
                f"Tool name: {tc.function.name} | Parameters: {tc.function.arguments}"
            )
        print("=" * 50)

        messages.append(response.message)

        # Step 3: Get tool results
        for tc in response.message.tool_calls:
            tool_result = functions_map[tc.function.name](
                **json.loads(tc.function.arguments)
            )
            tool_content = []
            for data in tool_result:
                tool_content.append(
                    {
                        "type": "document",
                        "document": {"data": json.dumps(data)},
                    }
                )
                # Optional: add an "id" field in the "document" object, otherwise IDs are auto-generated
            messages.append(
                {
                    "role": "tool",
                    "tool_call_id": tc.id,
                    "content": tool_content,
                }
            )

        # Step 4: Generate response and citations
        response = co.chat(
            model=model,
            messages=messages,
            tools=tools,
            temperature=0.3,
        )

    messages.append(
        {
            "role": "assistant",
            "content": response.message.content[0].text,
        }
    )

    # Print final response
    print("RESPONSE:")
    print(response.message.content[0].text)
    print("=" * 50)

    # Print citations (if any)
    verbose_source = (
        False  # Change to True to display the contents of a source
    )
    if response.message.citations:
        print("CITATIONS:\n")
        for citation in response.message.citations:
            print(
                f"Start: {citation.start}| End:{citation.end}| Text:'{citation.text}' "
            )
            print("Sources:")
            for idx, source in enumerate(citation.sources):
                print(f"{idx+1}. {source.id}")
                if verbose_source:
                    print(f"{source.tool_output}")
            print("\n")

    return messages
```

## Running the agent

Let's start with a broad query about "RAG code examples".

Since it's broad, this query shouldn't require any metadata filtering.

And this is shown by the agent's response, which provides only one parameter, `query`, in its tool call.

```python PYTHON
messages = run_agent("Do you have any RAG code examples")