1年振りに最新のSpeechLLMで音声データからのエンティティ抽出の検証

こんにちは、AIチームの杉山です。
本記事は AI Shift Advent Calendar 2025 15日目の記事です。

昨年のAdvent Calendarでは、OpenAI gpt-4o-audioを用いた音声データからのエンティティ抽出の検証という記事を執筆しました。

当時はまだ gpt-4o-audio-preview というプレビュー版のみでの検証でしたが、音声認識(ASR)を介さずに直接音声からエンティティ(ex. 店舗予約に必要な店舗名や商品名など)を抽出できる可能性にワクワクしたのを覚えています。
一方で、滑舌が悪い曖昧な音声に対しては音の近さが考慮できず誤ったエンティティを抽出したり、「音声を認識できません」「話者を特定できません」といったように、回答自体が拒否されるケースが多発するという課題も残りました。

あれから1年。
LLM界隈の進化は凄まじく、GoogleのGeminiやオープンソースモデルなど、画像や音声も入出力できるマルチモーダル対応は当たり前の機能となりました。
そこで今回は、 「1年経った今、同じタスクを最新のAIモデルで実行したら、あの時の課題は解決されているのか?」 を検証してみたいと思います。

検証の背景と目的

音声認識結果を用いたエンティティ抽出の例

前回の検証内容をおさらいします。
電話自動応答における「店舗予約」を想定し、以下の2パターンの音声データから、正しい店舗名(エンティティ)を抽出できるかをテストしました。

  1. 明瞭な音声 (clear_toyosu.wav): はっきり「豊洲です」と発話
  2. 曖昧な音声 (ambiguous_toyosu.wav): 曖昧に「豊洲です」と発話

それぞれの音声をGoogle音声認識にかけてみると前者は正しく「豊洲です」(confidence=0.97)、後者は「ナースです」(confidence=0.95)と認識されました。前者の場合であれば音声認識をしてNLP的なアプローチでも十分エンティティ抽出することができますが、後者の場合はそうはいかないため音の近さを考慮して抽出してくれることを期待します。
なお、電話自動応答プロダクトでの利用を想定しているため、音声は8kHzにダウンサンプリングしてLLMに入力しています。詳細な課題の説明は昨年の記事をご参照ください。

前回(1年前)の結果は以下の通りでした。

  • 明瞭な音声: 音声入力からヨミを考慮して正しく「豊洲」を選ぶことができた。
  • 曖昧な音声: モデルが回答を拒否、または関係のないエンティティを抽出し失敗。

今回の記事では、この音声データに対し現在利用可能な最新モデルで再検証を行います。

検証対象のモデル

今回は比較対象として、以下の最新モデルを使用します。

  1. OpenAI gpt-4o-audio-preview
     昨年検証したgpt-4o-audioの後、gpt-audioというモデルがリリースされたが、音声を入力するとレスポンスは返ってくるものの、gpt-4o-audioのように指示に従って回答する時もあれば「音声を確認し、文字起こしと候補の中から最も近いものを選びますので、少々お待ちください。」のように音声が与えられていないような回答をするときもある。
     不安定なのか用途が異なるのかは不明だが、今回は検証対象外として昨年同様gpt-4o-audioを使用。なお1年経った執筆時点でもpreviewは外れていないためモデル指定時は注意が必要。
  2. Google gemini-2.5-flash-lite
     音声対話中での利用を想定して選択した、Googleの最新の軽量モデル。
  3. Google gemini-3.0-pro-preview
     記事執筆時点での最高レベルのモデル。思考モードをoff(thinking budget=0)にできないため、レスポンスには時間がかかる。

検証コード

基本的な処理の流れは前回同様です。音声ファイルをBase64エンコードし、プロンプトと共にモデルへ入力します。

  • OpenAI

現在のOpenAI SDKではResponse APIが最新ですが、現時点では音声入力に対応していないため、引き続きchat.completions APIを使用する必要があります。

import base64
from openai import OpenAI

client = OpenAI(api_key=YOUR_API_KEY)

