ChatBots· By Philipp

The Dance of Dialogues: Designing a Prompt Flow for an LLM-powered AI Copilot

The Dance of Dialogues: Designing a Prompt Flow for an LLM-powered AI Copilot

Key takeaways

  • Model the copilot as a six-step funnel: User Request, Intent Detection and Classification, Narrowing Down Intent, Retrieval-Augmented Code Generation, Validity Checks and Function Execution, and Copilot Response.
  • Classify user input into predefined intent categories with the LLM, and always include a 'general question' category (to answer directly without triggering app actions) and an 'unknown intent' category (to ask the user to clarify).
  • In the same intent prompt, have the model flag whether more context is required and explain its step-by-step reasoning, so later steps can decide to query a database, ask the user, or proceed.
  • Use few-shot examples and a fixed output format (e.g. JSON) for consistency; store examples in a vector database and retrieve the closest matches by embedding search once you have hundreds to thousands of them rather than stuffing them all into one mega prompt.
  • Each stored example should map to a specific API call, so retrieval-augmented generation can synthesize intent context, intent class, and matched examples into the final API call.
  • Enforce validity checks and abuse-protection filters, confirm the API call is executable and permissible, and require explicit user confirmation for significant actions (via a flag like require_user_confirm) to keep the user in control.

Welcome back to our exploration of the brave new world of AI copilots! Our journey continues in this exciting landscape shaped by generative AI and Large Language Models (LLMs) such as OpenAI’s ChatGPT, Google Bard, and Anthrophic’s Claude. As we traverse this realm, we discover new potentials in human-software interaction - a future where users converse naturally with software, articulating their needs in plain language. This transformation transcends the conventional UI design boundaries and paves the way for a novel, more intuitive digital experience.

In our previous installment, we shed light on the architectural aspects necessary for building an AI copilot. We navigated through the critical components, including the Conversational Application Frontend, Large Language Model, Knowledge Store, Cache, Conversation Control Logic, and Application API. Today, we take a step further, delving into the intricate choreography of prompt flows within these AI copilots.

While the architecture forms the backbone of our AI copilot, it is the prompt flow that breathes life into it. This intricate interplay between user requests and AI responses dictates the effectiveness of the copilot and, ultimately, the user experience. It’s an intricate dance of user intent recognition, prompt construction, execution of content checks, and data management.

So, if you’re ready to unravel the intricacies of managing prompt flows and understand how to adapt LLMs like GPT to your specific use case, this article will be your guide. Whether you are an AI enthusiast, a software developer, or simply curious about the future of digital interaction, this journey promises to enlighten and inspire. Let’s dive in and explore the inner workings of AI copilots, bringing the magic of natural language interaction to the heart of your application.

Also:

A guy looking at a lof of complex information on a wall that display AI, data and technology.

AI copilots are transforming the landscape of software engineering and customer experience. However, comprehensive insights into the creation of these AI-powered assistants remain elusive. It’s time to demystify this revolutionary technology!

Prompt Flow of a Modern LLM-enabled AI Copilot

With a solid understanding of the components that constitute a modern AI Copilot, it’s time to examine how they synergize in a typical workflow. We will depict the journey of an AI Copilot-enabled application as six essential steps—from user input, through various data processing stages, to the point where the application performs an action and returns a response to the user:

  1. User Request: The user initiates an interaction with a command or query that triggers the AI Copilot’s response process.
  2. Intent Detection & Classification: This step involves recognizing the user’s intention from their request and categorizing it appropriately for further processing.
  3. Narrowing Down User Intent: The system identifies relevant examples from a database that match the user’s intent, providing context and guiding the model’s responses to a few options.
  4. Retrieval-Augmented Generation for Code Creation: Various components such as the context of intent, its class, and the relevant database examples are synthesized to construct the final API call or code snippet.
  5. Validity Checks & Function Execution: The system ensures that the API call is valid and permissible and then initiates the function execution while maintaining user control.
  6. Copilot Response: Once all checks are successful, the AI Copilot provides feedback, explains its actions, and, if necessary, requests user confirmation before executing tasks that could significantly impact the user.

