# 接入自定义 TTS 服务 (/zh-CN/ai/build/custom-model-integration/custom-tts-agent)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

通过接入自定义文本转语音 (TTS) 服务，你可以将自研 TTS、私有化部署 TTS 或第三方 TTS 服务作为对话式智能体的语音合成模块。本文介绍如何准备兼容 OpenAI TTS 协议的 HTTP 服务，并在创建对话式智能体时通过 TTS 配置接入该服务。

## 实现原理 [#实现原理]

Agents SDK 通过 `GenericTTS` 构造自定义 TTS 配置。启动智能体会话时，SDK 会将该配置序列化为 `tts.vendor = "generic_http"`，并由声网对话式 AI 引擎在需要播报文本时向你的 TTS HTTP 服务发起请求。

## 前提条件 [#前提条件]

开始前，请确保你已经：

- 已参考 [使用 Agents SDK](/zh-CN/ai/get-started/quick-start-agent) 或 [使用 RESTful API](/zh-CN/ai/get-started/quick-start) 实现与智能体对话的基本逻辑。
- 准备好可被声网对话式 AI 引擎访问的 TTS HTTP 服务。
- 确保 TTS 服务支持 HTTP/1.1 或更高版本，生产环境建议使用 HTTPS。
- 确保 TTS 服务能够返回 PCM 格式音频数据。
- 安装包含 `GenericTTS` `generic_http` 支持的 Agents SDK 版本。Go 和 TypeScript SDK 需要使用 `v2.4.0` 之后的版本；Python SDK 需要使用 `v2.4.1` 之后的版本。

:::warning[注意]
`GenericTTS` 当前只支持 HTTP 和 HTTPS endpoint。不要传入 `ws://` 或 `wss://` 地址，否则 SDK 会在构造 TTS vendor 时抛出错误。
:::

## 实现步骤 [#实现步骤]

### 1. 准备 TTS 服务接口 [#1-准备-tts-服务接口]

你的 TTS 服务需要提供一个兼容 OpenAI TTS 协议的 HTTP 接口。基础要求如下：

- 请求方法：`POST`
- 请求路径：`/audio/speech`
- 请求 Header：支持通过 `Authorization: Bearer <api_key>` 鉴权
- 请求 Body：JSON 格式
- 响应 Body：PCM 音频数据流

请求体示例如下：

```json
{
  "model": "your-tts-model",
  "input": "欢迎使用声网对话式 AI 引擎。",
  "voice": "alloy",
  "speed": 1.0,
  "sample_rate": 16000,
  "response_format": "pcm",
  "instruction": "calm"
}
```

请求体字段说明如下：

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `input` | String | 待合成的文本内容。由声网对话式 AI 引擎根据智能体回复自动传入。 |
| `model` | String | TTS 模型名称。如果你的 TTS 服务不区分模型，可以忽略该字段。 |
| `voice` | String | 音色名称。如果你的 TTS 服务不区分音色，可以忽略该字段。 |
| `speed` | Number | 语速。 |
| `sample_rate` | Integer | 输出音频采样率，单位为 Hz，默认值为 `16000`。 |
| `response_format` | String | 输出音频格式，默认值为 `pcm`。当前仅支持 `pcm`。 |
| `instruction` | String | 语音风格、情绪或其他播报指令。 |

:::warning[注意]
如果你的 TTS 服务不支持多采样率，请确保实际返回音频的采样率与通过 SDK 配置的 `sample_rate` 一致。
:::

### 2. 验证 TTS 服务响应 [#2-验证-tts-服务响应]

你可以先使用 curl 验证 TTS 服务是否能正常返回 PCM 音频流：

```bash
curl --request POST \
  --url https://your-tts-service.example.com/v1/audio/speech \
  --header 'Authorization: Bearer <your_tts_api_key>' \
  --header 'Content-Type: application/json' \
  --data '{
    "model": "your-tts-model",
    "input": "欢迎使用声网对话式 AI 引擎。",
    "voice": "alloy",
    "speed": 1.0,
    "sample_rate": 16000,
    "response_format": "pcm"
  }' \
  --output test.pcm
```

