1.4 rasa nlu 传递信息及 REST API 替代 rasa nlu
1.4.1 获取 rasa nlu 传给 rasa core 的响应
开始想在 rasa 内进行拦截,经过测试,难以实现
所以采用接口方式获取
启动 rasa nlu 服务
rasa run --enable-api
请求:
响应:
{
"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 简易版
首先来看一下结果
问:上海明天天气怎么样
再看看流程
首先给 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 了
整个流程是这样的
-
使用 Apipost 发送请求给 Rasa
需要发送一个 POST 请求到 Rasa 的
/model/parse
端点{ "text": "Hello,Hello", "session_id": "user_12345" }
Session ID:这是为了区分不同的用户会话。每个会话可以有独立的上下文和对话状态
我们可以根据需要生成不同的 session_id,比如用用户的 ID 或者生成一个随机字符串
咱们先来看一下接口打通后的样子:
-
配置 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;
-
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 进行处理
-
通过 Apipost 发送请求
使用命令启动 rasa 服务
rasa run -m models --enable-api --cors "*" --debug
成了!全链路打通了,nlu 是 node 处理的,rasa core 主要起到表单的作用,后文也主要涉及多轮对话
END
本文的主要目的是在项目中使用 Node 处理作为 nlu 使用,使用 rasa 自带的 nlu 毕竟控制力会有所减弱,笔者经过尝试终于打通了 nlu 的处理,通过接口传入 rasa,rasa 调用外部 nlu 处理,rasa 处理完成后返回,形成了闭环
标签:nlu,name,rasa,text,REST,weather,intent From: https://www.cnblogs.com/goicandoit/p/18639684