假如你想开一家“AI 智能餐厅”,每天迎来送往成百上千位顾客。你可以把后厨整体外包给大型连锁中央厨房——这就像直接调用大模型 API,省事但菜单不可控、客人数据全存在别人仓库里。而 Rasa 的选择,是给你一套完整开源、可私有化部署的“对话餐厅经营方案”。 在这家餐厅里,前台服务员负责听懂顾客想干什么(NLU 意图识别),顺手在小本子上记下“大杯、冰、拿铁”这些细节(实体提取);后厨按标准菜谱出餐(故事与规则);遇到特殊需求,就由值班厨师现场开火定制(自定义 Action);餐厅经理则拿着一块大白板,记下每位客人吃到哪一步,再决定下一步该上菜、催单还是结账(对话追踪与策略选择)。 这篇文章会带你从零认识 Rasa:它像开餐厅一样,把“听——记——想——做”拆成清晰模块。学完后你会明白,为什么越来越多企业做智能客服时选择 Rasa 而不是直接裸调大模型 API,也会敢于动手规划自己的第一个任务型聊天机器人。

岗位关联

学习 Rasa 能让你掌握任务型对话系统从数据准备、模型训练到业务集成的完整工程链路——这是大模型 API 调用替代不了的可控、可审计、可私有化的企业级核心能力。

目录
  1. 可视化演示
  2. Rasa 框架定位优势
  3. NLU 意图识别
  4. 实体槽位提取
  5. 故事规则管理
  6. 自定义动作
  7. 策略追踪管理
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

动态演示Rasa开源对话系统架构与开的核心机制,通过总览/传输/转换/输出四种模式展示关键概念与交互流程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

Rasa开源对话系统架构与开:Rasa Rasa开源对话系统架构概览 NLU意图识别与实体提取 核心机制可视化 Rasa开源对话系统架构与开整体架构与关键组件

Rasa 框架定位优势

开餐厅的第一步不是急着买菜,而是先定经营模式。Rasa 提供的就是一套“自建后厨”的方案:开源免费,源码全在手里;可以私有化部署,顾客数据不出自己的机房;模块化设计,让你能像搭积木一样组装对话机器人。它不像闭源大模型 API 那样把“脑子”放在别人服务器上,而是把完整的“大脑”搬到你家店里。

从技术视角看,Rasa 是一个基于 Python 的任务型对话系统框架。它把系统一分为二:NLU(自然语言理解)模块负责“听懂”,相当于前台服务员;Core 对话管理模块负责“想清楚下一步做什么”,相当于后厨调度和经理决策。两者通过 domain.yml 中的意图、实体、槽位和动作声明连接起来,形成一个可训练、可测试、可部署的完整闭环。

这套“前台听、后厨想”的架构,让餐厅可以随时调整菜单而不用换服务员,也可以换一套更聪明的服务员而不必拆掉后厨——这就是 Rasa 模块化设计的核心价值。

(intent,entities)=NLU(x)a=Policy(St)\begin{aligned}(\text{intent}, \text{entities}) &= \text{NLU}(x) \\a &= \text{Policy}(S_t)\end{aligned}
这个式子告诉你整个系统的核心分工:用户一句话先进 NLU 拆成“意图+实体”,再由对话策略根据当前状态决定接下来执行什么动作。
  1. NLU 解析x 是用户原始文本,比如“帮我查一下订单”,NLU 模块将它拆成结构化信息:意图 query_order,实体可能是空。
    (intent,entities)=NLU(x)(\text{intent}, \text{entities}) = \text{NLU}(x)
  2. 策略决策S_t 是当前对话状态(包括用户说了什么、槽位填了什么),策略模块从所有候选动作中选出 a。
    a=Policy(St)a = \text{Policy}(S_t)

NLU 意图识别

服务员上岗的第一课,是听懂顾客“想干什么”:顾客说“来个招牌菜”,这是“点餐”;说“我的菜怎么还没来”,这是“催菜”;说“买单”,这是“结账”。在 Rasa 中,这个过程叫意图识别——本质是一个文本分类任务,把一句话归到预设好的类别里。