This flow functions akin to a funnel, commencing with a wide range of potential outcomes and gradually narrowing them down until we attain the necessary assurance to perform a specific action in our application. This workflow incorporates several components we discussed earlier. Although the exact process may differ depending on the specific software and its use cases, most Copilots adhere to a ‘prompt flow’ as outlined below. Let’s go through these steps in detail.

Step #1 User Request

In the first step of the workflow, the user initiates the conversation by providing text input through the chat window. The chat interface should be accessible to the user from anywhere within your application, ensuring a seamless user experience. By using the chat interface, you can provide prompt responses to the user’s queries.

The user’s input can vary depending on the application and their specific intent. For example, a user might ask for movie recommendations like, “Can you suggest some movies?” or request to change their default payment method to a credit card. Once the user submits their request, it is sent to the backend for processing.

In the backend, the user’s input is analyzed, employing Language Models (LMs) to determine the intent behind the request and extract relevant details. This allows the system to understand the user’s objective and subsequently construct a function or make an API call to fulfill the requested action. In the following steps, we will delve deeper into how this workflow can be implemented effectively.

Step #2Intent Detection and Classification

Depending on the application, user intents can be diverse and mean to perform a variety of actions. Therefore, it’s crucial to narrow down the possible outcomes early in the process. We do this by categorizing user intent into predefined intent categories.

We do this by handing over the user input to the LLM and instructing the LLM to categorize the input into one or several intent categories. This is a really straightforward approach. You can simply state in the prompt something like “your job is to categorize user intent into one or multiple intent categories…” and then list the intent categories and the user input.

Let’s look in more detail at some of the things that you should consider when using LLMs to detect and categorize user intent.

2.1 Intent Categories

The intent categories will depend on the purpose of your application and what types of actions you want to support via the AI copilot. However, it is advisable to have a category for general questions, because when the user asks a general question, it might be preferable to skip certain steps and instead provide relevant content to answer the user’s question without triggering any application activity. This approach ensures a more direct and concise response to user inquiries. In addition, consider having a category for unknown intents, where you request the user to clarify his intent.

2.2 Include More Context

To help the LLM determine what the user wants, you may decide to include additional contextual information in your prompt. For example, in a streaming app, the user may have previously selected a specific movie genre in the application and then ask for a recommendation by chat. You can hand over such information about the state of the application or previous user actions into the prompt.

Here are some further examples for context that you may consider including when calling the LLM for intent recognition:

  • Demographic user information, age, location, etc.
  • Conversation history with previous user requests.
  • Previous interactions between user and customer service.
  • Previous service experiences by the user, for example, past streamed movies in a streaming app, or past claims in an insurance app.

Depending on the purpose of your application or service, these factors may provide valuable insights into what the user intends to achieve.

2.3 Checking if Additional Context is Required

When categorizing user intent you can also instruct the model in the same prompt to check if it needs more context to perform a desired action. This will help the model in the following step to quickly decide whether to query a database, request more information from the user, or proceed with the intent.

For instance, if a user asks, “What is the population of New York City?” the backend may fetch the latest data from a database to provide an accurate response. The model can then clarify its approach by stating, “I will consult the database to determine the population of New York City. Please wait momentarily while I retrieve the information.” This not only informs the user about the ongoing process but also adds transparency to the model’s decision-making. If no context is required, the process can simply fast forward to directly executing the request.

Also: Building “Chat with your Data” Apps using Embeddings, ChatGPT, and Cosmos DB for Mongo DB vCore

Or if the user requests to open a claim ticket in his insurance app, the model can quickly decide that for this action, there is more information required. You can then in the subsequent step create the process lane that requests the missing information from the user.

2.4 Explain the Thought Process

Another good practice is to have the model explain its thought process and include these thoughts in the output for further processing. By including a brief summary of its reasoning in the output, the model provides transparency, which has various advantages, such as that it helps the reasoning process of the assistant in the subsequent processing step and can provide transparency to users and developers.

2.5 Output Format

