Rasa 模拟实现超简易医生助手(适合初学练手)
下面是一个纯 Rasa 实现的医生助手第一版项目文件内容,具备基本的“多轮问诊”流程逻辑,通过 slot 存储用户的多个症状,在最后阶段给出“模拟的诊断建议”。
PS:完成这个之后,下一步我还想在Rasa工作过程中引入大模型辅助完成对话流程。
📁 项目结构与文件内容
✅ actions/actions.py
from typing import Any, Text, Dict, List
from rasa_sdk import Action, Tracker
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.events import SlotSet
class ActionAskMoreSymptoms(Action):
def name(self) -> Text:
return "action_ask_more_symptoms"
def run(self, dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
# 获取本轮对话中所有识别到的 symptom 实体
new_symptoms = tracker.get_slot("new_symptom") or []
# 获取历史症状
collected_symptoms = tracker.get_slot("collected_symptoms") or []
if new_symptoms:
# 将当前轮症状添加到历史症状列表中
collected_symptoms.extend(new_symptoms)
dispatcher.utter_message(text=f"已记录你的症状:{', '.join(new_symptoms)}。")
else:
dispatcher.utter_message(text="我没有识别到具体症状,请再描述一下。")
dispatcher.utter_message(text=f"目前已记录症状:{', '.join(collected_symptoms)}。还有其他不适吗?")
# 更新槽位
return [
SlotSet("collected_symptoms", collected_symptoms)
]
class ActionSimulateDiagnosis(Action):
def name(self) -> Text:
return "action_simulate_diagnosis"
def run(self, dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
symptoms = tracker.get_slot("collected_symptoms") or []
if not symptoms:
dispatcher.utter_message(text="我目前没有记录到任何症状。")
else:
symptom_list = ", ".join(symptoms)
dispatcher.utter_message(text=f"根据你提供的症状:{symptom_list},建议进一步检查。可能为常见疾病,请就医确认。")
return []
✅ data/nlu.yml
version: "3.1"
nlu:
- intent: greet
examples: |
- 你好
- 嗨
- intent: report_symptom
examples: |
- 我有点[头疼](symptom)
- [胸闷](symptom)
- 最近[恶心](symptom)
- [口干](symptom)
- [胸口发闷](symptom)
- [头疼](symptom)
- [喉咙痛](symptom)
- [发烧](symptom)
- [肚子疼](symptom)
- [胸口闷](symptom)
- [咳嗽](symptom)
- 感觉[恶心](symptom)
- 有点[鼻塞](symptom)
- intent: deny
examples: |
- 没有了
- 没有其他不适
- 没事了
- 没有
✅ data/rules.yml
version: "3.1"
rules:
- rule: 启动问诊
steps:
- intent: greet
- action: utter_greet
- rule: 用户说出症状后继续追问
steps:
- intent: report_symptom
- action: utter_ack_symptom
- action: action_ask_more_symptoms
- rule: 用户否认后进入诊断
steps:
- intent: deny
- action: action_simulate_diagnosis
✅ data/stories.yml
version: "3.1"
stories:
- story: 多轮问诊并诊断
steps:
- intent: report_symptom
- action: utter_ack_symptom
- action: action_ask_more_symptoms
- intent: report_symptom
- action: utter_ack_symptom
- action: action_ask_more_symptoms
- intent: deny
- action: action_simulate_diagnosis
✅ tests/test_stories.yml
version: "3.1"
stories:
- story: 测试完整问诊流程
steps:
- user: |
我头疼
intent: report_symptom
- action: utter_ack_symptom
- action: action_ask_more_symptoms
- user: |
还有点咳嗽
intent: report_symptom
- action: utter_ack_symptom
- action: action_ask_more_symptoms
- user: |
没有了
intent: deny
- action: action_simulate_diagnosis
✅ config.yml
recipe: default.v1
assistant_id: 20250412-010713-concrete-weapon
language: zh
pipeline:
- name: JiebaTokenizer
- name: RegexFeaturizer
- name: LexicalSyntacticFeaturizer
- name: CountVectorsFeaturizer
- name: DIETClassifier
epochs: 100
- name: EntitySynonymMapper
- name: FallbackClassifier
threshold: 0.4
ambiguity_threshold: 0.1
policies:
- name: RulePolicy
- name: UnexpecTEDIntentPolicy # 辅助检测用户意图偏差
max_history: 5
epochs: 100
✅ credentials.yml
rest:
✅ domain.yml
version: "3.1"
intents:
- greet
- report_symptom
- deny
slots:
new_symptom:
type: list
initial_value: []
influence_conversation: false
mappings:
- type: from_entity
entity: symptom
collected_symptoms:
type: any
initial_value: []
influence_conversation: false
mappings: [] # 添加一个空的 mappings 配置
entities:
- symptom
actions:
- utter_greet
- action_ask_more_symptoms
- action_simulate_diagnosis
responses:
utter_greet:
- text: "你好,我是医生助手,请描述你的症状。"
utter_ack_symptom:
- text: 已记录你的症状。
✅ endpoints.yml
action_endpoint:
#url: "http://localhost:5055/webhook"
#action_server是之后运行action的docker容器名字
url: "http://action_server:5055/webhook"
✅ 启动流程简要说明
1. 训练模型:
docker run -u $(id -u):$(id -g) -v $(pwd):/app rasa/rasa:3.6.21-full train
2. 创建一个 bridge 网络
docker network create rasa-net
然后用这个网络跑两个容器:
3.启动 action server 服务器(一个终端)
docker run --rm -u $(id -u):$(id -g) --network rasa-net -v $(pwd):/app -p 5055:5055 --name action_server rasa/rasa:3.6.21-full run actions
#--name action_server注意这里设置的容器名需要和action_endpoint里的设置匹配
4.启动对话测试 rasa shell(另一个终端)
docker run --rm -it -u $(id -u):$(id -g) --network rasa-net -v $(pwd):/app rasa/rasa:3.6.21-full shell
这样两个容器在同一个网络里,localhost:5055
就能通了。
博主私人备注:
用于检测nul
docker run --rm -it -u $(id -u):$(id -g) --network rasa-net -v $(pwd):/app rasa/rasa:3.6.21-full shell nlu