开发者需要先在 NLU 训练数据(如 nlu.yml)中为每个意图准备若干示例句子,例如:

然后通过 config.yml 配置 NLU 管道:分词器把句子切成词,特征化器把词变成向量,分类器(如 DIETClassifier)在这些向量上学习意图边界。训练完成后,模型对每句新输入算出每个意图的概率。

服务员听到顾客说“查订单”,大脑里把“点餐”“催菜”“结账”这些意向都快速过了一遍,最终确定“催菜”的把握最大——这就是意图分类。Rasa 还会输出置信度(如 0.87),当所有意图的概率都不高时,它会触发回退机制,让服务员礼貌地说:“不好意思,我没听清,您再说一遍?”

P(ci∣x)=exp⁡(zi)∑j=1Cexp⁡(zj)\displaystyle P(c_i | x) = \frac{\exp(z_i)}{\sum_{j=1}^{C} \exp(z_j)}
这是 Softmax 公式:把分类器对每个意图的原始打分变成一组和为 1 的概率,得分最高的意图就是最终预测。
  1. 原始分数分类器给每个意图 i 打一个分数 z_i,分数越高表示越像这个意图。
    ziz_i
  2. 指数放大exp 会把负分变成接近 0 的正数、正分变得更大,拉开意图之间的差距。
    exp⁡(zi)\exp(z_i)
  3. 归一化除以所有意图的指数之和,把结果压到 0 到 1 之间,变成可以比较的概率。
    ∑j=1Cexp⁡(zj)\sum_{j=1}^{C} \exp(z_j)
yaml5 行
- intent: query_order  examples: |    - 我的订单到哪了    - 帮我查一下快递    - 订单状态是什么

实体槽位提取

光知道顾客“想点餐”还不够,你还得知道他想点什么、要几杯、加不加冰。这就要靠实体提取:从句子中抽取出具体的业务信息。比如“来两杯冰美式”,意图是 order_drink,实则是“美式”(饮品名)、“两杯”(数量)、“冰”(温度偏好)。

在 Rasa 中,实体通过训练数据标注来教会模型识别。最常用的标注格式是 BIO:B 表示实体开始,I 表示实体中间,O 表示非实体。模型学到的是:某个词的上下文让它属于哪类实体。提取到的实体并不会自动产生作用,它们要放进“槽位”(slot)——就像服务员把小纸条贴到顾客对应的白板格子里。

服务员把“两杯”“冰”“美式”三个小纸条分别贴进数量、温度、饮品三个槽位格子——顾客下次再说“改成热的”,模型只用更新“温度”这一格就行。槽位是对话状态的临时记忆,不是数据库,对话结束或被重置后就会清空。

Y∗=arg⁡max⁡Y∏t=1TP(yt∣x1,…,xT)\displaystyle Y^* = \arg\max_Y \prod_{t=1}^{T} P(y_t | x_1, \dots, x_T)
这是序列标注的决策公式:模型为句子里的每个词挑选一个标注(B/I/O),让整句话的标注序列概率最大。
  1. 逐词标注对输入句子 x_1 到 x_T,每个词 x_t 都对应一个标签 y_t,如 B-drink、I-drink、O。
    P(yt∣x1,…,xT)P(y_t | x_1, \dots, x_T)
  2. 连乘求整体把每个词标签的概率连乘,得到整句标注序列的概率。
    ∏t=1TP(yt∣x1,…,xT)\prod_{t=1}^{T} P(y_t | x_1, \dots, x_T)
  3. 选最优序列argmax 表示在所有可能的标注序列中,挑概率最大的那个作为最终结果。
    arg⁡max⁡Y\arg\max_Y

故事规则管理

有了前台理解和细节记录,餐厅还需要一套“服务流程手册”:客人进门先引导入座,然后递菜单,点完餐确认一遍,上菜后询问口味,最后引导结账。Rasa 中的“故事”(stories)干的就是这件事——把典型的对话路径按顺序写下来,让模型学会“什么时候该做什么”。

故事文件 stories.yml 的写法像一条流水账:

