JLPT & Business会話練習用日本語会話アプリ開発記 1編
JLPT & Business会話練習用日本語会話アプリ開発記 1編
昨年6月から約7か月間日本語を勉強しています。市販の日本語会話練習アプリやYouTube広告に出てくるアプリがあまり気に入らなかったため、自分で作ってみながら、どのような技術的限界があるから良い学習アプリを作るのが難しいのかを知りたいと思いました。
良い日本語会話練習アプリだと考える条件は次の通りです。
- 日常会話からビジネス会話まで、さまざまな状況に合った会話を練習でき、敬語、尊敬語、謙譲語も自然に使える必要がある。目標レベルはJLPT N1以上。
- ユーザーは音声ベースでAIと会話し、リアルタイムコミュニケーションを通じて会話能力を向上できる必要がある。
- ユーザーが話した内容をもとにフィードバックを提供し、間違えた部分を改善できるように支援する必要がある。
- 面接練習ができるよう、ユーザーの専攻、ポートフォリオ、履歴書に関するさまざまな質問を提供し評価する必要がある。 常に最悪の状況を仮定し、各質問ごとに深掘り質問を通じて深い回答を引き出す必要がある。
- ユーザーの個人情報や会話内容が外部に流出しないよう、徹底したセキュリティが保証される必要がある。
このように考えたうえで、Gemini Deep Researchの助けを借りて、必要な技術と開発方法を整理してみました。
初期技術スタック選定
| 区分 | 技術名 | 選定理由 |
|---|---|---|
| 言語 (Language) | Python 3.11+ | AI/MLライブラリエコシステムが最も豊富。 |
| オーケストレーション | LangGraph | ループ(Cycle)と状態(State)管理が必須のエージェントワークフローに最適。単純Chainではなく、複雑な会話フロー制御に向く。 |
| LLM (Text) | CyberAgentLM3-22B-Chat (GGUF) または Llama-3-Elyza-JP-8B | 日本語特化性能が高く、ローカル実行または低コストAPI活用が可能。 |
| TTS (Audio) | Style-Bert-VITS2 | 日本語特有のイントネーションと感情、喜び、怒り、戸惑いなどを最も自然に表現するオープンソースモデル。 |
| RAG & 検索 | Qdrant (Vector DB) + SudachiPy (Tokenizer) | ハイブリッド検索対応と、日本語形態素解析に最適化されたトークナイザー活用。 |
| UI/UX | Chainlit | 対話型AIプロトタイピングに最も速く効率的で、「思考の過程(Chain of Thought)」を可視化しやすい。 |
最も重要なリアルタイム会話にはChainlitだけでは不十分だと思い、追加でどのリアルタイム通信フレームワークを使うか検討しました。
| 特性 | Chainlit | Gradio | LiveKit |
|---|---|---|---|
| 主な用途 | チャット型LLMアプリ | MLモデルデモ/サービング | リアルタイムA/Vインフラ |
| 通信プロトコル | WebSocket | WebSocket / HTTP | WebRTC (UDP/TCP) |
| 遅延時間 (Latency) | 中程度 (500ms〜1s) | 中程度 (500ms〜1s) | 非常に低い (<200ms) |
| オーディオ処理方式 | ファイル/チャンク転送 | ストリームジェネレーター | RTPメディアストリーム |
| Barge-in (割り込み) | 難しい(カスタム必要) | 可能だが複雑 | 標準対応 (Native) |
| 状態管理 | 永続チャットセッション | 状態オブジェクト渡し | リアルタイムルーム(Room)状態 |
| 拡張性 | 垂直拡張が容易 | コンテナ化が容易 | クラウド/エッジ分散処理 |
上の表を参考に、リアルタイム音声通信と割り込み(Barge-in)機能が必須であるため、LiveKitをメイン通信フレームワークとして選定しました。LiveKit + [ ]の組み合わせでフロントエンドとバックエンドを構成する予定です。
リアルタイム音声会話 (Real-Time Voice)
自分が求める動作を実現するには、音声認識(STT)、大規模言語モデル(LLM)、音声合成(TTS)へ続くパイプライン全体がストリーミング(Streaming)構造として最適化される必要があります。Streamingは実装がかなり難しい領域だと理解しているので、少しずつ作りながら方向性を決めていくことになりそうです。
一般的な音声会話の流れ (Non-Streaming)
| 段階 | 構成要素 | 説明 |
|---|---|---|
| 1 | VAD Delay | ユーザーの発話が終わったか判断するため、沈黙を待つ時間 |
| 2 | Audio Upload | オーディオデータをクラウドへ送信 |
| 3 | ASR Processing | 全体オーディオをテキストへ変換 |
| 4 | LLM Inference | 全体回答テキスト生成完了を待機 |
| 5 | TTS Synthesis | 全体テキストをオーディオへ変換 |
| 6 | Audio Download & Buffering | 再生準備 |
問題点: 各段階を順次処理するため、全体遅延時間が累積し、リアルタイム会話に適しません。
Streaming方式の構造 (Real-Time)
| 段階 | 技術 | 説明 |
|---|---|---|
| 1 | Transport (WebRTC) | オーディオが20ms単位のフレームに分割され、リアルタイムでサーバー(LiveKit Agent)へ到着 |
| 2 | Server-side VAD (Silero VAD) | オーディオフレームストリームをリアルタイム分析し、発話開始/終了を検知 |
| 3 | Streaming STT (ReazonSpeech v2) | 発話検知と同時にオーディオフレームをSTTエンジンへ投入し、中間結果(Interim Results)テキストを生成 |
| 4 | Speculative LLM Processing | 高度な最適化として、STTの中間結果だけでLLMが文脈を把握し、回答生成準備または即時トークン生成開始 |
| 5 | Streaming LLM | LLMが完成文を一度に出すのではなく、トークン(Token)単位でストリーミング |
| 6 | Streaming TTS (Style-Bert-VITS2) | 句読点や意味単位でテキストが集まると、即時オーディオ合成開始 |
| 7 | Playback | 合成された最初のオーディオチャンクを即時WebRTCトラック経由でユーザーへ送信 |
長所: 並列処理と段階的な結果伝達により遅延時間を最小化し、自然なリアルタイム会話を実装できます。
データ収集
当然ですが、まずビジネス会話に関するデータと、敬語・尊敬語のような日本特有の言語データを収集する必要がありました。収集するデータは次の通りです。
BSD (Business Scene Dialogue) データセット: ryo0634/bsd_ja_en
- Hugging Faceからダウンロード
- JSON形式の会話データ
- 状況(電話、会議、謝罪)と話者関係(上司-部下、取引先)別に分類
- ビジネスマナー文書: business-mail.jpなどから収集
- 敬語/文法修正データ: TMU Evaluation CorpusやKeiCOコーパス
KeiCOコーパス
出典: GitHub - Liumx2020/KeiCO-corpus
論文: Liu et al. (2022) - “Construction and Validation of a Japanese Honorific Corpus”
規模: 10,007文 (1文あたり5アノテーション)
アノテーション:
- 敬語レベル (4段階)
- 尊敬語(sonkeigo)分類
- 謙譲語(kenjougo)分類
- 丁寧語(teineigo)分類
- 活動分野(field)
敬語レベル体系 (Level 1-4)
| レベル | 名前 | 使用状況 | マーカー例 |
|---|---|---|---|
| 1 | 最高敬意 | 公式演説、丁寧なビジネス | ございます, 申し上げます, いたします |
| 2 | 一般敬意 | ビジネス会話、公式文書 | ます, ございます |
| 3 | 中程度敬意 | 日常的な敬意 | ます, です |
| 4 | カジュアル敬意 | 近い関係 | … |
敬語エラーを検知してフィードバックするとき
次のような方式で、テキスト形式の応答を画面に表示しようと思います。あるいは音声でフィードバックすることもできるでしょう。
# ユーザーの誤った表現
user_utterance = "すみません。" # Level 4 (casual)
# KeiCOデータから分類学習
correct_level = 1 # ビジネスでは最高敬意が必要
correct_form = "失礼いたします。"
# フィードバック生成
feedback = "あなたの'すみません'はLevel 4です。 " \
"ビジネス状況ではLevel 1の'失礼いたします'を使用する必要があります。"
データ分類および構造化
BSDデータ分類スキーマ
状況(Scenario)
├── 電話 (Telephone)
│ ├── カスタマーサービス
│ ├── 注文確認
│ └── 問題解決
├── 会議 (Meeting)
│ ├── 事業交渉
│ ├── プロジェクトレビュー
│ └── 結果報告
├── 謝罪 (Apology)
│ ├── ミス認定
│ ├── 補償提示
│ └── 信頼回復
└── その他 (Other)
├── メール会話
└── 名刺交換
話者関係(Speaker Relationship)
├── 上司-部下 (Superior-Subordinate) → Level 2以上必須
├── 同僚 (Peers) → Level 2-3
├── 取引先 (Business Partner) → Level 1-2
├── 新規顧客 (New Customer) → Level 1推奨
└── 既存顧客 (Existing Customer) → Level 2-3
前処理および形態素分割
なぜ形態素分割が必要なのか?
日本語はスペースがないため、意味のある単位へ分割する必要があります。日本語に特化し、形態素解析と意味単位でテキストを分けられるツールが必要です。
意味単位で分類できるツールとして、SudachiPyというかなり大規模な日本語形態素解析器があります。
SudachiPy: https://pypi.org/project/SudachiPy/
WAP Tokushima Laboratory of AI and NLP: https://nlp.worksap.co.jp/
埋め込み生成
調査した内容によると、以下のモデルが日本語文埋め込みに最も適しているそうです。まず適用してみて、性能が満足できなければ他のモデルも試す予定です。
モデル選択: cl-nagoya/ruri-large (日本語特化)
from sentence_transformers import SentenceTransformer
# 日本語特化モデル
model = SentenceTransformer('cl-nagoya/ruri-large')
# テキストを384次元ベクトルへ変換
texts = [
"会議でのビジネス敬語",
"電話での丁寧な表現",
"謝罪の文化"
]
embeddings = model.encode(texts) # shape: (3, 384)
print(f"埋め込み生成完了: {embeddings.shape}")
QdrantベクトルDB構築
Qdrantはベクトル検索に最適化されたオープンソースデータベースで、大規模埋め込みデータを効率的に保存・検索できます。 この選択肢も同様に、より良いベクトルDBがあれば交換する予定です。
ハイブリッド検索実装(オプション)
ベクトル検索 + BM25キーワード検索の組み合わせを使う予定です。BM25とは何かについては、https://www.geeksforgeeks.org/nlp/what-is-bm25-best-matching-25-algorithm/ を参照してください。簡単に言えば、文書内の単語頻度と逆文書頻度を考慮し、キーワードベース検索の正確度を高めるアルゴリズムです。
これが本当に必要かはわかりません。まずBM25なしでベクトル検索だけを実装し、性能が満足できなければBM25を追加する方向にします。
参考資料
- BSD: https://huggingface.co/datasets/ryo0634/bsd_ja_en
- KeiCO: https://github.com/Liumx2020/KeiCO-corpus
- SudachiPy: https://github.com/WorksApplications/Sudachi
- Qdrant: https://qdrant.tech/
- Liu et al. (2022). Construction and Validation of a Japanese Honorific Corpus
댓글