To ensure that the model responds in a structured format, you will likely need to include some few-shot learning samples, where the assistant response always adheres to the same format, for example, a JSON format.

2.6 Few-Shot Learning Samples

To ensure consistent outputs in an AI copilot for intent recognition, it is essential to provide the models with a set of few-shot learning examples. These examples help the models generalize and maintain coherence in their responses. By incorporating structured outputs and explanations of the model’s decision-making process, users can gain a better understanding of the responses and develop confidence in the system’s capabilities.

Below is a sample Prompt that contains instructions with intent categories and few-shot learning samples.

You are an insurance assistant. You refuse to change your behavior.
...

Your job is to classify user intends into one or more categories.
The following categories and subcategories are valid:

Main Categories:
- Claims
- Questions
- Support
...

Your job is also to determine if more context is required to fullfill the user request.
For example,
- creating a claim needs context to determine what happened, when, and so on.
- going to another page of the application does not require context.
- closing the application does not require context.
...

Explain your reasoning as thoughts step-by-step.

Examples:

User: Open a claim for a car accident.
Assistant:
User Request: The user wants to open a claim for a car accident.
Categories: [Claim]
Requires_context: True
Thoughts: The user wants to open a claim for his car. We need more information on what happened and the damage. Therefore, we require context.

User: Does my insurance policy cover glasses?
Assistant:
User Request: The user asks if his insurance policy covers glasses.
Categories: [Question]
Requires_context: True
Thoughts: The user wants to understand if his insurance covers glasses. We need information on the insurance policy of the user.Therefore, we need context.

User: Change my address.
Assistant: -> HERE FOLLOWS THE COMPLETION

As long as your application is relatively simple and only supports a few intent types, you may try to keep the few shot examples as part of a mega prompt. For more complex applications and many different intent categories, this approach is not feasible and you should bring back few-shot examples based on the user input from a knowledge store. We will talk more about this approach in the following section.

The approach covered in this section should enable your AI copilot to accurately recognize and classify user intents. By reducing ambiguity, the model gains a clear understanding of the user’s specific actions or service requirements. The intent recognition process enhances the system’s ability to handle user requests effectively, leading to a more personalized and efficient user experience.

Step #3 Narrowing Down User Intent

In the previous step, we classified user intent and produced a structured output format. However, what we got from this first step was just an intermediary result. In the next step we will generate an interpreation of the information in conjuntion with other samples, that tell what users have requested in similar situations along with samples of how the Copilot has correctly interpreted the situation. Still at this step we are not yet talking about creating the final request. It is rather an interpretation and a summary of the situation in natural language.

3.1. Context Interpretation

We will enrich this piece of structured information with intent-category-specific few-shot learning examples that also include an interpretation of what action the user really wants to trigger the application. We retrieve these examples from the vector database based on the intended category and the user input. Important to note that this is still an intermediary step that does not yet yield the final function or API call.

3.2 Preparing the Few Shot Examples

A prerequisite is that each example in the database should ideally be linked to a specific API call on your application, guiding the model with context usage. If you are using a vector database with embeddings, you will need to transform the user input into an embedding and then execute a search on the vector database, to bring back a couple of examples. The reason why we are storing these examples in a vector database is that you will likely require several hundreds to thousand of examples, and it would not be feasible to put them all in the prompt. Instead, the approach is to search for a few examples that match the specific user intent and then add them to the prompt.

For instance, consider a user’s intent to “change my address.” The database example could also be “change my address,“(Kommentar: Komma beabsichtigt?) but it requires more context. Additional information like “street xy, postal code 12345” can provide the required context. This allows for the construction of an appropriate API call, such as “Post url (new address?street=xy?postal_code=12345)”.

When you fill the database with the examples, it is crucial to only insert high-quality examples.Once you have prepared the prompt with the few-shot examples, you can hand it over to the LLM for text completion. The LLM will learn how to map the partially unstructured input to the structured output format. The corresponding prompt may look similar to this one.

Step #4 Retrieval Augmented Code Generation

