Создание голосового агента (предварительная версия)

Примечание

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

Узнайте, как использовать Voice Live с Microsoft Foundry Agent Service с помощью пакета SDK для VoiceLive на Python. В этой статье мы расширяем краткое руководство по созданию агента голосовой связи с помощью службы агента Foundry и Voice Live, добавляя расширенные функции и параметры интеграции.

Справочная документация Пакет (PyPi) | Дополнительные примеры на GitHub

Создание и запуск приложений для использования Voice Live с агентами для бесед в режиме реального времени.

Агенты предоставляют несколько преимуществ:

  • Используйте централизованную конфигурацию в самом агенте вместо кода сеанса.
  • Обрабатывайте сложную логику и диалоговое поведение для облегчения обновлений.
  • Автоматически подключитесь с помощью идентификатора агента.
  • Поддержка нескольких вариантов без изменения клиентского кода.

Сведения об использовании Voice Live без агентов Foundry см. в кратком руководстве по API Voice Live.

Совет

Вам не нужно развертывать звуковую модель с Microsoft Foundry для использования Voice Live. Voice Live полностью управляется и автоматически развертывает модель для вас. Сведения о доступности модели см. в документации по Voice Live.

Необходимые условия

Примечание

Этот документ ссылается на портал Microsoft Foundry (new) и последнюю версию службы агента Foundry.

  • Назначьте роль Azure AI User учетной записи пользователя. Роли можно назначить на портале Azure в разделе Access control (IAM)>Add role assignment.

Подготовка среды и создание агента

Выполните Быстрый запуск: создание голосового агента с помощью службы Foundry Agent и Voice Live, чтобы настроить вашу среду, конфигурировать агента с настройками Voice Live и протестировать ваш первый разговор.

Концепции интеграции агента

Используйте эти понятия, чтобы понять, как служба агента Voice Live и Foundry работают вместе в примере Python.

Контракт конфигурации агента

Укажите agent_config в настройках сеанса для идентификации целевого агента и проекта. Как минимум, включите agent_name и project_name. Добавьте agent_version, когда хотите закрепить поведение в определенной версии.

Модель проверки подлинности для режима агента

Используйте Microsoft Entra ID учетные данные для режима агента. Вызов агента в этом потоке не поддерживает аутентификацию с использованием ключей, поэтому настройте AzureCliCredential (или другие учетные данные токена Entra) для локальной разработки и развертывания.

Закрепление версий API

Чтобы поведение оставалось предсказуемым при предварительных обновлениях, закрепите поддерживаемое api_version в клиенте. Используйте одну и ту же версию последовательно в примерах быстрого старта и инструкциях, чтобы избежать дрейфа схемы.

Выравнивание бесед и трассировки

Рассматривайте поток агента и записи трассировки как историю текстовых сообщений, а не точную историю воспроизведения. Если ваше приложение допускает прерывание или усечение, включите обработку с учётом усечения, чтобы сохранённая история более точно соответствовала тому, что пользователь на самом деле слышал.

Подключение к определенной версии агента

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

AGENT_VERSION Задайте переменную среды или передайте agent_version параметр при инициализации помощника:

    def __init__(
        self,
        endpoint: str,
        credential: Union[AzureKeyCredential, AsyncTokenCredential],
        voice: str,
        agent_name: str,
        project_name: str,
        agent_version: Optional[str] = None,
        conversation_id: Optional[str] = None,
        foundry_resource_override: Optional[str] = None,
        agent_authentication_identity_client_id: Optional[str] = None,
    ):
        self.endpoint = endpoint
        self.credential = credential
        self.voice = voice
        # Build AgentSessionConfig internally
        self.agent_config: AgentSessionConfig = {
            "agent_name": agent_name,
            "agent_version": agent_version if agent_version else None,
            "project_name": project_name,
            "conversation_id": conversation_id if conversation_id else None,
            "foundry_resource_override": foundry_resource_override if foundry_resource_override else None, 
            "authentication_identity_client_id": agent_authentication_identity_client_id if agent_authentication_identity_client_id and foundry_resource_override else None,                
        }        
            # Connect using AgentSessionConfig (new SDK pattern)
            async with connect(
                endpoint=self.endpoint,
                credential=self.credential,
                api_version="2026-01-01-preview",
                agent_config=self.agent_config,
            ) as connection:
def main() -> None:
    """Main function."""
    endpoint = os.environ.get("VOICELIVE_ENDPOINT", "")
    voice_name = os.environ.get("VOICE_NAME", "en-US-Ava:DragonHDLatestNeural")
    agent_name = os.environ.get("AGENT_NAME", "")
    agent_version = os.environ.get("AGENT_VERSION")
    project_name = os.environ.get("PROJECT_NAME", "")
    conversation_id = os.environ.get("CONVERSATION_ID")
    foundry_resource_override = os.environ.get("FOUNDRY_RESOURCE_OVERRIDE")
    agent_authentication_identity_client_id = os.environ.get("AGENT_AUTHENTICATION_IDENTITY_CLIENT_ID")

    print("Environment variables:")
    print(f"VOICELIVE_ENDPOINT: {endpoint}")
    print(f"VOICE_NAME: {voice_name}")
    print(f"AGENT_NAME: {agent_name}")
    print(f"AGENT_VERSION: {agent_version}")
    print(f"PROJECT_NAME: {project_name}")
    print(f"CONVERSATION_ID: {conversation_id}")
    print(f"FOUNDRY_RESOURCE_OVERRIDE: {foundry_resource_override}")
    print(f"AGENT_AUTHENTICATION_IDENTITY_CLIENT_ID: {agent_authentication_identity_client_id}")

    if not endpoint or not agent_name or not project_name:
        sys.exit("Set VOICELIVE_ENDPOINT, AGENT_NAME, and PROJECT_NAME in your .env file.")

    # Create client with appropriate credential (Entra ID required for Agent mode)
    credential = AzureCliCredential()
    logger.info("Using Azure token credential")

    # Create and start voice assistant
    assistant = BasicVoiceAssistant(
        endpoint=endpoint,
        credential=credential,
        voice=voice_name,
        agent_name=agent_name,
        agent_version=agent_version,
        project_name=project_name,
        conversation_id=conversation_id,

В этом примере конфигурация версии применяется в трех местах:

  • В main()AGENT_VERSION считывается из среды.
  • В вызове BasicVoiceAssistant(...)agent_version передается конструктору класса.
  • В BasicVoiceAssistant.__init__ значение добавляется в self.agent_config, а затем отправляется в Voice Live через connect(..., agent_config=self.agent_config).

Значение agent_version соответствует строке версии, возвращаемой при создании или обновлении агента с помощью пакета SDK агента Foundry. Если это не указано, Voice Live подключается к последней версии агента.

Подключение к какому-либо агенту в другом ресурсе Foundry

Настройте Voice Live для подключения к агенту в другом ресурсе Foundry для обработки звука. Это полезно, когда:

  • Агент развертывается в регионе с различной доступностью функций.
  • Вы хотите разделить среды разработки и промежуточного хранения из рабочей среды
  • В организации используются различные ресурсы для разных рабочих нагрузок

Чтобы подключиться к агенту в другом ресурсе, настройте две дополнительные переменные среды:

  • FOUNDRY_RESOURCE_OVERRIDE: имя ресурса Foundry, в котором размещается проект агента (например, my-agent-resource).
  • AGENT_AUTHENTICATION_IDENTITY_CLIENT_ID: идентификатор клиента управляемой идентичности ресурса Voice Live, необходимый для проверки подлинности межресурсных взаимодействий.
    conversation_id: Optional[str] = None,
    foundry_resource_override: Optional[str] = None,
    agent_authentication_identity_client_id: Optional[str] = None,
):
    self.endpoint = endpoint
    self.credential = credential
    self.voice = voice
    # Build AgentSessionConfig internally
    self.agent_config: AgentSessionConfig = {
        "agent_name": agent_name,
        "agent_version": agent_version if agent_version else None,
        "project_name": project_name,
        "conversation_id": conversation_id if conversation_id else None,
        "foundry_resource_override": foundry_resource_override if foundry_resource_override else None, 
        "authentication_identity_client_id": agent_authentication_identity_client_id if agent_authentication_identity_client_id and foundry_resource_override else None,                
    }        
conversation_id = os.environ.get("CONVERSATION_ID")
foundry_resource_override = os.environ.get("FOUNDRY_RESOURCE_OVERRIDE")
agent_authentication_identity_client_id = os.environ.get("AGENT_AUTHENTICATION_IDENTITY_CLIENT_ID")

print("Environment variables:")
print(f"VOICELIVE_ENDPOINT: {endpoint}")
print(f"VOICE_NAME: {voice_name}")
print(f"AGENT_NAME: {agent_name}")
print(f"AGENT_VERSION: {agent_version}")
print(f"PROJECT_NAME: {project_name}")
print(f"CONVERSATION_ID: {conversation_id}")
print(f"FOUNDRY_RESOURCE_OVERRIDE: {foundry_resource_override}")
print(f"AGENT_AUTHENTICATION_IDENTITY_CLIENT_ID: {agent_authentication_identity_client_id}")

if not endpoint or not agent_name or not project_name:
    sys.exit("Set VOICELIVE_ENDPOINT, AGENT_NAME, and PROJECT_NAME in your .env file.")

# Create client with appropriate credential (Entra ID required for Agent mode)
credential = AzureCliCredential()
logger.info("Using Azure token credential")

