限时福利领取


背景痛点:传统客服为什么总“答非所问”

去年双十一,公司老客服系统直接“翻车”:用户问“我昨天下的单怎么还没发货”,机器人却回复“请提供订单号”。看似礼貌,实则完全没抓住“催发货”这个意图,更谈不上把“昨天”这个时间实体抽出来。
复盘发现三大硬伤:

  1. 关键词匹配式意图识别,换个说法就失效
  2. 没有上下文记忆,每轮对话都是“陌生人”
  3. 业务系统耦合在代码里,改一句回复就要上线

痛定思痛,我们决定用开源方案重新造轮子,最终选型落在了 Rasa——理由下面慢慢聊。

痛点漫画

技术选型:Rasa 凭啥脱颖而出

先把当时做的打分表搬出来(满分 5 分):

维度 Dialogflow LUIS+BotFram Rasa
数据隐私 2 2 5
中文效果 3 3 4
可定制 2 3 5
费用 2 2 5
社区活跃度 4 3 4

结论简单粗暴:

  1. 数据不出内网,GDPR、等保合规一票否决
  2. 需要深度对接内部 CRM、订单、物流接口,黑盒 SaaS 改不动
  3. 老板批的预算只够买两台 8C16G 云主机

于是 Rasa 成了唯一选项——Python 原生、MIT 协议、可离线训练、组件都能拆,自己改得起。

核心实现一:NLU 模型训练与数据标注

Rasa 把对话拆成 NLU(听懂话)和 Core(会接话)两大块。先搞定“听懂”。

  1. 准备语料
    用 Excel 拉了个模板,三列:text、intent、entities。发给客服小姐姐,按真实聊天记录标注。两周撸出 1.2 万条,覆盖 37 个意图、18 类实体。
    标注规范重点:

    • 意图动词+名词,如 order_cancelshipping_inquiry,别出现 want_to_know_shipping 这种啰嗦写法
    • 实体用 BILOU,同一实体不同表述都标,比如“昨天”“昨晚”全标 date:yesterday
  2. 训练配置
    中文先用 LanguageModelFeaturizer 加载哈工大 LTP,再接 DIETClassifier 联合训练意图+实体。config.yml 关键片段:

language: zh

pipeline:
  - name: JiebaTokenizer
  - name: LanguageModelFeaturizer
    model_name: bert
    model_weights: bert-base-chinese
  - name: DIETClassifier
    epochs: 100
    transformer_size: 256
    batch_size: 64
  1. 交叉验证
    rasa test nlu 一把梭,precision 0.89,recall 0.86,F1 0.87,基本可上线。对误分类样本再喂回去,三轮迭代后 F1 提到 0.91。

核心实现二:用 Rasa Core 设计多轮对话

有了意图,还得让机器人“记得住、聊得动”。Core 负责策略,官方推荐 3.x 新 Rule+Story 双轨制:

  1. Rule 兜底高频单轮
    例如“你好”“谢谢”直接回固定模板,不走复杂模型,省算力。

  2. Story 覆盖多轮
    把客服金牌话术抽象成流程图,再转成 Story 文件。举个例子——用户要改地址:

## shipping_change_address
* shipping_change_address
  - address_form
  - form{"name": "address_form"}
  - form{"name": null}
  - action_query_shipping
  - utter_change_success
  1. Domain 声明 slot
    地址改完写进 slot: delivery_address,后续物流查询节点直接复用,不用再问。

对话流程图

核心实现三:自定义 Action Server 实战

光会聊天不够,还得查订单、调接口、写数据库。Action Server 就是干这个的。

  1. 项目结构
actions/
├── actions.py
├── utils/
│   └── crm.py
└── requirements_actions.txt
  1. 代码示例:查询订单并返回物流状态
import os
import logging
from typing import Any, Dict, List, Text
from rasa_sdk import Action, Tracker
from rasa_sdk.executor import CollectingDispatcher
from actions.utils.crm import get_order_shipping

logger = logging.getLogger(__name__)
# 日志落盘,方便排查
handler = logging.FileHandler("/var/log/rasa/actions.log")
logger.addHandler(handler)

class ActionQueryShipping(Action):
    def name(self) -> Text:
        return "action_query_shipping"

    def run(self,
            dispatcher: CollectingDispatcher,
            tracker: Tracker,
            domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:

        order_id = tracker.get_slot("order_id")
        if not order_id:
            dispatcher.utter_message(text="亲,需要提供订单号哦~")
            return []

        try:
            data = get_order_shipping(order_id)
            status = data.get("status", "unknown")
            dispatcher.utter_message(
                text=f"订单 {order_id} 当前状态:{status}"
            )
            return [SlotSet("shipping_status", status)]
        except Exception as e:
            logger.exception("CRM exception")
            dispatcher.utter_message(text="物流查询开小差了,稍后再试")
            return []
  1. 错误处理要点
    • 任何第三方超时不抛异常,用 asyncio.wait_for 包一层
    • 返回统一错误话术,避免把栈追踪甩给用户
    • 关键节点打日志,order_id 必须可追踪

生产考量:性能、安全两手抓

性能测试与优化

  1. 压测工具:Locust 模拟 300 并发,平均响应 650 ms,95 线 1.2 s,老板嫌慢。
  2. 异步改造:
    • Action Server 用 asyncio 改写 IO 等待,响应降到 280 ms
    • Redis 缓存热点订单,命中率 62%,再减 90 ms
  3. 模型瘦身:
    • DIET transformer_size 从 256 压到 128,F1 掉 0.8%,但推理速度翻倍
    • 开启 rasa shell --productionSANIC_WORKERS=4,8C 机器 CPU 吃到 70%,刚好

安全性设计

  • 输入校验:正则+长度截断,防 SQL 注入和超长攻击
  • 敏感过滤:手机号、身份证用 presidio 打码,日志落盘前脱敏
  • HTTPS & JWT:Action 与业务系统走内网 HTTPS,Header 带 JWT,过期 30 s
  • 限流:Nginx limit_req_zone 每 IP 10 r/s,超频直接 503

避坑指南:那些踩过的坑

  1. 模型版本管理
    最初 git push 把模型文件也传上去,仓库膨胀到 2 G。后来改用 DVC 指向 OSS,只存 model.tar.gz 的指纹,回滚只需 dvc checkout
  2. 对话回退
    用户突然说“不对,我要取消”,记得在 Story 里加 * deny* stop,否则机器人继续追问,体验极差。
  3. 槽位冲突
    日期实体既想存“今天”又想存“2024-06-01”,结果互相覆盖。解决:用 slot_mappingdate_strdate_obj 两个槽,逻辑层再统一格式化。
  4. 中文数字归一化
    “三十七” 得先转成 “37”,再喂给后端。写个 number_normalizecustom_component,否则 CRM 查不到订单。

写在最后

整套流程跑下来,客服机器人上线首周就接住 62% 的咨询量,人工坐席从 24×7 轮班改成白天高峰兜底,省下的预算够我们再开两条产品线。

不过新烦恼也来了:广东用户一句“俾我睇下單嘢”直接让 NLU 原地懵圈——方言识别还没解。你的业务场景里遇到过类似问题吗?都怎么破?欢迎留言一起拆坑。

限时福利领取


Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