🧑‍🎓

GPT-4o mini API を使って言語学習アプリを作ってみた

2024/07/25に公開

先日、OpenAI が新しい大規模言語モデル(LLM)である GPT-4o mini を発表しました。

週末に軽く触っていて「これくらいの返答速度、品質、コストならオンデマンドで学習コンテンツを生成してもある程度機能するのでは?」とふと思い立ったので、サクッと動くものを作ってみました。こんな感じのアプリです。

まだ開発を始めて数日ですが、ある程度使えそうなレベルで形になったので LingoNuance という名前でSlack ワークスペース内で動作する連携アプリとして公開しています。ライブデモをこちらからインストールすることができます:

https://bit.ly/get-lingo-nuance

このアプリは取得するアクセス権限を必要最小限に絞っており、このアプリの bot との 1:1 の DM 以外のチャットには一切アクセスできません。ユーザー側からのメッセージ送信も無効化していて、誤って機密情報を与えてしまうこともありません。そのため、セキュリティ上の問題が発生するリスクは極めて低いとはいえますが、念の為、テスト用の Slack ワークスペースなどで試すようにしてください。

最近、フリープランのワークスペースを作る代わりにサンドボックス環境も作成できるようになったので、そちらでも OK です。

https://zenn.dev/slack/articles/2871491988a4bc

どのようなアプリかを説明している文章を転載しておきます:

Slack で使える LingoNuance を使って語学力をレベルアップしましょう!単語やフレーズの暗記だけの学習法を超えて、実際の場面で自然に返答する方法を学ぶことができます。言語学習がもっと楽しく実用的なものになるでしょう。

LingoNuance の使い方はとても簡単です。ラジオボタンを使って 4 つの選択肢から選ぶだけ。とてもシンプルですが、その過程で質問・選択肢をたくさん読むのでリーディングスピードの改善、ライティングに役立つフレーズの習得に役立ちます。またこのアプリはモバイルでも簡単に使えるように設計されているので、空いた時間に外出先でも学習できます。

LingoNuance の体験をカスタマイズするために CEFR レベルを目標としているレベルに合わせましょう。あなたの状況(例:留学生、国際企業のソフトウェアエンジニア、アメリカ在住の研究者など)をアプリに伝えることでより現実的なシチュエーションにあった設問が提供されます。また、母国語を設定しておくと、正解とともに翻訳も確認できるので、馴染みのない単語やフレーズをより簡単に理解することができます。

LingoNuance は無料で誰でも制限なく利用できます。言語学習を楽しんでください!

動作イメージ

上の短いビデオだと分かりにくいところもあると思うので、簡単に機能を紹介します。

インストールして LingoNuance との DM にアクセスすると、設定用のボタンが表示されるので、開くと以下の内容を設定することができます。

この設定で問題を出題してもらうとこんな感じになります。母語を質問に使うオプションを選択している場合は質問文は日本語になります。

ラジオボタンから選択肢をクリックすると、選択したものが太字になり、正解と翻訳が表示されます。

次は設定を少し変えてみましょう。シンガポールに留学中の大学生の設定にしてみます。

この設定だと質問内容が大きく変わります。

同じように回答すると、正解と翻訳が表示されます。

もし「翻訳が邪魔だなー」という場合、母国語の設定をブランクにすることで、学習中の言語の原文だけが表示されるようになります。

どのように学習コンテンツを作っているか

コンテンツの生成には GPT-4o mini の API を使っています。

まだ最適な質問と選択肢の組み合わせを 100% 生成できているわけではないので、細かいところは色々試しながら調整しているのですが、大まかには以下のような感じでやっています。

回答するユーザーの設定を伝える
  • 学習中の言語(英語、韓国語、スペイン語・・)
  • 目指している習熟レベル(CEFR で C2, C1, B2, B1, A2 から選択)
  • 母語(設定すると正解表示時に翻訳も併記、初期設定で Slack 利用言語を自動設定)
  • 状況のコンテキスト(留学生、外資企業の社員、研究者など)
  • 母語を問題文表示に使うかどうか(レベルが B1 や A2 の場合、問題文を学習中の言語で読むのは負荷が高いので、母語で表示して回答の選択肢だけを学習中言語にできる)
  • 同じ問題を出題しないようにこのユーザーとの DM の直近履歴を含める
出題全体を以下の内容を含む JSON 形式(後処理を楽にするため)で出力するよう伝える
  • 問題文、選択肢 1, 2, 3, 4、正解の選択肢番号、解説を生成する
  • 母語が選択されている場合は上のものを全て母語にしたものも付加する
回答しようがない曖昧な設問とならないよう以下を明確にするよう指示する
  • 遭遇しうる現実的な状況を想定した上でそこでどう応答するかという出題形式
  • 場面に関係する人々とのやりとり・彼らのプロフィールを含めて、できる限り詳細に描写する
  • その言語が話される国や地域の文化を考慮して状況や表現を選ぶ
  • 正解の選択肢が最も適切である理由を理解できるよう明快かつ具体的なヒントを含める
  • CEFR レベルが低い場合でもこの部分はできるだけ詳細にする
選択肢についても以下のような指示を伝える
  • 選択肢を作成する前に 1 から 4 のどれかをランダムに選び、3 なら選択肢 3 を正解にし 4 なら選択肢 4 を正解にすること(そうしないと 1 ばかりが正解になったりするため)
  • 選択肢の文章はできるだけ長くする(ただし Slack UI の制約上 140 文字まで)
  • 正解は他よりも明らかに関連性が高く、自然で説得力があることにに議論の余地がないこと
  • ネイティブスピーカーとの会話でも自然な応答として使える例を示す
  • A2 / B1 レベルの学習者向けにあえて文法が間違った文章を選択肢として含めるのは構わない

