見出し画像

kintoneのデータ定義形式を参考に、任意のアプリケーションのデータ定義をChatGPTで生成してもらう

先日、行政が公開している統計文章のような非構造化データをGPTを用いて構造化データへ変換する例を記事に書いたところ、大きな注目を頂くことができました。

あるデータを構造化データとして利活用するための分析コストパフォーマンスが低ければ低いほどGPTのようなLLMを利用してデータ変換を行うコストパフォーマンスが高くなることを示せたのと同時に、死蔵されやすい統計データの利活用への道筋を示せたことに対して評価頂けたのかなと思います。

いろいろなデータ変換のバリエーションを試しつつ、LLMの可能性を探って行けたら良いなー、などと感じています。

データ定義を元にデータ定義を生成したい

閑話休題。

あるプラットフォームにおけるデータ定義の構造を元に、プラットフォーム上で動作させるアプリケーションのデータ定義を行うことは、システムエンジニアのような仕事をしている人間のタスクとしてよくあることです。

以下はkintone APIにおけるデータ定義のフォーマットです。

kintoneは、サイボウズ株式会社が提供するクラウド型の業務改善プラットフォームであり、開発の知識がなくても自社の業務に合わせたシステムを簡単に作成できるクラウドサービスです。業務アプリを直感的に作成でき、チーム内で共有して業務効率化を図ることができます。日報・スケジュール管理・お問い合わせ管理・顧客管理・採用管理などの、実践的に使えるアプリを作成・運用することが可能です。
Perplexity.aiによるkintoneの説明
{
  "properties": {
    "文字列__1行_": {
      "type": "SINGLE_LINE_TEXT",
      "code": "文字列1行_0",
      "label": "文字列 (1行)",
      "noLabel": false,
      "required": true,
      "unique": true,
      "maxLength": "64",
      "minLength": "0",
      "defaultValue": "",
      "expression": "",
      "hideExpression": false
    },
    "数値": {
      "type": "NUMBER",
      "code": "数値_0",
      "label": "数値",
      "noLabel": true,
      "required": false,
      "unique": false,
      "maxValue": "64",
      "minValue": "0",
      "defaultValue": "12345",
      "expression": "",
      "digit": true,
      "displayScale": "",
      "unit": "$",
      "unitPosition": "BEFORE"
    },
    "ラジオボタン": {
      "type": "RADIO_BUTTON",
      "code": "ラジオボタン_0",
      "label": "ラジオボタン",
      "noLabel": false,
      "required": true,
      "defaultValue": "sample2",
      "options": {
        "sample1": {
          "label": "sample1",
          "index": "0"
        },
        "sample2": {
          "label": "sample2",
          "index": "1"
        },
        "sample3": {
          "label": "sample3",
          "index": "2"
        }
      },
      "align": "horizontal"
    },
    "チェックボックス": {
      "type": "CHECK_BOX",
      "code": "チェックボックス_0",
      "label": "チェックボックス",
      "noLabel": false,
      "required": false,
      "defaultValue": ["sample1", "sample3"],
      "options": {
        "sample1": {
          "label": "sample1",
          "index": "0"
        },
        "sample2": {
          "label": "sample2",
          "index": "2"
        },
        "sample3": {
          "label": "sample3",
          "index": "1"
        }
      },
      "align": "horizontal"
    },
    "日付": {
      "type": "DATE",
      "code": "日付_0",
      "label": "日付",
      "noLabel": false,
      "required": false,
      "unique": true,
      "defaultValue": "",
      "defaultNowValue": true
    },
    "日時": {
      "type": "DATETIME",
      "code": "日時_0",
      "label": "日時",
      "noLabel": false,
      "required": false,
      "unique": false,
      "defaultValue": "2012-07-19T00:00Z",
      "defaultNowValue": false
    },
    "添付ファイル": {
      "type": "FILE",
      "code": "添付ファイル_0",
      "label": "添付ファイル",
      "noLabel": true,
      "required": false,
      "thumbnailSize": "150"
    },
    "リンク": {
      "type": "LINK",
      "code": "リンク_0",
      "label": "リンク",
      "noLabel": true,
      "required": false,
      "unique": false,
      "defaultValue": "http://hoge.xxx",
      "maxLength": "64",
      "minLength": "0",
      "protocol": "WEB"
    },
    "ユーザー選択": {
      "type": "USER_SELECT",
      "code": "ユーザー選択_0",
      "label": "ユーザー選択",
      "noLabel": true,
      "required": false,
      "defaultValue": [
        {
          "code": "user1",
          "type": "USER"
        },
        {
          "code": "group1",
          "type": "GROUP"
        },
        {
          "code": "org1",
          "type": "ORGANIZATION"
        },
        {
          "code": "LOGINUSER()",
          "type": "FUNCTION"
        }
      ],
      "entities": [
        {
          "code": "user1",
          "type": "USER"
        },
        {
          "code": "group1",
          "type": "GROUP"
        }
      ]
    },
    "関連レコード一覧": {
      "type": "REFERENCE_TABLE",
      "code": "関連レコード一覧_0",
      "label": "関連レコード一覧",
      "noLabel": true,
      "referenceTable": {
        "relatedApp": {
          "app": "3",
          "code": "参照先アプリ"
        },
        "condition": {
          "field": "このアプリのフィールド",
          "relatedField": "参照するアプリのフィールド"
        },
        "filterCond": "数値 > 10 and 数値2 > 20",
        "displayFields": ["表示するフィールド1", "表示するフィールド2"],
        "sort": "ソートフィールド1 desc, ソートフィールド2 asc",
        "size": "5"
      }
    },
    "ルックアップ": {
      "type": "SINGLE_LINE_TEXT",
      "code": "ルックアップ_0",
      "label": "ルックアップ",
      "noLabel": true,
      "required": false,
      "lookup": {
        "relatedApp": {
          "app": "100",
          "code": "コピー元アプリのアプリコード"
        },
        "relatedKeyField": "コピー元のフィールド",
        "fieldMappings": [
          {
            "field": "コピー先のフィールド",
            "relatedField": "コピー元のフィールド"
          }
        ],
        "lookupPickerFields": ["ルックアップ選択時に表示されるフィールド1"],
        "filterCond": "数値 > 10 and 数値2 > 20",
        "sort": "ソートフィールド1 desc, ソートフィールド2 asc"
      }
    },
    "グループ": {
      "type": "GROUP",
      "code": "グループ_0",
      "label": "グループ",
      "noLabel": true,
      "openGroup": true
    },
    "テーブル": {
      "type": "SUBTABLE",
      "code": "テーブル_0",
      "label": "テーブル",
      "noLabel": false,
      "fields": {
        "文字列__1行_テーブル": {
          "type": "SINGLE_LINE_TEXT",
          "code": "文字列__1行_テーブル",
          "label": "文字列 (1行)テーブル",
          "noLabel": false,
          "required": true,
          "unique": false,
          "maxLength": "64",
          "minLength": "0",
          "defaultValue": "",
          "expression": "",
          "hideExpression": false
        }
      }
    },
    "ステータス": {
      "type": "STATUS",
      "code": "ステータス",
      "label": "ステータス",
      "enabled": "true"
    },
    "作業者": {
      "type": "STATUS_ASSIGNEE",
      "code": "作業者",
      "label": "作業者",
      "enabled": "true"
    },
    "カテゴリー": {
      "type": "CATEGORY",
      "code": "カテゴリー",
      "label": "カテゴリー",
      "enabled": "true"
    }
  },
  "revision": "2"
}

