株式会社COMPASS
🤖

実践プロンプトエンジニアリング -データに基づく改善サイクルの回し方-

2024/06/17に公開

こんにちは!株式会社COMPASSのデータ・AIユニットのR&D部でAIエンジニアをしている中本です!現在は主にLLMを用いた技術検証や、実際の開発現場での活用を目指した研究開発を行っています。最近球技大会でソフトボールをやってきたのですが、2試合やって全敗でした!負けはしたのですが、ヒットが打てたので嬉しかったです!研究開発も楽しいですが、いい天気の時に運動をすることも楽しいですね!

前回は問題の類似度推定に関する取り組みを紹介させてもらいましたが、COMPASSではその他にも様々なシーンでLLMを活用した取り組みを行っています。具体的な事例もたくさんありますが、今回はその中でもプロンプトエンジニアリングをどのように行っているか、どのように改善サイクルを回しているかというところについてご紹介します。後半では実際に出力したいアウトプットのゴールを設定した上で、どのように試行錯誤を進めているかというところについても具体的な事例をもとにご紹介できればと思います!

前回の記事はこちら
https://zenn.dev/qubena/articles/80ff8f883fd42f


この記事はこんな方におすすめ

  • これからLLMを使った取り組みを進めようとしている方
  • プロンプトエンジニアリングの進め方について知りたい方
  • プロンプトエンジニアリングの具体的な事例を探している方

背景

LLMが登場したことにより、AIによるデータの学習、アウトプットまでの流れに大きな変化が起きました。従来の機械学習は大量のデータを使ってモデルを訓練し、そのデータからパターンを学習する必要があり、特徴量をどのように見極めるか、どのようにその特徴量を拾うかなどについては高い専門性が必要でした。また、ユースケースに関しても特定のユースケースやタスク(画像分類や音声認識)に特化して作られることが多く、各タスクに対して個別にモデルを設計し、チューニングする必要がありました。

一方LLMは、解決したい課題に関するデータを用意する必要はありますが、何度もそのデータを投入して学習を繰り返すというよりも、期待する出力が出るような指示の設計(プロンプトエンジニアリング)を行っていくことでアウトプットを改善していくというのが主な流れとなっています。また、特定のユースケースに特化したモデルをユースケースごとに作っていくというよりも、やはりこちらもプロンプトエンジニアリングによりユースケースを実現していく形になります。このように、期待する結果を得るためのプロセスが今までとは大きく変わったと考えています。そして、言ってしまうと今までよりもより簡単に期待する結果を得られるようになったと言えるのではないかと考えています。

ただし、簡単とはいっても複雑なタスクを実現するためのプロンプトの作成には一定の知見が必要で、LLMにどのようなプロンプトを渡すとどのような結果が返ってくるかなどのクセを把握し、結果を見ながら改善していく必要があります。そこで今回は私が普段業務でどのようにプロンプトエンジニアリングを行っているかというところについての考え方や実際の事例をご紹介していければと思います!

プロンプトエンジニアリングの進め方

プロンプトエンジニアリングを行うにあたって、まず最初はシステムプロンプトとユーザープロンプトを見れるプレイグラウンドを使って、ベースとなるプロンプトをドラフトしていきます。ここまではプロンプトエンジニアリングをする人はみなさん共通かなと考えています。ここからはプロンプトエンジニアリングの進め方について、工夫しているポイントを紹介していきます。

ドラフトは日本語で書く

最初のドラフトの段階で行っている工夫として、ドラフトは日本語で書いていくという点です。LLMの性質として、学習基盤となる情報は基本的に英語であることが多いです。(Chat GPTは英語の情報を学習基盤としている)そのため、より正確な結果を得るためには英語でプロンプトを作成するというのが一つのベストプラクティスとなっています。一方で、私自身が英語に堪能であればそれも難しくないのですが、期待する結果を得るための細かい修正を行う場合、一つ一つの修正にやりたいことを英語に直すという工程が発生するので、ドラフトの段階で英語を扱うと細かい検証スピードが落ちてしまいます。そこで、まずは日本語でドラフトを書き、ある程度期待する結果が出るまで、細かい改善を繰り返します。特に、内容の本質に関わる部分もそうですが、出力をjsonで出してほしいけれども出してくれない、指示を出す角度を変えてみる、みたいな大枠でのドラフトを進めていきます。まずはこれがファーストステップです。