with open(YOUR_AUDIO_FILE_PATH, "rb") as wav_file:
    wav_data = wav_file.read()
encoded_string = base64.b64encode(wav_data).decode('utf-8')

completion = client.chat.completions.create(
    model="gpt-4o-audio-preview",
    # model="gpt-audio", 指定して動作はするが不安定
    modalities=["text"], # 出力のモーダル。音声も出力したい場合は["text", "audio"]とする。
    messages=[
        {
            "role": "user",
            "content": [
                { 
                    "type": "text",
                    "text": YOUR_PROMPT
                },
                {
                    "type": "input_audio",
                    "input_audio": { # 入力に音声を与える場合はinput_audioとしてbase64エンコードした文字列を指定
                        "data": encoded_string,
                        "format": "wav"
                    }
                }
            ]
        },
    ]
)

print(completion.choices[0].message.content)
  • Gemini
import base64
import os
import google.generativeai as genai
from google.generativeai import types

genai.configure(api_key=YOUR_API_KEY)

generation_config = {
  "temperature": 0,
  "top_p": 0.95,
  "top_k": 10,
  "response_mime_type": "application/json",
}

model = genai.GenerativeModel(
  model_name = "gemini-2.5-flash-lite",
  # Gemini-3-Proを使う場合は以下を指定
  # model_name = "gemini-3-pro-preview",
  generation_config=generation_config,
)

with open(YOUR_FILE_PATH, "rb") as wav_file:
    wav_data = wav_file.read()
encoded_string = base64.b64encode(wav_data).decode('utf-8')

response = model.generate_content(
    [
        YOUR_PROMPT,
        {"mime_type": "audio/wav", "data": encoded_string},
    ]
)

print(response.text)

プロンプトは前回より詳しく、音の近さを考慮したCoTを期待して以下の指示とします。
また、設定を少し難しくするために候補エンティティ集合は数を増やしてプロンプト中の10個としました。

まず、音声の文字起こし結果を出力してください。
次に、入力音声の認識結果から、読み方の近さを考慮して一番尤もらしいものを次の候補から選んでください。
候補:['神田', '杉山', '豊洲', '河野', '八重洲', '渋谷', '青梅', '高津', '銚子', '新宿']
入力音声は「候補+です」のように発話される可能性があります。
最後に、選んだ理由を出力し、回答は必ず候補の中から選んでカタカナで出力してください。
回答形式は以下のようにしてください。
{
  "transcription": "",
  "reason": "",
  "most_likely_candidate": "",
}

検証結果

それでは、結果を見ていきましょう。
以降記載した結果は、出力を詳細化したためその見やすさを考慮し、今回は1回実行しただけの再現性が低い結果であることはご了承ください。また、サンプルコードには記載していませんがリクエストを送ってからレスポンスが返ってくるまでの時間を計測し、Latencyとして結果に載せています。

1. 明瞭な音声 (clear_toyosu.wav)

まずは、前回も成功していた明瞭な音声です。

モデル出力結果Latency(sec)
gpt-4o-audio-preview{
"transcription": "豊洲です",
"reason": "認識結果の発音は「とよす」ですので、候補の中で最も近いのは「豊洲」になります。",
"most_likely_candidate": "豊洲"
}
1.569
gemini-2.5-flash-lite{
"transcription": "神田です",
"reason": "音声認識結果は「神田です」と最も近く、発話内容も「候補+です」の形式に合致しているため。",
"most_likely_candidate": "カンダ"
}
1.926
gemini-3.0-pro-preview{
"transcription": "豊洲です",
"reason": "入力音声の認識結果は「トヨスデス」でした。提供された候補リストの中で、読みが「トヨス」である「豊洲」が音声と完全に一致するため選定しました。",
"most_likely_candidate": "トヨス"
}
24.246

gpt-4o-audio-preview, gemini-3.0-pro-previewは正しく豊洲を選択できています(gpt-4o-audio-previewはカタカナで出力、という指示には従っていませんが)。一方でgemini-2.5-flash-liteは誤ってしまいました。普段使っている感覚だと正解できそうに感じましたが、複数回試しても神田や杉山になりがちで、CoTや文字起こしが苦手だったりといったモデルの癖があるのかもしれません。

