使用 .NET 开发 AI 应用(6): 为 AI 添加“记忆”

目录

提示工程

代码实现

结论


使用 .NET 开发 AI 应用(5): 创建第一个 AI 聊天机器人应用

在上一章中,我们创建了一个 AI 聊天机器人应用。但是在使用过程中,你会发现 AI 模型是没有“记忆”的。

举个例子,我们要AI记住我的名字,AI 也回复记住了,但当我们再次询问时,它却不记得了:

图片

这是因为 AI 模型是无状态的。 AI 模型旨在同时服务于成千上万的用户,而为每个用户维护一个持久的状态将是一个资源密集型的任务。

无状态的设计允许模型轻松地扩展到多个实例,而不需要同步用户状态,从而提高了效率和可靠性。

这种设计使得模型能够高效地服务于大量用户,但也限制了对话的连贯性。

然而,通过提示工程,我们可以巧妙地为 AI 添加“记忆”

提示工程

提示工程是一种技术,它通过精心设计的提示词,引导模型提供更准确、更相关的信息,使其更加符合特定的应用场景和研究领域。

提示词不仅包含指令或问题,还可以包含上下文、输入或示例等详细信息。这些元素共同作用,帮助模型更好地理解请求的意图,从而生成更加满意的答案。

例如,通过将对话历史转化为提示词,我们可以使模型在生成响应时考虑之前的交互。

这就像是给模型一个记忆的窗口,让它能够在一定程度上“记住”与用户的对话。

更多提示工程的相关知识,大家可以通过《面向开发者的 ChatGPT 提示词工程》这门免费课程(https://github.com/GitHubDaily/ChatGPT-Prompt-Engineering-for-Developers-in-Chinese)进行学习。

代码实现

我们使用的Gradio.Net已经记录下了对话历史,我们只需将其作为上下文传递给模型。这样,每次用户与AI交互时,模型都会接收到之前的对话,从而生成更加连贯和个性化的回答。

修改后的GenerateResponse方法使用提示模板传入之前的对话(和当前对话userPrompt):

static async IAsyncEnumerable<Output> GenerateResponse(Input input, Kernel kernel)
{
    var userPrompt = Textbox.Payload(input.Data[0]);
    var chatHistory = Chatbot.Payload(input.Data[1]);
    var chatMessages = ChatHistoryToPrompt(chatHistory);
    var promptTemplate = @"{{ $chatMessages }}
user:{{ $userPrompt }}
assistant:
";
    chatHistory.Add(new ChatbotMessagePair(new ChatMessage { TextMessage = userPrompt }, new ChatMessage { TextMessage = "" }));

    await foreach (var responseMessage in kernel.InvokePromptStreamingAsync<string>(promptTemplate, new() { { "chatMessages", chatMessages }, { "userPrompt", userPrompt } }))
    {
        if (!string.IsNullOrEmpty(responseMessage))
        {
            chatHistory.Last().AiMessage.TextMessage += responseMessage;

            yield return gr.Output("", chatHistory);
        }
        await Task.Delay(50);
    }
}

现在,我们再运行看下效果:

图片

结论

虽然LLM本身可能不具备记忆功能,但通过提示工程和适当的工具,我们可以克服LLM的无状态限制,为用户提供更加丰富和深入的对话体验。


完整源代码:

using Gradio.Net;
using Microsoft.SemanticKernel;
using System.Text;

string endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_GPT_NAME");
string apiKey = Environment.GetEnvironmentVariable("AZURE_OPENAI_API_KEY");

var kernel = Kernel.CreateBuilder()
    .AddAzureOpenAIChatCompletion(
        deploymentName: deploymentName,
        endpoint: endpoint,
        apiKey: apiKey)
    .Build();

App.Launch(await CreateBlocks(kernel));

static async Task<Blocks> CreateBlocks(Kernel kernel)
{
    using (var blocks = gr.Blocks())
    {
        var chatbot = gr.Chatbot();

        var txt = gr.Textbox(showLabel: false,
                placeholder: "输入文本并按回车键"
            );

        txt.Submit(streamingFn: (input) => GenerateResponse(input, kernel), inputs: new Gradio.Net.Component[] { txt, chatbot }, outputs: new Gradio.Net.Component[] { txt, chatbot });
        return blocks;
    }
}

static async IAsyncEnumerable<Output> GenerateResponse(Input input, Kernel kernel)
{
    var userPrompt = Textbox.Payload(input.Data[0]);
    var chatHistory = Chatbot.Payload(input.Data[1]);
    var chatMessages = ChatHistoryToPrompt(chatHistory);
    var promptTemplate = @"{{ $chatMessages }}
user:{{ $userPrompt }}
assistant:
";
    chatHistory.Add(new ChatbotMessagePair(new ChatMessage { TextMessage = userPrompt }, new ChatMessage { TextMessage = "" }));

    await foreach (var responseMessage in kernel.InvokePromptStreamingAsync<string>(promptTemplate, new() { { "chatMessages", chatMessages }, { "userPrompt", userPrompt } }))
    {
        if (!string.IsNullOrEmpty(responseMessage))
        {
            chatHistory.Last().AiMessage.TextMessage += responseMessage;

            yield return gr.Output("", chatHistory);
        }
        await Task.Delay(50);
    }
}

static string ChatHistoryToPrompt(IList<ChatbotMessagePair> chatHistory)
{
    var sb = new StringBuilder();
    foreach (var chatbotMessagePair in chatHistory)
    {
        sb.AppendLine($"user:{chatbotMessagePair.HumanMessage.TextMessage}");
        sb.AppendLine($"assistant:{chatbotMessagePair.AiMessage.TextMessage}");
    }
    return sb.ToString();
}

引入地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值