Semantic KernelのAIチャット作成ハンズオンに参加したまとめ(初歩)

# はじめに
Microsoft Build Japan 2023に参加し、その中で開催されていたSemantic Kernelを使ってAIチャットをつくってみようというハンズオンを受けてきました。
そこでやった中ででてきた関数や、そもそもSemanitic Kernelが何者かもわかってなかったので、そのへんをまとめてみました。

# 環境・言語
- Windows11
- Visual Studio Professional 2022 
- .NET7
- Azure OpenAI Service(申請が必要なので注意)
- C#

# Semantic Kernelとは

> Semantic Kernel は、 OpenAI、Azure OpenAI、Hugging Faceなどの AI サービスと C# や Python などの従来のプログラミング言語を簡単に組み合わせることができるオープンソース SDK です。そうすることで、両方の長所を組み合わせた AI アプリを作成できます。

引用元：[What is Semantic Kernel?](https://learn.microsoft.com/en-us/semantic-kernel/overview/)

自作アプリに簡単に大規模言語モデルを統合できるよということらしいです。
ので、chatGPTとか簡単に統合できるということ。

## SkillとPlanner
### Skill
AIプロンプトを定義したり、外部システムに接続したりできるらしい。
セマンティックスキル(プロンプトをベースに作成)、ネイティブスキル(コードでかいた処理をスキルとして登録)がある。

### Planner
複数のステップを実行できるAIエージェントを構築できる。
登録したSkillから問題解決に必要なSkillを自動で組み合わせて回答してくれる。


# Semantic Kernelを使ってAIチャットを作ってみる

ということでハンズオンではコードを穴埋めしていく感じだったのですが、一から作成してみました。
ハンズオンではBlazorプロジェクトで作成したため、Blazorプロジェクトで作成しています。

## Blazorプロジェクトを作成する

新しいプロジェクトの作成からBlazor Serverアプリを選択します。
![スクリーンショット 2023-07-01 153821.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/38fcdd0a-4742-acc7-a70a-6679f88afed5.png)

作成できたら試しに立ち上げてみるとこんな画面になるかと思います。
![スクリーンショット 2023-07-01 154046.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/fc783d5b-c7da-260e-9cff-a6ec6f34bd70.png)


### 余談
なぜか私はBlazorプロジェクトを立ち上げると以下のエラーが出てしまいました。
> InvalidOperationException: Cannot find the fallback endpoint specified by route values: { page: /_Host, area: }.

原因はよくわからないのですが、csprojファイルの```<PropertyGroup>```要素内に以下のコードを追加したらエラーが解消されました。

```
<UseRazorSourceGenerator>false</UseRazorSourceGenerator>
```

## NuGet追加
NuGetパッケージの追加から、以下を追加します。
※検索するときにプレリリースを含めるようにする
- Microsoft.SemanticKernel

## コード追加
コードは大事なところを抜粋してまとめています。
Semantic Kernelのサンプルがのっているこちらのgithubを見るとより理解が深まりました。
[08-chatGPT-with-DALL-E-2.ipynb](https://github.com/microsoft/semantic-kernel/blob/main/samples/notebooks/dotnet/08-chatGPT-with-DALL-E-2.ipynb)

### appsettings.jsonの追記
今回私はAzure OpenAI Serviceを使用したため、必要な設定値は以下3つでした。
- DeploymentName
- BaseUrl
- Key

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/cb2afc32-c8d0-b9ba-6801-2686ee9a544c.png)

DeploymentNameは👆の画像(Azure OpenAI Studio)のデプロイ名のところです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/7b033817-cf02-b272-8770-96019d645be0.png)
BaseUrlは👆の画像のエンドポイントのところ、
Keyはキー1かキー2のどちらかです。

ちなみに、OpenAIだとエンドポイントがいらない模様。