有効なテストデータの作成

実際のシステム開発においてもそうですが、動作を検証する場合、特に精度を検証したい場合はある程度豊富で多様性のあるテストデータがなければ、プロンプトを修正したことによって改善したかどうかがわかりにくくなってしまいます。そこで、あるタスクを行う対象となるテストデータを100件〜200件でもいいので頑張って作るようにしています。もちろん、多くテストデータがあればあるに越したことはないのですが、私が取り組んでいるタスクでは目安として上記の件数くらいを用意することを心がけています。また、各データの性質に偏りがないように集めていくというところも有効なデータを用意する上でも重要だと考えています。例えば私が取り組むタスクではキュビナに搭載されている問題を取り扱っています。その際にテストデータとしてある1学年だけ、文章題だけ、のように偏りがあると期待する結果が出ないことが多いのでなるべく満遍なく問題を集めるようにしています。その際に、私は問題の専門家ではないので、コンテンツ企画開発部の方々に相談したりするなど、なるべく正しく偏りなくテストデータを集められるような工夫をしています。テストデータが本当にこれで有効か?という観点を常に持っておくことが重要だと考えています。

丁寧なテスト結果の分析

テストデータが出来上がったら、今度は実際にプロンプトにテストデータを投入して実験をしていきます。偶然期待していた結果が出た!ということも絶対にないとは言い切れませんが、大体の場合は一発では期待する結果を得られないことが多いと思います。この時、気持ちとしてはなんとなく結果を見て目についたところから改善のための修正をしていきたくなりますが、できるだけ丁寧にうまくいかない原因を分析することが重要だと考えています。私はテストを行った時に、まずは期待しない結果が出たものだけをリストアップし、実際に起こっている現象を記載していきます。そして、その現象をカテゴライズし、課題の本質が何かを見極めます。課題の例としては、単純な得手不得手(画像が多い問題は苦手、など)、出力フォーマットが違う、ハルシネーションが起きている、などがあり、それぞれに何件ずつ当てはまっているのかといったところを見ながら、優先的に改善する箇所がどこかなどを決めて修正を加えていきます。書いてみても思いましたが、かなり泥臭い作業を行っていますね。

このように、いくつかの工夫をもとにプロンプトエンジニアリングを進めていきますが、サイクルとしては丁寧なテスト結果の分析から得られた知見をもとに、修正したプロンプトを適用して結果を見てまた分析をして...という作業を繰り返して改善をしていきます。

実際のタスクでプロンプトエンジニアリングを進めてみる

それでは今回も具体的な例を用いて実際にプロンプトエンジニアリングを進めてみましょう。今回取り扱うタスクは、キュビナの数学の問題テキストを「問題部分」と「解説部分」に分けるというものになります。前提として、キュビナの数学の問題は問題部分と解説部分に分かれています。下記の図の文字色が黒いものが問題部分、赤いものが解説部分となっています。


キュビナの数学の問題例。イラストの上側が問題部分、下側が解説部分。

以前の取り組みで、数式やイラストを含む画像をOCRやLLMを使ってテキスト化するというものがありましたが、この時、問題部分と解説部分を一つのテキストデータとして抽出していました。

数式やイラストを含む画像をOCRやLLMを使ってテキスト化した話についてはこちら。
https://zenn.dev/qubena/articles/abc8b2b7690668

実際に問題文を分析していくにあたっては問題部分のみを使った分析、解説部分のみを使った分析を行えるのが望ましいので、できれば抽出したテキストをこのように表現できると嬉しいです。

問題テキストをこんな感じで問題部分と解説部分に分けたい

ということで、キュビナの数学の問題テキストを「問題部分」と「解説部分」に分けるというタスクについて、前章の内容を踏まえてプロンプトエンジニアリングを行っていきましょう!