この情報を元に人間の手で新しくデータ定義を作るのは骨が折れます。簡単なスクリプトを書いて自動化することもできそうですが、LLMを使えばもっと簡単にデータ定義を作ることができます。

ChatGPTへのプロンプト

フォームのフィールドの種別が以下のJSONのように定義されている。

【ここにkintoneのデータ定義JSONを貼り付ける】

例えば「文字列__1行_」キーの示す情報は以下である。
- 項目の名前: 文字列__1行_
- 項目の型: SINGLE_LINE_TEXT

この定義を利用し、以下の項目を備える採用管理アプリケーションのデータ構造を表すようなJSONを作成せよ。またcodeはプログラムコードからの利用がしやすいよう、英数文字で表現せよ。

- 名前(テキスト、名字と名前を分けること)
- 性別(選択式)
- 誕生日(日付)
- 電話番号(テキスト、構造化する)
- 学歴(テーブル式で複数行登録できるように)
- 職歴(テーブル式で複数行登録できるように)
- 資格取得歴(テーブル式で複数行登録できるように)
- 志望動機(テキスト)
- 自己PR(テキスト)

データ定義をコンテキストとして与え、アウトプットして欲しい形式をふわっと指定しています。何となくよくありそうなデータ構造ですよね。

アウトプットされたJSON