### SemanticKernelLogicクラスとインターフェイスを作成
Logicというフォルダーを追加し、そこにSemantic Kernelを使用するためのもろもろの処理をかいてきます。
Program.csにスコープを追加するのを忘れずに…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/84e9d8b7-3671-eb00-8060-aa7d6a063b01.png)

### Kernelをインスタンス化してChatGPTをセットアップ
```C#:SemanticKernelLogic.cs       
IKernel kernel = new KernelBuilder()
    .WithLogger(_logger)
    .WithAzureChatCompletionService(deploymentName, baseUrl, key)
    .Build();
``` 

`WithAzureChatCompletionService`でサービスを登録しているようです。
登録したサービスがこれ👉`ChatCompletion`
チャット補完に特化した言語モデルです。チャット履歴から想定して新しいメッセージを返してくれます。


### ChatCompletionをインスタンス化

```C#:SemanticKernelLogic.cs
ChatCompletion = kernel.GetService<IChatCompletion>();

chatHistory = ChatCompletion.CreateNewChat("あなたはうそまるというキャラクターです。ユーザーの質問に対して語尾には必ず「ぴょん」をつけて回答してください。");
```

チャット履歴に新しいチャットオブジェクトを作成します。
`CreateNewChat`の引数にプロンプトメッセージをいれてあげることで、お茶目なAIアシスタントを作れます。


### チャットを入力したときの動きの追加

```C#:SemanticKernelLogic.cs
public async Task StreamRun(string input)
{
    chatHistory.AddUserMessage(input);

    ChatRequestSettings settings = new ChatRequestSettings();
    settings.MaxTokens = 2000;

    string message = await ChatCompletion.GenerateMessageAsync(chatHistory, settings);
    chatHistory.AddAssistantMessage(message);
}
```

`AddUserMessage`でチャット履歴にユーザーの会話(入力した内容)を追加します。
`ChatRequestSettings`ではチャットパラメータを設定できます。
設定できる内容は以下の通り。
|設定値|内容|
|--|--|
|MaxTokens|生成されるテキストの長さ|
|Temperature|値が低いほど確実な回答をする。高いほど独創的になる(らしい)|
|FrequencyPenalty|値が高いほど同じ単語が何度も生成されるのを防ぐ|
|TopP|Temperatureと似てる。出力の一貫性がでる。Temperatureと同時に変更してはダメ|
|PresencePenalty|値が高いほど同じ会話を何度もするのを防ぐ|
|StopSequences|チャットの生成を終了するテキスト|
|ResultsPerPrompt|指定した数だけ回答が生成される|
|TokenSelectionBiases|logit_biasと同じ。特定のトークンの出現確率が変更できる|

`GenerateMessageStreamAsync`で生成されたチャットメッセージをchatHistoryに追加します。
`AddAssistantMessage`で追加することでチャットボット側のメッセージに追加してくれます。

## できたもの
ハンズオンで作ったものからレイアウトは少しチャットっぽく変更しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/71c45aba-a311-8c01-0078-4954e2d93ea3.png)


# まとめ
Semantic Kernelの本当のさわりの部分をお試しという感じだったのですが、簡単にchatGptをアプリに組み込めました。
次はスキルの方についてもっと深堀してみたいと思います。

# 追記
ご要望があったため、ソースコードをgithubに載せました。
https://github.com/usomaru/test-ai-chat-bot
(レイアウトはテキスト入力する部分は崩れてます。時間を見て直したいと思います。)

# 参考
参加したハンズオン：[Semantic Kernelを使ってAIチャットアプリを構築する](https://microsoft-events.connpass.com/event/286537/)
- [Semantic Kernelを使ってGPTと外部ツールを簡単に連携してみる](https://acro-engineer.hatenablog.com/entry/2023/04/18/120000)
- [Semantic Kernel のサンプル概要](https://zenn.dev/hiromu/articles/20230430_semantikkernel)
- [Azure OpenAI Service を便利に使うための Semantic Kernel を試してみよう on C#](https://zenn.dev/microsoft/articles/semantic-kernel-1)