テストデータの用意

今回対象とするのはキュビナに搭載されている数学の問題です。用意するテストデータの目安として100〜200件程度と記載しましたが、今回の事例では97問を用意しました。テストデータとしては目安に対してやや少なめではありますが、前述の通り、問題のバリエーションはなるべく豊富になるように整えました。範囲としては小学校1年生の問題から中学校3年生の問題が混在しており、問題形式も計算問題、文章題、穴埋め問題、選択問題などキュビナに搭載されている問題のバリエーションをある程度満遍なくチョイスしました。また、そのうち約半数の42問が画像を含んでいる問題となっています。テストデータとしてはやや少なめな方ではあるものの、問題のバリエーションに偏りが出ないようにテストデータを用意できたので、テストデータとしては有効なものが揃ったのではないでしょうか。

期待する結果

今回取り扱うタスクのところでも触れましたが、既にテキスト化されている問題データを問題部分と解説部分に分割するというものです。具体的な例をもう少し詳細に見ていきましょう。先ほどの猫の数と犬の数の足し算の問題のテキストデータがこちらになります。

問題のテキストデータ

ねこが4ひきといぬが4ひきいます。
ぜんぶでなんびきかしきとこたえをかきましょう。
<figure>4匹の猫と4匹の犬がそれぞれ描かれており、猫と犬がそれぞれ4匹ずついます。</figure>
ねこ4ひきといぬ4ひきをあわせるので、たしざんのしきをつくります。
4+4
たしざんのけっかが8なので、こたえは8ぴきです。
4+4=8

図を見ると問題部分と解説部分については直感的に分割できるように見えますが、テキスト化されていると、問題部分と解説部分の切れ目はわかりづらい状態になっています。また、問題部分の「文章」と解説部分の「文章」を取得したいと考えていますので、画像が含まれている問題については画像の<figure>タグで囲まれた情報は落としたいです。そうした時に、1〜2行目が問題部分として抽出され、3行目は飛ばして、4〜7行目が解説部分として抽出されるというのが期待される挙動となります。

  • 問題部分

ねこが4ひきといぬが4ひきいます。
ぜんぶでなんびきかしきとこたえをかきましょう。

  • 解説部分

ねこ4ひきといぬ4ひきをあわせるので、たしざんのしきをつくります。
4+4
たしざんのけっかが8なので、こたえは8ぴきです。
4+4=8

プロンプト設計(1回目)

それでは実際にプロンプト設計に入っていきます。今回は記事としての分かりやすさも踏まえて、プロンプトは最後まで日本語を用いて行っていこうと思いますが、必要に応じて最終適用する段階で英訳したものにするなどの工夫ができると思います。では最初のドラフトをPlaygroundで作ってみました。


Playgroundでのドラフトの様子

ドラフトしたプロンプト全文

あなたは優秀なアシスタントです。

学校の先生は生徒の問題集を作りたいのですが、現在解説が書かれた資料のみを持っています。生徒には解説部分や答えは見せたくありません。
あなたのタスクは、問題文と解説文が混じった文章を、問題部分と解説部分に分割することです。

# ユーザーからの入力
- "target": 問題文と解説文が混じった文章
ここで、"target"には図が示されている場合があります。図は<figure></figure>で囲まれています。また、資料をOCR(文字認識)をした結果であるため、誤字なども含まれる可能性があります。

# 期待される出力内容
- "problem": 問題部分を抜き出したもの。(基本的に書き換えはしないこと。ただし、穴埋めの部分は"__"や"ア"など、適切なマスキングを行うこと。<figure>は含まないこと)
- "solution": 解説部分を抜き出したもの(基本的に書き換えはしないこと。<figure>を含まないこと。該当部分がない場合は、"None"を出力すること)

# 出力形式 (以下の形式の出力のみを行うこと。不要なことは出力しないこと)
{"problem": "~~~", "solution": "~~~"}

