在Rasa框架中如何编辑和确认表单槽位?

huangapple go评论56阅读模式
英文:

How to edit and confirm form slots in Rasa framework?

问题

I'm building a booking bot using Python and Rasa. I want to add a confirmation step when the user fills in all slots in my form. The requirements are:

  1. User may confirm the values.
  2. User may change the values.
  3. Bot must be expandable to handling other inputs and intents from the user.

I drew a flow-diagram which demonstrates more clearly the logic I want to implement:
flow-diagram

I have 2 questions:

  1. How do you usually implement the confirmation step?
  2. How would you implement the logic on the picture?

I'm using Rasa v3.5.13 and Rasa SDK v3.5.1.

I already tried the following:

  1. Confirmation within the form: I added an additional slot confirmation to the form, implemented extraction and validation to handle user input, but I couldn't make Rasa call custom actions before or after book_form is called. Inheriting from FormAction appeared to be impossible because it doesn't inherit Action from interfaces.py. Rules conflict with action_listen that is invoked right after book_form. Making a wrapper action around book_form and calling it instead of the original form works only in the first time, but then the active loop starts to call book_form instead of my wrapper.

  2. Confirmation after the form: passing a custom action in active_loop after book_form is filled in seems to work, but I found out that Rasa only calls the last FollowupAction returned by my custom action, but I want to call multiple actions on each iteration. I also tried to create a custom action that only sets the categorical slot confirmation_status with values: "initialized," "confirmed," "rejected," or "fixed." The idea was that stories can handle my logic relying on confirmation_status, but they do it poorly or don't do it at all. Two stories were not enough even to just activate action_extract_confirmation_status after active_loop was set to null, let alone handling all the logic.

So far, the second option seems to be okay if using rules instead of stories. But I need a lot of rules, and they may become a bottleneck in further development. Coding my logic in Python seems much more robust and easier to me, but I can't find a way to do this normally in Rasa.

UPD:

Tried out another approach:

  - rule: Activate confirmation loop
    steps:
      - action: book_form
      - slot_was_set:
          - requested_slot: null
      - active_loop: null
      - action: action_extract_confirmation_status
      - active_loop: action_extract_confirmation_status
    wait_for_user_input: false

  - rule: Ask for confirmation the first time
    condition:
      - active_loop: action_extract_confirmation_status
    steps:
      - action: action_extract_confirmation_status
      - slot_was_set:
          - confirmation_status: initialized
      - action: utter_introduce_slots
      - action: action_utter_slots
      - action: utter_ask_for_confirmation

  - rule: Ask for confirmation
    condition:
      - active_loop: action_extract_confirmation_status
    steps:
      - action: action_extract_confirmation_status
      - slot_was_set:
          - confirmation_status: fixed
      - action: action_utter_slots
      - action: utter_ask_for_confirmation

  - rule: Ask for correction in the confirmation loop
    condition:
      - active_loop: action_extract_confirmation_status
    steps:
      - action: action_extract_confirmation_status
      - slot_was_set:
          - confirmation_status: rejected
      - action: utter_ask_for_correction

  - rule: Finish confirmation
    condition:
      - active_loop: action_extract_confirmation_status
    steps:
      - action: action_extract_confirmation_status
      - slot_was_set:
          - confirmation_status: confirmed
      - active_loop: null
      - action: utter_booking_completed

And got another conflict:

- the prediction of the action 'action_utter_slots' in rule 'Ask for confirmation' is contradicting with rule(s) 'handling active loops and forms - action_extract_confirmation_status - action_listen' which predicted action 'action_listen'.
- the prediction of the action 'utter_ask_for_correction' in rule 'Ask for correction in confirmation loop' is contradicting with rule(s) 'handling active loops and forms - action_extract_confirmation_status - action_listen' which predicted action 'action_listen'.
- the prediction of the action 'utter_introduce_slots' in rule 'Ask for confirmation the first time' is contradicting with rule(s) 'handling active loops and forms - action_extract_confirmation_status - action_listen' which predicted action 'action_listen'.
Please update your stories and rules so that they don't contradict each other.

This is so annoying.

英文:

