
简介这是一套面向高校学生与初学者的Rasa中文聊天机器人完整开发实践资源适用于毕业设计、课程设计及AI项目入门开发聚焦自然语言理解NLU与对话管理Core两大核心能力落地。资源包含24个文件涵盖7个Markdown开发指南、6个YAML配置文件含domain、nlu、stories等、5个Python脚本含action服务与服务器启动、3个文本说明及2个Bash部署脚本整体压缩包仅4.42MB轻量易用且结构清晰。已有247人学习下载内容经实测可运行支持前端调用Rasa服务、集成图灵闲聊与心知天气API并提供Interactive Learning样本构建、MITIEsupervised_embeddings双管道训练方案及身份查询等典型场景案例。配套文档系统性强覆盖从环境搭建、NLU优化同义词/正则/查找表、Core逻辑设计到1.9.5版本升级排错的全流程是少有的兼顾原理讲解、代码解析与工程落地的中文Rasa实战资料。1. Rasa中文聊天机器人不是“调个API就完事”的玩具它是一套可落地、可调试、可交付的对话系统工程闭环你手头正赶着毕业设计 deadline导师说“做个智能客服原型”你搜到一堆“Python 聊天机器人”——结果点开全是while True: input() print()的硬编码回声或者更糟是套着 Flask 外壳、用 if-elif 堆出 200 行意图分支的“伪 NLU”。这种项目答辩时被问一句“如果用户说‘我昨天订的单怎么还没发货’你怎么识别‘发货状态查询’这个意图实体‘昨天’怎么归一化成相对时间”当场哑火。而这份 Rasa 中文聊天机器人源码包恰恰卡在真实工程与教学落地的交界点上它不是 demo而是跑通了NLU 意图识别 实体抽取 Core 对话管理 外部 API 对接 交互式样本增强全链路的最小可行系统。所有模块都带中文注释、训练日志截图、train.bash和run_server.bash一键启停脚本连 Windows 下 TensorFlow 兼容性问题Rasa 1.9.5 版本锁都提前踩过坑。适合课程设计快速验证对话逻辑也经得起毕设答辩追问——比如你能现场rasa interactive进入对话调试模式实时修正错标样本也能打开data/nlu.md看到“查天气”意图下混用了“今天北京天气怎么样”“北京明天会不会下雨”“气温多少度”三类表达并附有同义词表和正则规则。这不是教你怎么写 Python而是教你怎么构建一个会“听懂人话、记住上下文、调用服务、持续进化”的对话黑匣子。2. 从零启动解压即训、训完即跑的 Rasa 中文环境搭建与模型训练实操2.1 环境依赖与版本锁定为什么必须用 Rasa 1.9.5 而不是最新版项目更新日志明确提到“将 Rasa 版本升级到 1.9.5解决 win10 使用 tensorflow 出现的异常”。这不是随意选的旧版本而是经过实测的兼容性甜点区。Rasa 2.x 引入了rasa train core与rasa train nlu分离训练、--enable-api参数变更等 breaking change而本项目train.bash脚本、config.yml中的 pipeline 配置如supervised_embeddings、甚至actions目录下的自定义 action 类结构全部基于 1.9.5 的 API 设计。若强行升级你会遇到rasa train报错Unknown pipeline component RegexFeaturizer新版已移除server.py中rasa.core.agent.load_agent()方法签名变更导致无法加载模型actions模块 import 路径失效新版要求from rasa_sdk import Action因此环境初始化必须严格锁定# 创建独立虚拟环境强烈建议避免全局污染 python -m venv rasa_chitchat_env source rasa_chitchat_env/bin/activate # Linux/macOS # rasa_chitchat_env\Scripts\activate.bat # Windows # 安装指定版本注意Rasa 1.9.5 依赖 tensorflow2.3需避开 TF 2.3 的 ABI 不兼容 pip install rasa1.9.5 tensorflow2.2.0 numpy1.19.5 requests2.25.1 pip install rasa-sdk1.9.0 # 注意SDK 版本必须与 Rasa 主版本严格匹配提示requirements.txt中未显式声明tensorflow2.2.0但train.bash在 Windows 下失败的根本原因就是 TF 2.3 与 Rasa 1.9.5 C 扩展的 ABI 冲突。这是血泪经验——我曾因 pip 自动升级 TF 到 2.4 而重装系统三次。2.2 数据结构解析.md格式不是随便写的它是 Rasa 1.9.5 的 NLU 训练契约Rasa 1.9.5 使用 Markdown 格式定义训练数据其语法有严格约束。本项目data/目录下包含nlu.md意图与样例文本含实体标注stories.md对话流程路径Core 训练用domain.yml意图、实体、槽位、响应模板的全局声明以nlu.md中“查天气”意图为例## intent:chit_chat_weather - 今天[北京](location)天气怎么样 - [上海](location)明天会不会下雨 - [广州](location)气温多少度 - 查一下[深圳](location)的天气预报 - [杭州](location)现在温度是多少关键细节## intent:后必须是纯英文标识符chit_chat_weather不能含空格或中文这是模型内部 key实体标注[北京](location)中location是 domain.yml 中定义的实体类型且必须小写每行样例必须独占一行末尾不能有空格或 Tab同义词扩展不在.md文件里而在data/lookup_tables/location.txt中每行一个地名Rasa 会自动加载并用于 fuzzy 匹配。若你新增样例必须遵守此格式否则rasa train会静默跳过该行不报错但无效导致意图识别率骤降——这是新手最常翻车的点。2.3 一键训练train.bash脚本背后的真实执行逻辑与参数含义项目提供的train.bash并非简单包装它封装了 Rasa 1.9.5 的标准训练流程并预设了关键参数#!/bin/bash rasa train \ --config config.yml \ --domain domain.yml \ --data data/ \ --out models/ \ --fixed-model-name chitchat_model_$(date %Y%m%d_%H%M%S)逐参数说明--config config.yml指定 pipeline 配置。本项目使用supervised_embeddings而非pretrained_embeddings它通过监督学习联合优化意图和实体对中文短句泛化性更好--domain domain.yml声明所有可识别的意图、实体、槽位及响应模板。注意其中responses:下的utter_weather_info必须与actions.py中调用的 response 名一致--data data/Rasa 会递归扫描该目录下所有.md和.yml文件不要手动拆分数据到子文件夹否则部分文件可能被忽略--out models/模型输出目录生成chitchat_model_20200215_143022.tar.gz这样的时间戳命名压缩包--fixed-model-name强制指定模型名避免 Rasa 自动生成随机 hash 名方便后续run_server.bash精准加载。执行后你会看到类似输出2020-02-15 14:30:22 INFO rasa.nlu.model - Starting to train NLU component RegexFeaturizer. 2020-02-15 14:30:23 INFO rasa.nlu.model - Starting to train NLU component CountVectorsFeaturizer. ... 2020-02-15 14:32:18 INFO rasa.core.agent - Model directory models/chitchat_model_20200215_143022 created.训练耗时约 2~5 分钟取决于 CPU成功标志是models/目录下出现.tar.gz文件且rasa test nlu能返回 85% 的 F1 分数项目实测值为 89.2%。2.4 启动服务run_server.bash与server.py的双轨部署策略项目提供两种服务启动方式对应不同调试阶段方式一run_server.bash推荐用于快速验证#!/bin/bash rasa run \ --enable-api \ --cors * \ --debug \ --model models/chitchat_model_20200215_143022.tar.gz \ --endpoints endpoints.yml--enable-api开启 REST API供前端或 Postman 调用--cors *允许任意域名跨域请求开发阶段必备生产环境需替换为具体域名--debug输出详细日志包括每轮对话的 intent confidence、entity extraction 结果--endpoints.yml定义外部 action server 地址本项目指向http://localhost:5055/webhook。方式二server.py用于深度定制与 debugfrom rasa.core.agent import Agent from rasa.core.interpreter import RasaNLUInterpreter import asyncio async def main(): interpreter RasaNLUInterpreter(models/chitchat_model_20200215_143022/nlu) agent Agent( models/chitchat_model_20200215_143022/core, interpreterinterpreter, action_endpointhttp://localhost:5055/webhook ) # 启动内置 HTTP server仅用于测试非生产 await agent.handle_channels() if __name__ __main__: asyncio.run(main())区别在于rasa run是官方 CLI稳定但定制性弱server.py是手动加载模型便于在 PyCharm 中打断点调试agent.predict_next_action()的决策过程。例如当用户说“帮我查北京天气”你可以 step intoagent.handle_message()观察tracker中slots的变化、latest_event的类型这才是理解 Rasa Core 工作机制的正道。3. 对话引擎核心NLU 意图识别与实体抽取的 pipeline 配置与效果调优3.1config.yml中的supervised_embeddings管道为何比pretrained_embeddings更适合中文短句Rasa 1.9.5 提供多种 NLU pipeline本项目采用language: zh pipeline: - name: WhitespaceTokenizer - name: RegexFeaturizer - name: CountVectorsFeaturizer - name: CountVectorsFeaturizer analyzer: char_wb min_ngram: 1 max_ngram: 4 - name: DIETClassifier constrain_similarities: true - name: EntitySynonymMapper - name: ResponseSelector重点在CountVectorsFeaturizer的两次调用第一次默认基于词word的 one-hot 向量对中文需先分词但 Rasa 1.9.5 默认 tokenizer 仅空格切分故对中文效果差第二次analyzer: char_wb基于字符character的 n-gram 向量min_ngram:1, max_ngram:4意味着提取 1~4 字连续子串如“北京天气” → “北”、“北京”、“北京天”、“北京天气”、“京天”...这天然适配中文无空格分词特性且对错别字鲁棒“北就天气”仍能匹配“北”“京”“天”等字。而DIETClassifierDual Intent and Entity Transformer是 Rasa 自研的联合模型它同时优化意图分类和实体识别损失函数比传统 pipeline先 intent 后 entity更高效。项目更新日志称“改进 supervised_embeddings实体提取和意图识别明显提高”指的就是此配置组合。注意RegexFeaturizer用于匹配正则规则如手机号、日期EntitySynonymMapper将同义词映射到标准实体值如“首都”→“北京”二者必须放在DIETClassifier之后否则特征无法被 classifier 利用。3.2 实体抽取的边界处理如何让“昨天”变成相对时间Rasa 默认只识别预定义实体类型如location,time但“昨天”这类相对时间需额外处理。本项目在actions.py中实现from datetime import datetime, timedelta class ActionGetWeather(Action): def name(self) - Text: return action_get_weather def run(self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) - List[Dict[Text, Any]]: # 获取用户输入中的 time 实体 time_entity next((e for e in tracker.latest_message.get(entities, []) if e.get(entity) time), None) if time_entity and time_entity.get(value): # Rasa 识别出的 time 值可能是 昨天、今天、明天 raw_time time_entity[value] now datetime.now() if raw_time 昨天: target_date now - timedelta(days1) elif raw_time 明天: target_date now timedelta(days1) else: # 今天 或其他 target_date now # 调用天气 API 时传入 target_date.date().isoformat() ...关键点tracker.latest_message.get(entities)是 Rasa NLU 输出的原始实体列表time_entity[value]是用户原话中的字符串非标准化值需在 action 中做业务逻辑转换项目未使用DucklingHTTPExtractor需外挂服务而是靠RegexFeaturizerDIETClassifier识别基础 time 实体再由 action 做语义归一化——这是轻量级项目的务实选择。3.3 意图置信度阈值调优为什么chit_chat_greeting置信度只有 0.62 仍被接受Rasa 默认意图阈值为0.3但项目domain.yml中显式设置session_config: session_expiration_time: 60 carry_over_slots_to_new_session: true # 关键配置降低阈值以提升中文闲聊意图召回率 policies: - name: MemoizationPolicy - name: KerasPolicy epochs: 100 constrain_similarities: true - name: MappingPolicy - name: FallbackPolicy fallback_action_name: action_default_fallback # 当最高置信度 0.6 时触发 fallback threshold: 0.6 # 且与次高意图差距 0.1 时才 fallback避免抖动 ambiguity_threshold: 0.1这意味着若chit_chat_greeting置信度 0.62chit_chat_weather0.58则0.62 - 0.58 0.04 0.1触发 fallback用户收到“我不太明白能再说一遍吗”若chit_chat_greeting0.75chit_chat_weather0.20则0.75 - 0.20 0.55 0.1且0.75 0.6直接执行 greeting 响应。此配置平衡了准确率与召回率。中文闲聊语句模糊性强“哈喽”“你好啊”“hi”混用过高的threshold会导致大量 valid 意图被拒而ambiguity_threshold防止模型在两个相近意图间反复横跳。3.4 避坑NLU 训练常见问题排查现象rasa train成功但rasa shell中输入“北京天气”始终识别为chit_chat_greeting原因nlu.md中chit_chat_weather意图样例不足少于 5 条而chit_chat_greeting有 20 条模型过拟合 greeting 类别。解决按 1:1 比例扩充 weather 样例至少 15 条并加入口语化变体“北京今儿热不热”“北京这会儿下雨没”。现象实体location总是识别为空即使样例中写了[北京](location)原因domain.yml中未声明location实体或声明为entities: []空列表。解决检查domain.yml确保entities:下包含- location且大小写与.md文件中完全一致。现象rasa test nlu报错ValueError: Found sample with 0 features原因nlu.md中某行样例为空行或仅含空格Rasa 解析时生成空特征向量。解决用sed /^$/d data/nlu.md nlu_clean.md mv nlu_clean.md data/nlu.md删除所有空行。现象rasa interactive中修改样本后重新训练模型新样本未生效原因rasa interactive保存的样本默认存入data/interactive/子目录但train.bash的--data data/未递归扫描该目录。解决手动将data/interactive/*.md合并到data/nlu.md和data/stories.md或修改train.bash为--data data/ data/interactive/。现象Windows 下rasa train卡在Starting to train NLU component CountVectorsFeaturizer无响应原因TensorFlow 2.2.0 在 Win10 上的线程调度 bug与 Rasa 的 multiprocessing 冲突。解决在train.bash前添加环境变量set PYTHONIOENCODINGutf-8 set PYTHONUTF81或改用 WSL2 运行。4. 对话管理实战Stories 流程建模与 Interactive Learning 样本增强4.1stories.md不是脚本而是对话状态机的轨迹采样Rasa Core 通过 stories 学习对话策略其本质是(state, action)序列。本项目stories.md示例## story_01_weather_query * chit_chat_weather{location: 北京} - action_get_weather - utter_weather_info ## story_02_weather_with_time * chit_chat_weather{location: 上海, time: 明天} - action_get_weather - utter_weather_info关键解读* chit_chat_weather{...}是用户消息{...}是提取的实体槽位slot- action_get_weather是 bot 执行的 custom action调用外部 API- utter_weather_info是 domain.yml 中定义的响应模板内容为text: 北京今天晴气温 25°C。Rasa 1.9.5 的MemoizationPolicy会精确匹配完整 story 轨迹而KerasPolicy则学习 state-action 的泛化规律。因此story 数量不必穷举所有组合但需覆盖主干流程如 weather query → API call → response异常分支如用户中途说“算了”需action_revert_last槽位填充中断如用户先说“查天气”再补“北京”需form机制。4.2rasa interactive不是演示工具而是你的对话 debug 黑匣子运行rasa interactive --model models/chitchat_model_20200215_143022.tar.gz后你会进入交互式调试? Please type a message: 北京天气怎么样 Your input - 北京天气怎么样 Current slot values: location: None time: None Logged Data: intent: {name: chit_chat_weather, confidence: 0.82} entities: [{entity: location, value: 北京, start: 0, end: 2}] Next action: action_get_weather ? Correctly predicted next action action_get_weather? Yes此时你可修正意图若识别错误输入n→intent→ 选择正确意图修正实体输入n→entity→ 选择实体类型并标注起止位置修正 action输入n→action→ 选择应执行的 action保存样本输入sRasa 自动将修正后的对话轨迹存入data/interactive/。血泪经验rasa interactive是唯一能实时看到tracker状态slots、latest_event、followup_action的途径。我曾发现action_get_weather执行后location槽位被清空原因是action中未显式return [SlotSet(location, None)]导致下一轮对话丢失上下文——这个 bug 在rasa shell中根本无法定位。4.3forms机制如何让机器人主动追问缺失信息当用户只说“查天气”未提供location时bot 应追问。本项目在domain.yml中定义forms: - weather_form: required_slots: - location # - time # time 可选故注释掉并在stories.md中添加 form flow## story_form_weather * chit_chat_weather - weather_form - form{name: weather_form} * inform{location: 北京} - form{name: null} - action_get_weather - utter_weather_infoform{name: weather_form}表示启动表单form{name: null}表示表单结束。Rasa 会自动检查required_slots是否填满若location为空则执行utter_ask_location需在 domain.yml 中定义用户回复后再次校验直到所有 required slots 非空。4.4 避坑Stories 训练与执行常见问题排查现象rasa shell中用户说“查北京天气”bot 直接执行action_get_weather但未调用天气 API原因endpoints.yml中action_endpointURL 错误或actions服务未启动python -m rasa_sdk --actions actions。解决先运行python -m rasa_sdk --actions actions再检查curl http://localhost:5055/webhook是否返回{status:ok}。现象rasa interactive中 form 启动后用户说“北京”bot 却执行utter_ask_time而非utter_ask_location原因domain.yml中required_slots顺序错误或utter_ask_*响应模板名与 slot 名不匹配如utter_ask_location对应locationslot。解决确认required_slots列表首项为location且responses:下存在utter_ask_location。现象rasa train core报错Could not find a default starting policy原因stories.md中缺少以*开头的用户消息即没有初始 intentRasa 无法确定对话起点。解决确保至少一个 story 以* chit_chat_greeting或* chit_chat_weather开头。现象form 填充后location槽位值为None但tracker.get_slot(location)返回字符串原因actions.py中SlotSet(location, value)的value为NoneRasa 会清空槽位。解决在action中显式return [SlotSet(location, tracker.get_slot(location))]保持槽位值。现象rasa test core显示FormPolicy准确率 0%但实际对话正常原因test stories未覆盖 form 场景或stories.md中 form 相关 story 未被正确解析如form{name: null}缩进错误。解决用rasa visualize生成graph.html检查 form 节点是否连通。5. 外部服务对接图灵机器人与心知天气 API 的集成与异常熔断5.1actions.py中的双 API 调用为什么图灵走requests.post而天气走requests.get项目actions.py实现两个 custom actionclass ActionTulingChat(Action): def name(self) - Text: return action_tuling_chat def run(self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) - List[Dict[Text, Any]]: user_text tracker.latest_message.get(text, ) # 图灵 API 要求 POST JSON body payload { key: your_api_key, info: user_text, userid: rasa_user } try: resp requests.post(http://www.tuling123.com/openapi/api, jsonpayload, timeout5) data resp.json() reply data.get(text, 我暂时没听懂) except Exception as e: reply 网络繁忙请稍后再试 dispatcher.utter_message(textreply) return [] class ActionGetWeather(Action): def name(self) - Text: return action_get_weather def run(self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) - List[Dict[Text, Any]]: location tracker.get_slot(location) # 心知天气 API 走 GET 查询参数 url fhttps://api.seniverse.com/v3/weather/daily.json?keyyour_keylocation{location}languagezh-Hansunitc try: resp requests.get(url, timeout5) data resp.json() # 解析 weather data... except Exception as e: # 熔断逻辑 if timeout in str(e).lower(): reply 天气服务暂时不可用请稍后再试 else: reply 获取天气失败 dispatcher.utter_message(textreply) return []差异根源图灵 API 是通用聊天接口需传入info用户消息和userid会话 IDPOST 更安全心知天气是 RESTful APIlocation是路径参数GET 更符合语义且缓存友好。5.2 熔断与降级try-except不是摆设而是生产级对话的底线上述代码中timeout5是关键防止 API 延迟拖垮整个对话流Rasa 默认超时 60 秒用户早已失去耐心except Exception捕获所有网络异常ConnectionError, Timeout, JSONDecodeError对Timeout单独处理返回提示语“天气服务暂时不可用”而非笼统的“出错了”。更进一步可引入tenacity库实现指数退避重试from tenacity import retry, stop_after_attempt, wait_exponential retry(stopstop_after_attempt(3), waitwait_exponential(multiplier1, min1, max10)) def call_weather_api(location): url fhttps://api.seniverse.com/...location{location} resp requests.get(url, timeout5) resp.raise_for_status() return resp.json()但本项目为轻量级try-except已足够——毕竟毕设答辩时评委不会真去压测你的天气 API。5.3 API Key 安全为什么actions.py里明文写your_api_key是故意的项目源码中actions.py的 API Key 是占位符your_api_key这是教学设计的刻意留白。真实部署时绝不能硬编码密钥而应方式一推荐使用环境变量import os weather_key os.getenv(WEATHER_API_KEY, default_key)启动时export WEATHER_API_KEYxxx python -m rasa_sdk --actions actions方式二配置文件分离新建secrets.ymlgitignore 掉weather_api_key: xxx tuling_api_key: yyy在actions.py中import yaml with open(secrets.yml) as f: secrets yaml.safe_load(f)硬编码密钥一旦上传 GitHub等于公开泄露 API 权限——这是课程设计中最易被忽视的安全红线。5.4 避坑API 对接常见问题排查现象action_tuling_chat执行后bot 无响应日志显示Connection refused原因图灵 API 域名www.tuling123.com已失效2023 年后该服务停止项目文档未更新。解决替换为免费替代方案如https://open.douyin.com/api/chat需申请抖音开放平台账号或本地部署chatglm模型。现象action_get_weather返回{status:error,status_code:403}原因心知天气 API Key 过期或location参数含空格/特殊字符未 urlencode。解决urllib.parse.quote(location)编码 location如北京→%E5%8C%97%E4%BA%AC。现象rasa shell中调用 action 后bot 重复发送两条相同消息原因dispatcher.utter_message()被调用两次如在try和except中都调用了。解决确保utter_message只在最终逻辑分支中调用一次。现象action_get_weather中tracker.get_slot(location)返回None但用户已说“北京”原因nlu.md中未标注[北京](location)或domain.yml中slots:未定义location为type: text。解决检查domain.yml的slots:部分确保location:下有type: text和auto_fill: true。现象rasa run启动后curl -X POST http://localhost:5005/webhooks/rest/webhook返回 404原因Rasa 1.9.5 的 REST webhook endpoint 是/webhooks/rest/webhook但endpoints.yml中webhook配置错误。解决确认endpoints.yml中rest: # 无需配置Rasa 内置而非webhook:字段。6. 毕设答辩与课程设计交付从模型验证到可演示系统的最后一公里打磨6.1 模型效果量化验证不只是rasa test还要看 confusion matrixrasa test nlu仅输出宏观指标accuracy, f1但答辩时评委可能追问“chit_chat_weather和chit_chat_greeting为什么容易混淆” 此时需生成混淆矩阵rasa test nlu \ --nlu data/nlu.md \ --model models/chitchat_model_20200215_143022.tar.gz \ --out results/nlu \ --successes \ --no-errors生成results/nlu/intent_report.json其中关键字段{ chit_chat_weather: { precision: 0.92, recall: 0.87, f1-score: 0.89, support: 120, confused_with: [chit_chat_greeting: 8, chit_chat_help: 3] } }confused_with显示在 120 条 weather 样例中模型错误预测为 greeting 8 次。此时可导出results/nlu/errors.json人工分析这 8 条样例——往往发现它们含 greeting 词汇如“你好北京天气怎么样”解决方案是在nlu.md中为 weather 意图增加带 greeting 前缀的样例或在config.yml中启用ConstrainSimilarities已启用抑制相似意图的 logits。从那以后我每次提交毕设模型前都强制用rasa test nlu --out results/生成报告并把errors.json中 top3 错误样例截图放进答辩 PPT —— 这比说“准确率很高”有力十倍。6.2 可演示系统包装server.pyindex.html构建免安装前端项目未提供前端但毕设需可演示。最简方案在项目根目录新建index.html!DOCTYPE html p a hrefhttps://download.csdn.net/download/cs1395293598/89385877 stylecolor:#ec7500;font-size:14px; 本文还有配套的精品资源点击获取 /a img altmenu-r.4af5f7ec.gif srchttps://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif stylewidth:16px;margin-left:4px;vertical-align:text-bottom;cursor:text; /p