# 入出力例
1.
INPUT:
{target":"1本150円のリンゴをx個買ったときの式を, xを使って表しましょう。 リンゴをx個買ったときの代金は1個の値段×本数で求めることができるから代金は<math>150 \times x</math>と表せる。"}
OUTPUT:
{"problem": "1本150円のリンゴをx個買ったときの式を, xを使って表しましょう。", "solution": "リンゴをx個買ったときの代金は1個の値段×本数で求めることができるから代金は<math>150 \times x</math>と表せる。"}

2.
INPUT:
{"target":"次の数の逆数を求めましょう。 <math>\frac{1}{3} = \frac{1}{3}</math> である。 <math>\frac{1}{3} \times \frac{3}{1} = 1</math>となるので、<math>\frac{3}{1}</math> = 3が逆数である。"}
OUTPUT:
{"problem": "次の数の逆数を求めましょう。 <math>\frac{1}{3}", "solution": "\frac{1}{3}</math> である。 <math>\frac{1}{3} \times \frac{3}{1} = 1</math>となるので、<math>\frac{3}{1}</math> = 3が逆数である。"}

3.
INPUT:
{"target":"あおいフウセンが 17 こ, きいろいフウセンが 3こあります。どちらが なんこ おおいか、__を埋めましょう。<math>17 - 3 = 4</math><figure>12個の青いフウセンと4個の黄色いフウセンのイラスト</figure>"}
OUTPUT:
{"problem": "あおいフウセンが 17 こ, きいろいフウセンが 3こあります。どちらが なんこ おおいか、__を埋めましょう。<math>17 - 3 = __</math>", "solution": "NONE"}

ひとまずざっくりとかけたところで、実際の問題を1つ入力して、どのような挙動をするかを試してみました。試した問題はこちらです。


ドラフトしたプロンプトを試してみた問題

プロンプトを試してみた問題のテキストデータ

けいさんをしましょう。
12 - 9
12を10と2にわけてかんがえます。10から9をひくと1になるので、1と2をたしてこたえは3です。
<figure>3行にわたって2列のブロックのイラストが描かれています。最上行には12個のブロックがあり、そのうち10個が1つの大きな枠内に、残りの2個が別の枠内に配置されています。矢印によってブロックが動かされ、真ん中の行では10個のブロックから1個が除かれています。最下行では、除かれた1個のブロックが残りの2個のブロックの枠へ移動しており、合わせて3個のブロックが1つの枠内に配置されています。</figure>

実際にLLMにこの問題のテキストデータを入力してみた結果がこちらです。

プロンプトの実行結果

出力結果について、問題部分はproblem要素として、解説部分はsolution要素としてjson形式で出力をしていますが、この問題については期待通り問題部分と解説部分を分けて出力してくれていますね!ということで、他にも簡単に何問か試してみて、ある程度の結果が期待できそうだったので、残りの97件のデータでテストを行うことにしました。

実験結果

ということで、実際に97問でやってみた結果としてLLMによって抽出された問題部分、解説部分が、人力で分けた結果とどれくらい一致したのか?(完全一致したものはどれくらいか?)というところを基準に精度を測ってみました!その結果がこちらです。

問題部分の一致率 解説部分の一致率
69.1% 85.6%

解説部分については85.6%とまずまずな結果ではありますが、問題部分については69.1%と、数問試してみていけるかなと思っていたところもあり、期待していたほどの精度は出ませんでした。ということで、ここからプロンプトの改善を行っていくわけですが、まずは先ほどもご紹介した通り、テスト結果を分析してみたいと思います。今回は正しくない結果であったものに対して、間違えたのかというところを1問1問見ていき、それらをカテゴリ分けして、それぞれのカテゴリの間違いが何件ほどあるかというところをまとめてみました。

問題文の抽出について

  • 許容可能な表記ゆれなど、実際は正解として良い … 13件
  • 穴埋めじゃない箇所が穴埋めになってしまった … 7件
  • 問題部分に答えが含まれる … 5件
  • 穴埋めにすべきだが、できなかった(答えが含まれる) … 2件
  • 図が含まれる(今回は図は含まないようにしたい) … 1件
  • 抽出漏れの箇所がある … 1件
  • 途中式が含まれる … 2件

解説文の抽出について

  • 許容可能な表記ゆれなど、実際は正解として良い … 7件
  • 一部解説が不足(問題文側に含まれてしまった) … 5件
  • 問題文を一部含む … 2件

この中でも件数の多い「許容可能な表記ゆれなど、実際は正解として良い」についてですが、元のテキストに含まれない句読点が追加されていたり、ふりがなが無くなっていたり、と問題部分、解説部分の内容に直接関係ない部分の間違いとなります。最初の指針としては手動で分けたものと「完全一致するかどうか」で精度を測っていました。ですが、これらの間違いについては抽出するにあたってはクリティカルではないため許容して問題ないとした時に改めて精度を見てみると、このようになりました。

問題部分の一致率 解説部分の一致率
85.6% 92.8%

こうしてみると、1回目からかなりいい精度が出ていますね!ですが間違え方で多いものを見てみると、やはり問題によってうまく情報が抽出できていないため、特に問題部分の抽出精度の方を高めていきたいと考えています。ということで、問題部分の間違いの原因別の件数を見ていきましょう。

まずは、間違い件数1位の「穴埋めじゃない箇所が穴埋めになった」というものについてですが、これは問題情報が欠けてしまうということになるのでよくありません。実際の間違いを見てみましょう。

穴埋めじゃない箇所が穴埋めになった問題例

これに対して、LLMで実際に出力された結果がこちらになります。

  • 問題部分

下の図で, AO=CO, <math>¥angle OAD=¥angle OCB</math>ならば, AD=CBである。
このことを証明するために、次の問に答えなさい。
(1) AD=CBを導くには, どの三角形とどの三角形の合同を示せばよいか答えなさい。 (解答例 __)

  • 解説部分

<math>¥triangle AOD</math>と<math>¥triangle COB</math>が合同ならば, 合同である図形では対応する辺は等しいので, AD=CBであるといえる。

大部分がうまく抽出できているように見えます!しかし、ここまでうまくやってくれているのにも関わらず、問題部分の解答例の部分が、謎に穴埋めになってしまいました。。これはあくまで一例ではあるものの、句読点が追加されるなどの間違いに対して問題情報が欠落してしまうというのは問題があるということで、こちらは改善していきたいと思います。

次は、間違い件数2位「問題部分に答えが含まれる」というものについてです。特に、「式を答えなさい」という問題なのに、問題文側に式を入れてしまうパターンが多く見受けられました。こちらも実際の間違いを見てみましょう。

問題部分に答えが含まれる問題例

これに対して、LLMで実際に出力された結果がこちらになります。

  • 問題部分

えをみてたしざんのしきをかきましょう。しき <math>1 + 4</math>

  • 解説部分

1こと4こをあわせるので,しきは <math>1 + 4</math>。

これはいけません!文字通りですが、問題部分に答えが含まれてしまっています。こちらは見て明らかに改善した方が良い項目ということで、改善していきたいです。

このように、一つ一つ丁寧に結果を分析していくことにより、次回のプロンプト設計でどのような方針で直していくべきかというところを考察していきます。ということで、この結果を元にプロンプトを修正、つまりプロンプトエンジニアリングをしていきたいと思います!

プロンプト設計(2回目)

本来であれば全ての項目を分析してそれぞれを解消するように設計していくのですが、今回はハンズオン的な内容になっているので、前章で課題になった「穴埋めじゃない箇所が穴埋めになった」「問題部分に答えが含まれる」についてプロンプトエンジニアリングを行っていきます。

穴埋めじゃない箇所が穴埋めになった

まずこれを解消するときに、LLMが何を思ったのかを想像してみます。仮説ではありますが、今回は穴埋めがどのような時に用いられているのかをLLMがあまりよくわかっていなかったのではないかと考え、問題部分における穴埋めの扱いの部分を詳しく書き直してみました。

穴埋めの扱いを詳細にしたプロンプト

- 穴埋め問題の場合はすでに穴埋め部分が正しい答えで埋められていることがあります。その場合は"answer"を参考にしながら、"__"や、"ア", "イ"などの問題に適した形でマスキングした"problem"を出力ください。これは、元の問題が穴埋め問題だと思われる時(「__を埋めなさい」、「__に当てはまる言葉を答えなさい」など)のみに行ってください。

また、どこを穴埋めとし、どこを穴埋めとしないかを判断しやすくするために、入力テキストに、その問題の解答(この問題の場合は「△AOD,△COB」という情報)も入力に使うことにしました。

answerセクションを入力に追加

# ユーザーからの入力 

- "target": 問題文と解説文が混じった文章 ここで、"target"には図が示されている場合があります。図は<figure></figure>で囲まれています。また、資料をOCR(文字認識)をした結果であるため、誤字なども含まれる可能性があります。 

- "answer": 生徒が答える部分の解答です。解答欄が複数ある場合は<br>で分けられます。

実際にPlaygroundで実行してみた結果がこちらです。少なくとも先ほどの例の問題では改善が見込めているようです!

穴埋めの扱いを詳細にしたプロンプトの実行結果

問題部分に答えが含まれる

こちらについて、原因を色々と考えてみましたが、同じくこちらも回答を入れること、どこまでが問題文なのかを判断しやすくなるのではないかと考えました。また、この手の問題に特化した指示にはなりますが、式を答える問題では問題部分に式を含めないよう注記しました。

式を問題部分に入れないように注記

- 式を答える問題では、式は"solution"に分類してください。

こちらも実際にPlaygroundで実行してみた結果がこちらです。こちらもうまくいってそうですね!

問題部分に答えが含まれないように指示したプロンプトの実行結果

プロンプトの改修結果

ということで、上記を踏まえた改修後のプロンプトがこちらになります。先ほど検証した修正点については、注意事項という形でセクションを設け、全体的な注意事項として記載することにしました。また、最後に出力結果が正しいことと、問題に答えが入っていないことの確認を念押ししています。

あなたは優秀なアシスタントです。 学校の先生は生徒の問題集を作りたいのですが、現在解説が書かれた資料のみを持っています。生徒には解説部分や答えは見せたくありません。 あなたのタスクは、問題文と解説文が混じった文章を、問題部分と解説部分に分割することです。 

# ユーザーからの入力 
- "target": 問題文と解説文が混じった文章 ここで、"target"には図が示されている場合があります。図は<figure></figure>で囲まれています。また、資料をOCR(文字認識)をした結果であるため、誤字なども含まれる可能性があります。 
- "answer": 生徒が答える部分の解答です。解答欄が複数ある場合は<br>で分けられます。

# 期待される出力内容 
- "problem": 問題部分を抜き出したもの。
- "solution": 解説部分を抜き出したもの(該当部分がない場合は、"None"を出力すること) 

# 注意事項
- "problem"や"solution"は基本的に書き換えず、抜き出してください。
- 穴埋め問題の場合はすでに穴埋め部分が正しい答えで埋められていることがあります。その場合は"answer"を参考にしながら、"__"や、"ア", "イ"などの問題に適した形でマスキングした"problem"を出力ください。これは、元の問題が穴埋め問題だと思われる時(「__を埋めなさい」、「__に当てはまる言葉を答えなさい」など)のみに行ってください。
- <figure>は含まないでください。
- 式を答える問題では、式は"solution"に分類してください。
- 途中式や途中の計算結果は、"solution"か"problem"かを慎重に判断してください。

# 出力形式 (以下の形式の出力のみを行うこと。不要なことは出力しないこと) 
{"problem": "~~~", "solution": "~~~"} 

# 入出力例 
1. 
INPUT: {target":"1本150円のリンゴをx個買ったときの式を, xを使って表しましょう。 リンゴをx個買ったときの代金は1個の値段×本数で求めることができるから代金は150 \times xと表せる。", "answer":"150 \times x"} 
OUTPUT: {"problem": "1本150円のリンゴをx個買ったときの式を, xを使って表しましょう。", "solution": "リンゴをx個買ったときの代金は1個の値段×本数で求めることができるから代金は150 \times xと表せる。"} 

2. 
INPUT: {"target":"次の数の逆数を求めましょう。 \frac{1}{3}  \frac{1}{3} \times \frac{3}{1} = 1となるので、\frac{3}{1} = 3が逆数である。","answer":"3"} 
OUTPUT: {"problem": "次の数の逆数を求めましょう。 \frac{1}{3}", "solution": " \frac{1}{3} \times \frac{3}{1} = 1となるので、\frac{3}{1} = 3が逆数である。"} 

3. 
INPUT: {"target":"あおいフウセンが 17 こ, きいろいフウセンが 3こあります。どちらが なんこ おおいか、__を埋めましょう。<math>17 - 3 = 14</math><figure>17個の青いフウセンと14個の黄色いフウセンのイラスト</figure>", "answer":"-</br>14 "} 
OUTPUT: {"problem": "あおいフウセンが 17 こ, きいろいフウセンが 3こあります。どちらが なんこ おおいか、__を埋めましょう。17 __ 3 = __", "solution": "NONE"}

# 出力前に、本当に"problem"を見て、"answer"が導けることを再度確認してください。また、答えが"problem"に入っていないことを確認してください

実験結果(2回目)

ということで、2回目の結果を見ていきましょう!まずは前回同様、手動で分けた結果と完全一致したかどうかを見ていきます。

問題部分の一致率 解説部分の一致率
1回目 69.1% 85.6%
2回目 74.2% 72.1%

解説部分については数値が下がってしまっていますが、問題部分については大きく向上しました!そしてあくまでこれは「完全一致しているか」という観点になるので、許容できるものも含めると精度としては高くなるはず...ということで、こちらも前回と同様にテスト結果を分析していきます。

問題文の抽出について

  • 許容可能な表記ゆれなど、実際は正解として良い … 4件 (前回13件)
  • 穴埋めじゃない箇所が穴埋めになってしまった … 1件 (前回7件)
  • 問題部分に答えが含まれる … 1件 (前回5件)
  • 穴埋めにすべきだが、できなかった(答えが含まれる) … 5件 (前回2件)
  • 図が含まれる(今回は図は含まないようにしたい) … 0件 (前回1件)
  • 抽出漏れの箇所がある … 0件 (前回1件)
  • 途中式が含まれる … 0件 (前回2件)

解説文の抽出について

  • 許容可能な表記ゆれなど、実際は正解として良い … 16件 (前回7件)
  • 一部解説が不足(問題文側に含まれてしまった) … 4件 (前回5件)
  • 問題文を一部含む … 3件 (前回2件)

そして、許容可能な表記揺れなどの件数を前回同様考慮して抽出精度を見ていきます。抽出精度の結果はこちらです。

問題部分の一致率 解説部分の一致率
1回目 85.6% 92.8%
2回目 92.8% 92.8%

1回目と比較して、問題部分の抽出精度が大きく上がりました!特に重点的に対処した、「穴埋めじゃない箇所が穴埋めに」「問題部分に答えが含まれる」について大きな改善が見られました、嬉しい!今回は解説部分の改善には注目しなかったので、品質水準としては数値も同じなので同程度という形になりましたが、このように一つ一つ原因と対策をしっかり分析をしていくことで、期待する結果に近づけていくことはできそうです。

まとめ

今回はCOMPASSで行っているプロンプトエンジニアリングの進め方や、その進め方を用いて実際のタスクを例に検証を行った事例をご紹介させていただきました。いかがでしたでしょうか。LLMは様々なシーンで活用できますので、LLMを適用するドメインも多様ですし、それによって取り扱うタスクも異なってくると思います。今回ご紹介した進め方も、改善のアプローチの正解の一つだとは考えていますが、より良い進め方やドメインによる違いももちろんあると思います。そして、このアプローチそのものも今後改善していく余地が十分にあると思いますので、プロンプトだけではなく、その改善策も改善していければと思っています!

最後に、ここまでお読みいただいてありがとうございました。本記事が皆様の課題解決の一助になれば幸いです。

株式会社COMPASS
株式会社COMPASS

Discussion