生成AIアプリケーションを作る中で、大規模言語モデル(LLM)にJSONを生成してもらいたい場面があるかと思います。
一般的にはLangChainのJSON parserや、LLMのFunction callingでJSON部分を取得する方法がありますが、本記事は、純粋にプロンプトエンジニアリングのみで期待通りのJSONを生成する方法について、試行錯誤のまとめです。
よく陥る失敗パターン
例えば、以下のようなダミーデータをJSONで生成させたい場合、
{
"activityDate": "2024-07-02",
"account": "株式会社ダミー企業",
"subject": "初回訪問",
"detail": "株式会社ダミー企業との初回お打ち合わせを実施。製品Xを紹介し、・・・"
}
プロンプトの書き方によっては以下のようなレスポンスになり、後続のparse処理でエラーになることが考えられます。
失敗パターン#1 余計な文章が付加される
JSON部分のみを生成してほしいのに、前後に余計な説明文章が入ってくるパターン。
JSON形式を作成しました。
{
"activityDate": "2024-07-02",
"account": "株式会社ダミー企業",
"subject": "初回訪問",
"detail": "株式会社ダミー企業との初回お打ち合わせを実施。製品Xを紹介し、・・・"
}
このJSONデータには、以下の情報が含まれております。activityDa・・・
失敗パターン#2 JSON形式がおかしい
一部または全体的に、JSONが期待する形式と異なってしまうケース。
{
"アクティビティ日": "2024-07-02",
"企業": "株式会社ダミー企業",
"タイトル": "初回訪問",
"詳細": "株式会社ダミー企業との初回お打ち合わせを実施。製品Xを紹介し、・・・"
}
失敗パターン#3 そもそもJSONが作成されない
プロンプトの指示とフォーマットがあまりにもずれていると、そもそもJSONが全く作成されないケースも考えられます。
よくわかりませんでした。もう一度試してください。
解決策
上記パターンを回避し、期待するJSONを得るためのTipsです。
#1 Temperatureの設定
一般的にこの値が小さいと回答のバラツキが抑えられ、大きいとランダム度が増します。JSON生成では失敗パターン#1 余計な文章が付加される
の発生を抑えるために、極力temperature=0.0
に設定します。
#2 明確な指示
すごくシンプルなことですが、JSONのみを出力して欲しい旨をきちんと記述します。また、最終行をJSON:
で終わらせることでも、失敗パターン#1 余計な文章が付加される
の抑制効果が期待できます。
プロンプト
以下フォーマットのJSONを生成してください。
JSONフォーマット:
(フォーマットについて記述)
最終応答は、"{"で始まり"}"で終わる。または"["で始まり"]"で終わるJSONのみを出力し、JSON以外の文字は一切応答に含めないでください。
JSON:
#3 JSONフォーマットの指定
#3.1 JSON 形式
期待するJSONフォーマットを元に、項目値の部分に指示内容を自然言語で記述します。
{
"activityDate": "活動日(yyyy-MM-dd形式)",
"account": "顧客企業名",
"subject": "営業活動のタイトル",
"detail": "営業活動の詳細"
}
シンプルな構造だとこれで大丈夫なことが多いです。ただ、構造が複雑になればなるほど、期待と異なる形式で出力される可能性も高まります。
また、目視では問題なさそうでも実は特殊な文字コードのスペースが入っていて、後続のJSON parse処理でエラー発生。という事象に遭遇したことがありました。
=> なるべくJSONフォーマット部分には、余計なスペース・改行を含めない方が良さそうです。
以下フォーマットのJSONで返答してください。
JSONフォーマット:
{"activityDate":"活動日(yyyy-MM-dd形式)","account":"顧客企業名","subject":"営業活動のタイトル","detail":"営業活動の詳細"}
最終応答は、"{"で始まり"}"で終わる、または"["で始まり"]"で終わるJSONのみを出力し、JSON以外の文字は一切応答に含めないでください。
JSON:
#3.2 JSON Schema 形式
少し複雑な構造を扱う場合は、JSON Schema形式で記述するのがおすすめです。
{
"type": "object",
"description": "営業活動データ",
"properties": {
"activityDate": {"type": "string", "format": "date", "description": "営業活動の実施日"},
"account": {"type": "string", "description": "営業活動先企業"},
"subject": {"type": "string", "description": "営業活動の件名"},
"detail": {"type": "string", "description": "営業活動の詳細説明"}
}
}
JSON Schemaを使うとデータ型、LLMへの指示等を指定フォーマットで定義できるので、人間の可読性も確保しつつ、失敗パターン#2 JSON形式がおかしい
の発生をだいぶ抑えられます。
以下のJSON Schemaに厳密に従ってJSONで返答してください。
JSON Schema:
{
"type": "object",
"properties": {
"activityDate": {"type": "string", "format": "date", "description": "営業活動の実施日"},
"account": {"type": "string", "description": "営業活動先企業"},
"subject": {"type": "string", "description": "営業活動の件名"},
"detail": {"type": "string", "description": "営業活動の詳細説明"}
}
}
最終応答は、"{"で始まり"}"で終わる、または"["で始まり"]"で終わるJSONのみを出力し、JSON以外の文字は一切応答に含めないでください。
JSON:
ユースケース別のプロンプト例
これらTipsを実践した、いくつかのユースケースを想定したプロンプト例です。
ダミーデータ生成
以下のJSON Schemaに厳密に従って、ダミーの活動データ3件をJSONで生成してください。
JSON Schema:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "array",
"items": {
"type": "object",
"properties": {
"activityDate": {"type": "string", "format": "date", "description": "営業活動の実施日"},
"account": {"type": "string", "description": "営業活動先企業"},
"subject": {"type": "string", "description": "営業活動の件名"},
"detail": {"type": "string", "description": "営業活動の詳細説明"}
}
}
}
最終応答は、"["で始まり"]"で終わるJSONのみを出力し、JSON以外の文字は一切応答に含めないでください。
JSON:
[
{
"activityDate": "2022-04-01",
"account": "株式会社A",
"subject": "新製品プレゼンテーション",
"detail": "新製品のプレゼンテーションを行いました。詳細については、資料をご参照ください。"
},
{
"activityDate": "2022-04-02",
"account": "株式会社B",
"subject": "契約更新の打ち合わせ",
"detail": "契約更新についての打ち合わせを行いました。次回は具体的な条件について話し合う予定です。"
},
{
"activityDate": "2022-04-03",
"account": "株式会社C",
"subject": "新規ビジネス提案",
"detail": "新規ビジネスの提案を行いました。彼らは興味を持っているようで、引き続き話を進めていきます。"
}
]
非構造データ ⇒ 構造データ変換
自然言語文章をJSON形式の構造データに変換
ユーザインプットから活動データを抽出し、以下のJSON Schemaに厳密に従ってJSONを生成してください。
JSON Schema:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "array",
"items": {
"type": "object",
"properties": {
"activityDate": {"type": "string", "format": "date", "description": "営業活動の実施日"},
"account": {"type": "string", "description": "営業活動先企業"},
"subject": {"type": "string", "description": "営業活動の件名"},
"detail": {"type": "string", "description": "営業活動の詳細説明"}
}
}
}
ユーザインプット:
2024年6月10日の活動です。午前、株式会社ABCに訪問。新商品の提案を実施し、新商品の特長や価格について説明。その後、株式会社XYZにも訪問。契約更新の再確認と更新に関して話し合いました。午後には株式会社123にメールで見積もりを送付しました。
最終応答は、"["で始まり"]"で終わるJSONのみを出力し、JSON以外の文字は一切応答に含めないでください。
JSON:
[
{
"activityDate": "2024-06-10",
"account": "株式会社ABC",
"subject": "新商品の提案",
"detail": "新商品の特長や価格について説明"
},
{
"activityDate": "2024-06-10",
"account": "株式会社XYZ",
"subject": "契約更新の再確認と更新",
"detail": "契約更新に関して話し合い"
},
{
"activityDate": "2024-06-10",
"account": "株式会社123",
"subject": "見積もりの送付",
"detail": "メールで見積もりを送付"
}
]
非構造データ ⇒ 構造データ変換(エラーハンドリング対応)
前ユースケース非構造データ ⇒ 構造データ変換
を応用し、失敗パターン#3 そもそもJSONが作成されない
対策tとして、例外エラーも考慮したJSON構造を定義します。
- success - 正常時はtrue、エラー時はfalse
- payload - 正常時、データはpayloadに格納
- errorMessage - エラー発生時のみ、エラー内容をここに書き出す
ユーザーインプットから活動データを抽出し、以下のJSON Schemaに厳密に従ってJSONを生成してください。(もし抽出が上手くできない場合もJSON Schemaに厳密に従ってエラー内容をJSONで生成してください)
JSON Schema:
{
"type": "object",
"description": "営業活動データを抽出できた場合もエラーで抽出できなかった場合も対応したJSONです",
"properties": {"success": {"type": "boolean", "description":"営業活動データ抽出が成功したかどうか"}},
"required": ["success"],
"if": {"properties": { "success": { "const": true } }},
"then": {
"properties": {
"payload": {
"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": ["payload"]
},
"else": {
"properties": {
"errorMessage": {"type": "string", "description": "エラー内容の詳細を記述します"}
},
"required": ["errorMessage"]
}
}
ユーザーインプット:
(ユーザーインプット)
最終応答は、"{"で始まり"}"で終わる、または"["で始まり"]"で終わるJSONのみを出力し、JSON以外の文字は一切応答に含めないでください。`
JSON:
成功時
ユーザーインプット
2024年6月10日の活動です。午前、株式会社ABCに訪問。新商品の提案を実施し、新商品の特長や価格について説明。その後、株式会社XYZにも訪問。契約更新の再確認と更新に関して話し合いました。午後には株式会社123にメールで見積もりを送付しました。
{
"success": true,
"payload": [
{
"activityDate": "2024-06-10",
"account": "株式会社ABC",
"subject": "新商品の提案",
"detail": "新商品の特長や価格について説明"
},
{
"activityDate": "2024-06-10",
"account": "株式会社XYZ",
"subject": "契約更新の再確認",
"detail": "契約更新に関して話し合い"
},
{
"activityDate": "2024-06-10",
"account": "株式会社123",
"subject": "見積もりの送付",
"detail": "メールで見積もりを送付"
}
]
}
エラー発生時
ユーザーインプット
おはようございます。今日はいい天気ですね。
レスポンス
{
"success": false,
"errorMessage": "営業活動データが含まれていないため、抽出できませんでした。"
}
【付録】 JSON -> JSON Schema 変換
JSON Schemaを作成するのが面倒!という場合は、ChatGPTやClaudeあたりに以下プロンプトを投げてJSON Schemaのベースを作成してもらい、それを元に適宜修正していくのがおすすめです。
プロンプト
以下JSONをJSON Schema 形式(スキーマ:2020-12)に変換してください。
JSON:
(期待するJSONをここに記述)
Claude 3.5 Sonnet Artifactsでの実行イメージ
まとめ
JSONだけを出力させるためのプロンプトTipsをまとめます。
- temperature=0.0に設定する
- JSONだけ生成して欲しい旨を明確に指示する
- JSONフォーマットはJSON Schemaで記述する
- 最終行を
JSON:
で終わらせる - (JSONモード対応モデルを使う場合はONにする)