以下がアウトプットされたJSONです。

{
  "properties": {
    "last_name": {
      "type": "SINGLE_LINE_TEXT",
      "code": "last_name",
      "label": "名字",
      "noLabel": false,
      "required": true,
      "unique": false,
      "maxLength": "64",
      "minLength": "0",
      "defaultValue": "",
      "expression": "",
      "hideExpression": false
    },
    "first_name": {
      "type": "SINGLE_LINE_TEXT",
      "code": "first_name",
      "label": "名前",
      "noLabel": false,
      "required": true,
      "unique": false,
      "maxLength": "64",
      "minLength": "0",
      "defaultValue": "",
      "expression": "",
      "hideExpression": false
    },
    "gender": {
      "type": "RADIO_BUTTON",
      "code": "gender",
      "label": "性別",
      "noLabel": false,
      "required": true,
      "defaultValue": "male",
      "options": {
        "male": {
          "label": "男性",
          "index": "0"
        },
        "female": {
          "label": "女性",
          "index": "1"
        }
      },
      "align": "horizontal"
    },
    "birthday": {
      "type": "DATE",
      "code": "birthday",
      "label": "誕生日",
      "noLabel": false,
      "required": true,
      "unique": false,
      "defaultValue": "",
      "defaultNowValue": false
    },
    "phone": {
      "type": "GROUP",
      "code": "phone",
      "label": "電話番号",
      "noLabel": true,
      "openGroup": true,
      "fields": {
        "phone_number": {
          "type": "SINGLE_LINE_TEXT",
          "code": "phone_number",
          "label": "番号",
          "noLabel": true,
          "required": true,
          "unique": false,
          "maxLength": "11",
          "minLength": "10",
          "defaultValue": "",
          "expression": "",
          "hideExpression": false
        },
        "phone_type": {
          "type": "RADIO_BUTTON",
          "code": "phone_type",
          "label": "種類",
          "noLabel": true,
          "required": true,
          "defaultValue": "mobile",
          "options": {
            "mobile": {
              "label": "携帯電話",
              "index": "0"
            },
            "home": {
              "label": "自宅電話",
              "index": "1"
            },
            "work": {
              "label": "勤務先電話",
              "index": "2"
            }
          },
          "align": "horizontal"
        }
      }
    },
    "education": {
      "type": "SUBTABLE",
      "code": "education",
      "label": "学歴",
      "noLabel": false,
      "fields": {
        "school": {
          "type": "SINGLE_LINE_TEXT",
          "code": "school",
          "label": "学校名",
          "noLabel": false,
          "required": true,
          "unique": false,
          "maxLength": "64",
          "minLength": "0",
          "defaultValue": "",
          "expression": "",
          "hideExpression": false
        },
        "major": {
          "type": "SINGLE_LINE_TEXT",
          "code": "major",
          "label": "専攻",
          "noLabel": false,
          "required": true,
          "unique": false,
          "maxLength": "64",
          "minLength": "0",
          "defaultValue": "",
          "expression": "",
          "hideExpression": false
        },
        "degree": {
          "type": "RADIO_BUTTON",
          "code": "degree",
          "label": "学位",
          "noLabel": false,
          "required": true,
          "defaultValue": "bachelor",
          "options": {
            "bachelor": {
              "label": "学士",
              "index": "0"
            },
            "master": {
              "label": "修士",
              "index": "1"
            },
            "doctor": {
              "label": "博士",
              "index": "2"
            }
          },
          "align": "horizontal"
        },
        "start_date": {
          "type": "DATE",
          "code": "start_date",
          "label": "入学日",
          "noLabel": false,
          "required": true,
          "unique": false,
          "defaultValue": "",
          "defaultNowValue": false
        },
        "end_date": {
          "type": "DATE",
          "code": "end_date",
          "label": "卒業日",
          "noLabel": false,
          "required": true,
          "unique": false,
          "defaultValue": "",
          "defaultNowValue": false
        }
      }
    },
    "work_experience": {
      "type": "SUBTABLE",
      "code": "work_experience",
      "label": "職歴",
      "noLabel": false,
      "fields": {
        "company": {
          "type": "SINGLE_LINE_TEXT",
          "code": "company",
          "label": "会社名",
          "noLabel": false,
          "required": true,
          "unique": false,
          "maxLength": "64",
          "minLength": "0",
          "defaultValue": "",
          "expression": "",
          "hideExpression": false
        },
        "position": {
          "type": "SINGLE_LINE_TEXT",
          "code": "position",
          "label": "役職",
          "noLabel": false,
          "required": true,
          "unique": false,
          "maxLength": "64",
          "minLength": "0",
          "defaultValue": "",
          "expression": "",
          "hideExpression": false
        },
        "start_date": {
          "type": "DATE",
          "code": "start_date",
          "label": "入社日",
          "noLabel": false,
          "required": true,
          "unique": false,
          "defaultValue": "",
          "defaultNowValue": false
        },
        "end_date": {
          "type": "DATE",
          "code": "end_date",
          "label": "退社日",
          "noLabel": false,
          "required": false,
          "unique": false,
          "defaultValue": "",
          "defaultNowValue": false
        },
        "description": {
          "type": "MULTI_LINE_TEXT",
          "code": "description",
          "label": "業務内容",
          "noLabel": false,
          "required": false,
          "unique": false,
          "maxLength": "1000",
          "minLength": "0",
          "defaultValue": "",
          "expression": "",
          "hideExpression": false
        }
      }
    },
    "qualification": {
      "type": "SUBTABLE",
      "code": "qualification",
      "label": "資格取得歴",
      "noLabel": false,
      "fields": {
        "name": {
          "type": "SINGLE_LINE_TEXT",
          "code": "name",
          "label": "資格名",
          "noLabel": false,
          "required": true,
          "unique": false,
          "maxLength": "64",
          "minLength": "0",
          "defaultValue": "",
          "expression": "",
          "hideExpression": false
        },
        "date": {
          "type": "DATE",
          "code": "date",
          "label": "取得日",
          "noLabel": false,
          "required": true,
          "unique": false,
          "defaultValue": "",
          "defaultNowValue": false
        }
      }
    },
    "motivation": {
      "type": "MULTI_LINE_TEXT",
      "code": "motivation",
      "label": "志望動機",
      "noLabel": false,
      "required": false,
      "unique": false,
      "maxLength": "1000",
      "minLength": "0",
      "defaultValue": "",
      "expression": "",
      "hideExpression": false
    },
    "self_pr": {
      "type": "MULTI_LINE_TEXT",
      "code": "self_pr",
      "label": "自己PR",
      "noLabel": false,
      "required": false,
      "unique": false,
      "maxLength": "1000",
      "minLength": "0",
      "defaultValue": "",
      "expression": "",
      "hideExpression": false
    }
  },
  "revision": "1"
}

ちゃんとサブテーブルのようなデータ構造まで使って表現できているところが素晴らしいですね。

このように、あるデータからパターンを認知し、認知した情報を元に与えられたコンテキストから新しい情報を生成するようなプロンプトの実行精度は非常に高いなと体験的に感じています。

与えられた仕様やRawデータからアルゴリズムそのものをAIが考え実行するパラダイムはSoftware 2.0と呼ばれていますが、アプリケーション全体をLLMで生成するような大きなものでなくとも、個別の関数の実装をプロンプトで行うような流れは既に来ています。


この記事が気に入ったらサポートをしてみませんか?