店舗での接客チェックは、これまで人が録音を聞き返してチェックシートに記入する形でやっていました。

この作業をAIに任せられないか、という相談から始まったのが今回のPoC(概念実証。本格導入の前に「できそうかどうか」を小さく検証すること)です。


録音→文字起こし→チェック→AIによるアドバイス生成、という流れを実際に動くシステムとして組んでみました。

flowchart LR
A[録音] --> B[文字起こし]
B --> C[チェックシート自動入力]
C --> D[AIアドバイス生成]

先に結論だけ書くと、この一連の流れは既存のAI API(文字起こしとLLM)を組み合わせれば、技術的にはほぼ問題なく作れます。

手応えとしては、ほぼ想像通りでした。


ただし、共用端末でのログイン運用や録音し忘れの防止のような店舗現場ならではの運用面は、READMEに検討事項として書き出しただけで、今回のPoCでは手を付けていません。

技術的に作れることと、現場で使い続けられることは別の話だと思っています。


何を検証したのか

以下の4ステップで検証を進めました。

  1. 音声解析の精度検証: 店舗環境で録音した音声を正確に文字起こしできるか
  2. チェックシート転用の検証: 文字起こし結果からチェック項目の達成有無を判定できるか
  3. AIアドバイス機能の検証: 評価基準に基づいて適切なフィードバックを生成できるか
  4. 運用コストの試算: 実際のトークン(AIが処理する文章量の単位。利用料の計算にも使われる)使用量からランニングコストの見当をつける

どういう仕組みで動いているのか

技術構成はシンプルな「非同期ジョブ型」のWebシステムです。リクエストを受けたその場で処理を完結させず、裏側の順番待ちの列(キュー)に積んでおいて、空いたタイミングで実行する方式です。

flowchart TD
U["① スタッフが音声をアップロード"] --> Q["② 裏側の順番待ちリストに追加"]
Q --> W["③ 空いたタイミングで処理を開始"]
W --> T["文字起こし"] --> S["話者分離"] --> J["チェック項目の判定"]
J --> R["④ 結果を保存"] --> V["⑤ ユーザーが結果を確認"]

これを実際に使っている技術で書くとこうなります。

ブラウザ側の画面はNext.js、音声を受け取って保存するAPI側はFastAPIというフレームワークで組んでいます。

保存が終わるとRedis(処理待ちのタスクを一時的に貯めておく仕組み)にジョブを積み、Celeryという別プロセスのワーカーがそれを取り出して、文字起こし(OpenAI Whisper)→話者分離→チェック項目の判定、の順に処理します。

話者分離とチェック判定はLLM(大規模言語モデル)の推論で行っていて、OpenAIとAWS Bedrock(Claude)は設定だけで切り替えられるようにしてあります。


ユーザー側は処理状況を一定間隔で確認(ポーリング)しながら結果を受け取ります。

音声処理には数秒〜数十秒かかるので、待たせたまま固まった画面を見せるより、裏側で進めて後から結果を渡す形にしました。

工夫した点:AIサービスを"差し替えられる"ようにしておいた

文字起こしや話者分離・判定に使うAIサービスは、設定(環境変数)を変えるだけでOpenAIとAWS Bedrock(Claude)を切り替えられるようにしてあります。

「音声データを渡すと、テキストや話者ごとの発話リストが返ってくる」という入口と出口だけを決めておき、中身の実装はサービスごとに差し替え可能にする設計です。


これなら、あるAIサービスの精度やコストが合わなかったとき、システムを作り直さずに別のサービスへ切り替えられます。

これは行き当たりばったりで生まれた設計ではなく、最初からこの形にしようと決めて作った部分です。

AIは進化・入れ替わりが早い分野なので、まだどのサービスが最適か分からない段階のPoCだからこそ、あらかじめ差し替えられるようにしておく判断が効きました。


つまずいた点:音声ファイルが「.bin」になっていた

検証中、特定の音声ファイルだけ文字起こしが返ってこないという不具合にぶつかりました。

手元にあったデモ用の音声データで試していたときに気づいたものです。


調べてみると、アップロード時に許可していたファイル形式がwav / mp3 / webmの3つだけで、m4a(スマホでよく使われる形式)は未対応の拡張子として扱われ、ファイルが.binという汎用形式で保存されていました。

それをそのまま文字起こしAPIに送っていたので、形式を認識できずエラーや空応答になっていたわけです。


対応は、文字起こしAPI側が正式に対応している形式(m4aを含む)をアップロード許可リストに追加し、保存時の拡張子もそのまま維持するように直しただけです。

地味な修正ですが、開発中の動作確認だけでは気づきにくく、現場で実際に使われそうな形式を一通り試して初めて見つかった問題でした。


所感

文字起こし・話者分離・チェック判定は、既存のAI APIを組み合わせるだけで技術的には十分実現できました。

PoCとして「作れるかどうか」で悩む場面は、正直あまりなかったです。


苦労したのはむしろ、m4aのバグのような「想定外の使われ方」への対応でした。

開発中の動作確認だけでは気づきにくく、現場で実際に使われそうな形式を一通り試して初めて発覚しています。


全体を通しての実感は、想定通り簡単だった、という一言に尽きます。

AIは進化・入れ替わりが早い分野なので、今使っているサービスが半年後も最適とは限りません。

だからこそ「いつでもモデルやサービスを切り替えられるようにしておく」という設計判断をあらかじめしておいたのですが、それが絵に描いた餅ではなく実際に機能する形にできる、というところまで今回のPoCで確認できました。



筆者

足立 建(テックビーンズ株式会社)

Web開発歴20年。ドキュメントが不足した既存システムでも、コード・DB・ログから現状を整理し、保守しやすい構成へ改善することが得意。PHP/LaravelからReact/TypeScript、CMS構築まで幅広く対応し、要件が曖昧な段階から長く使える仕組みづくりを支援しています。

足立のプロフィールを見る


この記事の内容について、直接聞いてみませんか?

「うちのシステムでも整理できる?」「こんな改修はできる?」——そのレベルのご質問で大丈夫です。プロフィールページから足立に直接メッセージを送れます。

[ 足立建にメッセージを送る ]