Open2

Smart Paste 関連実験

Kazuki OtaKazuki Ota

これくらいのコードで汎用的に文字列からデータ抜き取ることが出来そう。

using Azure.Identity;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Planning;
using System.ComponentModel;

var builder = Kernel.CreateBuilder();
builder.AddAzureOpenAIChatCompletion(
    "gpt-35-turbo",
    "https://<<Azure OpenAI Service のリソース名>>.openai.azure.com/",
    new AzureCliCredential());

var kernel = builder.Build();

var formFillPlugin = new FormFillPlugin<Requester>();
kernel.Plugins.AddFromObject(formFillPlugin, pluginName: "RequesterFormFillPlugin");
kernel.Plugins.AddFromObject(new UserInputPlugin("""
    Contoso株式会社
    マイクロ太郎様

    はじめまして。
    株式会社Contoso2の田中太郎と申します。

    この度、貴社のホームページを拝見してご連絡いたしました。

    現在、弊社では貴社のピザデリバリーサービスの導入を検討しております。
    つきましては、ピザデリバリーサービスについての詳しい資料を拝見したく思っております。

    以下の宛先にお送りいただければ幸いです。

    ーーーーーーーーーーーーーーーーーーーーー

    sample@mail.example.com
    090-0000-0000

    ーーーーーーーーーーーーーーーーーーーーー

    お忙しいところ申し訳ございませんが、
    412日の社内検討会議に向けて参考にさせていただきたいので、
    それまでにご送付いただけますでしょうか。

    よろしくお願いいたします。
    """));

var planner = new FunctionCallingStepwisePlanner();
var result = await planner.ExecuteAsync(
    kernel,
    """
    ユーザー入力を読み取ってフォームに必要なデータを抜き出してフォームにデータを入力してください。
    フォームにデータを入力できたら Done と回答してください。
    フォームにデータを入力できなかった場合は、何が問題だったかを回答してください。
    """);
if (result.FinalAnswer == "Done")
{
    var r = formFillPlugin.FormData!;
    Console.WriteLine($"申込者: {r.FirstName} {r.LastName},  TEL: {r.PhoneNumber}, Email: {r.Email}");
}
else
{
    Console.WriteLine($"NG: {result.FinalAnswer}");
}

class UserInputPlugin(string userInput)
{
    [KernelFunction]
    [Description("ユーザーインプットを取得します。")]
    [return: Description("ユーザーインプット")]
    public string Get() => userInput;
}

class FormFillPlugin<T>
{
    private T? _formData;

    public T? FormData => _formData;

    [KernelFunction]
    [Description("フォームにデータを入力します。")]
    public void FillFormAsync([Description("フォームデータ")]T formData)
    {
        _formData = formData;
    }
}

class Requester
{
    public string FirstName { get; set; } = "";
    public string LastName { get; set; } = "";
    public string Email { get; set; } = "";
    public string PhoneNumber { get; set; } = "";
}

実行結果

申込者: 太郎 田中,  TEL: 090-0000-0000, Email: sample@mail.example.com
Kazuki OtaKazuki Ota

例えば、以下のようにメアドから電話番号を返すようなプラグインを組み込んでおくと

class RequesterSearchPlugin
{
    [KernelFunction]
    [Description("メールアドレスから電話番号を検索します。")]
    [return: Description("電話番号。見つからない場合は null を返す。")]
    public string? FindPhoneNumberFromEmail([Description("メールアドレス")]string email)
    {
        return email == "sample@mail.example.com" ?
            "090-XXXX-XXXX" :
            null;
    }
}

電話番号の無いテキストでも電話番号を探して入力してくれる。コード全体

using Azure.Identity;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Planning;
using System.ComponentModel;

var builder = Kernel.CreateBuilder();
builder.AddAzureOpenAIChatCompletion(
    "gpt-35-turbo",
    "https://<<Azure OpenAI Service のリソース名>>.openai.azure.com/",
    new AzureCliCredential());

var kernel = builder.Build();

var formFillPlugin = new FormFillPlugin<Requester>();
kernel.Plugins.AddFromType<RequesterSearchPlugin>();
kernel.Plugins.AddFromObject(formFillPlugin, pluginName: "RequesterFormFillPlugin");
kernel.Plugins.AddFromObject(new UserInputPlugin("""
    Contoso株式会社
    マイクロ太郎様

    はじめまして。
    株式会社Contoso2の田中太郎と申します。

    この度、貴社のホームページを拝見してご連絡いたしました。

    現在、弊社では貴社のピザデリバリーサービスの導入を検討しております。
    つきましては、ピザデリバリーサービスについての詳しい資料を拝見したく思っております。

    以下の宛先にお送りいただければ幸いです。

    ーーーーーーーーーーーーーーーーーーーーー

    sample@mail.example.com

    ーーーーーーーーーーーーーーーーーーーーー

    お忙しいところ申し訳ございませんが、
    412日の社内検討会議に向けて参考にさせていただきたいので、
    それまでにご送付いただけますでしょうか。

    よろしくお願いいたします。
    """));

var planner = new FunctionCallingStepwisePlanner();
var result = await planner.ExecuteAsync(
    kernel,
    """
    ユーザー入力を読み取ってフォームに必要なデータを抜き出してフォームにデータを入力してください。
    フォームに入力するデータが不足している場合は必要に応じて検索してください。
    フォームにデータを入力できたら Done と回答してください。
    フォームにデータを入力できなかった場合は、None を回答してください。
    """);
if (result.FinalAnswer == "Done")
{
    var r = formFillPlugin.FormData!;
    Console.WriteLine($"申込者: {r.FirstName} {r.LastName},  TEL: {r.PhoneNumber}, Email: {r.Email}");
}
else
{
    Console.WriteLine($"NG: {result.FinalAnswer}");
}

class UserInputPlugin(string userInput)
{
    [KernelFunction]
    [Description("ユーザーインプットを取得します。")]
    [return: Description("ユーザーインプット")]
    public string Get() => userInput;
}

class FormFillPlugin<T>
{
    private T? _formData;

    public T? FormData => _formData;

    [KernelFunction]
    [Description("フォームにデータを入力します。")]
    public void FillFormAsync([Description("フォームデータ")]T formData)
    {
        _formData = formData;
    }
}

class Requester
{
    public string FirstName { get; set; } = "";
    public string LastName { get; set; } = "";
    public string Email { get; set; } = "";
    public string PhoneNumber { get; set; } = "";
}

class RequesterSearchPlugin
{
    [KernelFunction]
    [Description("メールアドレスから電話番号を検索します。")]
    [return: Description("電話番号。見つからない場合は null を返す。")]
    public string? FindPhoneNumberFromEmail([Description("メールアドレス")]string email)
    {
        return email == "sample@mail.example.com" ?
            "090-XXXX-XXXX" :
            null;
    }
}

実行結果

申込者: 太郎 田中,  TEL: 090-XXXX-XXXX, Email: sample@mail.example.com

ユーザーの入力には電話番号の記載がないのに、ちゃんと電話番号が取れていることがわかる。