👌
「Prompty を読み込んで LangChain と Semantic Kernel で実行するのを試してみた」のコードを書きなおしてみた
1 つ前の記事で「Prompty を読み込んで LangChain と Semantic Kernel で実行するのを試してみた」という記事を書きました。
今回は、その時に書いた Prompty を読み込んで実行するコードをちょっと書きなおしてみました。
書きなおしたポイントは以下の通りです。
- その言語の命名規約の流儀に従う
- 癖で Python の変数名を camelCase にしてしまっていたので snake_case に修正
- 非同期処理を使うように変更
- LangChain なんだから Chain を使うように変更
- ストリームを使うように変更
- なるべくシンプルに書く
Python 版 (LangChain)
書きなおす前は以下のようなコードでした。
from langchain_prompty import create_chat_prompt
from langchain_openai import AzureChatOpenAI
import os
from dotenv import load_dotenv
from pathlib import Path
load_dotenv()
# Prompty ファイルを読み込む
promptyFilePath = Path(__file__).parent / 'basic.prompty'
prompt = create_chat_prompt(promptyFilePath)
# question パラメーターに値を設定した状態のものを作成する
promptText = prompt.invoke(
{
'question': 'クラスの定義の仕方について教えてください。'
}
)
# OpenAI にプロンプトを投げる
llm = AzureChatOpenAI(
openai_api_version=os.getenv('AZURE_OPENAI_API_VERSION'),
azure_deployment=os.getenv('AZURE_OPENAI_DEPLOYMENT_NAME'),
)
response = llm.invoke(promptText)
print(response.content)
書き換えた後のコードは以下のようになります。
import os
import asyncio
from dotenv import load_dotenv
from pathlib import Path
from langchain_prompty import create_chat_prompt
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import AzureChatOpenAI
load_dotenv()
# Prompty ファイルを読み込む
prompt = create_chat_prompt(Path(__file__).parent / 'basic.prompty')
# AOAI への接続用のクラスを作成
llm = AzureChatOpenAI(
openai_api_version=os.getenv('AZURE_OPENAI_API_VERSION'),
azure_deployment=os.getenv('AZURE_OPENAI_DEPLOYMENT_NAME'),
)
# 非同期用の関数を作成
async def get_response(chain):
async for chunk in chain.astream({ 'question': 'クラスの定義の仕方について教えてください。' }):
print(chunk, end='', flush=True)
print()
# チェーンを実行
chain = prompt | llm | StrOutputParser()
asyncio.run(get_response(chain))
C# 版 (Semantic Kernel)
C# 版も書き換えました。
書き換える前は以下のようなコードでした。
using Azure.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.SemanticKernel;
// 構成ファイルを読み込み
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
// カーネルを作成
var kernel = Kernel.CreateBuilder()
.AddAzureOpenAIChatCompletion(
configuration["OpenAI:DeploymentName"]!,
configuration["OpenAI:Endpoint"]!,
new AzureCliCredential())
.Build();
// Prompty ファイルを読み込んで KernelFunction を作成
#pragma warning disable SKEXP0040
var prompty = kernel.CreateFunctionFromPromptyFile("basic.prompty");
#pragma warning restore SKEXP0040
// 実行して結果を表示
var answer = await prompty.InvokeAsync<string>(kernel,
new KernelArguments
{
["question"] = "クラスの定義方法について教えてください。"
});
Console.WriteLine(answer);
こっちは接続先情報を記載したファイルの appsettings.json
を自前で読み込んだりしていたので Host.CreateApplicationBuilder
を使って自動で読み込んでくれる機能を使うようにしました。
// Prompty が実験的機能なので警告を無効化
#pragma warning disable SKEXP0040
using Azure.Identity;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.SemanticKernel;
var builder = Host.CreateApplicationBuilder(args);
// Semantic Kernel のためのサービスを登録
builder.Services.AddAzureOpenAIChatCompletion(
builder.Configuration["OpenAI:DeploymentName"]!,
builder.Configuration["OpenAI:Endpoint"]!,
new AzureCliCredential());
builder.Services.AddKernel();
var app = builder.Build();
// Kernel のインスタンスを取得して、Prompty のファイルを読み込んで関数を作成
var kernel = app.Services.GetRequiredService<Kernel>();
var prompty = kernel.CreateFunctionFromPrompty(await File.ReadAllTextAsync("basic.prompty"));
await foreach (var chunk in kernel.InvokeStreamingAsync<string>(
prompty,
new() { ["question"] = "クラス定義方法について教えてください。" }))
{
Console.Write(chunk);
}
Console.WriteLine();
まとめ
ということで、後でコード見直したら気になったので書き換えました。
どっちもスッキリしたと思います。
Python は素人なので、もうちょっといい書き方あるよとかあれば教えてください。
Discussion