Apexからプロンプトテンプレート呼び出し時、JSONモード
を有効にできるか?試しました。
本記事ではOpenAIのJSONモードを使用します
https://platform.openai.com/docs/guides/json-mode
JSONモードとは
一般的にプロンプトにJSONを出力させようとすると、生成コンテンツ内にJSON以外の余計な文字列が含まれる可能性があります。
OpenAIの一部対応モデルでは、JSONモード
を設定することで純粋にJSONのみ生成するよう制限することができ、後続パース処理でのエラー発生の軽減、パフォーマンス改善が期待できます。
対応モデル
現時点で、以下モデルが JSONモード
に対応しているようです。(2024年7月18日時点)
- gpt-4o
- gpt-4-turbo
- gpt-3.5-turbo
To prevent these errors and improve model performance, when using gpt-4o, gpt-4-turbo, or gpt-3.5-turbo, you can set...
プロンプトテンプレートでJSONモードを使うには
プロンプトテンプレートはApexから呼び出し可能です。Apexから呼び出す際、LLM側の設定を細かく指定することができます。また、LLMプロバイダー固有のパラメータを渡すことも可能です。
- ConnectApi
- EinsteinLlmAdditionalConfigInput (LLM共通の設定)
- additionalParameters (LLMプロバイダー固有の設定)
- EinsteinLlmAdditionalConfigInput (LLM共通の設定)
ConnectApi.EinsteinLlmAdditionalConfigInput
Additional configuration information for the LLM provider.
Property Type Description Required or Optional additionalParameters Map<String, ConnectApi.WrappedValue> Map of parameters and values for the LLM provider. Optional
このプロパティを使い、JSONモード
が有効になるようなOpenAI固有のパラメータを定義してLLMを呼び出します。
検証
フリーテキストの入力文章を指定フォーマットのJSONに変換するプロンプトを想定し、1.プロンプトテンプレート
とそれを呼び出す 2.Apex
を作成します。
1. プロンプトテンプレートの作成
呼び出すプロンプトテンプレートを、プロンプトビルダーで作成します。
設定
- 種別
Flex
- プロンプトテンプレート名
フリーテキストをJSONに変換
- API参照名
convertTextToJson
- リソース定義
- #1
- 名前:
フリーテキスト
- パラメータ名:
inputText
- データ型:
String
- 名前:
- #2
- 名前:
JSONスキーマ
- パラメータ名:
jsonSchema
- データ型:
String
- 名前:
- #1
プロンプトテンプレート
テンプレート本体
以下JSON Schemaに厳密に従って
ユーザーの入力文章からデータを抽出し
JSONデータを返答します
JSON Schema:"""
{!$Input:jsonSchema}
"""
ユーザーの入力文章:"""
{!$Input:inputText}
"""
JSON:
モデル
- OpenAI GPT 4 Omni
2. Apexコードの作成
JSONモード
でプロンプトテンプレートを呼び出すためのコード例です。
// テンプレートパラメータの設定
String promptTemplateName = 'convertTextToJson';
String jsonSchema = '';
String inputText = '';
// プロンプト呼び出しの設定
ConnectApi.EinsteinPromptTemplateGenerationsInput promptGenerationsInput = new ConnectApi.EinsteinPromptTemplateGenerationsInput();
promptGenerationsInput.isPreview = false;
// 入力パラメータの定義
ConnectApi.WrappedValue jsonSchemaWrappedValue = new ConnectApi.WrappedValue();
jsonSchemaWrappedValue.value = jsonSchema;
ConnectApi.WrappedValue inputTextWrappedValue = new ConnectApi.WrappedValue();
inputTextWrappedValue.value = inputText;
promptGenerationsInput.inputParams = new Map<String, ConnectApi.WrappedValue>{
'Input:jsonSchema' => jsonSchemaWrappedValue,
'Input:inputText' => inputTextWrappedValue
};
// LLM共通の設定
promptGenerationsInput.additionalConfig = new ConnectApi.EinsteinLlmAdditionalConfigInput();
promptGenerationsInput.additionalConfig.applicationName = 'PromptTemplateGenerationsInvocable';
promptGenerationsInput.additionalConfig.temperature = 0.0;
// OpenAI固有の設定 - JSONモード有効化
Map<String, String> jsonType = new Map<String, String>{
'type' => 'json_object'
};
ConnectApi.WrappedValue responseFormatProperty = new ConnectApi.WrappedValue();
responseFormatProperty.value = jsonType;
promptGenerationsInput.additionalConfig.additionalParameters = new Map<String, ConnectApi.WrappedValue>{
'response_format' => responseFormatProperty
};
// プロンプトテンプレートの呼び出し実行
ConnectApi.EinsteinPromptTemplateGenerationsRepresentation generationsOutput = ConnectApi.EinsteinLLM.generateMessagesForPromptTemplate(promptTemplateName, promptGenerationsInput);
ConnectApi.EinsteinLLMGenerationItemOutput response = generationsOutput.generations[0];
System.debug(response.text);
〜Apexコードの解説〜
[解説] テンプレートパラメータの設定
String promptTemplateName = 'convertTextToJson';
String jsonSchema = '';
String inputText = '';
- promptTemplateName
- 作成したプロンプトテンプレートのAPI参照名
'convertTextToJson'
を指定
- 作成したプロンプトテンプレートのAPI参照名
- jsonSchema
- 変換したいJSONオブジェクト構造をJSON Schema形式で記載
- inputText
- JSONに変換したい自然言語文章をここに記載
ConnectApi.WrappedValue jsonSchemaWrappedValue = new ConnectApi.WrappedValue();
jsonSchemaWrappedValue.value = jsonSchema;
ConnectApi.WrappedValue inputTextWrappedValue = new ConnectApi.WrappedValue();
inputTextWrappedValue.value = inputText;
promptGenerationsInput.inputParams = new Map<String, ConnectApi.WrappedValue>{
'Input:jsonSchema' => jsonSchemaWrappedValue,
'Input:inputText' => inputTextWrappedValue
};
- inputParams
- Input:jsonSchema
- 設定したテンプレートパラメータ
jsonSchema
- 設定したテンプレートパラメータ
- Input:inputText
- 設定したテンプレートパラメータ
inputText
- 設定したテンプレートパラメータ
- Input:jsonSchema
[解説] LLM共通の設定
LLM呼び出し時の設定を定義します。
// applicationName
promptGenerationsInput.additionalConfig.applicationName = 'PromptTemplateGenerationsInvocable';
// temperature
promptGenerationsInput.additionalConfig.temperature = 0.0;
// additionalParameters
promptGenerationsInput.additionalConfig.additionalParameters = new Map<String, ConnectApi.WrappedValue>();
- applicationName
-
'PromptTemplateGenerationsInvocable'
を指定
-
- temperature
- 今回は生成結果のランダム性を求めてないので
0.0
を指定
- 今回は生成結果のランダム性を求めてないので
-
additionalParameters
- MaxToken、temperature、numGenerations等以外のLLMプロバイダー固有のパラメータはここで定義
[解説] OpenAI固有の設定
プロンプトテンプレート呼び出し時のLLMプロバイダー固有(今回はOpenAI)の設定を定義します。
Map<String, String> jsonType = new Map<String, String>{
'type' => 'json_object'
};
ConnectApi.WrappedValue responseFormatProperty = new ConnectApi.WrappedValue();
responseFormatProperty.value = jsonType;
promptGenerationsInput.additionalConfig.additionalParameters = new Map<String, ConnectApi.WrappedValue>{
'response_format' => responseFormatProperty
};
今回は、ここにOpenAIが定めるJSONモード
を有効にするための設定として、response_format
を指定しています。
- additionalParameters
- response_format
{type: "json_object"}
- response_format
you can set response_format to { "type": "json_object" } to enable JSON mode. When JSON mode is enabled, the model is...
[解説] プロンプトテンプレートの呼び出し実行
promptTemplateName
とpromptGenerationsInput
を渡してメソッドを呼び出すことで、組み立てられたプロンプトがLLM側にリクエストされます。
ConnectApi.EinsteinPromptTemplateGenerationsRepresentation generationsOutput = ConnectApi.EinsteinLLM.generateMessagesForPromptTemplate(promptTemplateName, promptGenerationsInput);
最終的な promptTemplateName
, promptGenerationsInput
は以下の通りです。
-
promptTemplateName =
'convertTextToJson'
-
promptGenerationsInput
- isPreview =
false
- inputParams
- Input:jsonSchema =
jsonSchema
- Input:inputText =
inputText
- Input:jsonSchema =
- additionalConfig
- applicationName =
'PromptTemplateGenerationsInvocable'
- temperature =
0.0
- additionalParameters
- response_format
- type =
'json_object'
- type =
- response_format
- applicationName =
- isPreview =
3. プロンプト実行
以下の入力パラメータでプロンプトテンプレートを実行すると、
String jsonSchema = '{"$schema": "https://json-schema.org/draft/2020-12/schema","type": "object","properties": {"records": {"type": "array","items": {"type": "object","properties": {"activityDate": {"type": "string","format": "date","description": "営業活動の実施日"},"account": {"type": "string","description": "営業活動先企業"},"subject": {"type": "string","description": "営業活動の件名"},"detail": {"type": "string","description": "営業活動の詳細説明"}},"required": ["activityDate", "account", "subject", "detail"]}}},"required": ["records"]}';
String inputText = '2024年6月10日の活動です。午前、株式会社ABCに訪問。新商品の提案を実施し、新商品の特長や価格について説明。その後、株式会社XYZにも訪問。契約更新の再確認と更新に関して話し合いました。午後には株式会社123にメールで見積もりを送付しました。';
グラウンディング後のプロンプトは以下のようになります。
以下JSON Schemaに厳密に従って
ユーザーの入力文章からデータを抽出し
JSONデータを返答します
JSON Schema:"""
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"records": {
"type": "array",
"items": {
"type": "object",
"properties": {
"activityDate": {
"type": "string",
"format": "date",
"description": "営業活動の実施日"
},
"account": {
"type": "string",
"description": "営業活動先企業"
},
"subject": {
"type": "string",
"description": "営業活動の件名"
},
"detail": {
"type": "string",
"description": "営業活動の詳細説明"
}
},
"required": ["activityDate", "account", "subject", "detail"]
}
}
},
"required": ["records"]
}
"""
ユーザーの入力文章:"""
2024年6月10日の活動です。午前、株式会社ABCに訪問。新商品の提案を実施し、新商品の特長や価格について説明。その後、株式会社XYZにも訪問。契約更新の再確認と更新に関して話し合いました。午後には株式会社123にメールで見積もりを送付しました。
"""
JSON:
生成結果 (通常モードの場合)
JSONモードを使わず通常モードで出力すると、
```json
{
"records": [
{
"activityDate": "2024-06-10",
"account": "株式会社ABC",
"subject": "新商品の提案",
"detail": "新商品の特長や価格について説明"
},
{
"activityDate": "2024-06-10",
"account": "株式会社XYZ",
"subject": "契約更新の再確認",
"detail": "契約更新に関して話し合い"
},
{
"activityDate": "2024-06-10",
"account": "株式会社123",
"subject": "見積もり送付",
"detail": "メールで見積もりを送付"
}
]
}
```
文頭、文末に余計な文字 ```json
、 ```
が入ってしまいますが、
生成結果 (JSONモードの場合)
JSONモードをONにすると、
{
"records": [
{
"activityDate": "2024-06-10",
"account": "株式会社ABC",
"subject": "新商品の提案",
"detail": "新商品の特長や価格について説明"
},
{
"activityDate": "2024-06-10",
"account": "株式会社XYZ",
"subject": "契約更新の再確認",
"detail": "契約更新に関して話し合い"
},
{
"activityDate": "2024-06-10",
"account": "株式会社123",
"subject": "見積もり送付",
"detail": "メールで見積もりを送付"
}
]
}
無事、JSONのみを取得することができました!
おわりに
JSONモードを使うと、より正確で構造化されたデータを取得できるので便利です。ただ、油断は禁物です。適切なプロンプト設計が重要なのは変わらないので、プロンプトビルダーを活用して継続的にプロンプトを改善しましょう。