(4)semantic-kernel对话提示高级教程(利用AI发送邮件)

(4)semantic-kernel对话提示高级教程

在平常使用Semantic Kernel的时候,我们通常会利用Prompt为我们处理业务数据或者帮我们处理一些数据模型,也可以通过Prompt来实现一些高级的功能,下面我们通过一个案例来了解Semantic Kernel的对话提示功能和一些高级的用法。

利用Prompt帮我整理用户信息

很多场景下我们对于利用AI做应用处理的时候都会使用用户的信息,但是用户的信息是非常多的,我们需要对用户的信息进行整理,下面我们通过一个案例来了解如何利用Prompt帮我们整理用户的信息。

创建一个控制台的项目

  • 打开Visual Studio 2022,然后创建一个名称为4_Chat_Prompts的控制台项目
  • 然后复制以下代码到4_Chat_Prompts项目文件中

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <RootNamespace>_4_Chat_Prompts</RootNamespace>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.SemanticKernel" Version="1.12.0" />
  </ItemGroup>
</Project>
  

创建一个Kernel

  • 然后复制上一个教程的OpenAIHttpClientHandler.cs4_Chat_Prompts项目文件中。
  • 打开Program.cs
  • 然后复制以下代码到Program.cs文件中
using System.Text.Json;
using ConsoleApp1;
using Microsoft.SemanticKernel;

var kernel = Kernel.CreateBuilder()
    .AddOpenAIChatCompletion(
        modelId: "gpt-3.5-turbo",
        apiKey: "这里填写在https://api.token-ai.cn/创建的令牌",
        httpClient: new HttpClient(new OpenAIHttpClientHandler("https://api.token-ai.cn/")))
    .Build();

string info =
    @"
    张飞
    | 项目 | 信息 |
    | ---- | ---- |
    | 名字 | 张飞 |
    | 字号 | 益德 |
    | 出生日期 | 未知 |
    | 出生地 | 涿郡 |
    | 职业 | 汉末群雄、蜀汉五虎上将之一 |
    | 主要成就 | 蜀汉五虎上将之一,曾任益州牧,有勇猛之名 |
    | 逝世日期 | 221年 |
    | 主要关系 | 刘备的结义兄弟,关羽的结义兄弟 |

    刘备
    | 项目 | 信息 |
    | ---- | ---- |
    | 名字 | 刘备 |
    | 字号 | 玄德 |
    | 出生日期 | 161年 |
    | 出生地 | 涿郡 |
    | 职业 | 汉朝皇帝,蜀汉政权创立者 |
    | 主要成就 | 三国时期蜀汉的建立者和首任皇帝,有仁德之名 |
    | 逝世日期 | 223年 |
    | 主要关系 | 张飞和关羽的结义兄弟 |

    关羽
    | 项目 | 信息 |
    | ---- | ---- |
    | 名字 | 关羽 |
    | 字号 | 云长 |
    | 出生日期 | 未知 |
    | 出生地 | 河东解县 |
    | 职业 | 汉末群雄、蜀汉五虎上将之一 |
    | 主要成就 | 蜀汉五虎上将之一,曾任荆州牧,有忠义之名 |
    | 逝世日期 | 219年 |
    | 主要关系 | 刘备的结义兄弟,张飞的结义兄弟 |
    ";

