1. 概述
2.0版发生了很多变化。 确保通读本指南,以确保机器人的所有部分都已更新。 内置命令可以自动完成很多更新,其他更新则需要手动进行转换。 如果对这些更新或迁移过程有任何反馈,可以在论坛中发布。
2. 训练数据文件
从2.0版开始,新的默认训练数据格式为yaml。 仍支持Markdown,但在将来的版本中将不再使用。
可以使用以下命令将Markdown格式的现有NLU,Stories和NLG(即Response.md)训练数据文件转换为新的YAML格式:
rasa data convert nlu -f yaml --data={SOURCE_DIR} --out={TARGET_DIR}
rasa data convert nlg -f yaml --data={SOURCE_DIR} --out={TARGET_DIR}
rasa data convert core -f yaml --data={SOURCE_DIR} --out={TARGET_DIR}
转换后的文件将具有与原始文件相同的名称,但后缀为_converted.yml。
如果使用 forms或response selectors,则需要按照其各自的部分中的说明进行一些其他更改。
3. Policies
通过引入rules和RulePolicy,不推荐使用以下策略:
- Mapping Policy
 - Fallback Policy
 - Two-Stage-Fallback Policy
 - 
Form Policy
要自动迁移策略,可以运行以下命令: 
rasa data convert config
该命令将负责更新config.yml和domain.yml,同时使用.bak后缀备份现有文件。 如有必要,还将添加rules.yml。此更新后,forms仍将以旧格式正常运行,但是此命令不会自动将它们转换为新格式。 如forms部分所述,这应该手动完成。
如果不想使用自动转换命令,也可以手动迁移单个策略。
3.1 Manually migrating from the Mapping Policy
如果以前使用过Mapping Policy,则可以按照 FAQs上的文档将映射的意图转换为规则。 假设以前按如下方式映射了一个意图Ask_is_bot:
domain.yml
intents:
 - ask_is_bot:
     triggers: action_is_bot
变成规则就是下面这个样子:
rules.yml
rules:
- rule: Rule to map `ask_is_bot` intent
  steps:
  - intent: ask_is_bot
  - action: action_is_bot
而且,我们可以安全地从domain中删除所有触发器(triggers):
domain.yml
intents:
 - ask_is_bot
最后,可以在模型配置中将Mapping Policy替换为 Rule Policy:
config.yml
policies:
  # Other policies
  - name: RulePolicy
3.2 Manually migrating from the Fallback Policy
如果先前使用了Fallback Policy,则给定之前的配置,模型配置将转换为以下内容:
config.yml
policies:
  - name: "FallbackPolicy"
    nlu_threshold: 0.4
    core_threshold: 0.3
    fallback_action_name: "action_default_fallback"
    ambiguity_threshold: 0.1
新配置如下所示:
config.yml
policies:
  # Other policies
  - name: RulePolicy
    core_fallback_threshold: 0.3
    core_fallback_action_name: "action_default_fallback"
pipeline:
  # Other components
  - name: FallbackClassifier
    threshold: 0.4
    ambiguity_threshold: 0.1
此外,需要添加一条 rule来指定在NLU置信度较低的情况下要执行哪个操作:
rules.yml
rules:
  - rule: Ask the user to rephrase whenever they send a message with low NLU confidence
    steps:
    - intent: nlu_fallback
    - action: utter_please_rephrase
