首先,我想解释一下我的目标是什么。我的目标是创建一个人工智能机器人,充当酒店助理,能够为用户提供他们请求的任何酒店相关信息。它应该根据用户输入进行回答,并能够检查特定日期的房间可用性和定价。
我已经实现了房间可用性功能。这涉及到一个内核函数,该函数将 checkInDate、checkOutDate 和房间对象列表作为参数(例如,两个房间,一个房间可供 1 名成人使用,另一个房间可供 2 名成人和 1 名 6 岁儿童使用)。
这部分效果很好。例如,当我问“11月7日至14日期间有可供2位成人入住的房间吗?”它通过插件提供基于 API 连接的准确信息。
问题出现在内核函数的输出中,由于详细的模式,该输出目前庞大且复杂,包含大量的包和房间数据。处理这个会消耗大量的令牌,我遇到了
error 429
:
为了减少令牌负载,我考虑将响应分为两部分 a) 动态数据(例如价格) b) 静态(或不经常变化)数据(如套餐描述、房间描述等)。Azure OpenAI API 版本 2023-07-01-preview 下的 ChatCompletions_Create 操作请求已超出当前 OpenAI S0 定价层的令牌速率限制。请50秒后重试。如果您想进一步提高默认利率限制,请访问此处:https://aka.ms/oai/quotaincrease。
这种方法涉及将内核函数与矢量数据库相结合来存储房间和套餐的描述,因为这些描述不会经常更改。
第二个目标是让机器人能够“了解”酒店并回答有关酒店的问题(例如入住时间、游泳池可用性、停车选项等)。
我可以为此使用微调模型,但定期更新的矢量数据库也可能效果很好。但是,由于我以前从未使用过矢量数据库,因此我不熟悉如何将数据加载到其中或将其与我当前的用例集成。
所以,我的主要问题是:如何有效地将 Kernel 函数与这个向量数据库结合起来?
我目前所拥有的内容取自:https://github.com/PieEatingNinjas/copilot-semantickernel/tree/demo并根据我的用例进行调整(获取有关酒店房价的信息)
var builder = Kernel.CreateBuilder();
builder.Services.AddAzureOpenAIChatCompletion(
"gpt-4o-mini",
Secrets.AzureOpenAiEndpoint,
Secrets.AzureOpenAiApiKey
);
builder.Plugins.AddFromType<AvailabilityPlugin>();
builder.Plugins.AddFromType<DateHelper>();
Kernel kernel = builder.Build();
IChatCompletionService chatCompletionService =
kernel.GetRequiredService<IChatCompletionService>();
var systemMessage = HotelBotCore.MainMessage;
/*
Here message is something like: "You are friendly bot that is serving information about hotel. People may ask information about hote rates. To check those you have to have information about check in date, check out date and information about rooms and people in those rooms. When presenting those rates show information about package name, room type name, price and meals [And so on, and so on]
*/
var chatMessages = new ChatHistory(systemMessage);
Console.WriteLine("--- Hotel info ---");
Console.WriteLine("Bot > How may i help you");
// Start the conversation
while (true)
{
// Get user input
Console.Write("User > ");
chatMessages.AddUserMessage(Console.ReadLine()!);
// Get the chat completions
var result =
chatCompletionService.GetStreamingChatMessageContentsAsync(
chatMessages,
executionSettings: new OpenAIPromptExecutionSettings()
{
ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions,
Temperature = 0.2
},
kernel: kernel);
// Stream the results
string fullMessage = "";
Console.Write("Bot > ");
await foreach (var content in result)
{
Console.Write(content.Content);
fullMessage += content.Content;
}
Console.WriteLine();
// Add the message from the agent to the chat history
chatMessages.AddAssistantMessage(fullMessage);
}
只是为了在数据上添加更多背景信息。让我们想象一下,第一个版本中的内核函数以这种形式返回数据(当然最初有更多字段):
{
"PackageId": 1
"PackageName": "Package 1"
"PackageDescription": "Some long description"
"PackageRooms":
[
{
"RoomId": 1
"RoomDescription": "Long description"
"RoomPrice": 123
},
{
"RoomId": 2
"RoomDescription": "Another long description"
"RoomPrice": 456
}
]
}
我将模型更改为更简单:
{
"PackageId": 1
"PackageName": "Package 1"
"PackageRooms":
[
{
"RoomId": 1
"RoomPrice": 123
},
{
"RoomId": 2
"RoomPrice": 456
}
]
}
现在我希望这个人工智能机器人在呈现结果时能够从矢量数据库中获取有关这些房间的数据。这可能吗?如果没有,我会寻求建议如何克服我正在观察的这个令牌问题。但是,即使矢量数据库不是上面提出的第一个问题的答案,它也可能是第二个问题的答案(因此在被问到时提供有关酒店本身的附加信息),这样如果有人会问:
At what time do I need to check out of my room?
您可以在那里上传一些 PDF。但我不知道如何将它连接到我的代码
https://learn.microsoft.com/en-us/semantic-kernel/concepts/plugins/adding-native-plugins?pivots=programming-语言-csharp)。如果您直接使用 Open AI API(假设您使用 ChatGPT 作为语言模型),那么所谓的函数就是您的朋友(请参阅此处:https://platform.openai.com/docs/guides/function-calling)。
有了它们,您可以在插件中为酒店人工智能提供额外的功能,例如。 g。获取房间的状态,获取有关房间的更多信息等。插件元信息将在上下文中,但不是插件背后的完整信息集。此时,插件背后的数据源类型并不重要,因为您以编程方式使用它,因此它可以是关系数据库、矢量数据库、文件或任何内容。调用插件并返回其信息后,返回的信息也与插件元信息一起成为会话上下文的一部分。因此,您的上下文应该始终留有足够的令牌来完成单个会话,以查询有关酒店的信息或执行预订过程。