规则(rules)则负责那些不可商量的硬逻辑:比如用户要求取消订单,无论如何都必须先验证身份。在 Rasa 中,Rule Policy 的优先级高于学习式策略,保证规则被严格执行。除此之外,还需要设计回退处理(Fallback):当用户输入含糊不清或置信度太低时,机器人不硬猜,而是主动追问。

故事好比“常规情况怎么走”,规则好比“红线必须怎么走”,回退则是“走不通时怎么绕”。有了这三层,餐厅即使在客流高峰期也不会乱套。

St+1=f(St,ut,at)\displaystyle S_{t+1} = f(S_t, u_t, a_t)
这句公式描述对话状态如何一步步推进:旧的“白板状态”加上这一轮的用户输入和机器人动作,共同得出下一个状态。
  1. 旧状态S_t 表示进入本轮前,白板上已经记录的槽位和对话历史。
    StS_t
  2. 两个输入u_t 是本轮用户的消息,a_t 是机器人刚执行的动作。
    (ut,at)(u_t, a_t)
  3. 状态推进f 是更新函数,由追踪器完成,新状态 S_{t+1} 覆盖旧状态。
    St+1=f(St,ut,at)S_{t+1} = f(S_t, u_t, a_t)
yaml7 行
stories:- story: 点餐主流程  steps:  - intent: greet  - action: utter_greet  - intent: order_drink  - action: action_confirm_order

自定义动作

故事和规则能覆盖标准路径,但真实业务总有“现场发挥”:顾客问“我的订单到哪了”,机器人不能只是背一句台词,它得真的去查订单系统,再把结果告诉顾客。这就引出了自定义动作(Custom Action):编写 Python 类继承 Action,在 run() 方法里写业务逻辑。

一个典型的动作流程是:从追踪器里取出顾客的订单号(从槽位拿),调用外部订单 API 查询状态,拿到结果后拼成一句自然语言回复。动作写好后,要在服务端注册并告诉 Rasa:“当策略选择了 action_query_order 时,去调用这个 Python 方法。”这样,机器人就从“背台词”进化成了“真办事”。

厨师拿到订单小票(槽位),转身查一眼备货系统(API),回来告诉顾客“您的拿铁正在制作中”——这就是自定义动作在真实场景中的价值:让对话系统真正连上业务,而不只是聊天。

response=Action(St,API_result)\displaystyle \text{response} = \text{Action}(S_t, \text{API\_result})
这个式子表达自定义动作的本质:输入当前对话状态和外部接口返回结果,输出给用户看的最终回复。
  1. 取状态动作从 S_t 中取出槽位值,例如 order_id = "A1024"。
    StS_t
  2. 调接口把订单号传给外部系统,拿到 API_result 如“已发货”。
    API_result\text{API\_result}
  3. 生成回复把状态和外部结果拼成自然语言,作为 response 返回。
    response=Action(St,API_result)\text{response} = \text{Action}(S_t, \text{API\_result})

策略追踪管理

餐厅经理的白板是整个餐厅运转的中枢:每位客人吃到哪一步、有哪些忌口、还需要等多久,全都记在上面。Rasa 中对应的是 Dialogue State Tracker(对话状态追踪器),它把用户输入、槽位变化、历史动作全部汇总成当前状态向量;而 Policy(策略)则根据这个状态决定下一步动作。

Rasa 提供了多种策略:Rule Policy 严格执行规则,TED Policy 从故事中学习柔性决策,Memoization Policy 记住完全相同的对话历史。多个策略同时参与投票,最终选出得分最高的动作。还有一道保险:当所有候选动作的置信度都低于设定阈值(如 0.7)时,触发 Fallback 回退,让机器人主动澄清。

经理看一眼白板,发现顾客已经点完餐但还没付款,于是决定下一步是“提醒结账”而不是“继续推荐甜点”。这就是策略的价值——每个决策都基于当前状态,而不是盲目背流程。