服务成功处理请求后，应以 HTTP 分块传输编码（Chunked Transfer Encoding）的方式流式返回合成后的 PCM 音频数据。

如果请求失败，建议返回标准 HTTP 错误状态码，并在响应体中携带 JSON 格式错误信息。例如：

```json
{
  "error": {
    "message": "Incorrect API key provided.",
    "type": "invalid_request_error",
    "param": null,
    "code": "invalid_api_key"
  }
}
```

### 3. 配置智能体使用自定义 TTS [#3-配置智能体使用自定义-tts]

以下示例中的 `sttVendor`/`stt_vendor` 和 `llmVendor`/`llm_vendor` 表示已创建好的 STT 和 LLM vendor。实际接入时，请根据你的业务选择对应的语音识别和大语言模型服务并完成配置；本文重点展示如何通过 `GenericTTS` 接入自定义 TTS 服务。

<Tabs defaultValue="go" groupId="tts-config-method" persist>
<TabsList>
  <TabsTrigger value="go">Go</TabsTrigger>
  <TabsTrigger value="python">Python</TabsTrigger>
  <TabsTrigger value="typescript">TypeScript</TabsTrigger>
  <TabsTrigger value="restful-api">Restful API</TabsTrigger>
</TabsList>

<TabsContent value="go">

你可以使用 Agents SDK 的 `GenericTTS` 配置接入自定义 TTS 服务。

```go
import (
    Agora "github.com/AgoraIO/agora-agents-go/v2"
    agentkit "github.com/AgoraIO/agora-agents-go/v2/agentkit/cn"
    vendors "github.com/AgoraIO/agora-agents-go/v2/agentkit/cn/vendors"
)

sampleRate := vendors.SampleRate16kHz
speed := 1.0

client := agentkit.NewAgoraClient(agentkit.ClientOptions{
		AppID:          requireEnv("AGORA_APP_ID"),
		AppCertificate: requireEnv("AGORA_APP_CERTIFICATE"),
	  })

agent := agentkit.NewAgent(
    client,
    agentkit.WithTurnDetectionConfig(&agentkit.TurnDetectionConfig{
        Language: Agora.AsrLanguageZhCn.Ptr(),
    }),
).WithStt(
    // 替换为你已配置的 STT vendor。
    sttVendor,
).WithLlm(
    // 替换为你已配置的 LLM vendor。
    llmVendor,
// highlight-start
).WithTts(
    vendors.NewGenericTTS(vendors.GenericTTSOptions{
        URL: "https://your-tts-service.example.com/v1/audio/speech",
        Headers: map[string]string{
            "Authorization": "Bearer " + requireEnv("CUSTOM_TTS_API_KEY"),
        },
        Model:          "your-tts-model",
        Voice:          "alloy",
        Speed:          &speed,
        SampleRate:     &sampleRate,
        ResponseFormat: "pcm",
        Instruction:    "calm",
        AdditionalParams: map[string]interface{}{
            "enable_request_id": false,
        },
    }),
// highlight-end
)
```

</TabsContent>

<TabsContent value="python">

你可以使用 Agents SDK 的 `GenericTTS` 配置接入自定义 TTS 服务。

```python
from agora_agent import Agent, GenericTTS

client = Agora(
    area=Area.CN,
    app_id=os.environ["AGORA_APP_ID"],
    app_certificate=os.environ["AGORA_APP_CERTIFICATE"],
)

agent = (
    Agent(
        client=client,
        turn_detection={"language": "zh-CN"},
    )
    # 替换为你已配置的 STT vendor。
    .with_stt(stt_vendor)
    # 替换为你已配置的 LLM vendor。
    .with_llm(llm_vendor)
# highlight-start
    .with_tts(
        GenericTTS(
            url="https://your-tts-service.example.com/v1/audio/speech",
            headers={
                "Authorization": f"Bearer {require_env('CUSTOM_TTS_API_KEY')}",
            },
            model="your-tts-model",
            voice="alloy",
            speed=1.0,
            sample_rate=16000,
            response_format="pcm",
            instruction="calm",
            additional_params={
                "enable_request_id": False,
            },
        )
    )
# highlight-end
)
```

