Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】From Prototype to Production: How Promptfoo and Vitest Made podcast-it Reliable

2025年09月14日に「Dev.to」が公開したITニュース「From Prototype to Production: How Promptfoo and Vitest Made podcast-it Reliable」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

LLMを使ったアプリ開発では、生成AIの出力品質とシステム全体の動作確認が重要だ。PromptfooでLLMの出力品質を評価し、Vitestでシステム結合テストを実施。これにより開発速度とアプリの信頼性が大幅に向上した。

ITニュース解説

ブログ記事からポッドキャストのスクリプトと音声を生成する「podcast-it」というアプリケーションは、当初シンプルなCloudflare Workerとして作られた。しかし、これをプロトタイプから実際に信頼して使えるプロダクトへと成長させるには、特にLLM(大規模言語モデル)を活用したアプリケーションならではの課題があった。開発者はこのプロジェクトを通じて、LLMアプリケーション開発における重要な要素、特にLLMの出力評価(LLM evals)と統合テストの重要性を深く理解し、それらを導入することで開発速度とプロジェクトへの自信を大きく向上させることができた。

従来のソフトウェア開発では、テストは主にコードの動作が正しいかを確認する。例えば、関数が正しい値を返すか、APIが時間通りに応答するか、画面コンポーネントが期待通りに表示されるかといった点だ。しかし、生成AIアプリケーションではこれに加えて、「モデルが生成する出力の品質そのもの」という新たな側面が加わる。たとえAPIエンドポイントがすべて完璧に機能していても、生成されたスクリプトが機械的であったり、重要な情報が抜け落ちていたり、エピソードの構成が一貫していなかったりすれば、アプリケーションは「失敗」したと言える。

ここでLLM evalsが重要になる。これは、モデルを囲むコードだけでなく、アプリケーション内部でモデルがどのように振る舞うかをテストするものだ。生成されたテキストが多くの実行において「役に立つか」「正確か」「一貫性があるか」を測定することで、単なる試作品から人々が実際に信頼できるプロダクトへと進化させるための鍵となる。

このプロジェクトでは、Promptfooというツールを使ってLLM evalsを導入した。TypeScript環境で評価テストを迅速に作成できるようになり、例えば以下の項目を確認した。生成されたすべてのスクリプトに導入部と結論が含まれているか、ホストの名前がセリフに登場するか、ブログ記事にない情報が引用されるといった明らかな「幻覚」(事実ではない情報を生成すること)がないか、といった点である。Promptfooはnpm install --save-dev promptfooでインストールし、npm run evalsのようなカスタムスクリプトで実行できる。このスクリプトは、TypeScriptの型定義からJSONスキーマを生成したり、環境変数をPromptfooが利用できるように橋渡しをしたり、Promptfooの設定ファイルを使って評価を実行したりする。現在、このシステムでは、期待されるホストが使われているか、番組タイトルがスクリプト内で言及されているか、正しいJSONスキーマが使われているか、LLM自身が評価者として高いスコアを与えているか、スクリプトの内容が元記事と関連しているか、OpenAIのモデレーション基準を満たしているか、といった多岐にわたる評価を実施している。

LLM evalsがコンテンツの品質を確認する一方で、システム全体が正しく動作しているかを確認するのが統合テストの役割だ。開発中に発生する問題の多くは、モデルが奇妙な文章を生成するといったことではなく、リクエストが正しく保存されない、エピソードの処理が進まない、APIが誤ったステータスコードを返すといった、地味だが本質的なシステム側の問題だった。

これらの問題を捕捉するため、Vitestというテストフレームワークを使って統合テストを作成した。このテストでは、すべてのコンポーネントを模倣するのではなく、一時的なデータベースを立ち上げ、実際のRESTエンドポイント(APIの受付口)を操作する。これにより、エピソードの作成、処理フローの追跡、そして音声ファイルやメタデータが最終的に正しい場所に格納されることをシミュレートして検証できる。Vitestはnpm install --save-dev vitestでインストールし、Cloudflare Workers環境に合わせて、一時的なD1データベースとR2バケット(Cloudflareのストレージサービス)を使用するよう設定した。アプリケーションでデータベースの変更履歴を管理するために使われるマイグレーションスクリプトは、テスト実行前にも適用され、テスト環境と本番環境のデータベース構成を一致させる。これにより、エピソードの作成や削除が期待通りに機能するか、同じエピソードを二度作成しようとした場合に正しいステータスコードが返されるか、音声ファイルが適切な場所にアップロードされるかといった事柄を確認できる。

また、コードベースへの変更が既存機能を壊さないようにするため、Huskyというツールを導入し、Gitにコードをプッシュする前に自動でテストが実行されるようにした。prepushというスクリプトが設定され、型チェック、Vitestによるすべてのテスト実行、そしてLLM evalsスクリプトの実行を順次行い、モデルの振る舞いも期待通りであることを確認する。

PromptfooによるLLM evalsとVitestによる統合テストを開発サイクルに組み込んだことは、大きな進歩をもたらした。Promptfooはスクリプトに導入と結論があるか、ホスト名が一貫しているか、幻覚がないかといったコンテンツ品質に関する即座のフィードバックを提供した。同時に、VitestはAPI、データベースのマイグレーション、ストレージフローといったシステム全体が期待通りに機能していることを確認した。この二重のフィードバックループは、開発者に大きな自信を与えた。プロンプトを調整したり、コードをリファクタリングしたり、インフラを変更したりする際に、何かを壊すことを常に心配する必要がなくなった。evalsが失敗すればそれはコンテンツの問題だとわかり、テストが失敗すればそれはシステムの問題だとわかる。これら二つが連携することで、反復開発がよりスムーズになり、予期せぬ問題が減り、更新をリリースする際のリスクが大幅に軽減された。

このプロジェクトから得られた教訓として、TypeScriptの型をJSONスキーマに変換することで、評価内容とソースコードの間にずれが生じるのを防ぎ、手動設定の手間を省くことができた。また、自動化されたLLM evalsは、ホスト名がいつの間にか消えるといった、手動レビューでは見逃しやすい細かい回帰(以前は正しく動作していた機能が、変更によって動かなくなること)を発見するのに役立った。そして何よりも、ルーティング、状態管理、ストレージといったシステムを保護する統合テストと、トーン、構造、関連性といった出力コンテンツを保護するLLM evalsが互いに補強し合い、開発への確かな自信を築くことに貢献した。

「podcast-it」を単に「動くもの」から「信頼できるもの」へと進化させたのは、新しい機能を追加することではなく、「自信」を構築することだった。Promptfooは出力の品質を測定する手段を提供し、統合テストはシステムを安定させ、そしてユニットテストは依然として初期の小さなバグを早期に捕捉する。これらが一体となって、生成AIアプリケーションを継続的に開発するための安全網を形成する。LLMを使ってアプリケーションを構築する際には、このテストと評価のサイクルを早期に確立することが、将来的な多くの問題や痛みを避けるための鍵となる。