at=arg⁡max⁡a∈Aπ(a∣St)\displaystyle a_t = \arg\max_{a \in A} \pi(a | S_t)
策略决策公式:在所有可执行的动作集合 A 中,挑选当前状态下概率最高的那个动作。
  1. 候选动作集A 是所有可执行动作,如 utter_greet、action_query_order、action_confirm_order 等。
    AA
  2. 策略评估π(a | S_t) 表示在状态 S_t 下选择动作 a 的概率。
    π(a∣St)\pi(a | S_t)
  3. 选最高argmax 挑出概率最大的动作作为本轮输出。
    at=arg⁡max⁡a∈Aπ(a∣St)a_t = \arg\max_{a \in A} \pi(a | S_t)

AI 应用场景

电商智能客服订单查询

阶段:NLU 意图识别 → 实体槽位提取 → 自定义 Action → 外部 API 集成

解决的问题:传统客服依赖人工反复查询订单系统,高峰时段响应慢、成本高。用 Rasa 搭建后,用户发一句“我的快递到哪了”,NLU 识别出 query_order 意图,实体提取拿到订单号,自定义 Action 直接查询物流 API 并返回实时状态。整个过程无需人工介入,且数据完全在企业内网流转。

具体案例:某电商平台用 Rasa 搭建售中机器人。用户消息先进 NLU 管道,意图 query_order 命中置信度 0.9;槽位 order_id 被填入“JD1024“;策略选择 action_query_order;动作调用内部订单服务,返回”您的订单已从上海分拨中心发出”。整个链路耗时不到 800 毫秒,大幅减轻人工客服压力。

银行理财业务引导助手

阶段:故事规则管理 → 表单逻辑 → 多轮对话 → 策略回退

解决的问题:银行业务流程复杂,用户往往说不清自己需要什么。Rasa 可以通过 Form 表单逐步收集信息:先问风险偏好,再问投资金额,再问期限偏好,每轮只问一个关键问题。回答不清晰时触发回退机制,重新引导;敏感操作则用规则强制二次确认,满足合规要求。

具体案例:某银行在手机 App 中嵌入 Rasa 理财助手。用户说“我想买点稳健的理财”,助手确认风险等级(实体:稳健)、金额(实体:五万)、期限(实体:一年)后生成推荐方案;期间用户答非所问,模型置信度低于阈值,自动触发澄清追问,确保信息完整后再推进。

Python 演示

python38 行
"""Rasa 自定义动作:餐厅点餐助手查询订单状态"""from typing import Any, Text, Dict, Listfrom rasa_sdk import Action, Trackerfrom rasa_sdk.executor import CollectingDispatcher  class ActionQueryOrder(Action):    """查询用户订单状态并回复"""     def name(self) -> Text:        return "action_query_order"     def run(        self,        dispatcher: CollectingDispatcher,        tracker: Tracker,        domain: Dict[Text, Any],    ) -> List[Dict[Text, Any]]:        # 1. 从对话追踪器的槽位中取出订单号        order_id = tracker.get_slot("order_id")         # 2. 缺少订单号则追问        if not order_id:            dispatcher.utter_message(text="请问您的订单号是多少?")            return []         # 3. 调用外部 API 查询状态        status = self._query_api(order_id)         # 4. 把查询结果回复给用户        dispatcher.utter_message(            text="您的订单 {} 当前状态:{}".format(order_id, status)        )        return []     def _query_api(self, order_id: str) -> str:        """模拟外部订单系统接口,实际可换成 requests.get"""        return "已发货,正在派送中"
目的:演示 Rasa 自定义 Action 的完整写法——从追踪器槽位取数据、调用外部业务接口、再把结果通过 dispatcher 回复给用户。
  1. class ActionQueryOrder(Action):定义一个自定义动作类,必须继承 Action 基类,Rasa 才能识别它。
  2. def name(self) -> Text:返回动作的唯一标识名,这个名称要能和 domain.yml、故事文件中的引用对应上。
  3. tracker.get_slot("order_id")从对话追踪器中读取当前会话的槽位值,也就是之前 NLU 提取得的“订单号”。
  4. if not order_id:如果槽位为空,说明用户还没提供订单号,需要主动追问而不是硬查。
  5. dispatcher.utter_message(...)把自然语言回复发送给用户,这是动作输出的标准方式。
  6. return []返回事件列表,空列表表示本轮没有需要额外修改槽位的事件。
  7. self._query_api(order_id)调用封装的业务函数,真实场景中这里可以替换为 requests.get 等 HTTP 调用。
  8. "已发货,正在派送中"模拟外部 API 的返回结果,实际开发中这里是供应商系统的实时数据。