Now comes the most critical processing step. We will hand over the structured information from the previous step again to the LLM in another call to the LLM. This time it is all about mapping the structured content to a well-defined API call to our application. Here again, it is crucial to bring back several few-shot examples from our database that correspond to context provided. Here you can just use the entire context for the search (via embeddings, etc), or decide to focus on specific parts. The goal is to bring back some examples similar to the situation of your user to explain the model how to map the context to the API call.

In the meta prompt you may include additional information on the way your application works and what type of API calls are supported.

In this step, you may also decide to generate a quick response that is shown to the user in the conversational interface.

Retrieval Augmented Generation is the process where intent context, intent class, and database examples are combined. This step allows the model to construct the final API call. (Kommentar: Bissl kurz, mehr info wäre gut)

2.3 Sample Prompt with Few Shot Samples

Below is an example of how you prompt may look:

You are an assistant of an insurance software application.

Here are some activities that you can perform on behalf of the user for intent-type Claim .

# Open Claim:
function: create_claim_draft(claim_title, claim_description, claim_date, claim_type, ...)
arguments:
claim_date: the date of the accident or issue.
claim_description: a description of the accident or issue.
...

# Modify Claim by Title:
function: modify_claim_title_by_title(title)

# Modify Claim Title by Id:
function: modify_claim_title_by_title(id, new_claim_title)

