如何在网络聊天中添加多轮提示?
How can I add the multi-turn prompt in the webchat?
我在我的 qna 中添加了多轮提示,它们在 qna 网站上工作,但是在网络聊天中尝试时,提示没有出现。
他们在网络聊天中工作吗?
如果您想像 QnA 测试门户那样将结果显示为卡片,则需要将结果转换为自适应卡片。请参阅下面的代码片段。
截图
机器人代码 - onMessage - 节点
this.onMessage(async (context, next) => {
const qnaResults = await this.qnaMaker.getAnswers(context);
if (qnaResults[0]) {
const { answer, context: { prompts }} = qnaResults[0];
let reply;
if (prompts.length) {
const card = {
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"text": answer,
wrap: true
}
],
"actions": prompts.map(({ displayText }) => ({ type: "Action.Submit", title: displayText, data: displayText })),
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.1"
}
reply = { attachments: [CardFactory.adaptiveCard(card)] };
} else {
reply = answer;
}
await context.sendActivity(reply);
// If no answers were returned from QnA Maker, reply with help.
} else {
await context.sendActivity('No QnA Maker answers were found.');
}
await next();
});
}
希望对您有所帮助!
我已经回答了这个here。
基本上,您需要构建自己的对 QnA Maker 知识库的 HTTP 调用,而不是按照 this:
使用内置方法
public async Task<QnAResult[]> QueryQnAServiceAsync(string query, QnABotState qnAcontext)
{
var requestUrl = $"{_endpoint.Host}/knowledgebases/{_endpoint.KnowledgeBaseId}/generateanswer";
var request = new HttpRequestMessage(HttpMethod.Post, requestUrl);
var jsonRequest = JsonConvert.SerializeObject(
new
{
question = query,
top = _options.Top,
context = qnAcontext,
strictFilters = _options.StrictFilters,
metadataBoost = _options.MetadataBoost,
scoreThreshold = _options.ScoreThreshold,
}, Formatting.None);
request.Headers.Add("Authorization", $"EndpointKey {_endpoint.EndpointKey}");
request.Content = new StringContent(jsonRequest, System.Text.Encoding.UTF8, "application/json");
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var contentString = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<QnAResultList>(contentString);
return result.Answers;
}
然后检查结果是否有任何提示,并采取相应措施:
var query = inputActivity.Text;
var qnaResult = await _qnaService.QueryQnAServiceAsync(query, new QnABotState());
var qnaAnswer = qnaResult[0].Answer;
var prompts = qnaResult[0].Context?.Prompts;
if (prompts == null || prompts.Length < 1)
{
outputActivity = MessageFactory.Text(qnaAnswer);
}
else
{
outputActivity = CardHelper.GetHeroCard(qnaAnswer, prompts);
}
await turnContext.SendActivityAsync(outputActivity);
注意: 以上 "acting accordingly" 的代码仅适用于单级提示,根据我在顶部链接的回答。如果您想支持多级提示,那么您必须按照 this sample 实施状态系统 - 请参阅我的其他答案 here 了解更多详情。
注意 2: 正如下面评论中提到的,如果文本太长,使用上述方法 (HeroCard) 可能会导致标题被截断。为避免这种情况,您可以使用 Adaptive Dialogs or Adaptive Cards.
编辑
你应该可以通过这样的方式实现单级提示:
QnAResult.cs
public class QnAResult
{
public string[] Questions { get; set; }
public string Answer { get; set; }
public double Score { get; set; }
public int Id { get; set; }
public string Source { get; set; }
public QnAMetadata[] Metadata { get; set; }
public QnAContext Context { get; set; }
}
QnAResultList.cs
public class QnAResultList
{
public QnAResult[] Answers { get; set; }
}
IQnAService.cs
public interface IQnAService
{
Task<QnAResult[]> QueryQnAServiceAsync(string query, QnABotState qnAcontext, QnAMakerEndpoint qnAMakerEndpoint);
}
QnAService.cs
public class QnAService : IQnAService
{
private readonly HttpClient _httpClient;
private readonly IConfiguration _configuration;
public QnAService(HttpClient httpClient, IConfiguration configuration)
{
_httpClient = httpClient;
_configuration = configuration;
}
public async Task<QnAResult[]> QueryQnAServiceAsync(string query, QnABotState qnAcontext, QnAMakerEndpoint qnAMakerEndpoint)
{
var options = new QnAMakerOptions
{
Top = 3
};
var hostname = qnAMakerEndpoint.Host;
var endpoint = new QnAMakerEndpoint
{
KnowledgeBaseId = qnAMakerEndpoint.KnowledgeBaseId,
EndpointKey = qnAMakerEndpoint.EndpointKey,
Host = hostname
};
var requestUrl = $"{endpoint.Host}/knowledgebases/{endpoint.KnowledgeBaseId}/generateanswer";
var request = new HttpRequestMessage(HttpMethod.Post, requestUrl);
var jsonRequest = JsonConvert.SerializeObject(
new
{
question = query,
top = options.Top,
context = qnAcontext,
strictFilters = options.StrictFilters,
metadataBoost = options.MetadataBoost,
scoreThreshold = options.ScoreThreshold,
}, Formatting.None);
request.Headers.Add("Authorization", $"EndpointKey {endpoint.EndpointKey}");
request.Content = new StringContent(jsonRequest, System.Text.Encoding.UTF8, "application/json");
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var contentString = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<QnAResultList>(contentString);
return result.Answers;
}
}
CardHelper.cs
public class CardHelper
{
/// <summary>
/// Get Hero card
/// </summary>
/// <param name="cardTitle">Title of the card</param>
/// <param name="prompts">List of suggested prompts</param>
/// <returns>Message activity</returns>
public static Activity GetHeroCardWithPrompts(string cardTitle, QnAPrompts[] prompts)
{
var chatActivity = Activity.CreateMessageActivity();
var buttons = new List<CardAction>();
var sortedPrompts = prompts.OrderBy(r => r.DisplayOrder);
foreach (var prompt in sortedPrompts)
{
buttons.Add(
new CardAction()
{
Value = prompt.DisplayText,
Type = ActionTypes.ImBack,
Title = prompt.DisplayText
});
}
var plCard = new HeroCard()
{
Title = cardTitle,
Subtitle = string.Empty,
Buttons = buttons
};
var attachment = plCard.ToAttachment();
chatActivity.Attachments.Add(attachment);
return (Activity)chatActivity;
}
}
MyBot.cs HandleQnA()
QnAResult[] qnaResults = await _qnAService.QueryQnAServiceAsync(context.Activity.Text, new QnABotState(), _qnAMakerEndpoint);
if (qnaResults.Any())
{
// Get result by highest confidence
QnAResult highestRankedResult = qnaResults.OrderByDescending(x => x.Score).First();
string answer = highestRankedResult.Answer;
QnAPrompts[] prompts = highestRankedResult.Context?.Prompts;
if (prompts == null || prompts.Length < 1)
{
await context.SendActivityAsync(answer, cancellationToken: cancellationToken);
}
else
{
await context.SendActivityAsync(CardHelper.GetHeroCardWithPrompts(answer, prompts), cancellationToken: cancellationToken);
}
}
我使用的 NuGet 包是:
我在我的 qna 中添加了多轮提示,它们在 qna 网站上工作,但是在网络聊天中尝试时,提示没有出现。
他们在网络聊天中工作吗?
如果您想像 QnA 测试门户那样将结果显示为卡片,则需要将结果转换为自适应卡片。请参阅下面的代码片段。
截图
机器人代码 - onMessage - 节点
this.onMessage(async (context, next) => {
const qnaResults = await this.qnaMaker.getAnswers(context);
if (qnaResults[0]) {
const { answer, context: { prompts }} = qnaResults[0];
let reply;
if (prompts.length) {
const card = {
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"text": answer,
wrap: true
}
],
"actions": prompts.map(({ displayText }) => ({ type: "Action.Submit", title: displayText, data: displayText })),
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.1"
}
reply = { attachments: [CardFactory.adaptiveCard(card)] };
} else {
reply = answer;
}
await context.sendActivity(reply);
// If no answers were returned from QnA Maker, reply with help.
} else {
await context.sendActivity('No QnA Maker answers were found.');
}
await next();
});
}
希望对您有所帮助!
我已经回答了这个here。
基本上,您需要构建自己的对 QnA Maker 知识库的 HTTP 调用,而不是按照 this:
使用内置方法public async Task<QnAResult[]> QueryQnAServiceAsync(string query, QnABotState qnAcontext)
{
var requestUrl = $"{_endpoint.Host}/knowledgebases/{_endpoint.KnowledgeBaseId}/generateanswer";
var request = new HttpRequestMessage(HttpMethod.Post, requestUrl);
var jsonRequest = JsonConvert.SerializeObject(
new
{
question = query,
top = _options.Top,
context = qnAcontext,
strictFilters = _options.StrictFilters,
metadataBoost = _options.MetadataBoost,
scoreThreshold = _options.ScoreThreshold,
}, Formatting.None);
request.Headers.Add("Authorization", $"EndpointKey {_endpoint.EndpointKey}");
request.Content = new StringContent(jsonRequest, System.Text.Encoding.UTF8, "application/json");
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var contentString = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<QnAResultList>(contentString);
return result.Answers;
}
然后检查结果是否有任何提示,并采取相应措施:
var query = inputActivity.Text;
var qnaResult = await _qnaService.QueryQnAServiceAsync(query, new QnABotState());
var qnaAnswer = qnaResult[0].Answer;
var prompts = qnaResult[0].Context?.Prompts;
if (prompts == null || prompts.Length < 1)
{
outputActivity = MessageFactory.Text(qnaAnswer);
}
else
{
outputActivity = CardHelper.GetHeroCard(qnaAnswer, prompts);
}
await turnContext.SendActivityAsync(outputActivity);
注意: 以上 "acting accordingly" 的代码仅适用于单级提示,根据我在顶部链接的回答。如果您想支持多级提示,那么您必须按照 this sample 实施状态系统 - 请参阅我的其他答案 here 了解更多详情。
注意 2: 正如下面评论中提到的,如果文本太长,使用上述方法 (HeroCard) 可能会导致标题被截断。为避免这种情况,您可以使用 Adaptive Dialogs or Adaptive Cards.
编辑
你应该可以通过这样的方式实现单级提示:
QnAResult.cs
public class QnAResult
{
public string[] Questions { get; set; }
public string Answer { get; set; }
public double Score { get; set; }
public int Id { get; set; }
public string Source { get; set; }
public QnAMetadata[] Metadata { get; set; }
public QnAContext Context { get; set; }
}
QnAResultList.cs
public class QnAResultList
{
public QnAResult[] Answers { get; set; }
}
IQnAService.cs
public interface IQnAService
{
Task<QnAResult[]> QueryQnAServiceAsync(string query, QnABotState qnAcontext, QnAMakerEndpoint qnAMakerEndpoint);
}
QnAService.cs
public class QnAService : IQnAService
{
private readonly HttpClient _httpClient;
private readonly IConfiguration _configuration;
public QnAService(HttpClient httpClient, IConfiguration configuration)
{
_httpClient = httpClient;
_configuration = configuration;
}
public async Task<QnAResult[]> QueryQnAServiceAsync(string query, QnABotState qnAcontext, QnAMakerEndpoint qnAMakerEndpoint)
{
var options = new QnAMakerOptions
{
Top = 3
};
var hostname = qnAMakerEndpoint.Host;
var endpoint = new QnAMakerEndpoint
{
KnowledgeBaseId = qnAMakerEndpoint.KnowledgeBaseId,
EndpointKey = qnAMakerEndpoint.EndpointKey,
Host = hostname
};
var requestUrl = $"{endpoint.Host}/knowledgebases/{endpoint.KnowledgeBaseId}/generateanswer";
var request = new HttpRequestMessage(HttpMethod.Post, requestUrl);
var jsonRequest = JsonConvert.SerializeObject(
new
{
question = query,
top = options.Top,
context = qnAcontext,
strictFilters = options.StrictFilters,
metadataBoost = options.MetadataBoost,
scoreThreshold = options.ScoreThreshold,
}, Formatting.None);
request.Headers.Add("Authorization", $"EndpointKey {endpoint.EndpointKey}");
request.Content = new StringContent(jsonRequest, System.Text.Encoding.UTF8, "application/json");
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var contentString = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<QnAResultList>(contentString);
return result.Answers;
}
}
CardHelper.cs
public class CardHelper
{
/// <summary>
/// Get Hero card
/// </summary>
/// <param name="cardTitle">Title of the card</param>
/// <param name="prompts">List of suggested prompts</param>
/// <returns>Message activity</returns>
public static Activity GetHeroCardWithPrompts(string cardTitle, QnAPrompts[] prompts)
{
var chatActivity = Activity.CreateMessageActivity();
var buttons = new List<CardAction>();
var sortedPrompts = prompts.OrderBy(r => r.DisplayOrder);
foreach (var prompt in sortedPrompts)
{
buttons.Add(
new CardAction()
{
Value = prompt.DisplayText,
Type = ActionTypes.ImBack,
Title = prompt.DisplayText
});
}
var plCard = new HeroCard()
{
Title = cardTitle,
Subtitle = string.Empty,
Buttons = buttons
};
var attachment = plCard.ToAttachment();
chatActivity.Attachments.Add(attachment);
return (Activity)chatActivity;
}
}
MyBot.cs HandleQnA()
QnAResult[] qnaResults = await _qnAService.QueryQnAServiceAsync(context.Activity.Text, new QnABotState(), _qnAMakerEndpoint);
if (qnaResults.Any())
{
// Get result by highest confidence
QnAResult highestRankedResult = qnaResults.OrderByDescending(x => x.Score).First();
string answer = highestRankedResult.Answer;
QnAPrompts[] prompts = highestRankedResult.Context?.Prompts;
if (prompts == null || prompts.Length < 1)
{
await context.SendActivityAsync(answer, cancellationToken: cancellationToken);
}
else
{
await context.SendActivityAsync(CardHelper.GetHeroCardWithPrompts(answer, prompts), cancellationToken: cancellationToken);
}
}
我使用的 NuGet 包是: