結論
gpt-3.5-turbo が下記の性能をもつため、バッチシステムのコンバータでの商用利用が十分可能そうです
- コストが比較的安い (1000 tokenで0.002USD)
- messages の工夫とtemperature=0の指定で出力形式が安定する(システムに組み込むために重要)
- messages の工夫で性能を改善できる(コードが全く書けなくても!コードが書ける人でも普通にコード書くよりも全然早く作れそう)
検証内容
今回、対象にしたコンバータは経産省の住所変換コンポーネントです。ここのreadmeに記載のアウトプットのフォーマットは以下です
{
"@type": "場所型",
"住所": {
"@type": "住所型",
"表記": "霞が関2-1-10",
"都道府県": "東京都",
"都道府県コード": "http://data.e-stat.go.jp/lod/sac/C13000",
"市区町村": "千代田区",
"市区町村コード": "http://data.e-stat.go.jp/lod/sac/C13101",
"町名": "霞が関",
"丁目": "2",
"番地": "1",
"号": "10"
},
"地理座標": {
"@type": "座標型",
"緯度": "35.675551",
"経度": "139.750413"
}
}
これはinputもjson形式で書く必要がありますが、文字列を受け付けてそれっぽく返すか検証します。
検証結果
messages に指定するための文字列です。*ここのパターンの工夫次第で性能はまだまだあがりそうです
role_system ='日本の住所をパースする機能。IMI語彙記法の規約に従う'
question_1 = "霞が関2-1-10"
answer_1 = '''{
"@type": "場所型",
"住所": {
"@type": "住所型",
"表記": "霞が関2-1-10",
"都道府県": "東京都",
"都道府県コード": "http://data.e-stat.go.jp/lod/sac/C13000",
"市区町村": "千代田区",
"市区町村コード": "http://data.e-stat.go.jp/lod/sac/C13101",
"町名": "霞が関",
"丁目": "2",
"番地": "1",
"号": "10"
},
"地理座標": {
"@type": "座標型",
"緯度": "35.675551",
"経度": "139.750413"
}
}'''
question_2 = "霞が関 二の一の十"
answer_2 = '''{
"@type": "場所型",
"住所": {
"@type": "住所型",
"表記": "霞が関2-1-10",
"都道府県": "東京都",
"都道府県コード": "http://data.e-stat.go.jp/lod/sac/C13000",
"市区町村": "千代田区",
"市区町村コード": "http://data.e-stat.go.jp/lod/sac/C13101",
"町名": "霞が関",
"丁目": "2",
"番地": "1",
"号": "10"
},
"地理座標": {
"@type": "座標型",
"緯度": "35.675551",
"経度": "139.750413"
}
}'''
question_3 = "東京都千代田区霞が関2丁目1番地10号"
answer_3 = '''{
"@type": "場所型",
"住所": {
"@type": "住所型",
"表記": "霞が関2-1-10",
"都道府県": "東京都",
"都道府県コード": "http://data.e-stat.go.jp/lod/sac/C13000",
"市区町村": "千代田区",
"市区町村コード": "http://data.e-stat.go.jp/lod/sac/C13101",
"町名": "霞が関",
"丁目": "2",
"番地": "1",
"号": "10"
},
"地理座標": {
"@type": "座標型",
"緯度": "35.675551",
"経度": "139.750413"
}
}'''
問い合わせてみます
ask = "東京都千代田区千代田1番1号"
res = openai.ChatCompletion.create(
model="gpt-3.5-turbo-0301",
messages=[
{"role": "system", "content": role_system},
{"role": "user", "content": question_1},
{"role": "assistant", "content": answer_1},
{"role": "user", "content": question_2},
{"role": "assistant", "content": answer_2},
{"role": "user", "content": question_3},
{"role": "assistant", "content": answer_3},
{"role": "user", "content": ask}
]
)
print(res["choices"][0]["message"]["content"])
その出力
{
"@type": "場所型",
"住所": {
"@type": "住所型",
"表記": "千代田1-1",
"都道府県": "東京都",
"都道府県コード": "http://data.e-stat.go.jp/lod/sac/C13000",
"市区町村": "千代田区",
"市区町村コード": "http://data.e-stat.go.jp/lod/sac/C13101",
"町名": "千代田",
"丁目": "1",
"番地": "1",
"号": ""
},
"地理座標": {
"@type": "座標型",
"緯度": "35.693840",
"経度": "139.753136"
}
}
地理座標もだいたい正しく(番地単位では不正確)、市区町村コードも正しい結果が返ってきました。
以降、askの変数だけのせます
Qiita社の住所
入力
ask = "愛知県名古屋市中村区名駅3-28-12"
結果
{
"@type": "場所型",
"住所": {
"@type": "住所型",
"表記": "愛知県名古屋市中村区名駅3-28-12",
"都道府県": "愛知県",
"都道府県コード": "http://data.e-stat.go.jp/lod/sac/C23000",
"市区町村": "名古屋市中村区",
"市区町村コード": "http://data.e-stat.go.jp/lod/sac/C23208",
"町名": "名駅",
"丁目": "3",
"番地": "28",
"号": "12"
},
"地理座標": {
"@type": "座標型",
"緯度": "35.170764",
"経度": "136.881032"
}
}
すげぇ!!!
https://qiita.com/miya0001/items/598070abcdf0799daebc を参考に鼻血がでそうな入力で試します
入力
ask = "京都府京都市東山区大和大路通正面下る大和大路2"
出力
{
"@type": "場所型",
"住所": {
"@type": "住所型",
"表記": "京都府京都市東山区大和大路通正面下る大和大路2",
"都道府県": "京都府",
"都道府県コード": "http://data.e-stat.go.jp/lod/sac/C26000",
"市区町村": "京都市東山区",
"市区町村コード": "http://data.e-stat.go.jp/lod/sac/C26105",
"町名": "",
"丁目": "",
"番地": "大和大路通正面下る",
"号": "2"
},
"地理座標": {
"@type": "座標型",
"緯度": "34.994032",
"経度": "135.771858"
}
}
入力
ask = "七尾市藤橋町亥45番地1"
出力
{
"@type": "場所型",
"住所": {
"@type": "住所型",
"表記": "七尾市藤橋町亥45-1",
"都道府県": "石川県",
"都道府県コード": "http://data.e-stat.go.jp/lod/sac/C17000",
"市区町村": "七尾市",
"市区町村コード": "http://data.e-stat.go.jp/lod/sac/C17206",
"町名": "藤橋町",
"丁目": "",
"番地": "亥45",
"号": "1"
},
"地理座標": {
"@type": "座標型",
"緯度": "37.042778",
"経度": "136.964167"
}
}
おしい!
最後にプロンプトをチューニングしたらいけるか検証
answer_4 = '''{
"@type": "場所型",
"住所": {
"@type": "住所型",
"表記": "京都府京都市東山区大和大路通正面下る大和大路2",
"都道府県": "京都府",
"都道府県コード": "http://data.e-stat.go.jp/lod/sac/C26000",
"市区町村": "京都市東山区",
"市区町村コード": "http://data.e-stat.go.jp/lod/sac/C26105",
"町名": "大和大路",
"丁目": "2",
"番地": "",
"号": ""
},
"地理座標": {
"@type": "座標型",
"緯度": "34.990157",
"経度": "135.771012"
}
}'''
question_5 = "七尾市藤橋町亥45番地1"
answer_5 = '''{
"@type": "場所型",
"住所": {
"@type": "住所型",
"表記": "石川県七尾市藤橋町亥45-1",
"都道府県": "石川県",
"都道府県コード": "http://data.e-stat.go.jp/lod/sac/C17000",
"市区町村": "七尾市",
"市区町村コード": "http://data.e-stat.go.jp/lod/sac/C17205",
"町名": "藤橋町",
"丁目": "1",
"番地": "45",
"号": "1"
},
"地理座標": {
"@type": "座標型",
"緯度": "37.037160",
"経度": "136.953824"
}
}'''
ask = "京都府京都市東山区大和大路通正面下る大和大路1"
res = openai.ChatCompletion.create(
model="gpt-3.5-turbo-0301",
messages=[
{"role": "system", "content": role_system},
{"role": "user", "content": question_1},
{"role": "assistant", "content": answer_1},
{"role": "user", "content": question_2},
{"role": "assistant", "content": answer_2},
{"role": "user", "content": question_3},
{"role": "assistant", "content": answer_3},
{"role": "user", "content": question_4},
{"role": "assistant", "content": answer_4},
{"role": "user", "content": question_5},
{"role": "assistant", "content": answer_5},
{"role": "user", "content": ask}
],
temperature=0
)
print(res["choices"][0]["message"]["content"])
出力
申し訳ありませんが、京都市東山区には「大和大路通正面下る大和大路1」という住所は存在しません。もう一度住所を確認していただけますか?
流石に難しいか
気になるお値段ですが、Qiita社の住所のケースで1027tokenだったので、約0.002USDです。本当に大量に使う場合はChatGPT APIを叩く前にキャッシュするとか工夫できそうですが、0から開発するコストを考えるとかなり安いはずです。
今回はすでに公開されている開発済みのコンバータの再現なので、そのままの需要はなさそうですが、新規で新しいコンバータを開発するさいは、こんな感じで入出力のサンプルだけ用意しておけば、かなりの性能が出ますし、自前で開発してもどうせエッジケースの処理は苦しむので、まずは試してみる!が良さそうです
これはバッチ処理でも革命が起こりそうです