rasa nlu 传递信息及 REST API 替代 rasa nlu

1.4 rasa nlu 传递信息及 REST API 替代 rasa nlu

1.4.1 获取 rasa nlu 传给 rasa core 的响应

开始想在 rasa 内进行拦截,经过测试,难以实现

所以采用接口方式获取

启动 rasa nlu 服务

rasa run --enable-api

请求:

image-20241223201028535

响应:

{
	"text": "今天天气怎么样",
	"intent": {
		"name": "ask_weather",
		"confidence": 0.9999315738677979
	},
	"entities": [],
	"text_tokens": [
		[
			0,
			4
		],
		[
			4,
			7
		]
	],
	"intent_ranking": [
		{
			"name": "ask_weather",
			"confidence": 0.9999315738677979
		},
		{
			"name": "goodbye",
			"confidence": 0.0000572034805372823
		},
		{
			"name": "greet",
			"confidence": 0.0000109441825770773
		},
		{
			"name": "inform",
			"confidence": 2.0421576607532188e-7
		}
	]
}

那么我的 node 服务只需要传递这种类型的响应即可

使用命令启动 rasa core,并且打印日志

rasa run --enable-api --cors "*" --port 5006 --debug

经过实测,需要将 text 改为 message

可以以下面这种格式进行传递

{
  "sender": "user123",
  "message": "今天天气怎么样",
  "intent": "ask_weather",
  "entities": []
}

会收到以下响应

[
	{
		"recipient_id": "user123",
		"text": "你好!我可以帮你查询天气信息。你想查询哪一天的天气?"
	}
]

然而表面上是可行的,实际上依然调用了 rasa nlu,而如何实现只使用 rasa core 呢,请看下文分解

1.4.2 表单初步实现

1.4.2.1 简易版

首先来看一下结果

问:上海明天天气怎么样

image-20241224170819714

再看看流程

image-20241224171641542

首先给 rules.yml 配置

version: "3.1"

rules:
  - rule: 激活 form
    steps:
    - intent: weather
    - action: weather_form
    - active_loop: weather_form

  - rule: 提交 form
    condition:
      # Condition that from is active.
      - active_loop: weather_form
    steps:
      - action: weather_form
      - active_loop: null
      - slot_was_set:
        - requested_slot: null
      # The action we want to run when the form is submitted.
      - action: action_weather_form_submit

然后配置 nlu.yml

version: "3.1"

nlu:
  - intent: weather
    examples: |
      - 我想查一下[北京](address)的天气
      - 帮我看看[上海](address)[明天](date)的天气怎么样
      - 我想知道[广州](address)[后天](date)的天气情况
  - intent: affirm
    examples: |
      - 是的
      - 对呀
      - 没错
  - intent: deny
    examples: |
      - 不是
      - 不对
      - 不用了
  - intent: goodbye
    examples: |
      - 拜拜
      - 再见
      - 下次再聊

再是 config.yml

recipe: default.v1

assistant_id: 20241120-170106-khaki-margarine

language: zh # 改为中文

pipeline: 
  - name: JiebaTokenizer  # 使用支持中文的 Tokenizer
  - name: CountVectorsFeaturizer
    analyzer: "word"  # 基于分词结果生成特征
    min_ngram: 1
    max_ngram: 2
  - name: DIETClassifier
    epochs: 100
  - name: EntitySynonymMapper

# 配置对话管理
policies:
  - name: RulePolicy

domain.yml 也需要配置,这是关键,配置了两个实体,也会在外部动作服务器中用到

目前配置比较简单,其实只用到 weather 这个意图

version: "3.1"

intents:
  - weather
  - affirm
  - deny
  - goodbye

entities:
  - address
  - date

slots:
  # address 插槽,用于存储用户提供的地点
  address:
    type: text
    influence_conversation: false
    mappings:
      - type: from_entity
        entity: address
        not_intent: ["deny", "goodbye"]
        
  # date 插槽,用于存储用户提供的日期/时间
  date:
    type: text
    influence_conversation: false
    mappings:
      - type: from_entity
        entity: date
        not_intent: ["deny", "goodbye"]
        
forms:
  weather_form:
    required_slots:
    - address
    - date

actions:
  - weather_form
  - action_weather_form_submit

session_config:
  session_expiration_time: 60
  carry_over_slots_to_new_session: true

在 action_service.js 相比前文主要加了

else if (actionName === 'action_weather_form_submit') {
        const requestedAddress = tracker.slots.address || "未知地点";
        const requestedDatetime = tracker.slots.date || "未知时间";
        const fallbackMessage = `你想查询${requestedDatetime}${requestedAddress}的天气。那天是多云,温度22°C。`;
        console.log('Fallback Message:', fallbackMessage);
        res.json({
            events: [],
            responses: [{ text: fallbackMessage }]
        });
    }

1.4.2.2 加上实体识别版