var promptTemplate =
    @"
    ## 用户信息:
    {{$input}}

    ## 要求:
    - 您需要帮我将用户的名字,字号,出生日期,出生地,职业,主要成就,逝世日期,主要关系转换成到我提供的下面类中,以便让我支持序列化
    - 您不需要返回任何的回复,只返回json字符串防止序列化错误
    - 如果是多个请用[]包裹,然后你不要在外面多对象包括,我需要的结果是只返回 [{}] 这种效果。

    public class Info
    {
        /// <summary>
        /// 获取或设置名字。
        /// </summary>
        public string Name { get; set; }
    
        /// <summary>
        /// 获取或设置字号。
        /// </summary>
        public string Alias { get; set; }
    
        /// <summary>
        /// 获取或设置出生日期。
        /// </summary>
        public string BirthDate { get; set; }
    
        /// <summary>
        /// 获取或设置出生地。
        /// </summary>
        public string BirthPlace { get; set; }
    
        /// <summary>
        /// 获取或设置职业。
        /// </summary>
        public string Occupation { get; set; }
    
        /// <summary>
        /// 获取或设置主要成就。
        /// </summary>
        public string MainAchievement { get; set; }
    
        /// <summary>
        /// 获取或设置逝世日期。
        /// </summary>
        public string DeathDate { get; set; }
    }
    ";

var kernelArguments = new KernelArguments()
{
    ["input"] = info,
};

var json = await kernel.InvokePromptAsync(promptTemplate, kernelArguments);

var values = JsonSerializer.Deserialize<Info[]>(json.ToString());

foreach (var value in values)
{
    Console.WriteLine($"Name: {value.Name}");
    Console.WriteLine($"Alias: {value.Alias}");
    Console.WriteLine($"BirthDate: {value.BirthDate}");
    Console.WriteLine($"BirthPlace: {value.BirthPlace}");
    Console.WriteLine($"Occupation: {value.Occupation}");
    Console.WriteLine($"MainAchievement: {value.MainAchievement}");
    Console.WriteLine($"DeathDate: {value.DeathDate}");
    Console.WriteLine();
}

public class Info
{
    /// <summary>
    /// 获取或设置名字。
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// 获取或设置字号。
    /// </summary>
    public string Alias { get; set; }

    /// <summary>
    /// 获取或设置出生日期。
    /// </summary>
    public string BirthDate { get; set; }

    /// <summary>
    /// 获取或设置出生地。
    /// </summary>
    public string BirthPlace { get; set; }

    /// <summary>
    /// 获取或设置职业。
    /// </summary>
    public string Occupation { get; set; }

    /// <summary>
    /// 获取或设置主要成就。
    /// </summary>
    public string MainAchievement { get; set; }

    /// <summary>
    /// 获取或设置逝世日期。
    /// </summary>
    public string DeathDate { get; set; }
}

运行项目

然后运行项目,您会看到输出结果为:

Name: 张飞
Alias: 益德
BirthDate: 未知
BirthPlace: 涿郡
Occupation: 汉末群雄、蜀汉五虎上将之一
MainAchievement: 蜀汉五虎上将之一,曾任益州牧,有勇猛之名
DeathDate: 221年

Name: 刘备
Alias: 玄德
BirthDate: 161年
BirthPlace: 涿郡
Occupation: 汉朝皇帝,蜀汉政权创立者
MainAchievement: 三国时期蜀汉的建立者和首任皇帝,有仁德之名
DeathDate: 223年

Name: 关羽
Alias: 云长
BirthDate: 未知
BirthPlace: 河东解县
Occupation: 汉末群雄、蜀汉五虎上将之一
MainAchievement: 蜀汉五虎上将之一,曾任荆州牧,有忠义之名
DeathDate: 219

结论

在这里案例中我们通过Prompt帮我们整理了用户的信息,然后将用户的信息转换成了我们提供的类Info,然后我们通过JsonSerializerjson字符串转换成了Info类,然后我们输出了用户的信息。
这个实现有时候会受到模型的影响,如果模型不够好,可能会导致输出的结果不够准确,所以在使用的时候需要注意。
实际场景中,这个所谓的Info不一定是这种表格模板,也可以是pdf,word等等,只要你能够提供一个模板,Semantic Kernel都可以帮你处理。处理的效果跟模型和Prmopt都有关系
如果你确认你一定要用这个模型去处理,那么你就得调整您的Prompt,让模型更好的理解您的需求。

利用prompt进行发送邮件

在实际的开发中,我们经常会遇到发送邮件的需求,下面我们通过一个案例来了解如何利用Prompt来发送邮件。

