複数のプラグインを作成したら、AI エージェントがそれらを一緒に使用してユーザーのニーズを解決する方法が必要になります。 ここで計画が活かされます。
セマンティック カーネルは早い段階で、プロンプトを使用して呼び出す関数を選択するよう AI に要求するプランナーの概念を導入しました。 しかし、セマンティックカーネルが導入されて以来、OpenAIはモデルが関数を呼び出すためのネイティブな方法として「関数呼び出し」を導入しました。 Gemini、Claude、Mistral などの他の AI モデルでは、その後、コア機能として関数呼び出しが採用され、モデル間でサポートされる機能となっています。
このような進歩により、セマンティック カーネルは、タスクを計画および実行するための主要な方法として関数呼び出しを使用するように進化しました。
Von Bedeutung
関数呼び出しは、0613 以降の OpenAI モデルでのみ使用できます。 古いモデル (0314 など) を使用している場合、この機能はエラーを返します。 この機能を利用するには、最新の OpenAI モデルを使用することをお勧めします。
関数呼び出しによって "プラン" はどのように作成されますか?
最も単純な関数呼び出しは、AI が適切なパラメーターを使用して関数を呼び出すための方法にすぎません。 たとえば、ユーザーが電球をオンにしたいとします。 AI が適切なプラグインを持っていると仮定すると、関数を呼び出してライトをオンにすることができます。
役割 | メッセージ |
---|---|
🔵 ユーザー | ライト #1 をオンにしてください |
🔴 Assistant (関数呼び出し) | Lights.change_state(1, { "isOn": true }) |
🟢 ツール | { "id": 1, "name": "Table Lamp", "isOn": true, "brightness": 100, "hex": "FF0000" } |
🔴 アシスタント | ランプがオンになりました |
しかし、ユーザーがライトの ID を知らない場合はどうでしょうか。 または、ユーザーがすべてのライトをオンにしたい場合はどうなりますか? ここで計画が必要になります。 現在の LLM モデルは、ユーザーのニーズを解決するために関数を繰り返し呼び出す機能を備えています。 これは、AI が関数を呼び出し、結果を確認し、次に何を行うかを決定できるフィードバック ループを作成することによって実現されます。
たとえば、ユーザーは、電球を "切り替える" よう AI に求める場合があります。 AI では、まず電球の状態を確認してから、電源をオンまたはオフにするかどうかを決定する必要があります。
役割 | メッセージ |
---|---|
🔵 ユーザー | すべてのライトを切り替えてください |
🔴 Assistant (関数呼び出し) | Lights.get_lights() |
🟢 ツール | { "lights": [ { "id": 1, "name": "Table Lamp", "isOn": true, "brightness": 100, "hex": "FF0000" }, { "id": 2, "name": "Ceiling Light", "isOn": false, "brightness": 0, "hex": "FFFFFF" } ] } |
🔴 Assistant (関数呼び出し) |
Lights.change_state(1, { "isOn": false })
Lights.change_state(2, { "isOn": true })
|
🟢 ツール | { "id": 1, "name": "Table Lamp", "isOn": false, "brightness": 0, "hex": "FFFFFF" } |
🟢 ツール | { "id": 2, "name": "Ceiling Light", "isOn": true, "brightness": 100, "hex": "FF0000" } |
🔴 アシスタント | ライトが切り替えられた |
注
この例では、並列関数呼び出しも確認しました。 ここで、AI は複数の関数を同時に呼び出すことができます。 これは、AI がより迅速に複雑なタスクを解決するのに役立つ強力な機能です。 1106年に OpenAI モデルに追加されました。
自動計画ループ
セマンティック カーネルを使用しない関数呼び出しのサポートは比較的複雑です。 次の処理を実行するループを記述する必要があります。
- 各関数の JSON スキーマを作成する
- 以前のチャット履歴と関数スキーマを LLM に提供する
- LLM の応答を解析して、メッセージで応答するか、関数を呼び出すかを判断します
- LLM が関数を呼び出す場合は、LLM の応答から関数名とパラメーターを解析する必要があります
- 適切なパラメーターを使用して関数を呼び出す
- LLM が次に何をすべきかを判断できるように、関数の結果を返します。
- LLM がタスクを完了したと判断するか、ユーザーの支援が必要になるまで、手順 2 から 6 を繰り返します。
セマンティック カーネルでは、このループを自動化することで関数呼び出しを簡単に使用できます。 これにより、ユーザーのニーズを解決するために必要なプラグインの構築に集中できます。
注
パフォーマンスと信頼性の高い AI エージェントを構築するには、関数呼び出しループのしくみを理解することが不可欠です。 ループのしくみの詳細については、 関数呼び出し に関する記事を参照してください。
自動関数呼び出しの使用
セマンティック カーネルで自動関数呼び出しを使用するには、次の操作を行う必要があります。
- プラグインをカーネルに登録する
- AI に関数を自動的に呼び出すよう指示する実行設定オブジェクトを作成する
- チャット履歴とカーネルを使用してチャット完了サービスを呼び出す
ヒント
次のコード サンプルでは、ここで定義されている LightsPlugin
を使用 します。
using System.ComponentModel;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
// 1. Create the kernel with the Lights plugin
var builder = Kernel.CreateBuilder().AddAzureOpenAIChatCompletion(modelId, endpoint, apiKey);
builder.Plugins.AddFromType<LightsPlugin>("Lights");
Kernel kernel = builder.Build();
var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();
// 2. Enable automatic function calling
OpenAIPromptExecutionSettings openAIPromptExecutionSettings = new()
{
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
};
var history = new ChatHistory();
string? userInput;
do {
// Collect user input
Console.Write("User > ");
userInput = Console.ReadLine();
// Add user input
history.AddUserMessage(userInput);
// 3. Get the response from the AI with automatic function calling
var result = await chatCompletionService.GetChatMessageContentAsync(
history,
executionSettings: openAIPromptExecutionSettings,
kernel: kernel);
// Print the results
Console.WriteLine("Assistant > " + result);
// Add the message from the agent to the chat history
history.AddMessage(result.Role, result.Content ?? string.Empty);
} while (userInput is not null)
import asyncio
from semantic_kernel import Kernel
from semantic_kernel.connectors.ai import FunctionChoiceBehavior
from semantic_kernel.connectors.ai.chat_completion_client_base import ChatCompletionClientBase
from semantic_kernel.connectors.ai.open_ai import (
AzureChatCompletion,
AzureChatPromptExecutionSettings,
)
from semantic_kernel.contents import ChatHistory
from semantic_kernel.functions import kernel_function
async def main():
# 1. Create the kernel with the Lights plugin
kernel = Kernel()
kernel.add_service(AzureChatCompletion())
kernel.add_plugin(
LightsPlugin(),
plugin_name="Lights",
)
chat_completion: AzureChatCompletion = kernel.get_service(type=ChatCompletionClientBase)
# 2. Enable automatic function calling
execution_settings = AzureChatPromptExecutionSettings()
execution_settings.function_choice_behavior = FunctionChoiceBehavior.Auto()
# Create a history of the conversation
history = ChatHistory()
userInput = None
while True:
# Collect user input
userInput = input("User > ")
# Terminate the loop if the user says "exit"
if userInput == "exit":
break
# Add user input to the history
history.add_user_message(userInput)
# 3. Get the response from the AI with automatic function calling
result = await chat_completion.get_chat_message_content(
chat_history=history,
settings=execution_settings,
kernel=kernel,
)
# Print the results
print("Assistant > " + str(result))
# Add the message from the agent to the chat history
history.add_message(result)
# Run the main function
if __name__ == "__main__":
asyncio.run(main())
OpenAIAsyncClient client = new OpenAIClientBuilder()
.credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
.endpoint(CLIENT_ENDPOINT)
.buildAsyncClient();
// Import the LightsPlugin
KernelPlugin lightPlugin = KernelPluginFactory.createFromObject(new LightsPlugin(),
"LightsPlugin");
// Create your AI service client
ChatCompletionService chatCompletionService = OpenAIChatCompletion.builder()
.withModelId(MODEL_ID)
.withOpenAIAsyncClient(client)
.build();
// Create a kernel with Azure OpenAI chat completion and plugin
Kernel kernel = Kernel.builder()
.withAIService(ChatCompletionService.class, chatCompletionService)
.withPlugin(lightPlugin)
.build();
// Add a converter to the kernel to show it how to serialise LightModel objects into a prompt
ContextVariableTypes
.addGlobalConverter(
ContextVariableTypeConverter.builder(LightModel.class)
.toPromptString(new Gson()::toJson)
.build());
// Enable planning
InvocationContext invocationContext = new InvocationContext.Builder()
.withReturnMode(InvocationReturnMode.LAST_MESSAGE_ONLY)
.withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true))
.build();
// Create a history to store the conversation
ChatHistory history = new ChatHistory();
// Initiate a back-and-forth chat
Scanner scanner = new Scanner(System.in);
String userInput;
do {
// Collect user input
System.out.print("User > ");
userInput = scanner.nextLine();
// Add user input
history.addUserMessage(userInput);
// Prompt AI for response to users input
List<ChatMessageContent<?>> results = chatCompletionService
.getChatMessageContentsAsync(history, kernel, invocationContext)
.block();
for (ChatMessageContent<?> result : results) {
// Print the results
if (result.getAuthorRole() == AuthorRole.ASSISTANT && result.getContent() != null) {
System.out.println("Assistant > " + result);
}
// Add the message from the agent to the chat history
history.addMessage(result);
}
} while (userInput != null && !userInput.isEmpty());
自動機能呼び出しを使用すると、自動計画ループのすべてのステップが自動的に処理され、 ChatHistory
オブジェクトに追加されます。 関数呼び出しループが完了したら、 ChatHistory
オブジェクトを調べて、セマンティック カーネルによって行われたすべての関数呼び出しと結果を確認できます。
ステップワイズプランナーとハンドルバープランナーはどうなりましたか?
Stepwise および Handlebars プランナーは非推奨となり、セマンティック カーネル パッケージから削除されました。 これらのプランナーは、Python、.NET、または Java ではサポートされなくなりました。
ほとんどのシナリオでは、より強力で使いやすい 関数呼び出しを使用することをお勧めします。
既存のソリューションを更新するには、 Stepwise Planner 移行ガイドに従ってください。
ヒント
新しい AI エージェントの場合は、非推奨のプランナーの代わりに関数呼び出しを使用します。 柔軟性が向上し、組み込みのツールサポートが提供され、開発エクスペリエンスが簡単になります。
次のステップ
セマンティック カーネルでのプランナーの動作を理解したので、AI エージェントがユーザーに代わってタスクを最適に計画および実行できるように、AI エージェントに与える影響について詳しく学習できます。