</TabsContent>

<TabsContent value="typescript">

你可以使用 Agents SDK 的 `GenericTTS` 配置接入自定义 TTS 服务。

```typescript
import { Agent, GenericTTS } from 'agora-agents';

const client = new AgoraClient({
  area: Area.CN,
  appId: requireEnv("AGORA_APP_ID"),
  appCertificate: requireEnv("AGORA_APP_CERTIFICATE"),
});

const agent = new Agent({
  client,
  turnDetection: { language: 'zh-CN' },
})
  // 替换为你已配置的 STT vendor。
  .withStt(sttVendor)
  // 替换为你已配置的 LLM vendor。
  .withLlm(llmVendor)
  // highlight-start
  .withTts(
    new GenericTTS({
      url: 'https://your-tts-service.example.com/v1/audio/speech',
      headers: {
        Authorization: `Bearer ${process.env.CUSTOM_TTS_API_KEY}`,
      },
      model: 'your-tts-model',
      voice: 'alloy',
      speed: 1.0,
      sampleRate: 16000,
      responseFormat: 'pcm',
      instruction: 'calm',
      additionalParams: {
        enable_request_id: false,
      },
    })
  );
  // highlight-end
```

</TabsContent>

<TabsContent value="restful-api">

你可以调用 [POST 创建对话式智能体](/zh-CN/api-reference/api-ref/conversational-ai/join)接口时，在 `tts` 模块中将 `vendor` 设置为 `generic_http`，并配置你的 TTS 服务地址和参数。

```json
{
  "tts": {
    "vendor": "generic_http",
    "url": "https://your-tts-service.example.com/v1/audio/speech",
    "headers": {
      "Authorization": "Bearer <your_tts_api_key>"
    },
    "params": {
      "model": "your-tts-model",
      "voice": "alloy",
      "speed": 1.0,
      "sample_rate": 16000,
      "response_format": "pcm",
      "instruction": "calm",
      "enable_request_id": false
    }
  }
}
```

</TabsContent>
</Tabs>

相关配置说明如下：

<Tabs defaultValue="go" groupId="tts-config-method" persist>
<TabsList>
  <TabsTrigger value="go">Go</TabsTrigger>
  <TabsTrigger value="python">Python</TabsTrigger>
  <TabsTrigger value="typescript">TypeScript</TabsTrigger>
  <TabsTrigger value="restful-api">Restful API</TabsTrigger>
</TabsList>

<TabsContent value="go">

| 参数 | 类型 | 是否必需 | 说明 |
| --- | --- | --- | --- |
| `URL` | `string` | 是 | 自定义 TTS 服务的 HTTP(S) endpoint。 |
| `Headers` | `map[string]string` | 否 | 调用 TTS 服务时携带的请求头，常用于配置 `Authorization`。未设置时不会写入 `headers`。 |
| `APIKey` | `string` | 否 | TTS 服务鉴权 API key。 |
| `Model` | `string` | 否 | TTS 模型名称。 |
| `Voice` | `string` | 否 | 音色名称。 |
| `Speed` | `*float64` | 否 | 语速。 |
| `SampleRate` | `*vendors.SampleRate` | 否 | 输出音频采样率，单位为 Hz。如果你的 TTS 服务暂不支持多采样率，请确保返回音频的采样率与该配置一致。 |
| `ResponseFormat` | `string` | 否 | 输出音频格式。当前 ConvoAI 支持 `pcm`。 |
| `Instruction` | `string` | 否 | 语音风格、情绪或其他播报指令。 |
| `AdditionalParams` | `map[string]interface{}` | 否 | 透传给 TTS 服务的其他参数；同名字段会被非空的显式字段覆盖。 |
| `SkipPatterns` | `[]int` | 否 | 控制 TTS 跳过特定文本模式。 |

