Добавление упреждающих сообщений в агент голосовой связи в реальном времени (предварительная версия)

Замечание

Эта функция сейчас доступна в общедоступной предварительной версии. Эта предварительная версия предоставляется без соглашения об уровне обслуживания и не рекомендуется для использования в рабочей среде. Некоторые функции могут не поддерживаться или их возможности могут быть ограничены. Дополнительные сведения см. в разделе Supplemental Terms of Use for Microsoft Azure Previews.

Упреждающее взаимодействие позволяет агенту Voice Live говорить сначала, прежде чем пользователь взаимодействует с системой. Это может сделать агентов более естественными, более полезными и более адаптивными в начале беседы.

В этой статье показано, как реализовать упреждающие сообщения, используя шаблон цикла событий, представленный в кратком руководстве по началу работы с Голосовой трансляцией для агентов голосовой связи в режиме реального времени .

Voice Live предлагает два поддерживаемых метода:

  • Предварительно созданное приветствие — лучше всего подходит для детерминированного или фирменного сообщения
  • Приветствие, созданное LLM , лучше всего подходит для динамических и адаптивных запусков

Оба метода интегрируются естественно с циклом событий сеанса и гарантируют, что сообщение становится частью контекста беседы.

Используйте подход, который лучше всего соответствует вашим целям продукта и беседы.

Вы узнаете:

  • Как проактивное сообщение интегрируется в цикл событий
  • Как отслеживать начало беседы

Предпосылки

Перед началом работы рекомендуется иметь:

Это важно

Упреждающая отправка сообщений с pre_generated_assistant_message требует azure-ai-voicelive >= 1.2.0b2 и версии 2026-01-01-preview API. Установите пакет SDK предварительной версии с помощью:

pip install azure-ai-voicelive --pre

Этот пакет SDK в настоящее время находится в предварительной версии. Функции и API могут изменяться до общедоступной доступности.

Это важно

Упреждающая отправка сообщений с PreGeneratedAssistantMessage требует Azure.AI.VoiceLive >= 1.1.0-beta.1 и версии 2026-01-01-preview API. Установите пакет SDK предварительной версии с помощью:

dotnet add package Azure.AI.VoiceLive --prerelease

Этот пакет SDK в настоящее время находится в предварительной версии. Функции и API могут изменяться до общедоступной доступности.

Это важно

Упреждающая отправка сообщений с setPreGeneratedAssistantMessage требует azure-ai-voicelive >= 1.0.0-beta.3 и версии 2026-01-01-preview API. Добавьте зависимость предварительного просмотра в вашу pom.xml:

<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-ai-voicelive</artifactId>
    <version>1.0.0-beta.3</version>
</dependency>

Этот пакет SDK в настоящее время находится в предварительной версии. Функции и API могут изменяться до общедоступной доступности.

Это важно

Упреждающая отправка сообщений с preGeneratedAssistantMessage требует @azure/ai-voicelive >= 1.0.0-beta.2 и версии 2026-01-01-preview API. Для этого пакета SDK требуется Node.js 20 или более поздней версии. Установите пакет SDK предварительной версии с помощью:

npm install @azure/ai-voicelive@1.0.0-beta.2

Этот пакет SDK в настоящее время находится в предварительной версии. Функции и API могут изменяться до общедоступной доступности.

Как упреждающие сообщения интегрируются с циклом событий

Приложения Голосовой трансляции обычно обрабатывают события с помощью асинхронного цикла:

async for event in conn:
    await self._handle_event(event)
await foreach (SessionUpdate serverEvent in session.GetUpdatesAsync(cancellationToken))
{
    await HandleSessionUpdateAsync(serverEvent, cancellationToken);
}
session.receiveEvents()
    .subscribe(
        event -> handleServerEvent(event, audioProcessor),
        error -> System.err.println("Error: " + error.getMessage())
    );
const subscription = session.subscribe({
    onSessionUpdated: async (event, context) => {
        await handleEvent(event);
    }
});