# Create and start voice assistant
assistant = BasicVoiceAssistant(
    endpoint=endpoint,
    credential=credential,
    voice=voice_name,
    agent_name=agent_name,
    agent_version=agent_version,
    project_name=project_name,
    conversation_id=conversation_id,
    foundry_resource_override=foundry_resource_override,
    agent_authentication_identity_client_id=agent_authentication_identity_client_id,
        # Connect using AgentSessionConfig (new SDK pattern)
        async with connect(
            endpoint=self.endpoint,
            credential=self.credential,
            api_version="2026-01-01-preview",
            agent_config=self.agent_config,
        ) as connection:

Эта конфигурация разрешается в main(), а затем применяется при создании помощника.

  • FOUNDRY_RESOURCE_OVERRIDE и AGENT_AUTHENTICATION_IDENTITY_CLIENT_ID считываются из переменных среды.
  • Оба значения передаются в BasicVoiceAssistant(...).
  • В BasicVoiceAssistant.__init__ добавляются значения self.agent_config, которые отправляются в connect(..., agent_config=self.agent_config).

Важно

Для подключений между ресурсами требуются правильные назначения ролей. Убедитесь, что управляемое удостоверение ресурса Voice Live имеет роль Azure AI User в целевом ресурсе агента.

Добавление упреждающего сообщения при запуске сеанса

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

self.greeting_sent = False

if event.type == ServerEventType.SESSION_UPDATED:
    # <session_updated_metadata>
    logger.info("Session ready: %s", event.session.id)
    s, a, v = event.session, event.session.agent, event.session.voice
    await write_conversation_log("\n".join([
        f"SessionID: {s.id}", f"Agent Name: {a.name}",
        f"Agent Description: {a.description}", f"Agent ID: {a.agent_id}",
        f"Voice Name: {v['name']}", f"Voice Type: {v['type']}",
        f"Voice Temperature: {v['temperature']}", ""
    ]))
    # </session_updated_metadata>
    self.session_ready = True

    # <proactive_greeting>
    # Invoke Proactive greeting
    if not self.greeting_sent:
        self.greeting_sent = True
        logger.info("Sending proactive greeting request")
        try:
            await conn.conversation.item.create(
                item=MessageItem(
                    role="system",
                    content=[
                        InputTextContentPart(
                            text="Say something to welcome the user in English."
                        )
                    ]
                )
            )
            await conn.response.create()
        except Exception:
            logger.exception("Failed to send proactive greeting request")
    # </proactive_greeting>

    # Start audio capture once session is ready

В этом примере проактивное информирование применяется в три этапа:

  • self.greeting_sent = False инициализирует единовременное состояние приветствия.
  • В ветви SESSION_UPDATED, if not self.greeting_sent: ворота ограничивают упреждающее выполнение, чтобы оно выполнялось один раз за сеанс.
  • conn.conversation.item.create(...) добавляет инструкцию приветствия в контекст беседы и conn.response.create() создает произнесенные выходные данные.

Улучшение времени ожидания вызова инструмента и задержки

Используйте функцию Voice Live interim_response для сокращения времени ожидания в процессе вызова инструмента или при создании ответов агента с высокой задержкой.

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

  • Промежуточный ответ, сгенерированный с помощью LLM (llm_interim_response): использует облегченный LLM для динамического создания текста, учитывающего контекст. Лучше всего подходит для адаптивных, естественных звуковых ответов.
  • Статический промежуточный ответ (static_interim_response): случайным образом выбирается из предопределенного списка предоставленных текстов. Лучше всего подходит для детерминированного или фирменного обмена сообщениями.

Дополнительные сведения см. в разделе "Улучшение вызова инструмента и времени ожидания задержки с промежуточными ответами".

Созданное с помощью voice-live-agents-quickstart.py краткое руководство показывает необходимые дополнения коду для настройки этой функции следующим образом:

from azure.ai.voicelive.models import (
    InputAudioFormat,
    Modality,
    OutputAudioFormat,
    RequestSession,
    ServerEventType,
    MessageItem,
    InputTextContentPart,
    LlmInterimResponseConfig,
    InterimResponseTrigger,
    AzureStandardVoice,
    AudioNoiseReduction,
    AudioEchoCancellation,
    AzureSemanticVadMultilingual
)
    async def _setup_session(self) -> None:
        """Configure the VoiceLive session for audio conversation."""
        logger.info("Setting up voice conversation session...")

        # Set up interim response configuration to bridge latency gaps during processing
        interim_response_config = LlmInterimResponseConfig(
            triggers=[InterimResponseTrigger.TOOL, InterimResponseTrigger.LATENCY],
            latency_threshold_ms=100,
            instructions="""Create friendly interim responses indicating wait time due to ongoing processing, if any. Do not include
                            in all responses! Do not say you don't have real-time access to information when calling tools!"""
        )

        # Create session configuration
        session_config = RequestSession(
            modalities=[Modality.TEXT, Modality.AUDIO],
            input_audio_format=InputAudioFormat.PCM16,
            output_audio_format=OutputAudioFormat.PCM16,
            interim_response=interim_response_config,
            # Uncomment the following, if not stored with agent configuration on the service side
            # voice=AzureStandardVoice(name=self.voice),
            # turn_detection=AzureSemanticVadMultilingual(),
            # input_audio_echo_cancellation=AudioEchoCancellation(),
            # input_audio_noise_reduction=AudioNoiseReduction(type="azure_deep_noise_suppression")
        )

В этом примере настройка промежуточного ответа применяется внутри BasicVoiceAssistant._setup_session():

  • LlmInterimResponseConfig(...) определяет, когда активируются промежуточные ответы и какой стиль они используют.
  • RequestSession(...) присоединяет конфигурацию interim_response через поле.
  • conn.session.update(session=session_config) отправляет конфигурацию сеанса в Voice Live.

Используйте автоматическое сокращение для ответов, которые были прерваны

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

В этом примере в настоящее время показана обработка прерываний с response.cancel() при запуске речи, но auto_truncate не настраивается в turn_detection.

Примечание

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

Сведения о настройке и поддерживаемых параметрах см. в разделе "Обработка прерываний голосовой связи в журнале чата (предварительная версия)".

Повторное подключение к прежнему разговору с агентом

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

Voice Live возвращает метаданные сеанса в событии SESSION_UPDATED, когда сеанс успешно подключается:

if event.type == ServerEventType.SESSION_UPDATED:
    # <session_updated_metadata>
    logger.info("Session ready: %s", event.session.id)
    s, a, v = event.session, event.session.agent, event.session.voice
    await write_conversation_log("\n".join([
        f"SessionID: {s.id}", f"Agent Name: {a.name}",
        f"Agent Description: {a.description}", f"Agent ID: {a.agent_id}",
        f"Voice Name: {v['name']}", f"Voice Type: {v['type']}",
        f"Voice Temperature: {v['temperature']}", ""
    ]))

В этом обработчике событий метаданные сеанса и агента регистрируются при готовности сеанса.

Пример кода автоматически записывает сведения о сеансе в файл журнала бесед в папке logs/ (например, logs/2026-02-19_14-30-00_conversation.log). Идентификатор сеанса можно получить из этого файла после запуска сеанса.

Чтобы повторно подключиться к этой беседе, передайте идентификатор беседы в качестве переменной CONVERSATION_ID среды (или параметром conversation_id ):

    conversation_id: Optional[str] = None,
        "conversation_id": conversation_id if conversation_id else None,
conversation_id = os.environ.get("CONVERSATION_ID")

В этом примере повторное подключение беседы применяется в трех местах:

  • В main()CONVERSATION_ID считывается из среды.
  • В вызове BasicVoiceAssistant(...)conversation_id передается конструктору класса.
  • В BasicVoiceAssistant.__init__ значение присваивается self.agent_config как conversation_id.

Если задано допустимое conversation_id , агент извлекает предыдущий контекст беседы и может ссылаться на предыдущие обмены в ответах.

Примечание

Идентификаторы бесед привязаны к агенту и проекту. Попытка использовать идентификатор беседы с другим агентом приводит к созданию новой беседы.

Логгировать метаданные сеанса для обеспечения непрерывности и диагностики

Записывайте ключевые метаданные сеанса, включая идентификатор сеанса, в файл журнала беседы с меткой времени под logs/. Это поможет вам:

  • Определите сеанс для сценариев отладки и поддержки.
  • Сопоставляйте поведение, сообщаемое пользователем, с метаданными сеанса.
  • Отслеживайте выполнение с течением времени, сохраняя файлы журнала для каждого сеанса.

Данный код создает имя лог-файла и записывает метаданные сеанса при получении SESSION_UPDATED.


# Set up logging
## Add folder for logging
os.makedirs(os.path.join(_script_dir, 'logs'), exist_ok=True)

## Add timestamp for logfiles
timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
            s, a, v = event.session, event.session.agent, event.session.voice
            await write_conversation_log("\n".join([
                f"SessionID: {s.id}", f"Agent Name: {a.name}",
                f"Agent Description: {a.description}", f"Agent ID: {a.agent_id}",
                f"Voice Name: {v['name']}", f"Voice Type: {v['type']}",
                f"Voice Temperature: {v['temperature']}", ""
            ]))
async def write_conversation_log(message: str) -> None:
    """Write a message to the conversation log."""
    log_path = os.path.join(_script_dir, 'logs', logfilename)
    await asyncio.to_thread(
        lambda: open(log_path, 'a', encoding='utf-8').write(message + "\n")
    )

В этом примере ведение журнала метаданных сеанса применяется в трех местах:

  • Для каждого запуска создается файл журнала бесед с меткой времени.
  • К SESSION_UPDATED добавляются метаданные, включая идентификатор сеанса, имя агента и голосовая конфигурация.
  • write_conversation_log(...) добавляет записи в один и тот же файл в течение всего жизненного цикла беседы.

Используйте метаданные зарегистрированного сеанса с CONVERSATION_ID, чтобы возобновить беседу с тем же агентом в последующем сеансе.

В этой статье вы узнаете, как использовать Voice Live с службой агента Microsoft Foundry с помощью VoiceLive SDK для C#. Эта статья дополняет Краткое руководство: Создание голосового агента с помощью службы агент Foundry и Voice Live дополнительными сведениями о функциях и вариантах интеграции.

Документация по справке | Пакет (NuGet) | Дополнительные примеры на GitHub

Создание и запуск приложений для использования Voice Live с агентами для бесед в режиме реального времени.

Агенты предоставляют несколько преимуществ:

  • Используйте централизованную конфигурацию в самом агенте вместо кода сеанса.
  • Обрабатывайте сложную логику и диалоговое поведение для облегчения обновлений.
  • Автоматически подключитесь с помощью идентификатора агента.
  • Поддержка нескольких вариантов без изменения клиентского кода.

Сведения об использовании Voice Live без агентов Foundry см. в кратком руководстве по API Voice Live.

Совет

Вам не нужно развертывать звуковую модель с Microsoft Foundry для использования Voice Live. Voice Live полностью управляется и автоматически развертывает модель для вас. Сведения о доступности модели см. в документации по Voice Live.

Необходимые условия

Примечание

Это руководство относится к порталу Microsoft Foundry (new) и последней версии службы агента Foundry.

Подготовка среды и создание агента

Выполните Краткое руководство: Создание голосового агента с помощью службы агента Foundry и Voice Live, чтобы подготовить свою среду, настроить агента с параметрами Voice Live и провести первый тест.

Концепции интеграции агента

Эти понятия помогают понять, как служба агента Voice Live и Foundry работают вместе в примере C#.

Контракт конфигурации агента

Укажите AgentSessionConfig в настройках сеанса для идентификации целевого агента и проекта. Включите как минимум agentName и projectName. Добавьте AgentVersion, когда хотите закрепить поведение в определенной версии.

Проверка подлинности для режима агента

Используйте Microsoft Entra ID учетные данные для режима агента. Вызов агента не поддерживает проверку подлинности на основе ключей, поэтому настройте AzureCliCredential (или другие учетные данные токена Entra) для локальной разработки и развертывания.

Закрепление версий API

Используйте согласованную версию пакета SDK (Azure.AI.VoiceLive 1.1.0-beta.3) в файле проекта. Согласованное управление версиями позволяет прогнозировать поведение в предварительной версии обновлений и избегает смещения схемы.

Выравнивание бесед и трассировки

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

Подключение к определенной версии агента

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

Чтобы подключиться к определенной версии агента, задайте AGENT_VERSION переменную среды или передайте agentVersion параметр при инициализации помощника:

    // <agent_config>
    public BasicVoiceAssistant(string endpoint, string agentName, string projectName,
        string? agentVersion = null, string? conversationId = null,
        string? foundryResourceOverride = null, string? authIdentityClientId = null)
    {
        _endpoint = endpoint;

        // Build the agent session configuration
        var config = new AgentSessionConfig(agentName, projectName);
        if (!string.IsNullOrEmpty(agentVersion))
        {
            config.AgentVersion = agentVersion;
        }
        if (!string.IsNullOrEmpty(conversationId))
        {
            config.ConversationId = conversationId;
        }
        if (!string.IsNullOrEmpty(foundryResourceOverride))
        {
            config.FoundryResourceOverride = foundryResourceOverride;
            if (!string.IsNullOrEmpty(authIdentityClientId))
            {
                config.AuthenticationIdentityClientId = authIdentityClientId;
            }
        }
        _agentConfig = config;
    }
    // </agent_config>
// <main>
class Program
{
    static async Task Main(string[] args)
    {
        var endpoint = Environment.GetEnvironmentVariable("VOICELIVE_ENDPOINT");
        var agentName = Environment.GetEnvironmentVariable("AGENT_NAME");
        var projectName = Environment.GetEnvironmentVariable("PROJECT_NAME");
        var agentVersion = Environment.GetEnvironmentVariable("AGENT_VERSION");
        var conversationId = Environment.GetEnvironmentVariable("CONVERSATION_ID");
        var foundryResourceOverride = Environment.GetEnvironmentVariable("FOUNDRY_RESOURCE_OVERRIDE");
        var authIdentityClientId = Environment.GetEnvironmentVariable("AGENT_AUTHENTICATION_IDENTITY_CLIENT_ID");

        Console.WriteLine("Environment variables:");
        Console.WriteLine($"VOICELIVE_ENDPOINT: {endpoint}");
        Console.WriteLine($"AGENT_NAME: {agentName}");
        Console.WriteLine($"PROJECT_NAME: {projectName}");
        Console.WriteLine($"AGENT_VERSION: {agentVersion}");
        Console.WriteLine($"CONVERSATION_ID: {conversationId}");
        Console.WriteLine($"FOUNDRY_RESOURCE_OVERRIDE: {foundryResourceOverride}");

        if (string.IsNullOrEmpty(endpoint) || string.IsNullOrEmpty(agentName)
            || string.IsNullOrEmpty(projectName))
        {
            Console.Error.WriteLine("Set VOICELIVE_ENDPOINT, AGENT_NAME, and PROJECT_NAME environment variables.");
            return;
        }

        // Verify audio devices
        CheckAudioDevices();

        Console.WriteLine("🎙️ Basic Foundry Voice Agent with Azure VoiceLive SDK (Agent Mode)");
        Console.WriteLine(new string('=', 65));

        using var assistant = new BasicVoiceAssistant(
            endpoint, agentName, projectName,
            agentVersion, conversationId,
            foundryResourceOverride, authIdentityClientId);

        // Handle graceful shutdown
        using var cts = new CancellationTokenSource();
        Console.CancelKeyPress += (sender, e) =>
        {
            e.Cancel = true;
            cts.Cancel();
        };

        try
        {
            await assistant.StartAsync(cts.Token);
        }
        catch (OperationCanceledException)
        {
            Console.WriteLine("\n👋 Voice assistant shut down. Goodbye!");
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine($"Fatal Error: {ex.Message}");
        }

Конфигурация версии применяется в трех местах:

  • В Main() считайте AGENT_VERSION из переменной среды.
  • Передайте agentVersion конструктору BasicVoiceAssistant(...) .
  • В конструкторе задайте значение AgentSessionConfig через config.AgentVersion. Отправьте его в Voice Live через StartSessionAsync(SessionTarget.FromAgent(agentConfig)).

Значение agentVersion соответствует строке версии, возвращаемой при создании или обновлении агента с помощью пакета SDK агента Foundry. Если это не указано, Voice Live подключается к последней версии агента.

Подключение к какому-либо агенту в другом ресурсе Foundry

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

Это полезно в следующих сценариях:

  • Агент развертывается в регионе с разной доступностью функций.
  • Вы хотите отделять разработку и промежуточное развертывание от рабочей среды.
  • В организации используются различные ресурсы для разных рабочих нагрузок.

Чтобы подключиться к агенту в другом ресурсе, настройте две переменные среды:

  • FOUNDRY_RESOURCE_OVERRIDE: имя ресурса Foundry, в котором размещается проект агента (например, my-agent-resource).
  • AGENT_AUTHENTICATION_IDENTITY_CLIENT_ID: идентификатор клиента управляемой идентичности ресурса Voice Live, необходимый для проверки подлинности межресурсных взаимодействий.
    // <agent_config>
    public BasicVoiceAssistant(string endpoint, string agentName, string projectName,
        string? agentVersion = null, string? conversationId = null,
        string? foundryResourceOverride = null, string? authIdentityClientId = null)
    {
        _endpoint = endpoint;

        // Build the agent session configuration
        var config = new AgentSessionConfig(agentName, projectName);
        if (!string.IsNullOrEmpty(agentVersion))
        {
            config.AgentVersion = agentVersion;
        }
        if (!string.IsNullOrEmpty(conversationId))
        {
            config.ConversationId = conversationId;
        }
        if (!string.IsNullOrEmpty(foundryResourceOverride))
        {
            config.FoundryResourceOverride = foundryResourceOverride;
            if (!string.IsNullOrEmpty(authIdentityClientId))
            {
                config.AuthenticationIdentityClientId = authIdentityClientId;
            }
        }
        _agentConfig = config;
    }
    // </agent_config>
// <main>
class Program
{
    static async Task Main(string[] args)
    {
        var endpoint = Environment.GetEnvironmentVariable("VOICELIVE_ENDPOINT");
        var agentName = Environment.GetEnvironmentVariable("AGENT_NAME");
        var projectName = Environment.GetEnvironmentVariable("PROJECT_NAME");
        var agentVersion = Environment.GetEnvironmentVariable("AGENT_VERSION");
        var conversationId = Environment.GetEnvironmentVariable("CONVERSATION_ID");
        var foundryResourceOverride = Environment.GetEnvironmentVariable("FOUNDRY_RESOURCE_OVERRIDE");
        var authIdentityClientId = Environment.GetEnvironmentVariable("AGENT_AUTHENTICATION_IDENTITY_CLIENT_ID");

        Console.WriteLine("Environment variables:");
        Console.WriteLine($"VOICELIVE_ENDPOINT: {endpoint}");
        Console.WriteLine($"AGENT_NAME: {agentName}");
        Console.WriteLine($"PROJECT_NAME: {projectName}");
        Console.WriteLine($"AGENT_VERSION: {agentVersion}");
        Console.WriteLine($"CONVERSATION_ID: {conversationId}");
        Console.WriteLine($"FOUNDRY_RESOURCE_OVERRIDE: {foundryResourceOverride}");

        if (string.IsNullOrEmpty(endpoint) || string.IsNullOrEmpty(agentName)
            || string.IsNullOrEmpty(projectName))
        {
            Console.Error.WriteLine("Set VOICELIVE_ENDPOINT, AGENT_NAME, and PROJECT_NAME environment variables.");
            return;
        }

        // Verify audio devices
        CheckAudioDevices();

        Console.WriteLine("🎙️ Basic Foundry Voice Agent with Azure VoiceLive SDK (Agent Mode)");
        Console.WriteLine(new string('=', 65));

        using var assistant = new BasicVoiceAssistant(
            endpoint, agentName, projectName,
            agentVersion, conversationId,
            foundryResourceOverride, authIdentityClientId);

        // Handle graceful shutdown
        using var cts = new CancellationTokenSource();
        Console.CancelKeyPress += (sender, e) =>
        {
            e.Cancel = true;
            cts.Cancel();
        };

        try
        {
            await assistant.StartAsync(cts.Token);
        }
        catch (OperationCanceledException)
        {
            Console.WriteLine("\n👋 Voice assistant shut down. Goodbye!");
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine($"Fatal Error: {ex.Message}");
        }

Конфигурация определяется в Main() и применяется при создании помощника.

  • Прочитайте FOUNDRY_RESOURCE_OVERRIDE и AGENT_AUTHENTICATION_IDENTITY_CLIENT_ID из переменных среды.
  • Передайте оба значения конструктору BasicVoiceAssistant(...) .
  • В конструкторе задайте оба значения на AgentSessionConfig с помощью config.FoundryResourceOverride и config.AuthenticationIdentityClientId. Отправьте их в StartSessionAsync(SessionTarget.FromAgent(agentConfig)).

Важно

Для подключений между ресурсами требуются правильные назначения ролей. Убедитесь, что управляемое удостоверение ресурса Voice Live имеет роль Azure AI User в целевом ресурсе агента.

Добавление упреждающего сообщения при запуске сеанса

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

// <proactive_greeting>
private async Task SendProactiveGreetingAsync(CancellationToken cancellationToken)
{
    Console.WriteLine("Sending proactive greeting request");
    try
    {
        // Create a system message to trigger greeting
        await _session!.SendCommandAsync(
            BinaryData.FromObjectAsJson(new
            {
                type = "conversation.item.create",
                item = new
                {
                    type = "message",
                    role = "system",
                    content = new[]
                    {
                        new { type = "input_text", text = "Say something to welcome the user in English." }
                    }
                }
            }), cancellationToken).ConfigureAwait(false);

        // Request a response
        await _session!.SendCommandAsync(
            BinaryData.FromObjectAsJson(new { type = "response.create" }),
            cancellationToken).ConfigureAwait(false);
    }
    catch (Exception ex)
    {
        Console.Error.WriteLine($"Failed to send proactive greeting: {ex.Message}");
    }
}
// </proactive_greeting>

Упреждающий обмен сообщениями осуществляется в три этапа:

  • _greetingSent представляет собой bool, инициализированный до false для отслеживания состояния однократного приветствия.
  • SessionUpdateSessionUpdated В ветви выполнение if (!_greetingSent) контролируется, чтобы запускаться однократно для каждого сеанса.
  • SendCommandAsync(...) с полезной нагрузкой conversation.item.create добавляет приветствие в контекст беседы. Команда response.create создает голосовой вывод.

Улучшение времени ожидания вызова инструмента и задержки

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

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

  • Промежуточный ответ, сгенерированный с помощью LLM (LlmInterimResponseConfig): использует облегченный LLM для динамического создания текста, учитывающего контекст. Лучше всего подходит для адаптивных, естественных звуковых ответов.
  • Статический промежуточный ответ (StaticInterimResponseConfig): случайным образом выбирается из предопределенного списка предоставленных текстов. Лучше всего подходит для детерминированного или фирменного обмена сообщениями.

Дополнительные сведения см. в разделе "Улучшение вызова инструмента и времени ожидания задержки с промежуточными ответами".

В голосовом помощнике для быстрого запуска показаны необходимые дополнения кода:

// <setup_session>
private async Task SetupSessionAsync(CancellationToken cancellationToken)
{
    Console.WriteLine("Setting up voice conversation session...");

    // Create session configuration with interim response to bridge latency gaps
    var interimConfig = new LlmInterimResponseConfig
    {
        Instructions = "Create friendly interim responses indicating wait time due to "
            + "ongoing processing, if any. Do not include in all responses! Do not "
            + "say you don't have real-time access to information when calling tools!",
    };
    interimConfig.Triggers.Add(InterimResponseTrigger.Tool);
    interimConfig.Triggers.Add(InterimResponseTrigger.Latency);
    interimConfig.LatencyThresholdMs = 100;

    var options = new VoiceLiveSessionOptions
    {
        InputAudioFormat = InputAudioFormat.Pcm16,
        OutputAudioFormat = OutputAudioFormat.Pcm16,
        InterimResponse = BinaryData.FromObjectAsJson(interimConfig)
    };

    // Send session configuration
    await _session!.ConfigureSessionAsync(options, cancellationToken).ConfigureAwait(false);

    Console.WriteLine("Session configuration sent");
}
// </setup_session>

Временная настройка ответа применяется внутри SetupSessionAsync():

  • LlmInterimResponseConfig создается с пользовательскими инструкциями и триггерами для событий Tool и Latency.
  • Конфигурация сериализуется с помощью BinaryData.FromObjectAsJson() и назначается VoiceLiveSessionOptions.InterimResponse.
  • ConfigureSessionAsync(options) отправляет полную конфигурацию сеанса, включая промежуточный ответ, в Voice Live.

Используйте автоматическое сокращение для ответов, которые были прерваны

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

В настоящее время в примере показана обработка прерываний при CancelResponseAsync() запуске речи, но auto_truncate не настраивается в turn_detection.

Примечание

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

Сведения о настройке и поддерживаемых параметрах см. в разделе "Обработка прерываний голосовой связи" в журнале чата (предварительная версия ).

Повторное подключение к прежнему разговору с агентом

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

Когда сеанс успешно подключается, Voice Live возвращает метаданные сеанса в событии SessionUpdateSessionUpdated . Извлеките идентификатор сеанса и зайдите в файл беседы:

// <handle_events>
private async Task HandleEventAsync(SessionUpdate serverEvent, CancellationToken cancellationToken)
{
    switch (serverEvent)
    {
        case SessionUpdateSessionUpdated sessionUpdated:
            Console.WriteLine("Session updated and ready");

            var sessionId = sessionUpdated.Session?.Id;
            WriteLog($"SessionID: {sessionId}\n");

            // Send a proactive greeting
            if (!_greetingSent)
            {
                _greetingSent = true;
                await SendProactiveGreetingAsync(cancellationToken).ConfigureAwait(false);
            }

            // Start audio capture once session is ready
            _audioProcessor?.StartCapture();
            break;

В этом обработчике событий идентификатор сеанса извлекается из sessionUpdated.Session?.Id и записывается в журнал беседы.

Пример записывает сведения о сеансе в файл журнала бесед в папке logs/ (например, logs/conversation_20260219_143000.log).

Чтобы повторно подключиться, передайте идентификатор беседы в качестве переменной CONVERSATION_ID среды или conversationId параметра:

var conversationId = Environment.GetEnvironmentVariable("CONVERSATION_ID");
using var assistant = new BasicVoiceAssistant(
    endpoint, agentName, projectName,
    agentVersion, conversationId,
    foundryResourceOverride, authIdentityClientId);

Повторное подключение сеанса связи применяется в трех местах.

  • В Main() считывается CONVERSATION_ID из среды (строка 458).
  • Передайте значение конструктору BasicVoiceAssistant(...) (строки 483-486).
  • В конструкторе задайте значение AgentSessionConfig через config.ConversationId.

Если задано допустимое conversationId , агент извлекает предыдущий контекст беседы и может ссылаться на предыдущие обмены.

Примечание

Идентификаторы бесед привязаны к агенту и проекту. При использовании идентификатора разговора с другим агентом создается новый разговор.

Логгировать метаданные сеанса для обеспечения непрерывности и диагностики

В примере записываются ключевые метаданные сеанса, включая идентификатор сеанса, в файл logs/ журнала сеанса с отметкой времени. Это поможет вам:

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

Следующий код создает имя файла журнала и записывает метаданные сеанса при SessionUpdateSessionUpdated срабатывании:

private static readonly string LogFilename = $"conversation_{DateTime.Now:yyyyMMdd_HHmmss}.log";

// <handle_events>
private async Task HandleEventAsync(SessionUpdate serverEvent, CancellationToken cancellationToken)
{
    switch (serverEvent)
    {
        case SessionUpdateSessionUpdated sessionUpdated:
            Console.WriteLine("Session updated and ready");

            var sessionId = sessionUpdated.Session?.Id;
            WriteLog($"SessionID: {sessionId}\n");

            // Send a proactive greeting
            if (!_greetingSent)
            {
                _greetingSent = true;
                await SendProactiveGreetingAsync(cancellationToken).ConfigureAwait(false);
            }

            // Start audio capture once session is ready
            _audioProcessor?.StartCapture();
            break;
private static void WriteLog(string message)
{
    try
    {
        var logDir = Path.Combine(Directory.GetCurrentDirectory(), "logs");
        Directory.CreateDirectory(logDir);
        File.AppendAllText(Path.Combine(logDir, LogFilename), message + Environment.NewLine);
    }
    catch (IOException ex)
    {
        Console.Error.WriteLine($"Failed to write conversation log: {ex.Message}");
    }
}

Ведение журнала метаданных сеанса применяется в трех местах:

  • Для каждого прогона создается файл журнала беседы с меткой времени (conversation_YYYYMMDD_HHmmss.log строки 188–189).
  • Обработчик SessionUpdateSessionUpdatedизвлекает идентификатор сеанса и записывает его в журнал (строки 309–310).
  • WriteLog(...) добавляет записи в течение жизненного цикла беседы (строки 427–439).

Используйте метаданные сеанса, записанные в журнале, с CONVERSATION_ID, чтобы возобновить беседу с тем же агентом позже. Используйте идентификатор сеанса вместе с идентификатором разговора для диагностики и сценариев повторного подключения.

Узнайте, как использовать Voice Live с службой агента Microsoft Foundry с помощью набора SDK VoiceLive для JavaScript. В этой статье мы расширяем краткое руководство по созданию агента голосовой связи с помощью службы агента Foundry и Voice Live, добавляя расширенные функции и параметры интеграции.

Справочная документация | Пакет (npm) | Дополнительные примеры на GitHub

Создание и запуск приложений для использования Voice Live с агентами для бесед в режиме реального времени.

Агенты предоставляют несколько преимуществ:

  • Используйте централизованную конфигурацию в самом агенте вместо кода сеанса.
  • Обрабатывайте сложную логику и диалоговое поведение для облегчения обновлений.
  • Автоматически подключитесь с помощью идентификатора агента.
  • Поддержка нескольких вариантов без изменения клиентского кода.

Сведения об использовании Voice Live без агентов Foundry см. в кратком руководстве по API Voice Live.

Совет

Вам не нужно развертывать звуковую модель с Microsoft Foundry для использования Voice Live. Voice Live полностью управляется и автоматически развертывает модель для вас. Сведения о доступности модели см. в документации по Voice Live.

Примечание

Пакет SDK для Голосовой трансляции JavaScript предназначен для приложений на основе браузера с встроенной поддержкой WebSocket и веб-аудио. В этом руководстве Node.js используется с node-record-lpcm16 и speaker для работы в консольной среде. Полный пользовательский интерфейс голосовой связи на основе браузера см. в примере универсального помощника voice Live.

Необходимые условия

Примечание

Этот документ ссылается на портал Microsoft Foundry (new) и последнюю версию службы агента Foundry.

  • Назначьте роль Azure AI User учетной записи пользователя. Роли можно назначить на портале Azure в разделе Access control (IAM)>Add role assignment.

Подготовка среды и создание агента

Выполните Быстрый запуск: создание голосового агента с помощью службы Foundry Agent и Voice Live, чтобы настроить вашу среду, конфигурировать агента с настройками Voice Live и протестировать ваш первый разговор.

Концепции интеграции агента

Используйте эти понятия, чтобы понять, как служба агента Voice Live и Foundry работают вместе в примере JavaScript.

Контракт конфигурации агента

Задайте свойство с помощью объекта AgentSessionConfig в вызове agent, чтобы определить целевой агент и проект createSession(...). Как минимум, включите agentName и projectName. Добавьте agentVersion, когда хотите закрепить поведение в определенной версии.

Модель проверки подлинности для режима агента

Используйте Microsoft Entra ID учетные данные для режима агента. Вызов агента в этом потоке не поддерживает аутентификацию с использованием ключей, поэтому настройте DefaultAzureCredential (или другие учетные данные токена Entra) для локальной разработки и развертывания.

Закрепление версий API

Используйте согласованную версию пакета SDK (@azure/ai-voicelive@1.0.0-beta.3) в вашей package.json среде, чтобы обеспечить прогнозируемость поведения в предварительных версиях обновлений. Используйте одну и ту же версию последовательно в примерах быстрого старта и инструкциях, чтобы избежать дрейфа схемы.

Выравнивание бесед и трассировки

Рассматривайте поток агента и записи трассировки как историю текстовых сообщений, а не точную историю воспроизведения. Если ваше приложение допускает прерывание или усечение, включите обработку с учётом усечения, чтобы сохранённая история более точно соответствовала тому, что пользователь на самом деле слышал.

Подключение к определенной версии агента

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

AGENT_VERSION Задайте переменную среды или передайте agentVersion свойство при инициализации помощника:

  constructor(opts) {
    this.endpoint = opts.endpoint;
    this.credential = opts.credential;
    this.greetingText = opts.greetingText;
    this.noAudio = opts.noAudio;
    this.agentConfig = {
      agentName: opts.agentName,
      projectName: opts.projectName,
      ...(opts.agentVersion && { agentVersion: opts.agentVersion }),
      ...(opts.conversationId && { conversationId: opts.conversationId }),
      ...(opts.foundryResourceOverride && {
        foundryResourceOverride: opts.foundryResourceOverride,
      }),
      ...(opts.foundryResourceOverride &&
        opts.authenticationIdentityClientId && {
          authenticationIdentityClientId: opts.authenticationIdentityClientId,
        }),
    };

    this._session = null;
    this._audio = new AudioProcessor(!opts.noAudio, opts.audioInputDevice);
    this._greetingSent = false;
    this._activeResponse = false;
    this._responseApiDone = false;
  }
function parseArguments(argv) {
  const parsed = {
    endpoint: process.env.VOICELIVE_ENDPOINT ?? "",
    agentName: process.env.AGENT_NAME ?? "",
    projectName: process.env.PROJECT_NAME ?? "",
    agentVersion: process.env.AGENT_VERSION,
    conversationId: process.env.CONVERSATION_ID,
    foundryResourceOverride: process.env.FOUNDRY_RESOURCE_OVERRIDE,
    authenticationIdentityClientId:
      process.env.AGENT_AUTHENTICATION_IDENTITY_CLIENT_ID,
    audioInputDevice: process.env.AUDIO_INPUT_DEVICE,
    listAudioDevices: false,
    greetingText: undefined,
    noAudio: false,
    help: false,
  };
  const assistant = new BasicVoiceAssistant({
    endpoint: args.endpoint,
    credential,
    agentName: args.agentName,
    projectName: args.projectName,
    agentVersion: args.agentVersion,
    conversationId: args.conversationId,
    foundryResourceOverride: args.foundryResourceOverride,
    authenticationIdentityClientId: args.authenticationIdentityClientId,
    audioInputDevice: args.audioInputDevice,
    greetingText: args.greetingText,
    noAudio: args.noAudio,
  });

В этом примере конфигурация версии применяется в трех местах:

  • В main(), AGENT_VERSION считывается из process.env.
  • В конструкторе BasicVoiceAssistantagentVersion распространяется в agentConfig объект.
  • Конфигурация передается client.createSession({ agent: this.agentConfig }), который отправляет её на Voice Live.

Значение agentVersion соответствует строке версии, возвращаемой при создании или обновлении агента с помощью пакета SDK агента Foundry. Если это не указано, Voice Live подключается к последней версии агента.

Подключение к какому-либо агенту в другом ресурсе Foundry

Настройте Voice Live для подключения к агенту в другом ресурсе Foundry для обработки звука. Это полезно, когда:

  • Агент развертывается в регионе с различной доступностью функций.
  • Вы хотите разделить среды разработки и промежуточного хранения из рабочей среды
  • В организации используются различные ресурсы для разных рабочих нагрузок

Чтобы подключиться к агенту в другом ресурсе, настройте две дополнительные переменные среды:

  • FOUNDRY_RESOURCE_OVERRIDE: имя ресурса Foundry, в котором размещается проект агента (например, my-agent-resource).
  • AGENT_AUTHENTICATION_IDENTITY_CLIENT_ID: идентификатор клиента управляемой идентичности ресурса Voice Live, необходимый для проверки подлинности межресурсных взаимодействий.
  constructor(opts) {
    this.endpoint = opts.endpoint;
    this.credential = opts.credential;
    this.greetingText = opts.greetingText;
    this.noAudio = opts.noAudio;
    this.agentConfig = {
      agentName: opts.agentName,
      projectName: opts.projectName,
      ...(opts.agentVersion && { agentVersion: opts.agentVersion }),
      ...(opts.conversationId && { conversationId: opts.conversationId }),
      ...(opts.foundryResourceOverride && {
        foundryResourceOverride: opts.foundryResourceOverride,
      }),
      ...(opts.foundryResourceOverride &&
        opts.authenticationIdentityClientId && {
          authenticationIdentityClientId: opts.authenticationIdentityClientId,
        }),
    };

    this._session = null;
    this._audio = new AudioProcessor(!opts.noAudio, opts.audioInputDevice);
    this._greetingSent = false;
    this._activeResponse = false;
    this._responseApiDone = false;
  }
function parseArguments(argv) {
  const parsed = {
    endpoint: process.env.VOICELIVE_ENDPOINT ?? "",
    agentName: process.env.AGENT_NAME ?? "",
    projectName: process.env.PROJECT_NAME ?? "",
    agentVersion: process.env.AGENT_VERSION,
    conversationId: process.env.CONVERSATION_ID,
    foundryResourceOverride: process.env.FOUNDRY_RESOURCE_OVERRIDE,
    authenticationIdentityClientId:
      process.env.AGENT_AUTHENTICATION_IDENTITY_CLIENT_ID,
    audioInputDevice: process.env.AUDIO_INPUT_DEVICE,
    listAudioDevices: false,
    greetingText: undefined,
    noAudio: false,
    help: false,
  };
  const assistant = new BasicVoiceAssistant({
    endpoint: args.endpoint,
    credential,
    agentName: args.agentName,
    projectName: args.projectName,
    agentVersion: args.agentVersion,
    conversationId: args.conversationId,
    foundryResourceOverride: args.foundryResourceOverride,
    authenticationIdentityClientId: args.authenticationIdentityClientId,
    audioInputDevice: args.audioInputDevice,
    greetingText: args.greetingText,
    noAudio: args.noAudio,
  });

Эта конфигурация разрешается в main(), а затем применяется при создании помощника.

  • FOUNDRY_RESOURCE_OVERRIDE и AGENT_AUTHENTICATION_IDENTITY_CLIENT_ID считываются из process.env.
  • Оба значения распределяются по параметрам конструктора.
  • В конструкторе значения задаются условно для agentConfig объекта, который отправляется в client.createSession({ agent: this.agentConfig }).

Важно

Для подключений между ресурсами требуются правильные назначения ролей. Убедитесь, что управляемое удостоверение ресурса Voice Live имеет роль Azure AI User в целевом ресурсе агента.

Добавление упреждающего сообщения при запуске сеанса

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

async _sendProactiveGreeting() {
  const session = this._session;

  if (this.greetingText) {
    // Pre-generated assistant message (deterministic)
    console.log("[session] Sending pre-generated greeting ...");
    try {
      await session.sendEvent({
        type: "response.create",
        response: {
          preGeneratedAssistantMessage: {
            content: [{ type: "text", text: this.greetingText }],
          },
        },
      });
    } catch (err) {
      console.error("[session] Failed to send pre-generated greeting:", err.message);
    }
  } else {
    // LLM-generated greeting (default)
    console.log("[session] Sending proactive greeting ...");
    try {
      await session.addConversationItem({
        type: "message",
        role: "system",
        content: [
          {
            type: "input_text",
            text: "Say something to welcome the user in English.",
          },
        ],
      });
      await session.sendEvent({ type: "response.create" });
    } catch (err) {
      console.error("[session] Failed to send greeting:", err.message);
    }
  }
}

В этом примере проактивное информирование применяется в три этапа:

  • _greetingSent представляет собой boolean, инициализированный до false для отслеживания состояния однократного приветствия.
  • В обработчике onSessionUpdatedif (!this._greetingSent) инициирует упреждающее выполнение, которое выполняется один раз за сеанс.
  • session.addConversationItem(...) добавляет инструкцию приветствия в контекст беседы и session.sendEvent({ type: "response.create" }) создает произнесенные выходные данные.

Улучшение времени ожидания вызова инструмента и задержки

Voice Live предоставляет функцию interimResponse для сокращения времени ожидания, когда требуется вызов инструментов или возникает высокая задержка для получения ответа от агента.

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

  • Промежуточный ответ, сгенерированный с помощью LLM (llm_interim_response): использует облегченный LLM для динамического создания текста, учитывающего контекст. Лучше всего подходит для адаптивных, естественных звуковых ответов.
  • Статический промежуточный ответ (static_interim_response): случайным образом выбирается из предопределенного списка предоставленных текстов. Лучше всего подходит для детерминированного или фирменного обмена сообщениями.

Дополнительные сведения см. в разделе "Улучшение вызова инструмента и времени ожидания задержки с промежуточными ответами".

Голосовой помощник, созданный с помощью быстрого старта, показывает необходимые дополнения кода для настройки этой функции следующим образом:

async _setupSession() {
  console.log("[session] Configuring session ...");
  await this._session.updateSession({
    modalities: ["text", "audio"],
    inputAudioFormat: "pcm16",
    outputAudioFormat: "pcm16",
    interimResponse: {
      type: "llm_interim_response",
      triggers: ["tool", "latency"],
      latencyThresholdInMs: 100,
      instructions:
        "Create friendly interim responses indicating wait time due to ongoing processing, if any. " +
        "Do not include in all responses! Do not say you don't have real-time access to information when calling tools!",
    },
  });
  console.log("[session] Session configuration sent");
}

В этом примере настройка промежуточного ответа применяется внутри _setupSession():

  • interimResponse определяет, когда активируются промежуточные ответы и какой стиль они используют.
  • session.updateSession(...) отправляет конфигурацию сеанса в Voice Live, включая промежуточные параметры ответа.

Используйте автоматическое сокращение для ответов, которые были прерваны

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

В этом примере в настоящее время показана обработка прерываний с response.cancel при запуске речи, но auto_truncate не настраивается в turn_detection.

Примечание

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

Сведения о настройке и поддерживаемых параметрах см. в разделе "Обработка прерываний голосовой связи в журнале чата (предварительная версия)".

Повторное подключение к прежнему разговору с агентом

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

Когда сеанс подключается успешно, Voice Live возвращает метаданные сеанса в обработчике onSessionUpdated. Пример извлекает идентификатор сеанса из контекста и записывает его в файл беседы:

onSessionUpdated: async (event, context) => {
  const s = event.session;
  const agent = s?.agent;
  const voice = s?.voice;
  console.log(`[session] Session ready: ${context.sessionId}`);
  writeConversationLog(
    [
      `SessionID: ${context.sessionId}`,
      `Agent Name: ${agent?.name ?? ""}`,
      `Agent Description: ${agent?.description ?? ""}`,
      `Agent ID: ${agent?.agentId ?? ""}`,
      `Voice Name: ${voice?.name ?? ""}`,
      `Voice Type: ${voice?.type ?? ""}`,
      "",
    ].join("\n"),
  );
},

В этом обработчике событий идентификатор сеанса извлекается из context.sessionId и записывается в журнал беседы вместе с метаданными агента.

Пример кода записывает сведения о сеансе в файл журнала бесед в папке logs/ (например, logs/conversation_20260219_143000.log).

Чтобы повторно подключиться к этой беседе, передайте идентификатор беседы в качестве переменной CONVERSATION_ID среды (или свойством conversationId ):

conversationId: process.env.CONVERSATION_ID,
conversationId: args.conversationId,

В этом примере повторное подключение беседы применяется в трех местах:

  • В main(), CONVERSATION_ID считывается из process.env (строка 558).
  • Значение передается конструктору BasicVoiceAssistant .
  • В конструкторе conversationId условно распространяется на agentConfig объект.

Если задано допустимое conversationId , агент извлекает предыдущий контекст беседы и может ссылаться на предыдущие обмены в ответах.

Примечание

Идентификаторы бесед привязаны к агенту и проекту. Попытка использовать идентификатор беседы с другим агентом приводит к созданию новой беседы.

Логгировать метаданные сеанса для обеспечения непрерывности и диагностики

В примере записываются ключевые метаданные сеанса, включая идентификатор сеанса, в файл logs/ журнала сеанса с отметкой времени. Это поможет вам:

  • Определите сеанс для сценариев отладки и поддержки.
  • Сопоставляйте поведение, сообщаемое пользователем, с метаданными сеанса.
  • Отслеживайте выполнение с течением времени, сохраняя файлы журнала для каждого сеанса.

Данный код создает имя лог-файла и записывает метаданные сеанса при получении onSessionUpdated.

const logsDir = join(__dirname, "logs");
if (!existsSync(logsDir)) mkdirSync(logsDir, { recursive: true });

const timestamp = new Date()
  .toISOString()
  .replace(/[:.]/g, "-")
  .replace("T", "_")
  .slice(0, 19);
const conversationLogFile = join(logsDir, `conversation_${timestamp}.log`);

function writeConversationLog(message) {
  appendFileSync(conversationLogFile, message + "\n", "utf-8");
}

      onSessionUpdated: async (event, context) => {
        const s = event.session;
        const agent = s?.agent;
        const voice = s?.voice;
        console.log(`[session] Session ready: ${context.sessionId}`);
        writeConversationLog(
          [
            `SessionID: ${context.sessionId}`,
            `Agent Name: ${agent?.name ?? ""}`,
            `Agent Description: ${agent?.description ?? ""}`,
            `Agent ID: ${agent?.agentId ?? ""}`,
            `Voice Name: ${voice?.name ?? ""}`,
            `Voice Type: ${voice?.type ?? ""}`,
            "",
          ].join("\n"),
        );
      },

В этом примере ведение журнала метаданных сеанса применяется в трех местах:

  • logs/ Каталог создается, если он не существует, и файл журнала бесед с меткой времени (conversation_YYYYMMDD_HHmmss.log) создается для каждого запуска (строки 21–29).
  • Обработчик извлекает идентификатор сеанса из context.sessionId и записывает его вместе с метаданными агента в журнал (строки 306–321).
  • writeConversationLog(...) добавляет записи в один и тот же файл журнала на протяжении всего жизненного цикла беседы (строки 31–33).

Используйте метаданные зарегистрированного сеанса с CONVERSATION_ID, чтобы возобновить беседу с тем же агентом в последующем сеансе.

Используйте значение идентификатора сеанса вместе с идентификатором разговора для диагностики и повторного подключения.

Узнайте, как использовать Voice Live с Службой агента Microsoft Foundry с помощью VoiceLive SDK для Java. В этой статье мы расширяем краткое руководство по созданию агента голосовой связи с помощью службы агента Foundry и Voice Live, добавляя расширенные функции и параметры интеграции.

Справочная документация | Пакет (Maven) | Дополнительные примеры на GitHub

Создание и запуск приложений для использования Voice Live с агентами для бесед в режиме реального времени.

Агенты предоставляют несколько преимуществ:

  • Используйте централизованную конфигурацию в самом агенте вместо кода сеанса.
  • Обрабатывайте сложную логику и диалоговое поведение для облегчения обновлений.
  • Автоматически подключитесь с помощью идентификатора агента.
  • Поддержка нескольких вариантов без изменения клиентского кода.

Сведения об использовании Voice Live без агентов Foundry см. в кратком руководстве по API Voice Live.

Совет

Вам не нужно развертывать звуковую модель с Microsoft Foundry для использования Voice Live. Voice Live полностью управляется и автоматически развертывает модель для вас. Сведения о доступности модели см. в документации по Voice Live.

Необходимые условия

Примечание

Этот документ ссылается на портал Microsoft Foundry (new) и последнюю версию службы агента Foundry.

  • Назначьте роль Azure AI User учетной записи пользователя. Роли можно назначить на портале Azure в разделе Access control (IAM)>Add role assignment.

Подготовка среды и создание агента

Выполните Быстрый запуск: создание голосового агента с помощью службы Foundry Agent и Voice Live, чтобы настроить вашу среду, конфигурировать агента с настройками Voice Live и протестировать ваш первый разговор.

Концепции интеграции агента

Используйте эти понятия, чтобы понять, как служба агента Voice Live и Foundry работают вместе в примере Java.

Контракт конфигурации агента

Укажите AgentSessionConfig в настройках сеанса для идентификации целевого агента и проекта. Как минимум, включите agentName и projectName. Добавьте agentVersion, когда хотите закрепить поведение в определенной версии.

Модель проверки подлинности для режима агента

Используйте Microsoft Entra ID учетные данные для режима агента. Вызов агента в этом потоке не поддерживает аутентификацию с использованием ключей, поэтому настройте AzureCliCredential (или другие учетные данные токена Entra) для локальной разработки и развертывания.

Закрепление версий API

Используйте согласованную версию пакета SDK (azure-ai-voicelive:1.0.0-beta.5) в POM Maven, чтобы обеспечить прогнозируемость поведения в предварительных версиях обновлений. Используйте одну и ту же версию последовательно в примерах быстрого старта и инструкциях, чтобы избежать дрейфа схемы.

Выравнивание бесед и трассировки

Рассматривайте поток агента и записи трассировки как историю текстовых сообщений, а не точную историю воспроизведения. Если ваше приложение допускает прерывание или усечение, включите обработку с учётом усечения, чтобы сохранённая история более точно соответствовала тому, что пользователь на самом деле слышал.

Подключение к определенной версии агента

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

AGENT_VERSION Задайте переменную среды или передайте agentVersion параметр при инициализации помощника:

    // <agent_config>
    BasicVoiceAssistant(String endpoint, String agentName, String projectName,
                        String agentVersion, String conversationId,
                        String foundryResourceOverride, String authIdentityClientId) {
        this.endpoint = endpoint;

        // Build the agent session configuration
        AgentSessionConfig config = new AgentSessionConfig(agentName, projectName);
        if (agentVersion != null && !agentVersion.isEmpty()) {
            config.setAgentVersion(agentVersion);
        }
        if (conversationId != null && !conversationId.isEmpty()) {
            config.setConversationId(conversationId);
        }
        if (foundryResourceOverride != null && !foundryResourceOverride.isEmpty()) {
            config.setFoundryResourceOverride(foundryResourceOverride);
            if (authIdentityClientId != null && !authIdentityClientId.isEmpty()) {
                config.setAuthenticationIdentityClientId(authIdentityClientId);
            }
        }
        this.agentConfig = config;
    }
    // </agent_config>
// <main>
public static void main(String[] args) {
    String endpoint = System.getenv("VOICELIVE_ENDPOINT");
    String agentName = System.getenv("AGENT_NAME");
    String projectName = System.getenv("PROJECT_NAME");
    String agentVersion = System.getenv("AGENT_VERSION");
    String conversationId = System.getenv("CONVERSATION_ID");
    String foundryResourceOverride = System.getenv("FOUNDRY_RESOURCE_OVERRIDE");
    String authIdentityClientId = System.getenv("AGENT_AUTHENTICATION_IDENTITY_CLIENT_ID");

    System.out.println("Environment variables:");
    System.out.println("VOICELIVE_ENDPOINT: " + endpoint);
    System.out.println("AGENT_NAME: " + agentName);
    System.out.println("PROJECT_NAME: " + projectName);
    System.out.println("AGENT_VERSION: " + agentVersion);
    System.out.println("CONVERSATION_ID: " + conversationId);
    System.out.println("FOUNDRY_RESOURCE_OVERRIDE: " + foundryResourceOverride);

    if (endpoint == null || endpoint.isEmpty()
            || agentName == null || agentName.isEmpty()
            || projectName == null || projectName.isEmpty()) {
        System.err.println("Set VOICELIVE_ENDPOINT, AGENT_NAME, and PROJECT_NAME environment variables.");
        System.exit(1);
    }

    // Verify audio devices
    checkAudioDevices();

    System.out.println("🎙️ Basic Foundry Voice Agent with Azure VoiceLive SDK (Agent Mode)");
    System.out.println("=".repeat(65));

    BasicVoiceAssistant assistant = new BasicVoiceAssistant(
            endpoint, agentName, projectName,
            agentVersion, conversationId,
            foundryResourceOverride, authIdentityClientId);

    // Handle graceful shutdown
    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
        System.out.println("\n👋 Voice assistant shut down. Goodbye!");
    }));

    try {
        assistant.start();
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        System.out.println("\n👋 Voice assistant shut down. Goodbye!");
    } catch (Exception e) {
        System.err.println("Fatal Error: " + e.getMessage());
        e.printStackTrace();
    }
}
// </main>

В этом примере конфигурация версии применяется в трех местах:

  • В main()AGENT_VERSION считывается из среды.
  • В конструктор BasicVoiceAssistant(...) передается agentVersion.
  • В конструкторе значение присваивается AgentSessionConfig с помощью config.setAgentVersion(agentVersion), а затем отправляется в Voice Live через client.startSession(agentConfig).

Значение agentVersion соответствует строке версии, возвращаемой при создании или обновлении агента с помощью пакета SDK агента Foundry. Если это не указано, Voice Live подключается к последней версии агента.

Подключение к какому-либо агенту в другом ресурсе Foundry

Настройте Voice Live для подключения к агенту в другом ресурсе Foundry для обработки звука. Это полезно, когда:

  • Агент развертывается в регионе с различной доступностью функций.
  • Вы хотите разделить среды разработки и промежуточного хранения из рабочей среды
  • В организации используются различные ресурсы для разных рабочих нагрузок

Чтобы подключиться к агенту в другом ресурсе, настройте две дополнительные переменные среды:

  • FOUNDRY_RESOURCE_OVERRIDE: имя ресурса Foundry, в котором размещается проект агента (например, my-agent-resource).
  • AGENT_AUTHENTICATION_IDENTITY_CLIENT_ID: идентификатор клиента управляемой идентичности ресурса Voice Live, необходимый для проверки подлинности межресурсных взаимодействий.
    // <agent_config>
    BasicVoiceAssistant(String endpoint, String agentName, String projectName,
                        String agentVersion, String conversationId,
                        String foundryResourceOverride, String authIdentityClientId) {
        this.endpoint = endpoint;

        // Build the agent session configuration
        AgentSessionConfig config = new AgentSessionConfig(agentName, projectName);
        if (agentVersion != null && !agentVersion.isEmpty()) {
            config.setAgentVersion(agentVersion);
        }
        if (conversationId != null && !conversationId.isEmpty()) {
            config.setConversationId(conversationId);
        }
        if (foundryResourceOverride != null && !foundryResourceOverride.isEmpty()) {
            config.setFoundryResourceOverride(foundryResourceOverride);
            if (authIdentityClientId != null && !authIdentityClientId.isEmpty()) {
                config.setAuthenticationIdentityClientId(authIdentityClientId);
            }
        }
        this.agentConfig = config;
    }
    // </agent_config>
// <main>
public static void main(String[] args) {
    String endpoint = System.getenv("VOICELIVE_ENDPOINT");
    String agentName = System.getenv("AGENT_NAME");
    String projectName = System.getenv("PROJECT_NAME");
    String agentVersion = System.getenv("AGENT_VERSION");
    String conversationId = System.getenv("CONVERSATION_ID");
    String foundryResourceOverride = System.getenv("FOUNDRY_RESOURCE_OVERRIDE");
    String authIdentityClientId = System.getenv("AGENT_AUTHENTICATION_IDENTITY_CLIENT_ID");

    System.out.println("Environment variables:");
    System.out.println("VOICELIVE_ENDPOINT: " + endpoint);
    System.out.println("AGENT_NAME: " + agentName);
    System.out.println("PROJECT_NAME: " + projectName);
    System.out.println("AGENT_VERSION: " + agentVersion);
    System.out.println("CONVERSATION_ID: " + conversationId);
    System.out.println("FOUNDRY_RESOURCE_OVERRIDE: " + foundryResourceOverride);

    if (endpoint == null || endpoint.isEmpty()
            || agentName == null || agentName.isEmpty()
            || projectName == null || projectName.isEmpty()) {
        System.err.println("Set VOICELIVE_ENDPOINT, AGENT_NAME, and PROJECT_NAME environment variables.");
        System.exit(1);
    }

    // Verify audio devices
    checkAudioDevices();

    System.out.println("🎙️ Basic Foundry Voice Agent with Azure VoiceLive SDK (Agent Mode)");
    System.out.println("=".repeat(65));

    BasicVoiceAssistant assistant = new BasicVoiceAssistant(
            endpoint, agentName, projectName,
            agentVersion, conversationId,
            foundryResourceOverride, authIdentityClientId);

    // Handle graceful shutdown
    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
        System.out.println("\n👋 Voice assistant shut down. Goodbye!");
    }));

    try {
        assistant.start();
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        System.out.println("\n👋 Voice assistant shut down. Goodbye!");
    } catch (Exception e) {
        System.err.println("Fatal Error: " + e.getMessage());
        e.printStackTrace();
    }
}
// </main>

Эта конфигурация разрешается в main(), а затем применяется при создании помощника.

  • FOUNDRY_RESOURCE_OVERRIDE и AGENT_AUTHENTICATION_IDENTITY_CLIENT_ID считываются из переменных среды.
  • Оба значения передаются конструктору BasicVoiceAssistant(...) .
  • В конструкторе значения задаются на AgentSessionConfig через config.setFoundryResourceOverride(...) и config.setAuthenticationIdentityClientId(...), которые отправляются в client.startSession(agentConfig).

Важно

Для подключений между ресурсами требуются правильные назначения ролей. Убедитесь, что управляемое удостоверение ресурса Voice Live имеет роль Azure AI User в целевом ресурсе агента.

Добавление упреждающего сообщения при запуске сеанса

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

// <proactive_greeting>
private void sendProactiveGreeting() {
    logger.info("Sending proactive greeting request");
    try {
        // Create a system message to trigger greeting
        SystemMessageItem greetingMessage = new SystemMessageItem(
                Arrays.asList(new InputTextContentPart("Say something to welcome the user in English.")));
        ClientEventConversationItemCreate createEvent = new ClientEventConversationItemCreate()
                .setItem(greetingMessage);
        session.sendEvent(createEvent).block();

        // Request a response
        session.sendEvent(new ClientEventResponseCreate()).block();
    } catch (Exception e) {
        logger.log(Level.WARNING, "Failed to send proactive greeting", e);
    }
}
// </proactive_greeting>

В этом примере проактивное информирование применяется в три этапа:

  • greetingSent представляет собой boolean, инициализированный до false для отслеживания состояния однократного приветствия.
  • В ветви SESSION_UPDATED, if (!greetingSent) ворота ограничивают упреждающее выполнение, чтобы оно выполнялось один раз за сеанс.
  • sendEvent(new ClientEventConversationItemCreate()...) добавляет инструкцию приветствия в контекст беседы и sendEvent(new ClientEventResponseCreate()) создает произнесенные выходные данные.

Улучшение времени ожидания вызова инструмента и задержки

Используйте функцию Voice Live interimResponse для сокращения времени ожидания в процессе вызова инструмента или при создании ответов агента с высокой задержкой.

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

  • Промежуточный ответ, сгенерированный с помощью LLM (LlmInterimResponseConfig): использует облегченный LLM для динамического создания текста, учитывающего контекст. Лучше всего подходит для адаптивных, естественных звуковых ответов.
  • Статический промежуточный ответ (StaticInterimResponseConfig): случайным образом выбирается из предопределенного списка предоставленных текстов. Лучше всего подходит для детерминированного или фирменного обмена сообщениями.

Дополнительные сведения см. в разделе "Улучшение вызова инструмента и времени ожидания задержки с промежуточными ответами".

Голосовой помощник, созданный с помощью быстрого старта, показывает необходимые дополнения кода для настройки этой функции следующим образом:

// <setup_session>
private void setupSession() {
    logger.info("Setting up voice conversation session...");

    // Configure interim responses to bridge latency gaps during processing
    LlmInterimResponseConfig interimResponseConfig = new LlmInterimResponseConfig()
            .setTriggers(Arrays.asList(
                    InterimResponseTrigger.TOOL,
                    InterimResponseTrigger.LATENCY))
            .setLatencyThresholdMs(100)
            .setInstructions("Create friendly interim responses indicating wait time due to "
                    + "ongoing processing, if any. Do not include in all responses! Do not "
                    + "say you don't have real-time access to information when calling tools!");

    // Create session configuration
    VoiceLiveSessionOptions sessionOptions = new VoiceLiveSessionOptions()
            .setModalities(Arrays.asList(InteractionModality.TEXT, InteractionModality.AUDIO))
            .setInputAudioFormat(InputAudioFormat.PCM16)
            .setOutputAudioFormat(OutputAudioFormat.PCM16)
            .setInterimResponse(BinaryData.fromObject(interimResponseConfig));

    // Send session update
    session.sendEvent(new ClientEventSessionUpdate(sessionOptions)).block();
    logger.info("Session configuration sent");
}
// </setup_session>

В этом примере настройка промежуточного ответа применяется внутри BasicVoiceAssistant.setupSession():

  • LlmInterimResponseConfig определяет, когда активируются промежуточные ответы и какой стиль они используют.
  • VoiceLiveSessionOptions подключает эту конфигурацию через поле interimResponse (сериализованное через BinaryData.fromObject(...)).
  • session.sendEvent(new ClientEventSessionUpdate(sessionOptions)) отправляет конфигурацию сеанса в Voice Live.

Используйте автоматическое сокращение для ответов, которые были прерваны

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

В этом примере в настоящее время показана обработка прерываний с ClientEventResponseCancel при запуске речи, но auto_truncate не настраивается в turn_detection.

Примечание

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

Сведения о настройке и поддерживаемых параметрах см. в разделе "Обработка прерываний голосовой связи в журнале чата (предварительная версия)".

Повторное подключение к прежнему разговору с агентом

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

Когда сеанс успешно подключается, Voice Live возвращает метаданные сеанса в событии SESSION_UPDATED . Пример извлекает идентификатор сеанса и записывает его в файл беседы:

if (type == ServerEventType.SESSION_UPDATED) {
    logger.info("Session updated and ready");
    sessionReady = true;
    String sessionId = extractField(event, "id");
    writeLog(String.format("SessionID: %s\n", sessionId));

    // Send a proactive greeting
    if (!greetingSent) {
        greetingSent = true;
        sendProactiveGreeting();
    }

    // Start audio capture once session is ready
    try {
        audioProcessor.startCapture();
    } catch (LineUnavailableException e) {
        logger.log(Level.SEVERE, "Failed to start audio capture", e);
    }

В этом обработчике событий идентификатор сеанса извлекается из JSON события с помощью extractField(event, "id") и записывается в журнал беседы.

Пример кода записывает сведения о сеансе в файл журнала бесед в папке logs/ (например, logs/conversation_20260219_143000.log).

Чтобы повторно подключиться к этой беседе, передайте идентификатор беседы в качестве переменной CONVERSATION_ID среды (или параметром conversationId ):

String conversationId = System.getenv("CONVERSATION_ID");
BasicVoiceAssistant assistant = new BasicVoiceAssistant(
        endpoint, agentName, projectName,
        agentVersion, conversationId,
        foundryResourceOverride, authIdentityClientId);

В этом примере повторное подключение беседы применяется в трех местах:

  • В main(), CONVERSATION_ID считывается из окружения (строка 512).
  • Значение передается конструктору BasicVoiceAssistant(...) (строки 537-540).
  • В конструкторе значение устанавливается на AgentSessionConfig с помощью config.setConversationId(conversationId).

Если задано допустимое conversationId , агент извлекает предыдущий контекст беседы и может ссылаться на предыдущие обмены в ответах.

Примечание

Идентификаторы бесед привязаны к агенту и проекту. Попытка использовать идентификатор беседы с другим агентом приводит к созданию новой беседы.

Логгировать метаданные сеанса для обеспечения непрерывности и диагностики

Записывайте ключевые метаданные сеанса, включая идентификатор сеанса, в файл журнала беседы с меткой времени под logs/. Это поможет вам:

  • Определите сеанс для сценариев отладки и поддержки.
  • Сопоставляйте поведение, сообщаемое пользователем, с метаданными сеанса.
  • Отслеживайте выполнение с течением времени, сохраняя файлы журнала для каждого сеанса.

Данный код создает имя лог-файла и записывает метаданные сеанса при получении SESSION_UPDATED.

// Conversation log
private static final String LOG_FILENAME = "conversation_"
        + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")) + ".log";

        if (type == ServerEventType.SESSION_UPDATED) {
            logger.info("Session updated and ready");
            sessionReady = true;
            String sessionId = extractField(event, "id");
            writeLog(String.format("SessionID: %s\n", sessionId));

            // Send a proactive greeting
            if (!greetingSent) {
                greetingSent = true;
                sendProactiveGreeting();
            }

            // Start audio capture once session is ready
            try {
                audioProcessor.startCapture();
            } catch (LineUnavailableException e) {
                logger.log(Level.SEVERE, "Failed to start audio capture", e);
            }
    private void writeLog(String message) {
        try {
            Path logDir = Paths.get("logs");
            Files.createDirectories(logDir);
            try (PrintWriter writer = new PrintWriter(
                    new FileWriter(logDir.resolve(LOG_FILENAME).toString(), true))) {
                writer.println(message);
            }
        } catch (IOException e) {
            logger.warning("Failed to write conversation log: " + e.getMessage());
        }
    }

В этом примере ведение журнала метаданных сеанса применяется в трех местах:

  • Для каждого запуска создается файл журнала разговора с меткой времени (conversation_YYYYMMDD_HHmmss.log строки 92–95).
  • Обработчик SESSION_UPDATEDизвлекает идентификатор сеанса из JSON события и записывает его в журнал (строки 365–366).
  • writeLog(...) добавляет записи в один и тот же файл журнала на протяжении всего жизненного цикла беседы (строки 471–482).

Используйте метаданные зарегистрированного сеанса с CONVERSATION_ID, чтобы возобновить беседу с тем же агентом в последующем сеансе.

Используйте значение идентификатора сеанса вместе с идентификатором разговора для диагностики и повторного подключения.

Миграция из службы агента (классическая модель)

Если вы используете Voice Live со службой агентского обслуживания (classic), мы рекомендуем перейти на новую службу агентского обслуживания Foundry. Общие действия по миграции службы агента см. в разделе "Миграция из службы агента (классической) в службу агента Foundry.

Изменения пакета SDK для голосовой трансляции

Пакет SDK voice Live содержит типизированные классы конфигурации, заменяющие необработанные параметры запроса, используемые в классической интеграции:

Классический (версия 1) Новый (v2)
agent-id Параметр запроса agent_name в AgentConfig / AgentSessionConfig
agent-project-name Параметр запроса Конечная точка проекта в конструкторе клиента
agent-access-token Параметр запроса Автоматически обрабатывается пакетом SDK
Вручную connect() с диктовкой запроса Строго типизированные параметры, переданные в параметры сеанса AgentSessionConfig

Минимальные версии пакета SDK

Язык Пакет Минимальная версия
Python azure-ai-voicelive 1.0.0b5
C# Azure.AI.VoiceLive 1.1.0-beta.2
Java azure-ai-voicelive 1.0.0-beta.5
Javascript @azure/ai-voicelive 1.0.0-beta.3

До и после: настройка подключения Python

Классический (v1) — необработанные параметры запроса в connect():

async with connect(
    endpoint=self.endpoint,
    credential=self.credential,
    query={
        "agent-id": self.agent_id,
        "agent-project-name": self.foundry_project_name,
        "agent-access-token": agent_access_token
    },
) as connection:

New (v2) — строго типизированный AgentSessionConfig:

from azure.ai.voicelive import AgentConfig, AgentSessionConfig

agent_config = AgentConfig(agent_name=agent_name)
agent_session_config = AgentSessionConfig(agent_config=agent_config)

session_options = VoiceLiveSessionOptions(
    agent_session_config=agent_session_config,
    # ... other options
)

Полные примеры кода см. в кратком руководстве по новому агенту. Классическое краткое руководство все еще доступно.