</TabsContent>

<TabsContent value="python">

| 参数 | 类型 | 是否必需 | 说明 |
| --- | --- | --- | --- |
| `url` | `str` | 是 | 自定义 TTS 服务的 HTTP(S) endpoint。 |
| `headers` | `Dict[str, str]` | 否 | 调用 TTS 服务时携带的请求头，常用于配置 `Authorization`。未设置时不会写入 `headers`。 |
| `api_key` | `str` | 否 | TTS 服务鉴权 API key。 |
| `model` | `str` | 否 | TTS 模型名称。 |
| `voice` | `str` | 否 | 音色名称。 |
| `speed` | `float` | 否 | 语速。 |
| `sample_rate` | `int` | 否 | 输出音频采样率，单位为 Hz。如果你的 TTS 服务暂不支持多采样率，请确保返回音频的采样率与该配置一致。 |
| `response_format` | `str` | 否 | 输出音频格式。当前 ConvoAI 支持 `pcm`。 |
| `instruction` | `str` | 否 | 语音风格、情绪或其他播报指令。 |
| `additional_params` | `Dict[str, Any]` | 否 | 透传给 TTS 服务的其他参数；同名字段会被显式参数覆盖。 |
| `skip_patterns` | `List[int]` | 否 | 控制 TTS 跳过特定文本模式。 |

</TabsContent>

<TabsContent value="typescript">

| 参数 | 类型 | 是否必需 | 说明 |
| --- | --- | --- | --- |
| `url` | `string` | 是 | 自定义 TTS 服务的 HTTP(S) endpoint。 |
| `headers` | `Record<string, string>` | 否 | 调用 TTS 服务时携带的请求头，常用于配置 `Authorization`。未设置时不会写入 `headers`。 |
| `apiKey` | `string` | 否 | TTS 服务鉴权 API key。 |
| `model` | `string` | 否 | TTS 模型名称。 |
| `voice` | `string` | 否 | 音色名称。 |
| `speed` | `number` | 否 | 语速。 |
| `sampleRate` | `number` | 否 | 输出音频采样率，单位为 Hz。如果你的 TTS 服务暂不支持多采样率，请确保返回音频的采样率与该配置一致。 |
| `responseFormat` | `"pcm"` | 否 | 输出音频格式。当前 ConvoAI 支持 `pcm`。 |
| `instruction` | `string` | 否 | 语音风格、情绪或其他播报指令。 |
| `additionalParams` | `Record<string, unknown>` | 否 | 透传给 TTS 服务的其他参数；同名字段会被显式字段覆盖。 |
| `skipPatterns` | `number[]` | 否 | 控制 TTS 跳过特定文本模式。 |

</TabsContent>

<TabsContent value="restful-api">

| 配置路径 | 类型 | 是否必需 | 默认值 | 说明 |
| --- | --- | --- | --- | --- |
| `tts.vendor` | String | 是 | - | 设置为 `generic_http`，表示使用自定义 TTS 服务。 |
| `tts.url` | String | 是 | - | TTS 服务地址，要求兼容 OpenAI TTS 协议。 |
| `tts.headers` | Object | 否 | - | 调用 TTS 服务时携带的请求头，常用于配置 `Authorization`。 |
| `tts.params` | Object | 否 | - | TTS 请求参数。除本文列出的字段外，还支持按需配置其他字段，系统会将其透传给 TTS 服务。 |
| `tts.params.api_key` | String | 否 | - | TTS 服务鉴权 API key。如果配置该字段，系统会在调用 TTS 服务时自动携带 `Authorization: Bearer <api_key>`。 |
| `tts.params.model` | String | 否 | - | TTS 模型名称。 |
| `tts.params.voice` | String | 否 | - | 音色名称。如果你的 TTS 服务暂不支持多音色，可以忽略该参数。 |
| `tts.params.speed` | Number | 否 | - | 语速。 |
| `tts.params.sample_rate` | Integer | 否 | `16000` | 输出音频采样率，单位为 Hz。如果你的 TTS 服务暂不支持多采样率，请确保返回音频的采样率与该配置一致。 |
| `tts.params.response_format` | String | 否 | `pcm` | 输出音频格式。当前仅支持 `pcm`。 |
| `tts.params.instruction` | String | 否 | - | 语音风格、情绪或其他播报指令。 |
| `tts.params.enable_request_id` | Boolean | 否 | `false` | 是否在 TTS 请求体中附带 `request_id`、`request_seq_id` 和 `request_end`。 |