Когда сеанс будет готов, служба отправляет SESSION_UPDATED событие. Это идеальный момент для запуска упреждающего участия.

Так как приветствие должно выполняться только один раз на сеанс, вы отслеживаете состояние:

self.greeting_sent = False
private bool _greetingSent = false;
private AtomicBoolean greetingSent = new AtomicBoolean(false);
let greetingSent = false;

Внутри обработчика событий:

if event.type == ServerEventType.SESSION_UPDATED:
    if not self.greeting_sent:
        # ... send proactive message ...
        self.greeting_sent = True
if (serverEvent is SessionUpdateSessionUpdated)
{
    if (!_greetingSent)
    {
        // ... send proactive message ...
        _greetingSent = true;
    }
}
if (event.getType() == ServerEventType.SESSION_UPDATED) {
    if (!greetingSent.getAndSet(true)) {
        // ... send proactive message ...
    }
}
if (event.type === "session.updated") {
    if (!greetingSent) {
        // ... send proactive message ...
        greetingSent = true;
    }
}

Это гарантирует:

  • Приветствие срабатывает ровно один раз
  • Пользователь может начать взаимодействие сразу после этого.
  • Сообщение вводит контекст беседы, чтобы LLM понимал, что говорилось

Поддерживаемые параметры упреждающего сообщения

Voice Live поддерживает два механизма запуска беседы заранее.

Вы должны выбрать метод, который лучше всего подходит для вашего сценария.

Вариант 1. Предварительно созданное сообщение помощника

(Лучше всего подходит для детерминированных или фирменных приветствий)

Используйте этот параметр, если приложение уже знает, что должен сказать агент, например:

  • Статические приветственные сообщения
  • Случайно выбранные приветствия из предопределенного списка
  • Персонализированный текст приветствия (например, "Добро пожаловать обратно, Лиза!")

Сообщение:

  • Вставлено непосредственно в контекст беседы в качестве сообщения помощника
  • Синтезировано TTS
  • Под полным контролем разработчика

Полные спецификации параметров см pre_generated_assistant_message . в справочнике по API.

Пример: предварительно созданное приветствие

from azure.ai.voicelive.models import (
    ResponseCreateParams,
    AssistantMessageItem,
    OutputTextContentPart,
)

# Send a pre-generated assistant greeting
await conn.response.create(
    response=ResponseCreateParams(
        pre_generated_assistant_message=AssistantMessageItem(
            content=[
                OutputTextContentPart(
                    text="Hi Lisa, welcome back! How can I assist you today?"
                )
            ]
        )
    )
)
using System.Text.Json;

// Send a pre-generated assistant greeting
var greeting = "Hi Lisa, welcome back! How can I assist you today?";
var responseCreatePayload = new
{
    type = "response.create",
    response = new
    {
        pre_generated_assistant_message = new
        {
            type = "message",
            role = "assistant",
            content = new[]
            {
                new { type = "text", text = greeting }
            }
        }
    }
};
BinaryData eventData = BinaryData.FromObjectAsJson(responseCreatePayload);
await session.SendCommandAsync(eventData, cancellationToken).ConfigureAwait(false);
import com.azure.ai.voicelive.models.*;
import java.util.Arrays;

// Send a pre-generated assistant greeting
OutputTextContentPart textContent = new OutputTextContentPart(
    "Hi Lisa, welcome back! How can I assist you today?");
AssistantMessageItem assistantMessage = new AssistantMessageItem(Arrays.asList(textContent));

ResponseCreateParams responseParams = new ResponseCreateParams()
    .setPreGeneratedAssistantMessage(assistantMessage);

session.sendEvent(new ClientEventResponseCreate().setResponse(responseParams)).subscribe();
// Send a pre-generated assistant greeting
await session.sendEvent({
    type: "response.create",
    response: {
        preGeneratedAssistantMessage: {
            content: [
                {
                    type: "text",
                    text: "Hi Lisa, welcome back! How can I assist you today?"
                }
            ]
        }
    }
});