有关更多信息,请参见fallback文档。
3.3 Manually migrating from the Two-Stage-Fallback Policy
如果以前使用[Two-Stage-Fallback Policy(https://rasa.com/docs/rasa/policies#two-stage-fallback-policy),例如这样的配置:
config.yml
policies:
  - name: TwoStageFallbackPolicy
    nlu_threshold: 0.4
    ambiguity_threshold: 0.1
    core_threshold: 0.3
    fallback_core_action_name: "action_default_fallback"
    fallback_nlu_action_name: "action_default_fallback"
    deny_suggestion_intent_name: "out_of_scope"
新的配置如下所示:
config.yml
policies:
  # Other policies
  - name: RulePolicy
    core_fallback_threshold: 0.3
    core_fallback_action_name: "action_default_fallback"
pipeline:
  # Other components
  - name: FallbackClassifier
    threshold: 0.4
    ambiguity_threshold: 0.1
此外,还需要添加一条 rule以针对NLU置信度较低的消息激活Two-Stage Fallback。
rules.yml
rules:
  - rule: Implementation of the TwoStageFallbackPolicy
    steps:
    # This intent is automatically triggered by the `FallbackClassifier` in the NLU
    # pipeline in case the intent confidence was below the specified threshold.
    - intent: nlu_fallback
    # The Fallback is now implemented as a form.
    - action: action_two_stage_fallback
    - active_loop: action_two_stage_fallback
请注意,先前的参数fallback_nlu_action_name和deny_suggestion_intent_name不再可配置,并且具有固定值action_default_fallback和out_of_scope。
有关更多信息,请参见fallback文档。
4. Forms
从2.0版开始, forms的逻辑已从Rasa SDK移至Rasa Open Source,以简化实现并使其更容易用其他语言编写action servers。
这意味着Forms不再使用FormAction来实现,而是在domain中定义。 可以使用FormValidationAction处理有关请求槽值或slot validation的任何自定义设置。
考虑来自1.x的自定义Forms操作,如下所示:
from typing import Text, List, Any, Dict, Union
from rasa_sdk import Tracker
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.forms  import FormAction
class RestaurantForm(FormAction):
    def name(self) -> Text:
        return "restaurant_form"
    @staticmethod
    def required_slots(tracker: Tracker) -> List[Text]:
        return ["cuisine"]
    def slot_mappings(self) -> Dict[Text, Union[Dict, List[Dict]]]:
        return {
            "cuisine": self.from_entity(entity="cuisine", not_intent="chitchat"),
        }
    @staticmethod
    def cuisine_db() -> List[Text]:
        """Database of supported cuisines"""
        return ["caribbean", "chinese", "french"]
    def validate_cuisine(
        self,
        value: Text,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> Dict[Text, Any]:
        """Validate cuisine value."""
        if value.lower() in self.cuisine_db():
            # validation succeeded, set the value of the "cuisine" slot to value
            return {"cuisine": value}
        else:
            dispatcher.utter_message(template="utter_wrong_cuisine")
            # validation failed, set this slot to None, meaning the
            # user will be asked for the slot again
            return {"cuisine": None}
    def submit(
        self,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> List[Dict]:
        """Define what the form has to do
            after all required slots are filled"""
        # utter submit template
        dispatcher.utter_message(template="utter_submit")
        return []
通过删除FormPolicy并将 RulePolicy(如果尚未添加)添加到模型配置中,开始迁移:
config.yml
policies:
  # Other policies
  # ...
  - name: RulePolicy
然后,需要按照form文档中的描述在domain中定义form,所需的slots及其slot映射:
domain.yml
forms:
  restaurant_form:
    cuisine:
    - type: cuisine
      entity: cuisine
      not_intent: chitchat
如果通过运行命令来 convert your stories,那么我们将拥有一个可以处理form activation 和deactivation的story,如下所示:
stories.yml
stories:
  - story: cuisine form
    steps:
    - intent: request_restaurant
    - action: restaurant_form
    - active_loop: restaurant_form
    - active_loop: null
    - action: utter_submit
这可以很好地工作,但是处理form behavior的最佳方法是删除这个story,并且为form activation 和 submission定义两个单独的规则:
rules.yml
rules:
  - rule: Activate form
    steps:
    - intent: request_restaurant
    - action: restaurant_form
    - active_loop: restaurant_form
  - rule: Submit form
    condition:
    # Condition that form is active.
    - active_loop: restaurant_form
    steps:
    - action: restaurant_form
    - active_loop: null
    # The action we want to run when the form is submitted.
    - action: utter_submit
最后一步是实施custom action以验证form slots。 首先将custom action添加到domain中:
domain.yml
actions:
  # Other actions
  # ...
  - validate_restaurant_form
然后添加一个custom action,以验证cuisine slot:
from typing import Text, List, Any, Dict, Union
from rasa_sdk import Tracker
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk import FormValidationAction
from rasa_sdk.types import DomainDict
class RestaurantFormValidator(FormValidationAction):
    def name(self) -> Text:
        return "validate_restaurant_form"
    @staticmethod
    def cuisine_db() -> List[Text]:
        """Database of supported cuisines"""
        return ["caribbean", "chinese", "french"]
    def validate_cuisine(
        self,
        slot_value: Any,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: DomainDict,
    ) -> Dict[Text, Any]:
        """Validate cuisine value."""
        if slot_value.lower() in self.cuisine_db():
            # validation succeeded, set the value of the "cuisine" slot to value
            return {"cuisine": slot_value}
        else:
            # validation failed, set this slot to None, meaning the
            # user will be asked for the slot again
            return {"cuisine": None}
有关更多详细信息,请参见 forms文档。