Writing Actions in PolyAI: A Comprehensive Step-by-Step Guide
Hey there, aspiring conversational AI designer! Ever wondered how those incredibly smart chatbots anticipate your every need and respond so accurately? A huge part of that magic lies in something called "actions." If you're looking to build powerful and engaging conversational experiences with PolyAI, then understanding how to write effective actions is absolutely crucial.
Ready to dive in and unlock the full potential of your PolyAI bot? Let's get started!
Step 1: Understanding the Core Concept of Actions in PolyAI
Before we even touch a line of code or a configuration file, let's establish what an action truly is within the PolyAI ecosystem. Think of an action as a specific task or behavior that your bot can perform in response to a user's input or a particular state of the conversation.
It's not just about what the bot says, but what the bot does. This could involve:
- Responding with a specific message: The most common use, like "Hello!" or "What can I help you with today?" 
- Querying an external API: Fetching information from a database, a weather service, or an e-commerce platform. 
- Updating internal state variables: Remembering user preferences, tracking progress in a multi-step process, or setting flags. 
- Handing off to a human agent: When the bot can't resolve an issue, it might route the user to a live support representative. 
- Triggering a follow-up question: Guiding the user through a decision-making process. 
In PolyAI, actions are often defined within your conversation flow (typically in YAML files) and are triggered based on the recognized intent of the user, the current context of the conversation, and various conditions you define.
| How To Write Actions In Poly Ai | 
Step 2: Setting Up Your PolyAI Development Environment
To start writing actions, you'll need access to your PolyAI project. This typically involves:
- Access to the PolyAI Platform: This is where you'll manage your models, datasets, and deploy your bot. 
- Your Project Repository: Your bot's configuration, including actions, will be stored in a version-controlled repository (often Git). You'll need to clone this to your local machine. 
Sub-Step 2.1: Cloning Your Project
If you haven't already, open your terminal or command prompt and clone your PolyAI project repository:
git clone <your-polyai-project-url>
cd <your-polyai-project-directory>
Sub-Step 2.2: Familiarizing Yourself with the Project Structure
Within your project directory, you'll find various files and folders. Key areas relevant to actions include:
- models/: Contains your NLU models.
- dialogue/: This is often where your conversation flows and action definitions reside. Look for files like- dialogue.yamlor specific domain-based YAML files.
- actions/: Sometimes, custom action logic (especially for external API calls) might be defined in Python files within an- actionsdirectory.
Step 3: Defining Simple Text-Based Actions
Let's start with the most basic form of an action: a simple text response. These are typically defined directly within your dialogue flow.
Sub-Step 3.1: Locating Your Dialogue File
Navigate to the dialogue/ folder and open the relevant YAML file (e.g., dialogue.yaml).
Sub-Step 3.2: Writing a Basic Action
Imagine you have an intent called greet (when the user says "hello," "hi," etc.). You'd want your bot to respond appropriately. Here's how you might define an action for it:
intents:
  - greet
  
  responses:
    utter_greet:
        - text: "Hello! How can I help you today?"
            - text: "Hi there! What can I do for you?"
            In this example:
QuickTip: Let each idea sink in before moving on.
- utter_greetis the name of our action. It's a convention to prefix response actions with- utter_.
- Under - utter_greet, we define a list of possible responses. The bot will randomly select one to provide variety.
Sub-Step 3.3: Triggering the Action in a Rule or Story
Now, how does this utter_greet action get triggered? Through rules or stories in your dialogue flow.
Using Rules (for simple, direct responses):
rules:
              - rule: Say hello
                  steps:
                        - intent: greet
                              - action: utter_greet
                              This rule states: "If the user expresses the greet intent, then execute the utter_greet action."
Using Stories (for more complex, multi-turn conversations):
stories:
                                - story: User asks for greeting then help
                                    steps:
                                          - user: "Hi"
                                                  intent: greet
                                                        - bot: utter_greet
                                                              - user: "I need help with my account."
                                                                      intent: account_help
                                                                            - bot: utter_account_help
                                                                            Here, bot: utter_greet directly references the action name defined in your responses section.