Когда использовать этот параметр

Scenario Использовать?
Согласованный, фирменный обмен сообщениями ✔ Да
Персонализация на основе шаблонов или правил ✔ Да
Требуется детерминированные выходные данные ✔ Да
Хотите, чтобы модель была креативной? ✖ Нет

Вариант 2. Упреждающее приветствие, созданное LLM

(Лучше всего подходит для динамических и персонализированных приветствий)

В этом шаблоне вы указываете LLM создать приветствие.
Сначала вы создаете элемент диалога с системной инструкцией, а затем инициируете ответ.

Пример: приветствие, созданное LLM

from azure.ai.voicelive.models import (
    MessageItem,
    InputTextContentPart,
)

# Add an instruction telling the LLM to greet the user
await conn.conversation.item.create(
    item=MessageItem(
        role="system",
        content=[
            InputTextContentPart(
                text="Say something to welcome the user."
            )
        ]
    )
)

# Trigger LLM-generated greeting
await conn.response.create()
using Azure.AI.VoiceLive;

// Add an instruction telling the LLM to greet the user
var systemMessage = new SystemMessageItem(
    new InputTextContentPart("Say something to welcome the user."));
await session.AddItemAsync(systemMessage, cancellationToken).ConfigureAwait(false);

// Trigger LLM-generated greeting
await session.StartResponseAsync().ConfigureAwait(false);
import com.azure.ai.voicelive.models.*;
import java.util.Arrays;

// Add an instruction telling the LLM to greet the user
InputTextContentPart textContent = new InputTextContentPart(
    "Say something to welcome the user.");
SystemMessageItem systemMessage = new SystemMessageItem(Arrays.asList(textContent));

session.sendEvent(new ClientEventConversationItemCreate().setItem(systemMessage)).subscribe();

// Trigger LLM-generated greeting
session.sendEvent(new ClientEventResponseCreate()).subscribe();
// Add an instruction telling the LLM to greet the user
await session.addConversationItem({
    type: "message",
    role: "system",
    content: [
        {
            type: "input_text",
            text: "Say something to welcome the user."
        }
    ]
});

// Trigger LLM-generated greeting
await session.sendEvent({
    type: "response.create"
});

Когда использовать этот параметр

Scenario Использовать?
Адаптивные, контекстные приветствия ✔ Да
Персонализированный тон или содержимое ✔ Да
Вариации в сеансах ✔ Да
Прогнозируемые выходные данные, необходимые ✖ Нет

Интеграция упреждающего обмена сообщениями в обработчик событий

Ниже приведен объединенный шаблон, который подключает обработку циклов событий, отслеживание начала беседы и оба варианта упреждающего обмена сообщениями.

Интеграция событий сеанса

async def _handle_event(self, event):
    conn = self.connection
    ap = self.audio_processor

    if event.type == ServerEventType.SESSION_UPDATED:
        print("Session is ready.")
        self.session_ready = True

        # Start microphone capture
        ap.start_capture()

        # Trigger greeting once
        if not self.greeting_sent:
            self.greeting_sent = True

            # ----- Option 1: Pre-generated greeting -----
            # await send_pre_generated_greeting(conn)

            # ----- Option 2: LLM-generated greeting -----
            # await send_llm_generated_greeting(conn)

    elif event.type == ServerEventType.INPUT_AUDIO_BUFFER_SPEECH_STARTED:
        print("🎤 Listening...")
        ap.skip_pending_audio()

    elif event.type == ServerEventType.RESPONSE_AUDIO_DELTA:
        ap.queue_audio(event.delta)

    elif event.type == ServerEventType.RESPONSE_AUDIO_DONE:
        print("🎤 Ready for next input...")