常见误区

误区朋友听说我在学 Rasa,问我“那你是不是能让它像 ChatGPT 一样写诗、讲笑话、聊人生?”我说当然可以,结果试了发现根本不是那么回事。

正解Rasa 定位是“任务型对话框架”,擅长的是点餐、查订单、办业务这类目标明确的场景。它不会像大模型那样自由生成内容,更适合用预定义的回复模板和自定义动作完成任务。想要闲聊,需要接入额外的生成式模型;想要办业务,Rasa 才是可控高效的选择。

为何常见:人们听到“对话系统”就自然联想到智能陪聊机器人,忽略了任务型与生成式两种技术路线的根本区别。

误区“现在大模型都能零样本学习了,Rasa 是不是把意图说一遍就能用?”于是连标注语料都不写,直接跑模型,结果意图识别一塌糊涂。

正解Rasa 的 NLU 属于监督学习,每个意图至少需要 5-10 句典型表达,实体更需要逐词标注。故事文件要覆盖核心流程和分支路径。训练数据质量和数量直接决定对话效果。这就像餐厅的新服务员,必须经过菜单培训和场景演练才能上岗。

为何常见:大模型的少样本/零样本能力给人造成“标注数据已死”的错觉,但工程级 NLU 仍以监督学习为主。

误区“槽位不就是存用户信息的吗?那用户上次说喜欢喝美式,这次进来我直接按美式推荐就行。”结果槽位早就被清空了,推荐全乱套。

正解槽位是对话级临时记忆,服务于当前会话的上下文理解。每次新对话开始时,槽位通常会被重置。需要跨会话持久化的信息(如用户偏好画像)应存入外部数据库,在动作中主动读取。这就像服务员的白板,客人离开后会被擦干净,而不是永久存档。

为何常见:槽位概念的“存储”特性容易让人联想成数据库,忽略了它的生命周期边界。

误区“多写几百万条故事,把各种对话路径都覆盖到,机器人总该聪明了吧?”结果训练时间暴涨,模型反而互相冲突,效果变差。

正解故事文件讲究质量和覆盖度,而非数量。重复冗余的故事会让策略模型无所适从。应该围绕核心业务路径精心设计故事,用规则处理强约束路径,用回退处理未知情况。这就像菜谱不在多,把招牌菜做精才是餐厅立身之本。

为何常见:“数据越多模型越好”作为直觉在大数据时代深入人心,但在对话流程设计上,结构化和冲突消解比一味堆量重要得多。

面试题

Q1. Rasa 框架的两大核心模块分别是什么?

单选题 · easy

  • A.NLU 与对话管理← 正确答案
  • B.TTS 与语音识别
  • C.ASR 与机器翻译
  • D.分词与词性标注

答案:A。Rasa 的核心是 NLU(自然语言理解)负责听懂用户的意图和实体,对话管理(Core)负责决定下一步动作。就像餐厅的前台服务生和后厨调度,各管一段。B/C/D 分别属于语音合成、语音识别、NLP 基础工具,都不是 Rasa 的两大核心。

Q2. 在 Rasa 中,负责记录当前对话状态的组件是哪一个?

单选题 · easy

  • A.对话状态追踪器← 正确答案
  • B.模型训练数据集
  • C.配置文件解析器
  • D.日志收集处理器

答案:A。对话追踪器(Tracker)像餐厅经理的白板,记录槽位、历史用户消息、历史动作。训练数据、配置、日志都不承担运行时状态记录。理解追踪器是理解 Rasa 对话管理的第一步。

Q3. 以下哪些组件通常属于 Rasa NLU 管道的一部分?