实现发送邮件的功能

复制以下代码到Program.cs文件中

using System.ComponentModel;
using ConsoleApp1;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;

var kernel = Kernel.CreateBuilder()
    .AddOpenAIChatCompletion(
        modelId: "gpt-4",
        apiKey: "这里填写在https://api.token-ai.cn/创建的令牌",
        httpClient: new HttpClient(new OpenAIHttpClientHandler("https://api.token-ai.cn/")))
    .Build();

var emailPrompt =
    @"
## 需求:
- 我需要解决用户发送邮件问题,邮件参数包含以下参数
    - 收件人邮箱
        - required
        - email 
    - 邮件主题
        - required
        - 长度限制 100
        - title
    - 邮件内容
        - content
        - required 
- 在上面的参数如果是required则是必须的,如果用户没有提供那么你需要提示用户缺少哪些参数。
- 如果用户提供了参数,您需要提示不合法的参数,你不要提供测试用例,你需要提示用户哪些参数不合法。
- 上面要求都满足以后,需要提问用户是否确认发送,如果用户确认发送,那么你需要调用发送邮件。
";


kernel.Plugins.AddFromType<EmailTools>();

var chatHistory = new ChatHistory();

while (true)
{
    Console.Write("User > ");
    var input = Console.ReadLine();
    chatHistory.AddUserMessage(input);

    var chatResult = await kernel.GetRequiredService<IChatCompletionService>()
        .GetChatMessageContentAsync(chatHistory, new OpenAIPromptExecutionSettings()
        {
            ChatSystemPrompt = emailPrompt,
            MaxTokens = 500,
            Temperature = 0.5,
            TopP = 1,
            ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions
        }, kernel);

    if(string.IsNullOrEmpty(chatResult?.Content))
    {
        
        break;
    }
    
    Console.Write($"\nAssistant > {chatResult}\n");
    chatHistory.AddAssistantMessage(chatResult.Content);

    if (chatResult.Content.Contains("邮件发送成功"))
    {
        break;
    }
}

public class EmailTools
{
    [KernelFunction, Description("发送邮件")]
    public string SendEmail([Description("接收人")] string email, [Description("邮件主题")] string title,
        [Description("邮件内容")] string? content)
    {
        Console.WriteLine($"发送邮件给 {email} 主题:{title} 内容:{content}");
        // Send email
        return "邮件发送成功";
    }
}

启动项目

然后运行项目,您会看到输出结果为:

User > 发邮件给239573049@qq.com

Assistant > 你需要提供邮件的主题和内容。
User > 邮件主题 参加晚宴

Assistant > 你还需要提供邮件的内容。
User > 邮件内容 今晚上参加李白的晚宴

Assistant > 好的,我收到了你的邮件信息:
- 收件人: 239573049@qq.com
- 邮件主题: 参加晚宴
- 邮件内容: 今晚上参加李白的晚宴

请确认是否发送邮件?
User > 确认发送
发送邮件给 239573049@qq.com 主题:参加晚宴 内容:今晚上参加李白的晚宴

Assistant > 邮件已成功发送给239573049@qq.com。

实现结论

在上面我们实现了通过prompt进行多轮对话然后发送邮件给指定的邮箱,并且对于用户的输入进行了校验,如果用户输入不合法,那么我们会提示用户输入不合法的参数,如果用户输入合法,那么我们会提示用户是否确认发送邮件,如果用户确认发送,那么我们会调用发送邮件的方法,然后发送邮件。

这一个案例对于AI的要求是非常高的,因为我们需要对用户的输入进行校验,然后对用户的输入进行处理,然后再进行发送邮件,这个案例是一个比较复杂的案例,但是也是一个比较实用的案例,很多模型多无法达到我们的要求,所以我们需要对模型进行调整,让模型更好的适应我们的需求。

文档站点:https://docs.token-ai.cn/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值