生成AIテストで従来のアサーションが成立しなくなる理由

レスポンスが固定文字列と一致することをアサートすれば、2回目の実行では、プロダクトとは無関係な理由でテストが失敗します。部分文字列との一致まで条件を緩めれば、微妙に誤った出力でもテストは通ってしまいます。どちらも役に立ちません。そしてこの両者の間を行き来した結果、チームは「生成機能はテストできない」という結論に至るのです。

代わりに何をアサートするか

プロパティJSONとして妥当であること、必須フィールドが存在すること、長さが上限内であること、実在する情報源を引用していること。いずれも検証可能で、実行をまたいでも安定しています。
拒否応答拒否すべきものを拒否し、しかもそれが一貫していること。スイートの中で最も価値の高いチェックになることも少なくありません。
グラウンディングすべての記述が、与えられたコンテキスト内の何かに遡って裏付けられること。文体の良し悪しを判定することなく、事実の捏造を検出できます。

結果ではなく率で見る

1回の実行からは何も分かりません。同じ入力を何度も実行し、プロパティが成立する頻度を追跡します。測定の単位は率であり、注目すべきシグナルは単発の失敗ではなく、その率の変化です。

これはリグレッションの意味も変えます。問うべきは「完璧かどうか」ではなく、常に「この変更によって先週より悪化したかどうか」です。

アサートするプロパティを選ぶ

難しいのは仕組みの部分ではなく、答えそのものを検証できない状況で何を検証するかを決めることです。有効な入口は、「どうであれば良い出力か」ではなく「どうであれば使えない出力か」を問うことです。

「使えない」は具体的です。呼び出し側がパースできない不正な形式の出力、実在しないものへの引用、本来は回答すべきだったのに拒否した応答、本来は拒否すべきだったのに回答した応答、後続の処理で上限を超えてしまうコンテンツ。いずれも二値で判定でき、いずれも品質に関する意見ではなく、実際に起きた障害に対応しています。

一方で「良い」は、レビューする人によって変わる判断であり、ゲートとして組み込む価値はありません。追いたいのであれば、サンプルに対する人によるレビューで追跡し、パイプラインの中には入れないことです。パイプラインに入れれば、意思決定ではなく議論を生むだけです。

従来どおりテストできる部分

生成機能を含むプロダクトであっても、その大部分は決定的に動作する通常のソフトウェアです。認証、ストレージ、レート制限、機能を取り巻くインターフェースなどです。これらはすべて従来どおりにテストすべきであり、一部が非決定的だからといってプロダクト全体を非決定的なものとして扱えば、低コストで得られるカバレッジを大きく失うことになります。

境界は明示的に引きます。その内側ではプロパティと率を用い、外側では稼働中のアプリケーションに対して通常のアサーションを用います。

ターミナル

npm install -g @testsprite/testsprite-cli
testsprite setup

インストールを避けたい場合は、ダッシュボードで同じことができます。コマンドラインでできるその他の操作は、すべてこちらにまとめられています: CLI リポジトリ。

方法は2つあり、どちらを選ぶかは結局のところ、パイプラインを誰が所有するかという問題です。ダッシュボードから GitHub App を連携する方法なら、リポジトリへの変更は一切必要ありません。ビルドがすでに出力しているデプロイに反応するためです。一方、 GitHub Actions のステップを追加する方法では、チェックがリポジトリ内に置かれ、ビルドの他の部分と同じようにレビューの対象になります。

TestSprite がその機能の周辺をどこまでカバーするか

対象となるのは、プロダクトのうち決定的に動作する大部分です。多くのチームでは、こちらが圧倒的に大きな割合を占めます。認証、ストレージ、レート制限、機能を取り巻くインターフェース、そしてユーザーが実際に通るすべてのフローは通常のソフトウェアであり、従来どおりにテストできます。Auto-Authentication は実行全体を通してセッションを維持し、Dynamic Variables は呼び出し間で値を引き継ぎ、Dependency Chains は実行順序を導出し、Auto-Cleanup はその実行が作成したものだけを正確に削除します。

テストカバレッジはプロダクトから生成され、平易な言葉で調整でき、変更のたびにデプロイ済みのアプリケーションに対して実行されます。そのため、厳密に検証できる部分は厳密に検証されます。

生成機能そのものにはプロパティと率が必要で、これは独自の合格基準を持つ別のテスト基盤になります。この境界を明示的に引くことが、決定的なコードに統計的な手法を持ち込んでしまうことや、完全一致が失敗し続けたためにアサーションそのものを諦めてしまうことを防ぎます。

出力の採点にAIを使ってもよいのでしょうか。

一般的な手法であり、機能します。ただし注意点があります。採点する側にも固有の失敗パターンがあり、それ自体のキャリブレーションが必要です。信頼する前に、サンプルで人間の判断と照らし合わせて確認してください。

意味のある率を得るには何回の実行が必要ですか。

実行を増やしても数値が動かなくなる回数です。数百回ではなく数十回から始め、安定するかどうかを見てください。

生成機能のテストはマージをブロックすべきですか。

拒否率が大幅に下がった場合はブロックすべきです。品質のわずかな変動ではブロックすべきではありません。さもなければ、パイプラインは単なるノイズになります。

コストはどうなりますか。

繰り返し実行すればコストがかかります。変更のたびに全件を実行するのではなくサンプリングし、全件は定期的なスケジュールで実行してください。

プロンプトのテストと同じことですか。

関連しています。率の変化の最も一般的な原因はプロンプトの変更であり、これはプロンプトをバージョン管理された成果物として扱うべき十分な理由になります。

要点

一致ではなく、プロパティと率です。

生成AIテストでは、完全一致のアサーションを、プロパティ・拒否応答・グラウンディングに置き換え、多数の実行にわたる率として測定します。プロダクトのうち決定的に動作する大部分は従来どおりにテストし、境界は明示的に引いてください。