private async Task HandleSessionUpdateAsync(SessionUpdate serverEvent, CancellationToken cancellationToken)
{
    if (serverEvent is SessionUpdateSessionUpdated sessionUpdated)
    {
        Console.WriteLine("Session is ready.");
        _sessionReady = true;

        // Start microphone capture
        await _audioProcessor.StartCaptureAsync();

        // Trigger greeting once
        if (!_greetingSent)
        {
            _greetingSent = true;

            // ----- Option 1: Pre-generated greeting -----
            // await SendPreGeneratedGreetingAsync(_session, cancellationToken);

            // ----- Option 2: LLM-generated greeting -----
            // await SendLlmGeneratedGreetingAsync(_session, cancellationToken);
        }
    }
    else if (serverEvent is SessionUpdateInputAudioBufferSpeechStarted)
    {
        Console.WriteLine("🎤 Listening...");
        await _audioProcessor.StopPlaybackAsync();
    }
    else if (serverEvent is SessionUpdateResponseAudioDelta audioDelta)
    {
        await _audioProcessor.QueueAudioAsync(audioDelta.Delta.ToArray());
    }
    else if (serverEvent is SessionUpdateResponseAudioDone)
    {
        Console.WriteLine("🎤 Ready for next input...");
    }
}
private void handleServerEvent(SessionUpdate event, AudioProcessor audioProcessor) {
    ServerEventType eventType = event.getType();

    if (eventType == ServerEventType.SESSION_UPDATED) {
        System.out.println("Session is ready.");
        sessionReady = true;

        // Start microphone capture
        audioProcessor.startCapture();

        // Trigger greeting once
        if (!greetingSent.getAndSet(true)) {

            // ----- Option 1: Pre-generated greeting -----
            // sendPreGeneratedGreeting(session);

            // ----- Option 2: LLM-generated greeting -----
            // sendLlmGeneratedGreeting(session);
        }
    } else if (eventType == ServerEventType.INPUT_AUDIO_BUFFER_SPEECH_STARTED) {
        System.out.println("🎤 Listening...");
        audioProcessor.skipPendingAudio();
    } else if (eventType == ServerEventType.RESPONSE_AUDIO_DELTA) {
        SessionUpdateResponseAudioDelta audioEvent = (SessionUpdateResponseAudioDelta) event;
        audioProcessor.queueAudio(audioEvent.getDelta());
    } else if (eventType == ServerEventType.RESPONSE_AUDIO_DONE) {
        System.out.println("🎤 Ready for next input...");
    }
}
const subscription = session.subscribe({
    onSessionUpdated: async (event, context) => {
        console.log("Session is ready.");
        sessionReady = true;

        // Start microphone capture
        startMicrophoneCapture();

        // Trigger greeting once
        if (!greetingSent) {
            greetingSent = true;

            // ----- Option 1: Pre-generated greeting -----
            // await sendPreGeneratedGreeting(session);

            // ----- Option 2: LLM-generated greeting -----
            // await sendLlmGeneratedGreeting(session);
        }
    },

    onInputAudioBufferSpeechStarted: async (event, context) => {
        console.log("🎤 Listening...");
        skipPendingAudio();
    },

    onResponseAudioDelta: async (event, context) => {
        queueAudio(event.delta);
    },

    onResponseAudioDone: async (event, context) => {
        console.log("🎤 Ready for next input...");
    }
});

Вспомогательные функции приветствия

async def send_pre_generated_greeting(conn):
    try:
        await conn.response.create(
            response=ResponseCreateParams(
                pre_generated_assistant_message=AssistantMessageItem(
                    content=[
                        OutputTextContentPart(
                            text="Welcome! I'm here to help you get started."
                        )
                    ]
                )
            )
        )
    except Exception as e:
        print(f"Failed to send pre-generated greeting: {e}")

async def send_llm_generated_greeting(conn):
    try:
        await conn.conversation.item.create(
            item=MessageItem(
                role="system",
                content=[
                    InputTextContentPart(
                        text="Greet the user warmly and briefly explain how you can help."
                    )
                ]
            )
        )
        await conn.response.create()
    except Exception as e:
        print(f"Failed to send LLM-generated greeting: {e}")
