> This is a page from the ElevenLabs documentation. For a complete page index, fetch https://elevenlabs.io/docs/llms.txt. For the full documentation in a single file, fetch https://elevenlabs.io/docs/llms-full.txt.

# 客户端事件

**客户端事件**是从服务器发送到客户端的系统级事件，用于实现实时通信。这些事件向客户端应用传递音频、转写内容、智能体回复及其他关键信息。

> **Note**
>
> 有关可从客户端发送到服务器的事件，请参阅[客户端到服务器事件](/docs/zh/eleven-agents/customization/events/client-to-server-events)文档。

## 概述

客户端事件对于维持对话的实时性至关重要。它们提供从初始化元数据到已处理音频和智能体回复的所有信息。

> **Info**
>
> 这些事件属于 WebSocket 通信协议的一部分，由我们的 SDK 自动处理。对于高级实现和调试，了解这些事件至关重要。

## 客户端事件类型

#### conversation_initiation_metadata

* 开始对话时自动发送
* 初始化对话设置和参数

```json
// Example initialization metadata
{
  "type": "conversation_initiation_metadata",
  "conversation_initiation_metadata_event": {
    "conversation_id": "conv_123",
    "agent_output_audio_format": "pcm_44100",  // TTS output format
    "user_input_audio_format": "pcm_16000"    // ASR input format
  }
}
```

#### queue_status

* 智能体达到并发限制时，仅发送给在[通话队列](/docs/zh/eleven-agents/guides/call-queueing)中等待的来电者
* `waiting` 在 `conversation_initiation_metadata` 之后、任何等待音频之前发送一次
* 等待结束时，`admitted` 或 `timed_out` 会发送一次。`timed_out` 后会以代码 4300 关闭 WebSocket
* 始终发送给排队中的来电者。无需在智能体的 `client_events` 配置中启用

> **Note**
>
> 来电者排队时，等待音频会作为常规 `audio` 事件到达。请使用此事件显示等待状态，而不要将等待音频视为智能体语音。

```json
// Example queue status event structure
{
  "type": "queue_status",
  "queue_status_event": {
    "status": "waiting"  // "waiting" | "admitted" | "timed_out"
  }
}
```

```javascript
// Example queue status handler
websocket.on('queue_status', (event) => {
  const { status } = event.queue_status_event;
  if (status === 'waiting') {
    showWaitingState();
  } else if (status === 'admitted') {
    hideWaitingState();
  } else if (status === 'timed_out') {
    showAllAgentsBusyMessage();
  }
});
```

#### ping

* 需要立即响应的运行状况检查事件
* 由 SDK 自动处理
* 用于维持 WebSocket 连接

```json
  // Example ping event structure
  {
    "ping_event": {
      "event_id": 123456,
      "ping_ms": 50  // Optional, estimated latency in milliseconds
    },
    "type": "ping"
  }
```

```javascript
  // Example ping handler
  websocket.on('ping', () => {
    websocket.send('pong');
  });
```

#### audio

* 包含用于播放的 Base64 编码音频
* 包含用于跟踪和排序的数字事件 ID
* 处理语音输出流
* 包含具有字符级时间信息的对齐数据

> **Note**
>
> 通过 WebRTC 连接时，不会发送 `audio` 事件，因为音频由 LiveKit 直接处理。

```json
// Example audio event structure
{
  "audio_event": {
    "audio_base_64": "base64_encoded_audio_string",
    "event_id": 12345,
    "alignment": {  // Character-level timing data
      "chars": ["H", "e", "l", "l", "o"],
      "char_durations_ms": [50, 30, 40, 40, 60],
      "char_start_times_ms": [0, 50, 80, 120, 160]
    }
  },
  "type": "audio"
}
```

```javascript
// Example audio event handler
websocket.on('audio', (event) => {
  const { audio_event } = event;
  const { audio_base_64, event_id, alignment } = audio_event;
  audioPlayer.play(audio_base_64);

  // Use alignment data for synchronized text display
  const { chars, char_start_times_ms } = alignment;
  chars.forEach((char, i) => {
    setTimeout(() => highlightCharacter(char, i), char_start_times_ms[i]);
  });
});
```

#### user_transcript

* 包含已完成的语音转文本结果
* 表示完整的用户话语
* 用于对话历史记录

```json
// Example transcript event structure
{
  "type": "user_transcript",
  "user_transcription_event": {
    "user_transcript": "Hello, how can you help me today?"
  }
}
```

```javascript
// Example transcript handler
websocket.on('user_transcript', (event) => {
  const { user_transcription_event } = event;
  const { user_transcript } = user_transcription_event;
  updateConversationHistory(user_transcript);
});
```

#### agent_response

* 包含完整的智能体消息
* 消息完成后发送一次，因此在语音对话中，通常会在该消息的音频开始流式传输后才到达
* 用于显示和历史记录