再通过接口获取 rasa nlu 给 rasa core 传递的信息,这个例子加上了

{
	"text": "明天北京天气怎么样",
	"intent": {
		"name": "weather",
		"confidence": 0.9994596838951111
	},
	"entities": [
		{
			"entity": "address",
			"start": 2,
			"end": 4,
			"confidence_entity": 0.9538565278053284,
			"value": "北京",
			"extractor": "DIETClassifier",
			"processors": [
				"EntitySynonymMapper"
			]
		}
	],
	"text_tokens": [
		[
			0,
			2
		],
		[
			2,
			4
		],
		[
			4,
			6
		],
		[
			6,
			9
		]
	],
	"intent_ranking": [
		{
			"name": "weather",
			"confidence": 0.9994596838951111
		},
		{
			"name": "goodbye",
			"confidence": 0.0003240504302084446
		},
		{
			"name": "deny",
			"confidence": 0.00021139439195394516
		},
		{
			"name": "affirm",
			"confidence": 0.000004957571491104318
		}
	]
}

可以看到使用 nlu 识别的并不是很好,那么现在是时候使用外部接口处理 nlu 了

整个流程是这样的

  1. 使用 Apipost 发送请求给 Rasa

    需要发送一个 POST 请求到 Rasa 的 /model/parse 端点

    {
      "text": "Hello,Hello",
      "session_id": "user_12345"
    }
    

    Session ID:这是为了区分不同的用户会话。每个会话可以有独立的上下文和对话状态

    我们可以根据需要生成不同的 session_id,比如用用户的 ID 或者生成一个随机字符串

    咱们先来看一下接口打通后的样子:

    image-20241229172418569
  2. 配置 NLU 模块调用外部服务

    这里需要注意,虽然在 endpoints.yml 中给的是

    nlu:
      url: "http://127.0.0.1:5002/toRasa"
    

    但是在外部服务中接口需要配置 toRasa/model/parse

    我在 node 中就需要这样配置

    const toRasaModelRouter = require('./routes/toModelRasa');
    app.use('/toRasa/model/parse', toRasaModelRouter);
    

    toModelRasa.js 代码如下,目前是写死测试的

    const express = require('express');
    const axios = require('axios');
    const router = express.Router();
    require('dotenv').config();
    
    // 路由处理器
    router.post('/', async (req, res) => {
        try {
            const { text } = req.body;
    
            if (!text) {
                return res.status(400).json({ error: 'Missing "text" in request body.' });
            }
    
            // 处理意图识别结果
            let intent = 'weather';  // 硬编码为 "weather"
            const intentConfidence = 1.0;
    
            // 处理实体识别结果,硬编码两个实体
            const entities = [
                {
                    entity: 'address',
                    value: '北京',
                    start: text.indexOf('北京'),
                    end: text.indexOf('北京') + '北京'.length
                },
                {
                    entity: 'date',
                    value: '明天',
                    start: text.indexOf('明天'),
                    end: text.indexOf('明天') + '明天'.length
                }
            ];
    
            // 构建 Rasa 所需的 JSON 格式
            const rasaPayload = {
                text: text,
                intent: {
                    name: intent,
                    confidence: intentConfidence
                },
                entities: entities
            };
    
            console.log("Constructed rasaPayload:", rasaPayload);
    
            // 将 Rasa 的响应返回给客户端
            res.json(rasaPayload);
        } catch (error) {
            console.error('Error in /toRasa:', error.message);
            res.status(500).json({ error: 'Internal Server Error' });
        }
    });
    
    module.exports = router;
    
  3. Rasa Core 处理

    rasa nlu 因为不处理了,所以 config.yml 进行了修改

    pipeline:
      - name: "WhitespaceTokenizer"
      - name: "RegexFeaturizer"
      - name: "CountVectorsFeaturizer"
      - name: "LexicalSyntacticFeaturizer"
      - name: "ResponseSelector"
        epochs: 50
      - name: "FallbackClassifier"
        threshold: 0.3
        ambiguity_threshold: 0.1
    

    rasa 得到 nlu 的处理结果后,会将这些信息传递给 Rasa Core

    在当前例子中就是 RulePolicy 进行处理

  4. 通过 Apipost 发送请求

使用命令启动 rasa 服务

rasa run -m models --enable-api --cors "*" --debug
image-20241229215137283

成了!全链路打通了,nlu 是 node 处理的,rasa core 主要起到表单的作用,后文也主要涉及多轮对话

END

本文的主要目的是在项目中使用 Node 处理作为 nlu 使用,使用 rasa 自带的 nlu 毕竟控制力会有所减弱,笔者经过尝试终于打通了 nlu 的处理,通过接口传入 rasa,rasa 调用外部 nlu 处理,rasa 处理完成后返回,形成了闭环

posted @   goicandoit  阅读(36)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示