先日身内でオフラインLT会を開催したのですが、その中でゲーム内でGemini APIを使って文章を生成する話がありました。Geminiは無料枠が結構大きい!ということからプロンプトエンジニアリングの手法まで、興味深い話を聞けてとても面白かったのですが、APIを叩く部分は手動で(ライブラリ等は使わずHttpClient
を用いて)やっていると聞いて、いいライブラリがあるかなーと探したんですが(実際サードパーティのライブラリは結構あるんですが)どうにも決定打がない。
というわけで作りました!Gemini APIを.NET / Unityから叩くためのクライアントライブラリ「GemiNet」です。NuGetで配布しているため、Unityで利用する場合はNuGetForUnityなどを利用してください。
GemiNetの設計指針は公式TypeScript(JavaScript) SDKであるgoogle/genaiに近いAPIを提供することです。これはCysharp/Claudiaの解説記事でも述べられている通りですが、公式SDKから変換する際の認知負荷は少ない方が良いでしょう。
というわけで、GemiNetのコードは以下の通り。
using GemiNet;
var GeminiApiKey = Environment.GetEnvironmentVariable("GEMINI_API_KEY");
using var ai = new GoogleGenAI
{
ApiKey = GeminiApiKey
};
var response = await ai.Models.GenerateContentAsync(new()
{
Model = "gemini-2.0-flash-001",
Contents = "Why is the sky blue?",
});
Console.WriteLine(response.GetText());
そして、これに対応する公式SDKのコードは以下の通りです。
import {GoogleGenAI} from '@google/genai';
const GEMINI_API_KEY = process.env.GEMINI_API_KEY;
const ai = new GoogleGenAI({apiKey: GEMINI_API_KEY});
const response = await ai.models.generateContent({
model: 'gemini-2.0-flash-001',
contents: 'Why is the sky blue?',
});
console.log(response.text);
かなり近いんじゃないでしょうか。もちろんC#のライブラリらしくちゃんと型付けされているので、見た目だけでなく書き心地もかなり良いはずです。
もちろんStreamingでの生成や、Live APIというWebSocketを使ったステートフルなセッションを構築するAPIにも対応しています。
var request = new GenerateContentRequest
{
Model = Models.Gemini2_0Flash,
Contents = "Hello, Gemini!"
};
await foreach (var response in GenerateContentStreamAsync(request))
{
Console.WriteLine(response.GetText());
}
Microsoft.Extensions.AI
また、GemiNet.Extensions.AIという追加パッケージではMicrosoft.Extensions.AIの抽象化層に対応した拡張が用意されています。
using GemiNet;
using GemiNet.Extensions.AI;
using var ai = new GoogleGenAI();
var client = ai.AsChatClient(Models.Gemini2_0Flash);
var response = await client.GetResponseAsync([new(ChatRole.User, "What is AI?")]);
var embeddingGenerator = ai.AsEmbeddingGenerator(Models.Gemini2_0Flash);
var embedding = await embeddingGenerator.GenerateEmbeddingAsync("Hello, Gemini!");
Microsoft.Extensions.AIは様々なLLMに対応するための抽象化層を提供するライブラリです。
Semantic Kernelの抽象化部分を取り出して強化したような感じで、今後Semantic Kernel自体もMicrosoft.Extensions.AIに依存する形に作り替えられる予定です。Microsoft.Extensions.AI自体の解説は以下の記事がわかりやすいので、そちらを読んでもらえると良いでしょう。(若干情報が古いのでAPIに違いがあったりしますが、雰囲気は何となくわかるはず)
今後LLMを組み込んだ開発でメインになっていくであろうライブラリなので、対応しておくことは悪くないでしょう。
また、GemiNet自体にもFunction Callingの機能は搭載されていますが、スキーマを都度組み立てる必要があるのでそのままだと扱いにくいでしょう。Microsoft.Extensions.AIを用いることで、これらを簡単に実装することが可能になります。
Live API
先ほどもチラッと紹介しましたが、GeminiにはLive APIというスタートフルなセッションを構築して双方向にやりとりを行うためのAPIが存在します。GemiNetではこれをサポートしており、以下のようにして利用することが可能です。
using GemiNet;
using var ai = new GoogleGenAI();
await using var session = await ai.Live.ConnectAsync(new()
{
Model = Models.Gemini2_0FlashLive,
Config = new()
{
ResponseModalities = [Modality.Text]
}
});
_ = Task.Run(async () =>
{
await session.SendRealtimeInputAsync(new()
{
Text = "Hello, Gemini!"
});
});
await foreach (var message in session.ReceiveAsync())
{
Console.WriteLine(message.ServerContent!.GetText());
}
await foreach
よりもObservableで取りたい!というような場合には、Cysharp/R3を用いて変換してあげるのが良いでしょう。
using GemiNet;
using R3;
using var ai = new GoogleGenAI();
await using var session = await ai.Live.ConnectAsync(new()
{
Model = Models.Gemini2_0FlashLive,
Config = new()
{
ResponseModalities = [Modality.Text]
}
});
var subscription = Observable.CreateFrom(session.ReceiveAsync())
.Subscribe(msg =>
{
Console.WriteLine(message.ServerContent!.GetText());
});
まとめ
今ではLLMも様々なモデルが出てきていて、用途によって都度使い分けるような状況になってきています。Geminiの利点はやはりAPIの圧倒的なコストパフォーマンスの高さで、個人〜中規模程度のプロダクトで試すには最適な選択肢ではないでしょうか。Microsoft.Extensions.AIの登場でSDKの差し替えも容易になっているので、色々なものを試してみるのも悪くないでしょう。
というわけでGemiNet、かなり使いやすいライブラリになっていると思うので、是非是非使ってみてください…!
Views: 2