> **Note**
>
> 如需在智能体文本生成时显示，请使用下文所述的 `agent_chat_response_part` 事件，而非等待此事件。

```json
// Example response event structure
{
  "type": "agent_response",
  "agent_response_event": {
    "agent_response": "Hello, how can I assist you today?"
  }
}
```

```javascript
// Example response handler
websocket.on('agent_response', (event) => {
  const { agent_response_event } = event;
  const { agent_response } = agent_response_event;
  displayAgentMessage(agent_response);
});
```

#### agent_response_correction

* 包含中断后的截断回复
* 更新显示的消息
* 保持对话准确性

```json
// Example response correction event structure
{
  "type": "agent_response_correction",
  "agent_response_correction_event": {
    "original_agent_response": "Let me tell you about the complete history...",
    "corrected_agent_response": "Let me tell you about..."  // Truncated after interruption
  }
}
```

```javascript
// Example response correction handler
websocket.on('agent_response_correction', (event) => {
  const { agent_response_correction_event } = event;
  const { corrected_agent_response } = agent_response_correction_event;
  displayAgentMessage(corrected_agent_response);
});
```

#### agent_response_metadata

* 包含来自自定义 LLM 回复的任意元数据
* 仅在使用[自定义 LLM](/docs/zh/eleven-agents/customization/llm/custom-llm)时发送
* 必须在智能体的 `client_events` 配置中明确启用

> **Note**
>
> 此事件专用于自定义 LLM 集成。它允许自定义 LLM 服务器随回复传递额外元数据，供客户端应用使用。

```json
// Example agent response metadata event structure
{
  "type": "agent_response_metadata",
  "agent_response_metadata_event": {
    "metadata": {
      // Any key-value pairs returned by your custom LLM
      "key": "value"
    },
    "event_id": 12345
  }
}
```

```javascript
// Example metadata handler
websocket.on('agent_response_metadata', (event) => {
  const { agent_response_metadata_event } = event;
  const { metadata, event_id } = agent_response_metadata_event;

  // Use metadata for UI updates, logging, or analytics
  console.log(`Response ${event_id} metadata:`, metadata);
  updateResponseDetails(metadata);
});
```

#### client_tool_call

* 表示智能体希望客户端执行的函数调用
* 包含工具名称、工具调用 ID 和参数
* 需要在客户端执行函数，并将结果发送回服务器

> **Info**
>
> 如果使用 SDK，将提供回调来处理将结果发送回服务器的操作。

```json
// Example tool call event structure
{
  "type": "client_tool_call",
  "client_tool_call": {
    "tool_name": "search_database",
    "tool_call_id": "call_123456",
    "parameters": {
      "query": "user information",
      "filters": {
        "date": "2024-01-01"
      }
    }
  }
}
```

```javascript
// Example tool call handler
websocket.on('client_tool_call', async (event) => {
  const { client_tool_call } = event;
  const { tool_name, tool_call_id, parameters } = client_tool_call;

  try {
    const result = await executeClientTool(tool_name, parameters);
    // Send success response back to continue conversation
    websocket.send({
      type: "client_tool_result",
      tool_call_id: tool_call_id,
      result: result,
      is_error: false
    });
  } catch (error) {
    // Send error response if tool execution fails
    websocket.send({
      type: "client_tool_result",
      tool_call_id: tool_call_id,
      result: error.message,
      is_error: true
    });
  }
});
```

#### agent_tool_response

* 指示智能体何时执行了工具函数
* 包含工具元数据和执行状态
* 可了解智能体在对话期间的工具使用情况

```json
// Example agent tool response event structure
{
  "type": "agent_tool_response",
  "agent_tool_response": {
    "tool_name": "skip_turn",
    "tool_call_id": "skip_turn_c82ca55355c840bab193effb9a7e8101",
    "tool_type": "system",
    "is_error": false
  }
}
```

```javascript
// Example agent tool response handler
websocket.on('agent_tool_response', (event) => {
  const { agent_tool_response } = event;
  const { tool_name, tool_call_id, tool_type, is_error } = agent_tool_response;

  if (is_error) {
    console.error(`Agent tool ${tool_name} failed:`, tool_call_id);
  } else {
    console.log(`Agent executed ${tool_type} tool: ${tool_name}`);
  }
});
```

#### agent_tool_response_full_payload

* 与 `agent_tool_response` 对应，此外还会将工具的完整结果载荷作为字符串流式传输到 `full_tool_result`。
* 在客户端呈现工具输出，以便显示或进行下游处理。
* 必须在智能体的 `client_events` 配置中明确启用。

> **Warning**
>
> 此事件会向客户端公开完整工具结果，其中可能包含敏感数据。仅在客户端受信任且能够处理此载荷时启用。超过 64 KB 的结果会自动截断。