</TabsContent>
</Tabs>

:::info[信息]
鉴权信息可以通过请求头中的 `Authorization` 传递，也可以通过 API key 字段传入。如果你的服务同时支持两种方式，建议优先使用请求头，便于和现有 HTTP 鉴权逻辑保持一致。
:::

### 4. 启动会话 [#4-启动会话]

完成配置后，启动智能体会话。会话启动后，对话式 AI 引擎会在智能体需要播报 LLM 回复时自动调用你的 TTS 服务。

```go tab="Go" tabGroup="language"
session := agent.CreateSession(agentkit.CreateSessionOptions{
    Channel:    requireEnv("AGORA_CHANNEL"),
    AgentUID:   requireEnv("AGORA_AGENT_UID"),
    RemoteUIDs: []string{"*"},
})

agentSessionID, err := session.Start(ctx)
if err != nil {
    log.Fatal(err)
}

log.Printf("Agent started: %s", agentSessionID)
```

```python tab="Python" tabGroup="language"
session = agent.create_session(
    channel=require_env("AGORA_CHANNEL"),
    agent_uid=require_env("AGORA_AGENT_UID"),
    remote_uids=["*"],
)

agent_session_id = session.start()
print(f"Agent started: {agent_session_id}")
```

```typescript tab="TypeScript" tabGroup="language"
const session = agent.createSession({
  channel: process.env.AGORA_CHANNEL!,
  agentUid: process.env.AGORA_AGENT_UID!,
  remoteUids: ['*'],
});

const agentSessionId = await session.start();
console.log('Agent started:', agentSessionId);
```

## 按需接收请求标识 [#按需接收请求标识]

如果你的 TTS 服务需要区分同一轮播报中的多次请求，可以将 `enable_request_id` 作为附加参数透传给 TTS 服务。

```go tab="Go" tabGroup="language"
AdditionalParams: map[string]interface{}{
    "enable_request_id": true,
}
```

```python tab="Python" tabGroup="language"
additional_params={
    "enable_request_id": True,
}
```

```typescript tab="TypeScript" tabGroup="language"
additionalParams: {
  enable_request_id: true,
}
```

开启后，系统会在发送给 TTS 服务的请求体中附带以下字段：

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `request_id` | String | 单次 TTS 请求的唯一标识。 |
| `request_seq_id` | Integer | 同一轮播报内的请求序号，从 `0` 开始递增。 |
| `request_end` | Boolean | 是否为同一轮播报的最后一次请求。 |

## 参考信息 [#参考信息]

### 示例项目 [#示例项目]

声网提供了开源的自定义 TTS 示例项目供你参考，你可以前往下载或查看其中的源代码。

<Cards>
  <Card title="recipe-agent-custom-tts" href="https://github.com/AgoraIO-Conversational-AI/recipe-agent-custom-tts" />
</Cards>

### 相关文档 [#相关文档]

- [Agents SDK 快速开始](/zh-CN/ai/get-started/quick-start-agent)
- [Go SDK API 参考：NewGenericTTS](/zh-CN/api-reference/conversational-ai/agent-go#newgenerictts)
- [Python SDK API 参考：GenericTTS](/zh-CN/api-reference/conversational-ai/agent-python#generictts)
- [TypeScript SDK API 参考：GenericTTS](/zh-CN/api-reference/conversational-ai/agent-typescript#generictts)