多选题 · mid

  • A.分词器组件← 正确答案
  • B.特征化器组件← 正确答案
  • C.意图分类器组件← 正确答案
  • D.对话策略组件

答案:ABC。NLU 管道从原始文本出发,依次经过分词、特征化、意图分类和实体识别。对话策略属于 Core 对话管理模块,负责决策动作,不属于 NLU 管道。就像服务员的前台工作不包含经理的调度职责。

Q4. 用户说“帮我订一个双人套餐”,其中“双人套餐”在 Rasa 中应被识别为?

单选题 · easy

  • A.用户意图
  • B.实体对象← 正确答案
  • C.系统动作
  • D.策略选择

答案:B。“订套餐”才是意图(想做什么),“双人套餐”是实体(具体信息)。实体会被填入槽位供后续动作使用。类比:顾客说“来两份牛排”,“点餐”是意图,“两份”“牛排”是实体。

Q5. 编写 Rasa 自定义动作时,必须继承的基类是?

单选题 · mid

  • A.Action 类← 正确答案
  • B.Tracker 类
  • C.NLU 模型类
  • D.Dispatcher 类

答案:A。自定义动作需要继承 Action 基类并实现 name() 和 run() 方法。Tracker 是读取状态的对象,Dispatcher 是发送消息的工具,它们都不是基类。就像厨师要遵循后厨标准流程,而不是把自己当成传菜员。

Q6. 当用户输入置信度低于设定阈值时,Rasa 通常会触发哪种机制?

单选题 · mid

  • A.Fallback 回退← 正确答案
  • B.无限次重试动作
  • C.忽略该条消息
  • D.重启对话服务

答案:A。低置信度时 Rasa 触发 Fallback 回退,让机器人主动澄清“没听清,请再说一遍”。这与服务员听不清顾客点单时的反应一致,而不是假装听懂或一遍遍硬猜。

Q7. 在 Rasa 中,以下哪个文件用于定义故事(典型对话流程)?

单选题 · mid

  • A.stories.yml← 正确答案
  • B.nlu.yml
  • C.domain.yml
  • D.config.yml

答案:A。stories.yml 定义故事,记录“用户说什么→机器人做什么”的典型路径;nlu.yml 是意图和实体训练数据;domain.yml 声明意图、动作、槽位;config.yml 配置 NLU 管道与策略。四者分工明确。

Q8. 下列关于 Rasa 规则的描述,说法正确的是?

单选题 · mid

  • A.规则通常优先于学习式策略← 正确答案
  • B.规则必须从训练数据中学习
  • C.规则只能处理单轮对话
  • D.规则与故事完全等价

答案:A。Rule Policy 定义的规则会覆盖 TED Policy 等学习式策略,保证硬性逻辑必须执行。规则不需要学习,是开发者手写的“铁律”;它可以处理多轮对话(比如先验证身份再取消订单);故事是柔性路径,规则是刚性约束。

Q9. 关于 Rasa 槽位机制的描述,哪些是正确的?

多选题 · hard

  • A.槽位用于保存当前对话上下文← 正确答案
  • B.槽位可在自定义动作中修改← 正确答案
  • C.槽位等同于数据库持久表
  • D.槽位可用于表单信息校验← 正确答案

答案:ABD。槽位是对话级临时记忆,动作中可以通过事件修改;表单(Form)通过槽位收集并校验信息。C 错误:槽位不是持久化数据库,对话结束后会重置。类比服务员的白板,客人离场即擦除。

Q10. 当 Rasa 的 NLU 同时识别出两个高置信度意图,但均低于 0.7 阈值时,系统会如何反应?

单选题 · hard

  • A.选置信度最高的意图
  • B.触发 Fallback 回退← 正确答案
  • C.随机挑一个意图
  • D.两个意图都尝试

答案:B。Rasa 判断标准是阈值而非相对高低:所有意图都低于阈值,说明模型“没把握”,触发回退让用户澄清。这就像服务员对“来那个”“随便”这类模糊点单,宁可追问也不要猜错,避免上错菜反而更麻烦。