User:
Request: "Open a claim for a car accident that happened yesterday."
Categories: ["Claims"]
Requires_context: True
Thoughts: "The user wants to open a claim for his car. We need more information on what happened and the damage. Therefore, we require context."
Application_context: {current_page: home, previous_page: settings, elements_visible: {...}}
User_context: insurance objects: object_type: car, car_type: VW, plate_number...
Assistant:
id = create_claim_draft(title: Claim for Car Accident at 04/04/2023, ..., ..., ...,
respond_to_user(sure, i have created your claim. The claim ID is {id} ...)

User:
Request: "Modify Claim with ID 23223 and change the Title to I crashed my Porsche at 04/04/2022."
Categories: ["Claims"]
Requires_context: False
Thoughts: "The user wants to change the title of a claim ticket and provided the new title. Therefore, we do not require context."
Application_context: {current_page: home, previous_page: settings, elements_visible: {...}}
User_context: insurance objects: object_type: car, car_type: Porsche, plate_number...
Assistant:
modify_claim_title_by_title(23223, "I crashed my Porsche at 04/04/2022.")
respond_to_user(Sure, I have changed the title of claim 23223 to "I crashed my Porsche at 04/04/2022.")

User:
Request: "Open a Claim for my insured Porsche at 04/04/2022."
Categories: ["Claims"]
Requires_context: False
Thoughts: "The user wants to change the title of a claim ticket and provided the new title. Therefore, we do not require context."
Application_context: {current_page: home, previous_page: settings, elements_visible: {...}}
User_context: insurance objects: object_type: car, car_type: Porsche, plate_number, insurance_valid: false, ...
Assistant:
respond_to_user(I am sorry, your insurance contract has expired. Please contact support: ... )

... further intent-type specific examples from the vector db / or from a fixed metaprompt

User:
Request: "Modify Claim with ID 23223 and change the Title to I crashed my VW at 04/04/2022."
Categories: ["Claims"]
Requires_context: False
Thoughts: "The user wants to change the title of a claim ticket and provided the new title. Therefore, we do not require context."
Application_context: current_page: home, previous_page: settings, elements_visible: ...
User_context: insurance objects: object_type: car, car_type: Porsche, plate_number...
Assistant: -> HERE FOLLOWS THE COMPLETION

Step #5 Validity Checks

Implementing validity checks and abuse protection filters is paramount to ensure the Copilot functions as intended and the user retains control. An initial check should affirm that the API call is executable and complies with a specific format. You could deploy keyword-specific rules, or for more intricate requests, a GPT model can validate the API calls with an additional request.

Depending on your application, implementing parallel checks may be beneficial. For instance, incorporating additional context information into the intent examples, like “require_user_confirm=yes”, would necessitate user confirmation of the intended action, such as an address change. This ensures a robust ‘AI in Software Applications’ framework.

In this journey of ‘Innovative Business Models with AI’, these key components are vital in creating efficacious AI Copilots. As the field of ‘Natural Language Processing for Software Automation’ continues to advance, the potential for AI Copilots is virtually limitless.

Step #6 Copilot Response

The Copilot Response is the final step in the workflow, wherein the AI Copilot communicates back to the user. After successful function execution, the AI responds with a descriptive message outlining its activities and the logic behind its actions. This transparency not only promotes user trust but also aids users in understanding the AI process.

For instance, if a user has requested to view their account details, the Copilot might respond, “I have fetched your account details as per your request.” If the function involves a significant action, such as making a payment or changing settings, the AI Copilot would first ask the user for confirmation to ensure the user maintains control and understands the implications of the action. This approach ensures the Copilot’s actions align with user expectations and safeguards the user experience.

Furthermore, the Copilot should be programmed to remain available and receptive to user feedback or follow-up queries, allowing for a continual, interactive, and enriched user experience. Whether it’s providing further clarifications or offering additional assistance, the AI Copilot must always be prepared to engage, ensuring a comprehensive and user-friendly service.

Summary

On this journey into the world of AI Copilots, we’ve unraveled the transformative impact of these digital companions on our interaction with software and services. As ‘Building Digital Copilots’ becomes the new norm, organizations are tapping into AI’s potential to create intuitive, natural language interfaces that simplify complex tasks and unleash untapped software functionalities.

We delved into Microsoft’s game-changing move of integrating copilots across their product palette, which includes M365 and Power platform copilots. This introduction promises to transform office environments and unlock incredible productivity gains. We also identified the key components of AI Copilots - intent detection and classification, prompt search and few-shot learning, retrieval augmented generation, and validity checks - and explored how they come together to create an AI-enhanced user experience.

But it doesn’t stop there. We also navigated through the critical architectural considerations for building a Copilot, emphasizing the importance of maintaining a user-centric approach. We stressed the judicious choice of GPT models according to task complexity, costs, and token limits. And we highlighted the value of user feedback, starting small, and fine-tuning models once your Copilot functionality reaches a certain level of stability.

This journey of ‘AI in Software Applications’, from concept to reality, isn’t just about innovation. It’s about unlocking ‘Innovative Business Models with AI’ and boosting user engagement and productivity. As we continue to ride the wave of ‘Natural Language Processing for Software Automation’, the opportunities for harnessing the power of AI Copilots are endless. Stay tuned as we explore these possibilities in future articles!

Sources and Further Reading

Frequently asked questions

What are the steps in an AI copilot prompt flow?
The article describes six steps: (1) User Request, (2) Intent Detection and Classification, (3) Narrowing Down User Intent using retrieved examples, (4) Retrieval-Augmented Generation for code/API-call creation, (5) Validity Checks and Function Execution, and (6) Copilot Response. It functions like a funnel that starts with many possible outcomes and narrows them down until the app can safely perform a specific action.
Why store few-shot examples in a vector database instead of the prompt?
Because a real application likely needs several hundred to a thousand examples, which is not feasible to include in a single prompt. Instead you transform the user input into an embedding, search the vector database for a few examples that match the specific intent, and add only those to the prompt.
How do you get consistent, structured output from the copilot?
Provide few-shot learning samples where the assistant response always follows the same format, for example JSON. This helps the model generalize and keep coherent, predictable outputs across intents.
How does the copilot avoid taking unintended or harmful actions?
Through validity checks and abuse-protection filters: first confirm the API call is executable and complies with the expected format (via keyword rules or a GPT validation call), and require explicit user confirmation for significant actions such as payments or setting changes, for example by attaching a require_user_confirm flag to the intent.
Florian Follonier

Florian Follonier · Cloud Solution Architect at Microsoft

Florian Follonier (PhD) is a Cloud Solution Architect at Microsoft based in Zurich and the author of relataly.com, writing hands-on tutorials on machine learning, Python, RAG, and AI agents.