I'm building a booking bot using Python and Rasa. I want to add a confirmation step when user fills in all slots in my form. The requirements are:

  1. User may confirm the values.
  2. User may change the values.
  3. Bot must be expandable to handling other inputs and intents from the user.

I drew a flow-diagram which demonstrates more clearly the logic I want to implement:
flow-diagram

I have 2 questions:

  1. How do you usually implement the confirmation step?
  2. How would you implement the logic on the picture?

I'm using Rasa v3.5.13 and Rasa SDK v3.5.1.

I already tried the following:

  1. Confirmation within the form: I added an additional slot confirmation to the form, implemented extraction and validation to handle user input, but I couldn't make Rasa to call custom actions before or after book_foorm is called. Inheriting from FormAction appeared to be impossible, because it doesn't inherit Action from interfaces.py. Rules conflict with action_listen that is invoked right after book_foorm. Making a wrapper action around book_foorm and calling it instead of the original form works only in the first time, but then active loop starts to call book_foorm instead of my wrapper.

  2. Confirmation after the form: passing a custom action in active_loop after book_form is filled in seems to work, but I found out that Rasa only calls the last FollowupAction returned by my custom action, but I want to call multiple actions on each iteration. I also tried to create a custom action that only sets the categorical slot confirmation_status with values: "initialized", "confirmed", "rejected" or "fixed". The idea was that stories can handle my logic relying on confirmation_status, but they do it poorly or don't do it at all. Two stories were not enough even to just activate action_extract_confirmation_status after active_loop was set to null, let alone handling all the logic.

So far, the second option seems to be OK if using rules instead of stories. But I need a lot of rules, and they may become a bottleneck in the further development. Coding my logic in python seems much more robust and easier to me, but I can't find a way to do this normally in Rasa.

UPD:

Tried out another approach:

  - rule: Activate confirmation loop
    steps:
      - action: book_form
      - slot_was_set:
          - requested_slot: null
      - active_loop: null
      - action: action_extract_confirmation_status
      - active_loop: action_extract_confirmation_status
    wait_for_user_input: false

  - rule: Ask for confirmation the first time
    condition:
      - active_loop: action_extract_confirmation_status
    steps:
      - action: action_extract_confirmation_status
      - slot_was_set:
          - confirmation_status: initialized
      - action: utter_introduce_slots
      - action: action_utter_slots
      - action: utter_ask_for_confirmation

  - rule: Ask for confirmation
    condition:
      - active_loop: action_extract_confirmation_status
    steps:
      - action: action_extract_confirmation_status
      - slot_was_set:
          - confirmation_status: fixed
      - action: action_utter_slots
      - action: utter_ask_for_confirmation

  - rule: Ask for correction in confirmation loop
    condition:
      - active_loop: action_extract_confirmation_status
    steps:
      - action: action_extract_confirmation_status
      - slot_was_set:
          - confirmation_status: rejected
      - action: utter_ask_for_correction

  - rule: Finish confirmation
    condition:
      - active_loop: action_extract_confirmation_status
    steps:
      - action: action_extract_confirmation_status
      - slot_was_set:
          - confirmation_status: confirmed
      - active_loop: null
      - action: utter_booking_completed

And got another conflict:

- the prediction of the action 'action_utter_slots' in rule 'Ask for confirmation' is contradicting with rule(s) 'handling active loops and forms - action_extract_confirmation_status - action_listen' which predicted action 'action_listen'.
- the prediction of the action 'utter_ask_for_correction' in rule 'Ask for correction in confirmation loop' is contradicting with rule(s) 'handling active loops and forms - action_extract_confirmation_status - action_listen' which predicted action 'action_listen'.
- the prediction of the action 'utter_introduce_slots' in rule 'Ask for confirmation the first time' is contradicting with rule(s) 'handling active loops and forms - action_extract_confirmation_status - action_listen' which predicted action 'action_listen'.
Please update your stories and rules so that they don't contradict each other.

This is so annoying.

答案1

得分: 0