Step 4: Implementing Actions with Slots and Context
Actions become truly powerful when they can utilize information gathered during the conversation. This information is stored in "slots."
Sub-Step 4.1: Defining Slots
First, you need to define the slots in your domain.yml or a similar configuration file. For example, let's say you want to ask for the user's name:
slots:
                                                                              user_name:
                                                                                  type: text
                                                                                      influence_conversation: false # Does not directly influence dialogue flow, just stores information
                                                                                      Sub-Step 4.2: Capturing Slot Values
You can capture slot values through entities recognized by your NLU model or by asking direct questions.
Example: Capturing Name from Entity
nlu:
                                                                                        - intent: provide_name
                                                                                            examples: |
                                                                                                  - My name is [John Doe](user_name)
                                                                                                        - Call me [Alice](user_name)
                                                                                                        Example: Asking for Name and Storing It
rules:
                                                                                                          - rule: Ask for name if not provided
                                                                                                              condition:
                                                                                                                    - active_loop: null
                                                                                                                          - slot_was_set:
                                                                                                                                    user_name: null
                                                                                                                                        steps:
                                                                                                                                              - intent: ask_name # User asks "What's your name?"
                                                                                                                                                    - action: utter_ask_name
                                                                                                                                                          - user: "[My name is Bob](user_name)" # User provides name
                                                                                                                                                                  intent: inform_name
                                                                                                                                                                        - action: action_set_name # A custom action to set the slot
                                                                                                                                                                        Sub-Step 4.3: Using Slots in Actions
Now, let's make our utter_greet action personalized:
responses:
                                                                                                                                                                          utter_greet_personalized:
                                                                                                                                                                              - text: "Hello {user_name}, how can I help you today?"
                                                                                                                                                                                  - text: "Hi there, {user_name}! What can I do for you?"
                                                                                                                                                                                  Notice the {user_name}. PolyAI automatically replaces this with the value of the user_name slot if it's set.
Step 5: Developing Custom Actions for Complex Logic
For anything beyond simple text responses or slot filling, you'll need custom actions. These are typically written in Python and allow you to interact with external systems, perform calculations, or implement intricate decision-making.
Reminder: Reading twice often makes things clearer.
Sub-Step 5.1: Creating a Custom Action File
Inside your project, you'll typically have an actions/ directory. Create a Python file (e.g., actions.py) within it.
# actions.py
                                                                                                                                                                                  
                                                                                                                                                                                  from polyai.actions import Action
                                                                                                                                                                                  from polyai.events import SlotSet
                                                                                                                                                                                  
                                                                                                                                                                                  class ActionSetUserName(Action):
                                                                                                                                                                                      def name(self):
                                                                                                                                                                                              return "action_set_user_name"
                                                                                                                                                                                              
                                                                                                                                                                                                  def run(self, dispatcher, tracker, domain):
                                                                                                                                                                                                          user_name = tracker.get_slot("user_name")
                                                                                                                                                                                                                  if user_name:
                                                                                                                                                                                                                              dispatcher.utter_message(f"Nice to meet you, {user_name}!")
                                                                                                                                                                                                                                      else:
                                                                                                                                                                                                                                                  dispatcher.utter_message("I didn't quite catch your name.")
                                                                                                                                                                                                                                                          return [] # No events to return for this simple example
                                                                                                                                                                                                                                                          Let's break this down:
- from polyai.actions import Action: Imports the base- Actionclass.
- from polyai.events import SlotSet: Used if your action needs to modify slots.
- class ActionSetUserName(Action):: Defines your custom action class.
- def name(self):: Crucially, this method returns the unique name of your action (e.g.,- action_set_user_name). This is the name you'll use in your dialogue flow.
- def run(self, dispatcher, tracker, domain):: The core logic of your action.- dispatcher: Used to send messages back to the user (- dispatcher.utter_message).
- tracker: Provides access to the current state of the conversation, including slot values (- tracker.get_slot).
- domain: Provides access to the bot's domain configuration.
 
- return []: Actions can return a list of events (e.g.,- SlotSet,- FollowupAction). For simple actions, an empty list is fine.
Sub-Step 5.2: Registering Your Custom Action
You need to tell PolyAI about your custom action. This is done in your domain.yml file under the actions section:
actions:
                                                                                                                                                                                                                                                            - action_set_user_name
                                                                                                                                                                                                                                                            Sub-Step 5.3: Triggering Your Custom Action
