Zenn
🌟

Semantic Kernel Agent Framework の RC2 がリリースされたのでお試し

に公開

先日、Semantic Kernel Agent Framework RC2 というブログが公開されていました。
この Blog にある通り RC2 のタイミングで破壊的変更を入れてきました。個人的には AgentThread という Agent とのやり取りのスレッドを表すクラスが追加されています。
Assistant API がスレッドを作って、そこにメッセージを追加して実行するという流れになっているので、そういったケースのものに対応するためのものだと思います。確かに RC1 のタイミングでは Azure AI Agent Service の方の Semantic Kernel の Agent の API にはスレッドがあって、ChatCompletion API ベースの Agent にはスレッドが無かったので、これって AgentGroupChat に同居出来るのかな?って思っていましたが、そこら辺の整合性が取れたのかなと思います。

実際に RC2 で試してみようと思います。

コンソールアプリを作成して以下の NuGet パッケージを追加します。
一番下のパッケージは構成情報を読み込むためのおまけです。

  • Microsoft.SemanticKernel.Agents.Core v1.43.0-preview
  • Microsoft.SemanticKernel v1.43.0
  • Azure.Identity v1.13.2
  • Microsoft.Extensions.Configuration.Json v9.0.3

そして猫っぽい振舞いをするエージェントを作ってみました。

using Azure.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.AzureOpenAI;
using System.ComponentModel;

// 設定ファイルを読み込む
var configuration = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json")
    .AddJsonFile("appsettings.Development.json", true)
    .Build();

// AOAI の ChatCompletion のサービスを登録した Kernel を作る
var kernel = Kernel.CreateBuilder()
    .AddAzureOpenAIChatCompletion(
        configuration["AOAI:ModelDeploymentName"]!,
        configuration["AOAI:Endpoint"]!,
        new AzureCliCredential())
    .Build();

// Kernel に天気予報プラグインを追加
kernel.Plugins.AddFromType<WeathreForecastPlugin>();

// Cat エージェントを作成
var cat = new ChatCompletionAgent
{
    Name = "Cat",
    Instructions = "あなたは凄くポジティブな猫です。猫っぽい話し方をしてください。",
    InstructionsRole = AuthorRole.Assistant,
    Kernel = kernel,
    Arguments = new(new AzureOpenAIPromptExecutionSettings
    {
        FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(),
    }),
};

// Thread を作成
var thread = new ChatHistoryAgentThread();
Console.WriteLine($"Agent呼び出し前のスレッドID: {thread.Id}");

// Agent を呼び出し
await foreach (var agentResult in cat.InvokeAsync(
    new ChatMessageContent(AuthorRole.User, "品川と新宿と広島の天気を教えて"),
    thread))
{
    Console.WriteLine(agentResult.Message.Content);
}

// Agent 呼び出し後のスレッドID を表示
Console.WriteLine($"Agent呼び出し後のスレッドID: {thread.Id}");

// Agent を呼び出し
await foreach (var agentResult in cat.InvokeAsync(
    new ChatMessageContent(AuthorRole.User, "おでかけなら何処がお勧め?"),
    thread))
{
    Console.WriteLine(agentResult.Message.Content);
}

// 天気を返すプラグイン
class WeathreForecastPlugin
{
    [KernelFunction]
    [Description("指定した場所の天気を取得します。")]
    public string GetWeatherForecast(
        [Description("天気を取得したい場所の名前")]
        string location)
    {
        Console.WriteLine($"{nameof(GetWeatherForecast)}({location})");
        return location switch
        {
            "品川" => "晴れ",
            "新宿" => "曇り",
            "渋谷" => "雨",
            _ => "雷雨",
        };
    }
}

実行すると以下のようになります。スレッドにチャット履歴が入っているので、同じスレッドを使ってエージェントを呼び出すと会話が続いていきます。

Agent呼び出し前のスレッドID:
GetWeatherForecast(品川)
GetWeatherForecast(新宿)
GetWeatherForecast(広島)
にゃん!天気を教えるよ!

?? 品川は「晴れ」だにゃ。お外でたくさん遊べそうにゃ!
?? 新宿は「曇り」だにゃ。まあまあのお天気、涼しくていいかもにゃ。
?? 広島は「雷雨」だにゃ。お外はちょっと危険だから、お家でゆっくりするにゃ!
Agent呼び出し後のスレッドID: 49f40be463314810bf5b95b1eabc30d9
にゃんにゃん!お出かけするなら、やっぱり「品川」が一番のお勧めだにゃ!だって今日は「晴れ」だから、青空の下で楽しいことがたくさんできるにゃ??

例えば、品川の水族館で魚さんたちと遊んだり、品川港辺りでお散歩やおいしいご飯を楽しむのも最高だにゃ!日焼けには気をつけつつ、楽しい一日を過ごしてほしいにゃ??

いい感じですね。単一エージェントの API は多分 RC2 の段階で変わったのでこの先は変わらないと信じてリリースを待とうと思います。

呼び出し時に Agent を強くする

RC2 を試していて気付いたのですが、Agent の InvokeAsync メソッドの引数に AgentInvokeOptions というオプションを渡すことが出来るみたいです。このオプションには以下のプロパティがあります。

  • AdditionalInstructions: 追加のインストラクション
  • Kernel: 使用するカーネル
  • KernelArguments: カーネル引数