以下是翻译好的代码部分:

    async def run(
            self,
            dispatcher: CollectingDispatcher,
            tracker: Tracker,
            domain: DomainDict
    ) -> List[EventType]:
        latest_confirmation_status = tracker.get_slot('confirmation_status')
        latest_intent = tracker.get_intent_of_latest_message()
        latest_entities = tracker.latest_message.get('entities')

        logging.debug(f'Latest confirmation status: {latest_confirmation_status}; '
                      f'Latest intent: {latest_intent}; '
                      f'Latest entities: {latest_entities}')

        if latest_confirmation_status == INACTIVE:
            dispatcher.utter_message(response='utter_introduce_slots')
            dispatcher.utter_message(format_slot_values(tracker))
            dispatcher.utter_message(response='utter_ask_for_confirmation')
            return [ActiveLoop(ACTION_NAME), SlotSet("confirmation_status", RUNNING)]
        elif latest_confirmation_status == RUNNING:
            if latest_entities:
                dispatcher.utter_message(format_slot_values(tracker))
                dispatcher.utter_message(response='utter_ask_for_confirmation')
                return []
            elif latest_intent == 'affirm':
                dispatcher.utter_message(response='utter_booking_completed')
                return [ActiveLoop(None), SlotSet("confirmation_status", COMPLETED)]
            elif latest_intent == 'deny':
                dispatcher.utter_message(response='utter_ask_for_correction')
                return []
            else:
                logging.warning('Aborted confirmation loop')
                return [ActiveLoop(None), SlotSet("confirmation_status", ABORTED)]
        else:
            raise ValueError(f'Unexpected status: {repr(latest_confirmation_status)}')
  - rule: 激活确认循环
    steps:
      - action: book_form
      - slot_was_set:
          - requested_slot: null
      - active_loop: null
      - action: action_confirm
      - active_loop: action_confirm

  - rule: 中止确认循环
    steps:
      - slot_was_set:
          - confirmation_status: aborted
      - active_loop: null

  - rule: 完成确认循环
    steps:
      - slot_was_set:
          - confirmation_status: completed
      - active_loop: null
英文:

The only way I could do this is to implement everything in a single action, and set this action as an active loop.

    async def run(
            self,
            dispatcher: CollectingDispatcher,
            tracker: Tracker,
            domain: DomainDict
    ) -> List[EventType]:
        latest_confirmation_status = tracker.get_slot('confirmation_status')
        latest_intent = tracker.get_intent_of_latest_message()
        latest_entities = tracker.latest_message.get('entities')

        logging.debug(f'Latest confirmation status: {latest_confirmation_status}; '
                      f'Latest intent: {latest_intent}; '
                      f'Latest entities: {latest_entities}')

        if latest_confirmation_status == INACTIVE:
            dispatcher.utter_message(response='utter_introduce_slots')
            dispatcher.utter_message(format_slot_values(tracker))
            dispatcher.utter_message(response='utter_ask_for_confirmation')
            return [ActiveLoop(ACTION_NAME), SlotSet("confirmation_status", RUNNING)]
        elif latest_confirmation_status == RUNNING:
            if latest_entities:
                dispatcher.utter_message(format_slot_values(tracker))
                dispatcher.utter_message(response='utter_ask_for_confirmation')
                return []
            elif latest_intent == 'affirm':
                dispatcher.utter_message(response='utter_booking_completed')
                return [ActiveLoop(None), SlotSet("confirmation_status", COMPLETED)]
            elif latest_intent == 'deny':
                dispatcher.utter_message(response='utter_ask_for_correction')
                return []
            else:
                logging.warning('Aborted confirmation loop')
                return [ActiveLoop(None), SlotSet("confirmation_status", ABORTED)]
        else:
            raise ValueError(f'Unexpected status: {repr(latest_confirmation_status)}')
  - rule: Activate confirmation loop
    steps:
      - action: book_form
      - slot_was_set:
          - requested_slot: null
      - active_loop: null
      - action: action_confirm
      - active_loop: action_confirm

  - rule: Abort confirmation loop
    steps:
      - slot_was_set:
          - confirmation_status: aborted
      - active_loop: null

  - rule: Complete confirmation loop
    steps:
      - slot_was_set:
          - confirmation_status: completed
      - active_loop: null

huangapple
  • 本文由 发表于 2023年7月20日 22:11:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76730773.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定