マルチモーダル音声・テキストエージェント
音声エージェントシステムで、話し言葉による応答と画面上のテキストを連携させます。
「マルチモーダル音声・テキストエージェント」はCoddyKit上の無料AI Prompt Engineeringレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAI Prompt Engineering学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AI Prompt Engineeringコースには全4レッスンが含まれています。
音声のみのコンテキストとマルチモーダルなコンテキスト
音声AIエージェントは、根本的に異なる次の2つのコンテキストで動作します。
- 音声のみ:スマートスピーカー、IVR、電話など。ユーザーは音声だけを聞き、画面は見ません
- マルチモーダル:モバイルアプリ、Webアプリ、車載ダッシュボードなど。ユーザーは画面を見ながら、同時に音声を聞けます
これらのコンテキストには、それぞれ異なる応答戦略が必要です。音声のみの場合は、すべてを話し言葉で伝えなければなりません。マルチモーダルの場合は、話す内容と表示する内容を連携させられます。
音声のみの応答をプロンプトで指定する
音声のみのコンテキストでは、LLMは視覚情報がまったくなくても機能する応答を生成する必要があります。つまり、画面上の要素への言及、目で追う必要があるリスト、書式があって初めて意味をなす内容を避けなければなりません。
VOICE_ONLY_SYSTEM_PROMPT = (
'You are a voice-only assistant. The user cannot see any screen.\n\n'
'Requirements:\n'
'- Never reference visual elements ("tap here", "see the chart", "the blue button")\n'
'- Never use numbered or bulleted lists — use spoken sequences instead:\n'
' BAD: "1. First do X 2. Then do Y"\n'
' GOOD: "Start by doing X. When that is done, do Y."\n'
'- Limit responses to what can be comfortably spoken in 30 seconds\n'
'- Offer to give more detail rather than overwhelming the user\n'
'- Use verbal signposts: "First", "Next", "Finally"\n'
'- Read out all important data: codes, dates, amounts as full words'
)
print(VOICE_ONLY_SYSTEM_PROMPT)発話と画面上のテキストを連携させる
マルチモーダルなコンテキストでは、音声と画面に内容を分けて提示できます。音声では、会話的・感情的・動的な内容を扱います。画面では、密度の高い情報、表、長文のテキストを扱います。
MULTIMODAL_SYSTEM_PROMPT = (
'You are a multimodal assistant with both a voice and a screen.\n\n'
'When responding, consider what each modality does best:\n\n'
'SPEAK (voice):\n'
'- Conversational summary, emotional tone, key highlights\n'
'- Guide the user to look at the screen when needed:\n'
' "I have shown the details on screen. The key number to notice is..."\n\n'
'SHOW (screen):\n'
'- Detailed data, tables, long lists, code, maps, images\n\n'
'When your response includes structured data, respond in this format:\n'
'SPOKEN: <what to say aloud>\n'
'VISUAL: <what to display on screen in markdown>'
)
# Example LLM output for multimodal response:
EXAMPLE_MULTIMODAL_OUTPUT = (
'SPOKEN: Your top three expenses this month are food, transport, and entertainment. '
'Food was the biggest, almost double your budget. Check the screen for the full breakdown.\n\n'
'VISUAL: | Category | Budget | Actual | Difference |\n'
'|---|---|---|---|\n'
'| Food | $400 | $780 | -$380 |\n'
'| Transport | $150 | $162 | -$12 |\n'
'| Entertainment | $100 | $145 | -$45 |'
)
print(EXAMPLE_MULTIMODAL_OUTPUT)音声エージェント向けにLLMの出力を構造化する
音声エージェントのアプリケーションでは、音声用と画面用にそれぞれ解析して振り分けられるよう、LLMに構造化された出力を返させます。JSONや、定義済みのセクション形式が適しています。
import anthropic
import json
client = anthropic.Anthropic(api_key='sk-ant-...')
VOICE_AGENT_SYSTEM = (
'You are a financial voice assistant. For each response, return JSON with:\n'
'{\n'
' "spoken": "Short spoken response (max 2 sentences)",\n'
' "visual_title": "Header for the on-screen card (optional)",\n'
' "visual_content": "Detailed content for screen (markdown, optional)",\n'
' "action_label": "Button label if action needed (optional)",\n'
' "action_type": "one of: none, confirm, navigate, call"\n'
'}\n'
'Return only the JSON object.'
)
def voice_agent_query(user_message):
r = client.messages.create(
model='claude-opus-4-5',
max_tokens=500,
system=VOICE_AGENT_SYSTEM,
messages=[{'role': 'user', 'content': user_message}]
)
try:
response_data = json.loads(r.content[0].text)
return response_data
except json.JSONDecodeError:
return {'spoken': r.content[0].text, 'visual_content': None}
result = voice_agent_query('What is my account balance?')
print('SPEAK:', result.get('spoken'))
print('SHOW:', result.get('visual_content', 'Nothing to display'))音声エージェントのトランスクリプトを整形する
音声エージェントの会話は、デバッグ、コンプライアンス、品質レビューのためにトランスクリプトとして記録する必要があります。話者、タイムスタンプ、音声出力と視覚出力の両方を記録できる形式にしてください。
import datetime
import json
class VoiceTranscript:
def __init__(self, session_id):
self.session_id = session_id
self.turns = []
def add_user_turn(self, text, audio_duration_ms=None):
self.turns.append({
'speaker': 'user',
'timestamp': datetime.datetime.utcnow().isoformat(),
'text': text,
'audio_duration_ms': audio_duration_ms,
})
def add_agent_turn(self, spoken_text, visual_content=None, action=None):
self.turns.append({
'speaker': 'agent',
'timestamp': datetime.datetime.utcnow().isoformat(),
'spoken': spoken_text,
'visual': visual_content,
'action': action,
})
def save(self, filepath):
with open(filepath, 'w') as f:
json.dump({'session_id': self.session_id, 'turns': self.turns}, f, indent=2)
print(f'Transcript saved: {filepath}')
# Usage
transcript = VoiceTranscript('session_001')
transcript.add_user_turn('What is my balance?', audio_duration_ms=1200)
transcript.add_agent_turn('Your balance is four hundred dollars.', visual_content='Balance: $400')
transcript.save('/tmp/session_001_transcript.json')音声入力エラーに対応する
音声エージェントは、言葉の聞き間違い、不完全な発話、周囲の雑音など、音声認識エラーに適切に対応する必要があります。曖昧な入力を検出し、そこから回復するようLLMに指示してください。
import anthropic
client = anthropic.Anthropic(api_key='sk-ant-...')
AMBIGUITY_HANDLING_SYSTEM = (
'You are a voice assistant. User input comes from speech recognition '
'and may contain transcription errors.\n\n'
'When input seems unclear or ambiguous:\n'
'1. State what you think the user might have meant.\n'
'2. Ask a single clarifying yes/no question to confirm.\n'
'3. Never ask more than one question at a time.\n'
'4. Offer the most likely interpretation as the default.\n\n'
'Example:\n'
'Input: "transfer five hundred to john or gene" (ambiguous name)\n'
'Response: "It sounds like you want to transfer five hundred dollars. '
'Did you mean John Smith or Gene Lee?"'
)
def handle_voice_input(user_speech):
r = client.messages.create(
model='claude-opus-4-5',
max_tokens=200,
system=AMBIGUITY_HANDLING_SYSTEM,
messages=[{'role': 'user', 'content': user_speech}]
)
return r.content[0].text
print(handle_voice_input('pay the electric company bill thing'))音声会話でのターンテイキング
テキストチャットとは異なり、音声では明示的なターン管理が必要です。エージェントはいつ話すのをやめて聞くべきかを把握し、ユーザーはエージェントが話し終えたことを知る必要があります。自然な終了の合図を含む応答を生成するよう、プロンプトを設計してください。
TURN_TAKING_SYSTEM = (
'You are a voice assistant. Responses must be designed for spoken conversation:\n\n'
'End each response with exactly ONE of:\n'
'- A direct question inviting the user to respond\n'
'- A clear statement that the task is complete (e.g., "That is done.")\n'
'- An explicit offer to continue (e.g., "Is there anything else?")\n\n'
'Never end mid-thought. Never trail off. '
'Avoid open-ended statements that leave the user unsure if they should speak.\n\n'
'GOOD endings:\n'
'- "The transfer is complete. Would you like a confirmation number?"\n'
'- "That is all I have. Is there anything else?"\n'
'BAD endings:\n'
'- "You might also want to consider..." (open, unclear)\n'
'- "The balance is..." (incomplete)'
)
print(TURN_TAKING_SYSTEM[:300])割り込みへの対応
ユーザーは音声エージェントの発話を遮ることがあります。システムは割り込みを検出し(VAD(音声活動検出)による)、エージェントに適切な再開や方向転換を促さなければなりません。会話の途中で話題が変わっても受け入れられるよう、LLMに指示してください。
import anthropic
client = anthropic.Anthropic(api_key='sk-ant-...')
INTERRUPTION_SYSTEM = (
'You are a voice assistant. Users may interrupt mid-conversation.\n\n'
'If the user changes topic abruptly, smoothly acknowledge the change:\n'
'"Of course. Let us switch to that." Then answer the new question.\n\n'
'If the user says something like "wait", "stop", "hold on":\n'
'Pause and say "Sure, take your time" and wait for them to continue.\n\n'
'If the user repeats a question, they likely did not hear the answer:\n'
'Say "Let me repeat that." and say it again more slowly.\n\n'
'Never express frustration at interruptions or repetition.'
)
def handle_conversation(turns):
"""Handle multi-turn voice conversation with interruptions."""
messages = []
for speaker, text in turns:
messages.append({'role': speaker, 'content': text})
r = client.messages.create(
model='claude-opus-4-5',
max_tokens=200,
system=INTERRUPTION_SYSTEM,
messages=messages
)
return r.content[0].text
# Simulate an interruption scenario
conversation = [
('user', 'What is my balance?'),
('assistant', 'Your checking account balance is four hundred dollars and—'),
('user', 'Actually wait, can you tell me my savings instead?'),
]
print(handle_conversation(conversation))音声を補完する画面表示
画面を利用できる場合は、画面上の内容が音声を補完するように設計してください。音声をそのまま重複して表示するのではありません。詳細は画面で扱い、ナビゲーションと感情的な働きかけは音声で行います。
def render_multimodal_response(agent_output):
"""
Render a voice agent response to both TTS and screen components.
agent_output: dict with 'spoken', 'visual_content', 'action_label'
"""
# Route to TTS
spoken = agent_output.get('spoken', '')
if spoken:
send_to_tts(spoken) # Your TTS function
print(f'[AUDIO] {spoken}')
# Route to screen
visual = agent_output.get('visual_content')
if visual:
render_card_on_screen(visual) # Your UI function
print(f'[SCREEN] {visual[:100]}')
# Optional action button
action_label = agent_output.get('action_label')
if action_label:
show_action_button(action_label) # Your UI function
print(f'[BUTTON] {action_label}')
def send_to_tts(text):
print(f'TTS: {text}')
def render_card_on_screen(content):
print(f'Screen card: {content[:50]}')
def show_action_button(label):
print(f'Button: {label}')
# Test it
render_multimodal_response({
'spoken': 'I found three flights to New York.',
'visual_content': '| Flight | Departs | Price |\n|---|---|---|\n| AA101 | 08:00 | $299 |',
'action_label': 'Book cheapest'
})アクセシビリティに関する考慮事項
音声AIは、視覚障害や運動機能の困難があるユーザーにとって、それ自体がアクセシビリティ機能になります。音声を主なインターフェースとして利用するユーザーも支援できるよう、エージェントを設計してください。
ACCESSIBILITY_VOICE_SYSTEM = (
'This voice assistant serves users who may be using voice as their '
'primary access method due to disability or preference.\n\n'
'Guidelines:\n'
'- Never require the user to see a screen to complete a task.\n'
'- Read out all information that matters, including confirmation codes, '
'totals, and status messages.\n'
'- Offer to repeat any information: '
'"I can repeat that if you would like."\n'
'- Describe any actions you took: '
'"I have sent the confirmation to your email."\n'
'- Accept multiple phrasings for the same command — users phrase '
'voice commands inconsistently.\n'
'- Confirm all destructive or financial actions before executing:\n'
' "Just to confirm: you want to transfer $500 to John. Is that right?"'
)
print(ACCESSIBILITY_VOICE_SYSTEM[:300])音声エージェントの応答をテストする
音声エージェントの応答をテストするには、テキスト応答とは異なるアプローチが必要です。発話された音声(韻律、明瞭さ、自然さ)と視覚要素(完全性、書式)の両方を評価しなければなりません。テキストでは読みやすい応答でも、読み上げると不自然に聞こえることがあります。
エージェントの出力をTTSエンジンで音声に変換し、文の長さ、略語の発音、Markdownの痕跡がないこと、ターンテイキングの合図を自動的に品質チェックするテストパイプラインを構築してください。
知識チェック:音声のみの制約
音声のみのコンテキスト(画面のないスマートスピーカー)では、どのようなエージェントの応答が最も適切ですか。
まとめ:マルチモーダルな音声・テキストエージェント
音声エージェントには、音声のみ(画面なし)とマルチモーダル(音声+画面)の2つのモードがあります。音声のみの応答は、視覚的な参照を避け、言葉による道しるべを使って、完全に音声だけで機能する必要があります。マルチモーダルな応答では、会話の要約や感情的なトーンを音声で、詳細なデータや長文のテキストを画面で扱うように内容を分けます。簡単に振り分けられるよう、LLMには構造化された出力(spokenフィールドとvisualフィールドを含むJSON)を返すよう指示してください。明確な応答の終了、自然な割り込み対応、明示的な繰り返しのサポートによって、ターンテイキングを設計します。アクセシビリティを常に考慮してください。音声は、それを最も必要とするユーザーにとって主要なインターフェースであることが多いからです。
AI チューターと学ぶ AI Prompt Engineering — 無料
ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。
- コース
- 53
- レッスン
- 199
よくある質問
「マルチモーダル音声・テキストエージェント」レッスンは無料ですか?
はい。「マルチモーダル音声・テキストエージェント」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AI Prompt Engineeringコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AI Prompt Engineeringコースには全4レッスンが含まれています。
「マルチモーダル音声・テキストエージェント」で何を学びますか?
音声エージェントシステムで、話し言葉による応答と画面上のテキストを連携させます。 ブラウザで直接実行するハンズオンコードでAI Prompt Engineeringを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
AI Prompt Engineeringを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのAI Prompt Engineeringは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「マルチモーダル音声・テキストエージェント」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このAI Prompt Engineeringレッスンでコードを書いて実行できますか?
はい。すべてのAI Prompt Engineeringレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- 自然な音声のためのTTSプロンプトパターン
- SSMLと韻律の制御
- Voice AIのペルソナ設計
- マルチモーダル音声・テキストエージェント