```json
// Example agent tool response full payload event structure
{
  "type": "agent_tool_response_full_payload",
  "agent_tool_response_full_payload": {
    "tool_name": "lookup_order",
    "tool_call_id": "lookup_order_c82ca55355c840bab193effb9a7e8101",
    "tool_type": "webhook",
    "is_error": false,
    "full_tool_result": "{\"order_id\": \"ORD-789\", \"status\": \"shipped\"}",
    "truncated": false
  }
}
```

#### React

```tsx
// Example agent tool response full payload handler (using @elevenlabs/react)
import { ConversationProvider } from '@elevenlabs/react';

function App() {
  return (
    <ConversationProvider
      onAgentToolResponse={(response) => {
        if (!('full_tool_result' in response)) return;
        const { tool_name, tool_call_id, is_error, full_tool_result, truncated } = response;

        if (is_error) {
          console.error(`Agent tool ${tool_name} failed:`, tool_call_id);
        } else {
          console.log(`Tool ${tool_name} returned:`, full_tool_result);
        }

        if (truncated) {
          console.warn(`Tool ${tool_name} result was truncated (exceeded 64 KB).`);
        }
      }}
    >
      <Agent />
    </ConversationProvider>
  );
}
```

#### JavaScript

```javascript
// Example agent tool response full payload handler (using @elevenlabs/client)
import { Conversation } from '@elevenlabs/client';

const conversation = await Conversation.startSession({
  agentId: 'agent_7101k5zvyjhmfg983brhmhkd98n6',
  onAgentToolResponse: (response) => {
    if (!('full_tool_result' in response)) return;
    const { tool_name, tool_call_id, is_error, full_tool_result, truncated } = response;

    if (is_error) {
      console.error(`Agent tool ${tool_name} failed:`, tool_call_id);
    } else {
      console.log(`Tool ${tool_name} returned:`, full_tool_result);
    }

    if (truncated) {
      console.warn(`Tool ${tool_name} result was truncated (exceeded 64 KB).`);
    }
  },
});
```

#### vad_score

* 语音活动检测评分事件
* 表示用户正在说话的概率
* 值范围为 0 到 1，值越高表示语音置信度越高

```json
// Example VAD score event
{
  "type": "vad_score",
  "vad_score_event": {
    "vad_score": 0.95
  }
}
```

#### mcp_tool_call

* 指示智能体何时执行了 MCP 工具函数
* 包含工具名称、工具调用 ID 和参数
* 以四种状态之一调用：`loading`、`awaiting_approval`、`success` 和 `failure`。

```json
{
  "type": "mcp_tool_call",
  "mcp_tool_call": {
    "service_id": "xJ8kP2nQ7sL9mW4vR6tY",
    "tool_call_id": "call_123456",
    "tool_name": "search_database",
    "tool_description": "Search the database for user information",
    "parameters": {
      "query": "user information",
    },
    "timestamp": "2024-09-30T14:23:45.123456+00:00",
    "state": "loading",
    "approval_timeout_secs": 10
  }
}
```

#### agent_chat_response_part

* 将智能体生成中的回复文本作为 `start`、`delta` 和 `stop` 消息进行流式传输
* 在纯文本模式下始终发送；在语音对话中，必须在智能体的 `client_events` 配置中明确启用
* 当智能体或活跃流程使用阻塞型护栏时不会发送，因为护栏必须先评估完整回复，才能释放任何内容
* `response_id` 用于标识正在流式传输的消息，并与稍后确认该消息的 `agent_response` 的 `response_id` 匹配

```json
// Example start event
{
  "type": "agent_chat_response_part",
  "text_response_part": {
    "type": "start",
    "text": "",
    "event_id": 12345,
    "response_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
  }
}
```

```json
// Example delta event with text chunk
{
  "type": "agent_chat_response_part",
  "text_response_part": {
    "type": "delta",
    "text": "Hello, how can I",
    "event_id": 12345,
    "response_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
  }
}
```

```json
// Example stop event
{
  "type": "agent_chat_response_part",
  "text_response_part": {
    "type": "stop",
    "text": "",
    "event_id": 12345,
    "response_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
  }
}
```

```javascript
// Example handler
websocket.on('agent_chat_response_part', (event) => {
  const { text_response_part } = event;
  const { type: partType, text, response_id } = text_response_part;

  if (partType === 'start') {
    initializeResponseBuffer(response_id);
  } else if (partType === 'delta') {
    appendToResponseBuffer(response_id, text);
  } else if (partType === 'stop') {
    finalizeResponse(response_id);
  }
});
```

#### agent_reasoning_response_part