2. 曖昧な音声 (ambiguous_toyosu.wav)

次に、前回の課題だった曖昧な音声です。

モデル出力結果latency(sec)
gpt-4o-audio-preview{
"transcription": "たかつです",
"reason": "発音が「たかつです」と聞こえたため、候補の中で最も近い「高津」を選びました。",
"most_likely_candidate": "高津"
}
1.659
gemini-2.5-flash-lite{
"transcription": "神田です",
"reason": "音声認識結果は「神田です」と最も近く、候補の中から読み方が最も尤もらしい「カンダ」と発音されているため。",
"most_likely_candidate": "カンダ"
}
1.891
gemini-3.0-pro-preview{
"transcription": "Does desu",
"reason": "音声認識結果の「Does」は、発音記号で/dʌz/や/doʊz/となり、候補の中で音韻的に最も近いのは「豊洲(トヨス)」です。「Does」の語頭の破裂音/d/は「トヨス」の/t/(有声音と無声音の関係)に近く、語尾の/z/または/s/の響きも共通しています。「八重洲(ヤエス)」は語頭が/y/であり、「Does」の音とは距離があります。",
"most_likely_candidate": "トヨス"
}
22.629

昨年同様gpt-4o-audio-previewと、gemini-2.5-flash-liteも正解することはできませんでした。一方で、gemini-3.0-pro-previewはついに正解することができました。reasoningの内容も、4年前のAdvent Calendarに書いた記事(音声認識結果とエンティティ候補との音素列アラインメントによるマッチングの検証)でやりたいと考えていた

モチベーションとしては読みを用いた編集距離やアラインメントよりも、「sh」と「ch」や「hy」と「ky」の類似性を考慮できるのではないかと考えたためです。

のような音的な近さを考慮した(ように見える)エンティティ抽出が行えています。

Latencyに関しては、上2つはどちらも2秒弱でレスポンスが返ってきています。音声対話中にエンティティ抽出だけで2秒弱かかるのは少し遅く感じますが、相槌などで推論時間を稼ぐなどの工夫である程度軽減できそうです。gemini-3.0-pro-previewは20秒以上かかっており、正解はできているもののこのままでは音声対話中に使用するのは厳しそうです。今後思考モードがoffにできるようになったり、gemini 3系の軽量モデルが出た際には都度検証し、プロダクトへの適用可能性を探っていきたいと思います。

終わりに

今回は、1年前に検証したSpeechLLMによるエンティティ抽出を最新モデルで再評価しました。

この1年でのモデルの進化は、単なる精度の向上だけでなく、指示に対する追従性や曖昧さへの対処という点でも進展が見られました。従来のカスケード型音声対話システムでは音声認識→テキストでの言語理解が一般的でしたが、汎用的な音声認識器では専門用語のような一般的でないエンティティの認識が困難でした。そういったケースに特化した専用の音声認識モデルがなくても、今回のような仕組みで認識できるようになる可能性が見えてきました。
一方で、抽出(リンキング)対象のエンティティ集合が、たとえば取引先会社名や小売店の取り扱い商品名など数千・数万以上になったときにどうすべきかなどといった問題点も残っており、Latencyの課題も含めLLM一つで全てが解決できるものではなく、我々としては引き続き実運用で使える機能の開発に取り組んでいきます。

AI Shiftでは、こうした最新のマルチモーダル技術をいち早くキャッチアップし、電話自動応答をはじめとするプロダクトの体験向上に取り組んでいます。
音声対話の未来を一緒に作りたいエンジニアの方、ぜひお話ししましょう!
少しでも興味を持っていただけましたら、カジュアル面談でお話しませんか?
(オンライン・19時以降の面談も可能です!)

【面談フォームはこちら】
https://hrmos.co/pages/cyberagent-group/jobs/1826557091831955459

PICK UP

TAG