Rasa表单验证中途触发意图时如何停用表单?
RASA表单中途退出功能实现解决方案
问题背景
使用RASA框架开发registration_form表单收集用户注册信息,槽位均为text类型,映射条件为active_loop: registration_form。需求是用户输入/exit触发deactivate意图时,中途停用表单,返回初始状态并发送问候消息。
当前配置
domain.yml
slots: email: type: text influence_conversation: false mappings: - type: from_text conditions: - active_loop: registration_form requested_slot: email username: type: text influence_conversation: false mappings: - type: from_text conditions: - active_loop: registration_form requested_slot: username quit_form: type: bool influence_conversation: true mappings: - type: from_text
尝试方案及问题
- 验证方法中直接停用表单:在
validate_email中检测退出意图后返回事件列表,触发UserWarning: Cannot validate email: make sure the validation method returns the correct output.警告,表单仍继续询问后续槽位。 - 添加故事处理退出:编写故事指定触发
deactivate意图时调用action_deactivate_loop,训练时提示规则/故事冲突,预测应为action_listen却指定了action_deactivate_loop。
解决步骤
1. 修正表单验证类的逻辑
FormValidationAction的validate_*方法仅允许返回槽位键值对字典,不能直接返回事件。需重写run方法提前拦截退出意图:
from typing import Text, Dict, Any, List from rasa_sdk import FormValidationAction, Tracker from rasa_sdk.executor import CollectingDispatcher from rasa_sdk.types import DomainDict from rasa_sdk.events import SlotSet, ActiveLoop class ValidateForm(FormValidationAction): data = {} signup_response = {} def name(self) -> Text: return "validate_registration_form" def run( self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: DomainDict, ) -> List[Dict[Text, Any]]: # 优先检测退出意图 latest_text = tracker.latest_message.get("text", "").lower() if tracker.get_intent_of_latest_message() == "deactivate" or "/quit" in latest_text: dispatcher.utter_message(text="已退出注册流程,欢迎随时再来!") # 清空已收集槽位并停用表单 return [ ActiveLoop(None), SlotSet("email", None), SlotSet("username", None) ] # 正常执行验证逻辑 return super().run(dispatcher, tracker, domain) # 保留原有验证逻辑,移除退出检测代码 def validate_email( self, slot_value: Any, dispatcher: CollectingDispatcher, tracker: Tracker, domain: DomainDict, ) -> Dict[Text, Any]: slot_value = slot_value.lower() if email_validation(slot_value): if user_validation_from_local_db("email", slot_value) or user_validation(value=slot_value): dispatcher.utter_message(text="Email exists, try entering another email") return {"email": None} self.data['email'] = slot_value return {"email": slot_value} else: dispatcher.utter_message(text="Email is not valid, please enter a valid email.") return {"email": None} def validate_username( self, slot_value: Any, dispatcher: CollectingDispatcher, tracker: Tracker, domain: DomainDict, ) -> Dict[Text, Any]: if username_validation(slot_value): if user_validation_from_local_db('username', slot_value) or user_validation(value=slot_value): dispatcher.utter_message(text="Username exists, try entering another username") return {"username":None} self.data['username'] = slot_value return {"username": slot_value} else: dispatcher.utter_message("Please enter a valid Username.\nMake sure username only consists lower-case characters, numbers, underscore(_) and no spaces.") return {'username':None}
2. 使用规则替代故事处理退出
表单退出属于明确的触发-响应流程,用规则替代故事可避免训练冲突,在rules.yml中添加:
- rule: Exit registration form steps: - active_loop: registration_form - intent: deactivate - action: action_deactivate_loop - active_loop: null - action: utter_greet # 替换为你的问候动作
3. 简化domain.yml配置(可选)
若无需通过槽位控制退出,可移除quit_form槽:
slots: email: type: text influence_conversation: false mappings: - type: from_text conditions: - active_loop: registration_form requested_slot: email username: type: text influence_conversation: false mappings: - type: from_text conditions: - active_loop: registration_form requested_slot: username
4. 完善deactivate意图训练数据
在nlu.yml中补充意图示例:
- intent: deactivate examples: | - /exit - quit - exit - stop - cancel - 退出 - 取消
关键说明
validate_*方法仅支持返回槽位字典,事件需在run方法中返回,否则会触发验证警告。- 规则比故事更适合处理表单这类结构化流程,可避免训练时的冲突问题。
内容的提问来源于stack exchange,提问作者sarveshsta
相关产品推荐
相关产品推荐