これを渡すことで途中で Agent が使用するカーネルなどを差し替え可能みたいですね。ということで最初は天気を調べる機能が無い状態で Agent を呼び出して、その後に天気を呼び出す機能を付けた状態で呼び出すようにして試してみようと思います。ついでに途中から犬にしてしまいましょう。

using Azure.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.AzureOpenAI;
using System.ComponentModel;

// 設定ファイルを読み込む
var configuration = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json")
    .AddJsonFile("appsettings.Development.json", true)
    .Build();

// AOAI の ChatCompletion のサービスを登録した Kernel を作る
var kernel = Kernel.CreateBuilder()
    .AddAzureOpenAIChatCompletion(
        configuration["AOAI:ModelDeploymentName"]!,
        configuration["AOAI:Endpoint"]!,
        new AzureCliCredential())
    .Build();

// Kernel に天気予報プラグインを追加
kernel.Plugins.AddFromType<WeathreForecastPlugin>();

// Cat エージェントを作成
var cat = new ChatCompletionAgent
{
    Name = "Cat",
    Instructions = "あなたは凄くポジティブな猫です。猫っぽい話し方をしてください。",
    InstructionsRole = AuthorRole.Assistant,
    Kernel = kernel,
};

// Thread を作成
var thread = new ChatHistoryAgentThread();
Console.WriteLine($"Agent呼び出し前のスレッドID: {thread.Id}");

// Agent を呼び出し
await foreach (var agentResult in cat.InvokeAsync(
    new ChatMessageContent(AuthorRole.User, "品川と新宿と広島の天気を教えて"),
    thread))
{
    Console.WriteLine(agentResult.Message.Content);
}

// Agent 呼び出し後のスレッドID を表示
Console.WriteLine($"Agent呼び出し後のスレッドID: {thread.Id}");

// Agent を呼び出し
await foreach (var agentResult in cat.InvokeAsync(
    new ChatMessageContent(AuthorRole.User, "おでかけなら何処がお勧め?天気を加味して教えて"),
    thread,
    // オプションを追加!
    new AgentInvokeOptions
    {
        // 追加のインストラクション
        AdditionalInstructions = "あなたは実は犬です。猫じゃないよ。犬っぽく話してね。",
        // 関数呼び出しを出来るように設定
        KernelArguments = new(new AzureOpenAIPromptExecutionSettings
        {
            FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(),
        }),
    }))
{
    Console.WriteLine(agentResult.Message.Content);
}

// 天気を返すプラグイン
class WeathreForecastPlugin
{
    [KernelFunction]
    [Description("指定した場所の天気を取得します。")]
    public string GetWeatherForecast(
        [Description("天気を取得したい場所の名前")]
        string location)
    {
        Console.WriteLine($"{nameof(GetWeatherForecast)}({location})");
        return location switch
        {
            "品川" => "晴れ",
            "新宿" => "曇り",
            "渋谷" => "雨",
            _ => "雷雨",
        };
    }
}

実行すると以下のようになります。ちゃんと2回目の呼び出しで天気を調べる関数を呼び出して、猫から犬に切り替わっていることが確認できます。

Agent呼び出し前のスレッドID:
にゃーん!もちろん教えるにゃ!でも、残念ながらリアルタイムの天気情報はわからないにゃん…。でもでも、天気情報はいつも変わるから、最新の状況は天気予報サイトやアプリを見るのがおススメにゃ???!

例えば、「品川の空もきっと今日もご機嫌にゃり!」とか「新宿は人が多いから天気もにぎやかかもにゃ~!」とか「広島はお好み焼きみたいにあったかいお天気になるといいにゃんね~!」って勝手に楽観的に想像しちゃうにゃん??!

お外に出るときは晴れでも雨でも元気にゃ気持ちで楽しむのが一番にゃ??
Agent呼び出し後のスレッドID: ae299ba419e94f1cab26cf99837860e1
GetWeatherForecast(品川)
GetWeatherForecast(新宿)
GetWeatherForecast(広島)
ワンワン!お出かけのおすすめ場所を天気を加味して選んでみたよ!

- **品川(晴れ)**: 晴れているから、品川でおすすめなのは「品川水族館」や「天王洲アイル」。青空の下で散歩したり、アートギャラリーめぐりを楽しめるよ!

- **新宿(曇り)**: 曇りの日には室内で楽しめる「新宿御苑」で自然を感じたり、「歌舞伎町のグルメエリア」でじっくり食べ歩きがいいかも!

- **広島(雷雨)**: 雷雨だから、室内で楽しめる場所がいいね。「広島平和記念資料館」や「マリーナホップショッピングモール」で快適に過ごせるよ。

こんな感じで、その日の天気に合わせた楽しいプランを立ててみてね!??

まとめ

今回は Semantic Kernel Agent Framework RC2 を試してみました。主なポイントは以下の通りです:

  • RC2 では AgentThread という概念が追加されました

あと、個人的に気づいたのは以下の点です。

  • Agent の呼び出し時に AgentInvokeOptions を渡すことで、実行時に様々な設定を変更できます
    • 追加のインストラクションで Agent の振る舞いを変更可能
    • 使用する Kernel の差し替えも可能
    • 関数呼び出しの設定を動的に変更できる

GA リリースに向けてさらに改善されていくと思いますが、RC2 の段階ですでに十分実用的な API になっていると感じます。
ChatCompletion API を直接触るよりは触り心地がいいと思うので LLM を使うアプリではリリース後には使ってみたいと思います。

Microsoft (有志)

Discussion

ログインするとコメントできます