Now you can use action_set_user_name just like any other action in your rules or stories:
rules:
                                                                                                                                                                                                                                                              - rule: User provides name
                                                                                                                                                                                                                                                                  steps:
                                                                                                                                                                                                                                                                        - intent: inform_name
                                                                                                                                                                                                                                                                              - action: action_set_user_name
                                                                                                                                                                                                                                                                              Step 6: Actions for API Calls and External Integrations
This is where custom actions truly shine. You can integrate your bot with virtually any external system.
Sub-Step 6.1: Setting up Your API Client (in actions.py)
You'll need to import libraries for making HTTP requests (e.g., requests).
# actions.py
                                                                                                                                                                                                                                                                              import requests
                                                                                                                                                                                                                                                                              from polyai.actions import Action
                                                                                                                                                                                                                                                                              from polyai.events import SlotSet
                                                                                                                                                                                                                                                                              
                                                                                                                                                                                                                                                                              class ActionGetWeather(Action):
                                                                                                                                                                                                                                                                                  def name(self):
                                                                                                                                                                                                                                                                                          return "action_get_weather"
                                                                                                                                                                                                                                                                                          
                                                                                                                                                                                                                                                                                              def run(self, dispatcher, tracker, domain):
                                                                                                                                                                                                                                                                                                      city = tracker.get_slot("city") # Assume 'city' slot is filled
                                                                                                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                                                              if not city:
                                                                                                                                                                                                                                                                                                                          dispatcher.utter_message("Which city would you like the weather for?")
                                                                                                                                                                                                                                                                                                                                      return [] # No events, waiting for city input
                                                                                                                                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                                                                                              try:
                                                                                                                                                                                                                                                                                                                                                          api_key = "YOUR_OPENWEATHERMAP_API_KEY" # Replace with your actual API key
                                                                                                                                                                                                                                                                                                                                                                      url = f"http://api.openweathermap.org/data/2.5/weather?q={city}&appid={api_key}&units=metric"
                                                                                                                                                                                                                                                                                                                                                                                  response = requests.get(url)
                                                                                                                                                                                                                                                                                                                                                                                              data = response.json()
                                                                                                                                                                                                                                                                                                                                                                                              
                                                                                                                                                                                                                                                                                                                                                                                                          if response.status_code == 200:
                                                                                                                                                                                                                                                                                                                                                                                                                          temperature = data["main"]["temp"]
                                                                                                                                                                                                                                                                                                                                                                                                                                          description = data["weather"][0]["description"]
                                                                                                                                                                                                                                                                                                                                                                                                                                                          dispatcher.utter_message(f"The current temperature in {city} is {temperature}°C with {description}.")
                                                                                                                                                                                                                                                                                                                                                                                                                                                                      else:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      dispatcher.utter_message(f"Sorry, I couldn't get the weather for {city}. Please try again later.")
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              except Exception as e:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          dispatcher.utter_message("There was an error fetching the weather. Please try again.")
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      print(f"Error fetching weather: {e}")
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              return []
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              Sub-Step 6.2: Updating Your Domain and NLU
You'd need an intent for asking about weather and an entity for capturing the city.
intents:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                - ask_weather
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                entities:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  - city
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  slots:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    city:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        type: text
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        responses:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          utter_ask_city:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              - text: "Which city would you like the weather for?"
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              nlu:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                - intent: ask_weather
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    examples: |
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          - What's the weather like in [London](city)?
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                - Weather in [New York](city)
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      - Tell me about the weather
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      Sub-Step 6.3: Defining the Rule to Trigger the Action
rules:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        - rule: Get weather
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            steps:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  - intent: ask_weather
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        - action: action_get_weather
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        This rule will trigger action_get_weather. If the city slot is already filled from the user's initial query (e.g., "weather in London"), the action will proceed immediately. If not, the action_get_weather itself can prompt the user for the city, as shown in the Python code.
Step 7: Managing Action Fallback and Error Handling
It's crucial to gracefully handle situations where your bot doesn't understand the user or encounters errors during action execution.
Sub-Step 7.1: Implementing a Fallback Action
Tip: Read aloud to improve understanding.
PolyAI provides a default fallback mechanism, but you can customize it.
responses:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          utter_unclear:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              - text: "I'm sorry, I didn't understand that. Could you rephrase?"
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  - text: "I'm not sure what you mean. Can you tell me more?"
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  rules:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    - rule: Respond to unclear intent
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        steps:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              - intent: nlu_fallback # Triggered when NLU confidence is low
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    - action: utter_unclear
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    Sub-Step 7.2: Error Handling within Custom Actions
As shown in the ActionGetWeather example, always include try-except blocks around external API calls or other potentially error-prone code. Provide user-friendly error messages.
Step 8: Best Practices for Writing Effective Actions
- Clear Naming Conventions: Use descriptive names for your actions (e.g., - utter_greet,- action_book_appointment).
- Modularity: Break down complex actions into smaller, reusable components, especially in your Python custom actions. 
- Idempotency: Design actions so that executing them multiple times with the same input doesn't have unintended side effects. This is particularly important for actions that modify external systems. 
- Testing: Thoroughly test your actions in various scenarios, including edge cases and error conditions. 
- Logging: Implement robust logging within your custom actions to aid in debugging and monitoring. 
- Asynchronous Operations: For long-running tasks, consider using asynchronous programming to avoid blocking the bot's response. 
- User Feedback: Provide clear feedback to the user about the status of an action (e.g., "Searching for flights...", "Your order has been placed."). 
- Security: If your actions handle sensitive data or interact with secure APIs, ensure proper authentication and authorization. Never hardcode sensitive credentials directly in your code. Use environment variables or a secure configuration management system. 
Step 9: Testing and Iterating
Building a great conversational AI is an iterative process.
Sub-Step 9.1: Running Your Bot Locally
You can test your bot and actions locally using the PolyAI CLI.
polyai run
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    This will typically start a server where you can interact with your bot through a command line interface or a web interface.
Sub-Step 9.2: Using the PolyAI Platform for Testing and Monitoring
The PolyAI platform provides excellent tools for:
- Interactive Testing: Directly converse with your bot. 
- Debugging: View the conversation flow, recognized intents, and triggered actions. 
- Training & Evaluation: Improve your NLU models and track bot performance. 
Sub-Step 9.3: Iterative Refinement
Based on your testing, you'll constantly refine your:
- NLU: Add more training examples for intents and entities. 
- Dialogue Flow: Adjust rules and stories to handle various conversational paths. 
- Actions: Improve the logic, error handling, and responses of your actions. 
Congratulations! You've now got a solid foundation for writing powerful and effective actions in PolyAI. Keep experimenting, keep learning, and watch your conversational AI capabilities soar!
Frequently Asked Questions about Writing Actions in PolyAI
How to define a simple text response action in PolyAI?
You define simple text responses in your responses section of a YAML file (e.g., dialogue.yaml) by giving the action a name (e.g., utter_greet) and listing the text messages it can say.
QuickTip: Revisit key lines for better recall.
How to trigger an action in a PolyAI conversation?
Actions are typically triggered by rules or stories in your dialogue flow. Rules are for direct, intent-driven responses, while stories define multi-turn conversational paths.
How to use slot values within PolyAI actions?
You can access slot values within custom actions using tracker.get_slot("slot_name"). For text responses, you can directly embed slot values using curly braces: {slot_name}.
How to create a custom action in PolyAI for complex logic?
Custom actions are Python classes that inherit from polyai.actions.Action. You define a name() method and implement your logic within the run() method, using dispatcher to send messages and tracker to access conversation state.
How to integrate external APIs with PolyAI actions?
Use custom actions (Python) to make HTTP requests to external APIs (e.g., using the requests library). Process the API response and formulate appropriate bot replies using dispatcher.utter_message.
How to handle errors in PolyAI custom actions?
Always wrap external API calls and other potentially problematic code within try-except blocks in your custom actions. Provide user-friendly fallback messages using dispatcher.utter_message.
How to pass parameters to a custom action in PolyAI?
Parameters are typically passed to custom actions implicitly through slot values. The action retrieves the necessary information from the tracker object.
How to ensure a PolyAI action responds with different messages each time?
For utter_ actions in your YAML responses, provide a list of multiple text messages. PolyAI will randomly select one from the list for variety.
How to define actions that update slot values in PolyAI?
Within a custom action, you can return SlotSet events (e.g., return [SlotSet("slot_name", "new_value")]) to programmatically update slot values.
How to test PolyAI actions during development?
You can run your PolyAI bot locally using polyai run and interact with it through the command line. The PolyAI platform also offers interactive testing and debugging tools.