private async Task SendPreGeneratedGreetingAsync(
    VoiceLiveSession session, 
    CancellationToken cancellationToken)
{
    try
    {
        var greeting = "Welcome! I'm here to help you get started.";
        var responseCreatePayload = new
        {
            type = "response.create",
            response = new
            {
                pre_generated_assistant_message = new
                {
                    type = "message",
                    role = "assistant",
                    content = new[]
                    {
                        new { type = "text", text = greeting }
                    }
                }
            }
        };
        BinaryData eventData = BinaryData.FromObjectAsJson(responseCreatePayload);
        await session.SendCommandAsync(eventData, cancellationToken).ConfigureAwait(false);
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Failed to send pre-generated greeting: {ex.Message}");
    }
}

private async Task SendLlmGeneratedGreetingAsync(
    VoiceLiveSession session, 
    CancellationToken cancellationToken)
{
    try
    {
        var systemMessage = new SystemMessageItem(
            new InputTextContentPart("Greet the user warmly and briefly explain how you can help."));
        await session.AddItemAsync(systemMessage, cancellationToken).ConfigureAwait(false);
        await session.StartResponseAsync().ConfigureAwait(false);
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Failed to send LLM-generated greeting: {ex.Message}");
    }
}
private void sendPreGeneratedGreeting(VoiceLiveSessionAsyncClient session) {
    try {
        OutputTextContentPart textContent = new OutputTextContentPart(
            "Welcome! I'm here to help you get started.");
        AssistantMessageItem assistantMessage = new AssistantMessageItem(Arrays.asList(textContent));

        ResponseCreateParams responseParams = new ResponseCreateParams()
            .setPreGeneratedAssistantMessage(assistantMessage);

        session.sendEvent(new ClientEventResponseCreate().setResponse(responseParams))
            .doOnError(error -> System.err.println("Failed to send pre-generated greeting: " + error.getMessage()))
            .subscribe();
    } catch (Exception e) {
        System.err.println("Failed to send pre-generated greeting: " + e.getMessage());
    }
}

private void sendLlmGeneratedGreeting(VoiceLiveSessionAsyncClient session) {
    try {
        InputTextContentPart textContent = new InputTextContentPart(
            "Greet the user warmly and briefly explain how you can help.");
        SystemMessageItem systemMessage = new SystemMessageItem(Arrays.asList(textContent));

        session.sendEvent(new ClientEventConversationItemCreate().setItem(systemMessage))
            .doOnError(error -> System.err.println("Failed to add conversation item: " + error.getMessage()))
            .subscribe();
        session.sendEvent(new ClientEventResponseCreate())
            .doOnError(error -> System.err.println("Failed to create response: " + error.getMessage()))
            .subscribe();
    } catch (Exception e) {
        System.err.println("Failed to send LLM-generated greeting: " + e.getMessage());
    }
}
async function sendPreGeneratedGreeting(session) {
    try {
        await session.sendEvent({
            type: "response.create",
            response: {
                preGeneratedAssistantMessage: {
                    content: [
                        {
                            type: "text",
                            text: "Welcome! I'm here to help you get started."
                        }
                    ]
                }
            }
        });
    } catch (error) {
        console.error("Failed to send pre-generated greeting:", error.message);
    }
}

async function sendLlmGeneratedGreeting(session) {
    try {
        await session.addConversationItem({
            type: "message",
            role: "system",
            content: [
                {
                    type: "input_text",
                    text: "Greet the user warmly and briefly explain how you can help."
                }
            ]
        });
        await session.sendEvent({
            type: "response.create"
        });
    } catch (error) {
        console.error("Failed to send LLM-generated greeting:", error.message);
    }
}

Выбор правильного подхода

Требование Предварительно сгенерировано Сгенерированный LLM
Прогнозируемые, скриптовые приветствия
Согласованность и контролируемый язык фирменной символики В зависимости от инструкций
Адаптивное и персонализированное содержимое Если вы не реализуете его
Разнообразие бесед
Минимальная подсказка модели

Дальнейшие шаги