概ね「そんな感じになるだろうなー」という印象かもしれませんが、最後にある「選択肢の順序の制御」は疑問に思われた人もいるかもしれません。ここを生成 AI にやらせているのは、そうしないと自然言語で書かれた解説部分との整合性が取れなくなるためです。「プロンプトを作る前に乱数で決めた数字を埋めて選択肢の正解をどこに配置するかを具体的に指定する」という方法も試してみましたが、これだと実際に正解かどうかに関係なく、問答無用で「その番号が正解だ」という間違った出力を作ってしまうのでやめました。

2024/08/27 更新: 上記の実装でしばらく意図通りに動いていたのですが、8 月に入ってからしばらくして、当時のプロンプト(1-4 のうちランダムに数字を一つ選んで、それに対応する選択肢を正解にしてくださいという命令)だと正解の位置が固定されてしまうように挙動が変わったため、「正解の選択肢の位置はランダムになるようにしてください」という感じのもっと素直な命令に変更しました。モデル自体に追加で微調整が入ったのか、あるいは API サーバー内の前処理・後処理が多少変更されたのかはわかりませんが・・リリース後もこのような変更はありえるんですねぇ。

この形式に落ち着いた経緯

そんなこんなで試行錯誤した結果(今もまだ続けていますが)、許容範囲と言ってよさそうな品質の出題が安定的にできるようになった印象です。

この出題形式にする前は、出題形式にバリエーションが欲しいという理由から「言語学習者の役に立つ出題」といったような曖昧な指示にしていました。しかし、この指示では、無茶苦茶な出題(形式と言葉の対応だけが合っていて人間が回答不能なもの)をしてしまうことが多く、うまくいきませんでした。

今の形式の難点としては、やっていくうちに選択肢の書き出しでなんとなく正解かどうかわかるようになってきたりはするのですが・・(笑)、型が決まっていることで「何なんだ、この意味不明な質問は・・・」というものが出てくることはほぼなくなりました(少なくとも上位の CEFR レベルでは)。

ただ、上で引用したアプリの説明にもあるように「たくさん読む」というのもこのアプリの目的だったりするので「頭出しだけ読んで機械的にどんどん正解していく」というよりも「質問と選択肢をちゃんと読む」「知らない単語やフレーズが出てきたら翻訳を読んで理解する」という使い方がよいのではないかなと思っています。

まだ残っている課題

一定の形にはなったものの、今もまだ以下のような課題があるなぁと感じています。

  • 「正解の理由の意味がわからない」という問題を抑制した結果、だいたいのパターンで「前向きに話を進める善良な市民」というパーソナリティを期待する出題になりがち(悪いわけではないが、出題傾向の幅がない)
  • その言語が話される国や地域の文化を考慮するよう指示を入れてはいるが、プロンプトが英語で書かれているためか、英語的な表現が多く、他言語でベストな表現ではないケースがある
  • 初学者がついていけるレベルの出題ではない(私の韓国語や息子の英語はまだ A1 レベルなので全くついていけない)
  • CEFR A1 だとまともな問題を作ることができない(「彼は何時に来ますか?」「5 時です」とか「夏は何をするのが良いですか?」とかそんなレベルになってしまう)
  • 初学者向けに類義語を問うようなシンプルな問題も作らせてみたが、CEFR の考慮をうまくできないし、問題としてもかなり微妙なものが出てきがち

アプリの技術スタック

最後に軽く技術スタックについても触れておきます。

今回のアプリの利用シーンを Slack に限定する必要は特にないのですが、(本業なので)それでやるのが早いということから、以下の構成でつくりました。

アプリのフレームワークとしては Slack Edge を使っています。Cloudflare Workers をはじめとするエッジファンクションで動作する TypeScript のフレームワークです。このフレームワークについては、最初にリリースしたときに詳しい記事を書いたので、ご興味あれば読んでみてください。

https://zenn.dev/seratch/articles/c370cf8de7f9f5

今のところ、ソースコードを公開する予定はないのですが、ある程度開発が落ち着いてきて、公開する意義がありそうなら公開するかもしれません。

(・・・ここで急に少し本業の宣伝みたいになりますが)

ちなみに一般論として、この手のアプリを Slack プラットフォームで作る場合、ログイン認証、UI 設計、モバイルアクセスへの最適化などの非機能要件を自分で実装しなくてよいという開発者目線でのメリットがあります。一方で「Web サイトでできることができない」など UI 上の制約などのデメリットもありますし、そもそもエンドユーザーが「Slack で使いたい」と思っていることが前提なので、もちろん要件次第ではあります。

今後の展開

このアプリを作ったのは「とにかく週末にふと思いついたアイデアを試してみたかった!」というのが一番の理由ですが、少なくとも自分自身が長く使い続けられるものにしたいなという気持ちもあります。

今の出題形式だけだと限界がありそうなので、時間を見つけて他のアイデアも色々試していきたいなと思っています。

また、このアプリで試したアイデアは、良質なデータを提供できる RAG の仕組みと連携させることで「社内 e-learning コンテンツを自動生成する」といった方向性でも発展性があるのかもしれないと感じました。

以上、生成 AI を使って LingoNuance というアプリを作ってみたという話でした。これを読んで興味を持った方は、ぜひライブデモをインストールして試してみてください。

https://bit.ly/get-lingo-nuance

Discussion