`agent_reasoning_response_part` 会在纯文本对话期间流式传输模型提供的推理内容。
在 `client_events` 中启用此事件，并为智能体开启[推理摘要](/docs/zh/eleven-agents/customization/llm#reasoning-summary)。服务器会发送
`start`、`delta` 和 `stop` 消息。在语音对话期间，或当智能体或活跃流程使用阻塞型护栏时，不会发送此事件。

> **Note**
>
> 此事件及对应的 SDK 回调属于实验性功能。其行为和结构可能在任何版本中发生变化。

**`事件载荷`**

```json title="事件载荷" focus={3-7}
{
  "type": "agent_reasoning_response_part",
  "reasoning_response_part": {
    "type": "delta",
    "text": "The user asked to cancel, so I should verify the account before continuing.",
    "event_id": 123456
  }
}
```

开始和停止事件使用空的 `text` 值。

**`处理推理事件`**

```javascript title="处理推理事件" focus={6-14}
import { Conversation } from '@elevenlabs/client';

const conversation = await Conversation.startSession({
  agentId: 'agent_7101k5zvyjhmfg983brhmhkd98n6',
  textOnly: true,
  onAgentReasoningResponsePart: ({ type, text, event_id }) => {
    if (type === 'start') {
      initializeReasoningBuffer(event_id);
    } else if (type === 'delta') {
      appendToReasoningBuffer(text);
    } else if (type === 'stop') {
      finalizeReasoning();
    }
  },
});
```

#### agent_response_complete

* 当智能体完成回复（包括所有待处理工具调用）时触发。此事件之后，只有当用户提供新输入或轮次超时触发新轮次时，智能体才会继续产生输出。
* 必须在智能体的 `client_events` 配置中明确启用

```json
// Example agent response complete event structure
{
  "type": "agent_response_complete",
  "agent_response_complete_event": {
    "event_id": 12345
  }
}
```

```javascript
// Example handler
websocket.on('agent_response_complete', (event) => {
  const { agent_response_complete_event } = event;
  const { event_id } = agent_response_complete_event;

  console.log(`Agent response ${event_id} complete`);
});
```

#### guardrail_triggered

* 当[护栏](/docs/zh/eleven-agents/best-practices/guardrails)违规导致对话结束时触发。护栏触发重试且重试成功时不会发送。
* 事件本身就是信号，除 `type` 字段外不携带任何载荷。
* 必须在智能体的 `client_events` 配置中明确启用。

```json
// Example guardrail triggered event structure
{
  "type": "guardrail_triggered"
}
```

```javascript
// Example guardrail triggered handler (using @elevenlabs/client)
import { Conversation } from '@elevenlabs/client';

const conversation = await Conversation.startSession({
  agentId: 'agent_7101k5zvyjhmfg983brhmhkd98n6',
  onGuardrailTriggered: () => {
    console.warn('Guardrail triggered — conversation will end.');
  },
});
```

## 事件流程

以下是对话期间的典型事件顺序：

```mermaid
sequenceDiagram
    participant Client
    participant Server

    Server->>Client: conversation_initiation_metadata
    Note over Client,Server: Connection established
    Server->>Client: ping
    Client->>Server: pong
    Server->>Client: audio
    Note over Client: Playing audio
    Note over Client: User responds
    Server->>Client: user_transcript
    Server->>Client: audio
    Server->>Client: agent_response
    Server->>Client: client_tool_call
    Note over Client: Client tool runs
    Client->>Server: client_tool_result
    Server->>Client: audio
    Server->>Client: agent_response
    Note over Client: Playing audio
    Note over Client: Interruption detected
    Server->>Client: agent_response_correction

```

当智能体达到并发上限且已启用[呼叫排队](/docs/zh/eleven-agents/guides/call-queueing)时，服务器会在 `conversation_initiation_metadata` 与第一个 `audio` 事件之间发送 `queue_status` 事件。等待音频会以 `audio` 事件的形式传送，直到呼叫者获准接入。

### 最佳实践

1. **错误处理**

   * 为每种事件类型实现适当的错误处理
   * 记录重要事件，便于调试
   * 妥善处理连接中断

2. **音频管理**

   * 合理缓冲音频块
   * 在中断时做好清理
   * 管理音频资源

3. **连接管理**

   * 及时响应 PING 事件
   * 实现重连逻辑
   * 监控连接状态

## 故障排除

#### 连接问题

* 确保 WebSocket 连接正常
* 检查 PING/PONG 响应
* 验证 API 凭据

#### 音频问题

* 检查音频块处理
* 验证音频格式兼容性
* 监控内存使用情况

#### 事件处理

* 记录所有事件，便于调试
* 实现错误边界
* 检查事件处理程序注册情况

> **Info**
>
> 如需详细实现示例，请查看我们的 [SDK 文档](/docs/zh/eleven-agents/libraries/python)。