如果你是Realtime API的新手,可尝试 stepfun-realtime-api。本指南将介绍使用 Realtime API 时模型功能(如音频生成、文本生成、函数调用)所需的事件流程,以及如何理解实时会话的状态。 在模型生成响应的过程中,服务器会发出多个生命周期事件。您可以监听这些事件(如
response.text.delta),在响应生成时向用户提供实时反馈。
服务器发出的事件完整列表见Realtime API 事件列表,它们按大致的发出顺序排列,同时包含文本生成相关的客户端事件。
实时语音到语音会话
实时会话是模型与连接的客户端之间的有状态交互。会话的关键组成部分包括:- 会话(Session) 对象:控制交互参数,如使用的模型、生成输出的语音、其他配置等。
- 对话(Conversation):表示当前会话中生成的用户输入项和模型输出项。
- 响应(Responses):模型生成的音频或文本项,会被添加到对话中。
快速开始:创建 WebSocket 语音链路
通过WebSocket连接需使用以下连接信息:| 类别 | 详情 |
|---|---|
| URL | wss://api.stepfun.com/v1/realtime |
| 查询参数 | model:需连接的实时模型,比如 step-audio-2/step-audio-2-mini/step-1o-audio |
| 请求头 | Authorization: Bearer YOUR_API_KEY |
示例1:使用ws模块(Node.js环境)
示例2:使用websocket-client库(Python环境)
会话生命周期事件
通过WebSocket启动会话后,服务器会发送session.created事件,表明会话已准备就绪。在客户端,您可以通过session.update事件更新当前会话配置。大多数会话属性可以随时更新,但模型用于音频输出的voice(语音)在会话期间模型首次以音频响应后,就无法再修改。实时会话的最长持续时间为30分钟。
以下示例展示了通过session.update客户端事件更新会话的操作。
更新本会话中模型使用的系统指令
session.updated事件,包含会话的新状态。
| 相关客户端事件 | 相关服务器事件 |
|---|---|
| session.update | session.created session.updated |
文本输入与输出
要使用实时模型生成文本,您可以向当前对话添加文本输入,请求模型生成响应,并监听服务器发送的事件以了解模型响应的进度。为了生成文本,会话必须配置为text(文本)模态(默认已启用)。
使用conversation.item.create客户端事件创建新的文本对话项。
创建包含用户输入的对话项
response.create事件以启动模型响应。如果当前会话同时启用了音频和文本,模型将同时返回音频和文本内容。如果只想生成文本,可以在发送response.create客户端事件时指定,如下所示。
生成仅文本响应
response.done事件。该事件将包含模型生成的完整文本,如下所示。
监听response.done以查看最终结果
response.text.delta),在响应生成时向用户提供实时反馈。服务器发出的事件完整列表见下文的“相关服务器事件”,它们按大致的发出顺序排列,同时包含文本生成相关的客户端事件。
| 事件类型 | 说明 |
|---|---|
| conversation.item.create | conversation.item.created response.output_item.added response.content_part.added response.text.delta response.text.done response.content_part.done response.output_item.done response.done rate_limits.updated |
音频输入与输出
实时API最强大的功能之一是与模型进行语音到语音交互,无需中间的文本转语音或语音转文本步骤。这降低了语音界面的延迟,并为模型提供了更多关于语音输入的语调和抑扬顿挫的信息。语音选项
实时会话支持配置多种内置语音用于音频输出。您可以通过session.update 或 response.create 请求中的 voice 参数来设置模型的声音。当前的语音选项包括 qingchunshaonv、wenrounansheng、elegantgentle-female、livelybreezy-female 等。
请注意,一旦模型在会话中生成了音频,该会话的 voice 设置将无法修改。
step-audio-2 模型支持音色复刻功能。您可以通过上传音频文件创建自定义音色,并在实时会话的 voice 参数中使用其 ID。详情请参考复刻音色。
使用WebSocket处理音频
通过WebSocket发送和接收音频时,您需要做更多工作来从客户端发送媒体和从服务器接收媒体。下面是一个表格,描述了WebSocket会话期间通过WebSocket发送和接收音频所需的事件流程。 以下事件按生命周期顺序排列,但有些事件(如delta事件)可能同时发生。
| 生命周期阶段 | 客户端事件 | 服务器事件 |
|---|---|---|
| 会话初始化 | session.update | session.created session.updated |
| 用户音频输入 | conversation.item.create(发送完整音频消息) input_audio_buffer.append(分块流式传输音频) input_audio_buffer.commit(禁用VAD时使用) response.create(禁用VAD时使用) | input_audio_buffer.speech_started input_audio_buffer.speech_stopped input_audio_buffer.committed |
| 服务器音频输出 | input_audio_buffer.clear(禁用VAD时,或者需要主动创建一轮输出时使用) | conversation.item.created response.created response.output_item.created response.content_part.added response.audio.delta response.audio_transcript.delta response.text.delta response.audio.done response.audio_transcript.done response.text.done response.content_part.done response.output_item.done response.done rate_limits.updated |
向服务器流式传输音频输入
要向服务器流式传输音频输入,可以使用input_audio_buffer.append客户端事件。该事件要求您通过套接字向实时API发送Base64编码的音频字节块。每个块的大小不能超过15 MB。
输入块的格式可以为整个会话配置,也可以为每个响应单独配置。
- 会话级:
session.update中的session.input_audio_format - 响应级:
response.create中的response.input_audio_format
发送完整音频消息
也可以创建包含完整音频录制的对话消息。使用conversation.item.create客户端事件创建带有input_audio内容的消息。
创建完整音频输入对话项
处理WebSocket的音频输出
您需要监听response.audio.delta事件,其中包含模型发来的base64编码音频数据块。您需要缓冲这些块并将其写入文件。
请注意,response.audio.done和response.done事件实际上不包含音频数据,只包含音频内容的转录文本。要获取实际的字节数据,需要监听response.audio.delta事件。
输出块的格式可以为整个会话配置,也可以为每个响应单独配置。
- 会话级:
session.update中的session.output_audio_format - 响应级:
response.create中的response.output_audio_format
语音活动检测
默认情况下,实时会话启用语音活动检测(VAD),这意味着API会判断用户何时开始或停止说话,并自动响应。禁用VAD
可以通过session.update客户端事件将turn_detection设置为null来禁用VAD。这对于需要精细控制音频输入的界面很有用,例如按键通话界面。
禁用VAD后,客户端必须手动发出一些额外的客户端事件来触发音频响应:
- 手动发送
input_audio_buffer.commit,这将为对话创建新的用户输入项。 - 手动发送
response.create以触发模型的音频响应。 - 在开始新的用户输入之前发送
input_audio_buffer.clear。
自定义 Tool Call
目前 StepFun Realtime API 内置了以下工具: web_search 和 retrieval。 另外,也支持自定义工具调用(Tool Call),用户可以根据需求定义自己的工具并在会话中使用。工具配置方式
在 update session 请求中配置 tools 参数来启用工具功能:网络搜索工具 web_search
通过type: "web_search" 工具,模型可实时访问互联网,获取最新信息和数据。适用于需要广泛知识和实时数据的场景。
使用示例
在 update session 请求的 tools 参数中添加以下结构:高级参数
options.top_k: 指定返回结果的数量,默认为 5。options.timeout_seconds: 请求超时时间,默认为 3 秒。
知识库检索工具 retrieval
通过type: "retrieval" 工具,模型可实时访问指定知识库(Vector Store),精准回答用户问题。适用于垂直领域问答场景,用户可以提前定义用于参考的回复数据。
一、功能配置步骤
在 update session 请求的 tools 参数中添加以下结构:二、参数详解
| 参数 | 是否必填 | 说明 |
|---|---|---|
| type | 是 | 固定值 “retrieval”,声明使用知识库检索功能。 |
| function.description | 是 | 关键提示:用1-2句话明确触发条件,例如:“仅当问题与菜谱、食材或烹饪相关时使用本知识库”。 |
| options.vector_store_id | 是 | 知识库的唯一ID(示例:133192900598194176),需提前在平台创建。 |
| options.prompt_template | 否 | 定制化提示模板,支持占位符 \{\{knowledge\}\}(检索到的片段)和 \{\{query\}\}(用户原始问题);若不提供则使用默认模板。默认:从文档\{\{knowledge\}\}中找到问题\{\{query\}\}的答案。根据文档内容中的语句提取答案,若文档中无答案则告知用户无法回答 |
三、工作原理
- 触发条件:用户问题匹配 description 中的领域描述(如“如何煎牛排?”)。
- 知识检索:
- 系统根据 vector_store_id 定位知识库。
- 将用户问题
\{\{query\}\}嵌入为向量,检索最相关的知识片段。
- 生成答案:
- 自动将
\{\{knowledge\}\}和\{\{query\}\}填入 prompt_template。 - 模型基于模板生成最终回复(例:“根据知识库:牛排需每面煎2分钟…”)。
四、最佳实践
- 在 description 中精准描述:
"description": "仅限回答菜谱步骤、食材替代方案、烹饪时间问题,其他问题忽略检索" - 错误处理:在 prompt_template 中明确无答案时的响应,例如:“下面是检索到的结果: {{knowledge}},如果未在知识库中找到关于{{query}}的信息,请告诉用户尝试更具体的问题。”
- 避免冲突:如果你启用了内置工具的 web_search ,模型可能会尝试调用 web 搜索而不是在知识库,你可以在初始化会话时,通过 instructions 引导其优先使用知识库:
“你是一个专业烹饪助手,当用户询问菜谱、食材处理或烹饪技巧时,必须从知识库中检索答案。若知识库无相关信息,需明确告知用户。“
自定义 Tool Call
通过自定义函数调用,你可以扩展模型的能力,使其能够执行特定业务逻辑(如查询天气、生成星座运势等)。基本流程如下:- 配置函数:在会话级别定义可用函数
- 检测调用:模型根据用户输入决定是否调用函数
- 执行函数:客户端使用生成的参数执行自定义代码
- 返回结果:将函数执行结果返回给模型并获取最终响应
函数配置
通过session.update 事件的 session.tools 参数添加函数定义:
函数调用流程
1. 检测函数调用
当用户输入触发函数调用时,您将收到包含函数调用参数的对话项:2. 接收函数参数
参数生成过程中会收到增量更新事件:3. 返回函数执行结果
客户端执行函数后,需要将结果返回给模型:4. 触发模型响应
返回函数结果后,需要手动触发模型生成最终响应:完整示例:星座运势查询
1. 配置星座运势函数
2. 用户请求与函数调用
用户输入:“我的运势如何?我是水瓶座。” 模型检测到需要调用函数,返回调用参数:3. 返回函数执行结果
4. 获取最终响应
注意,函数调用和语音可能会出现在同一轮,比如如果有 get_weather 函数,模型可能会先输出:“让我先查查天气” 的口水话,然后再创建函数调用。这样的好处是,如果有比较复杂的函数调用,可以利用语音播放的时间来并行处理函数调用的生成。但是你需要注意要在语音播放完后才调用 response.create 来触发最终回复。
开发技巧
实现开场白
在某些应用场景下,你可能希望在对话开始时,模型能够主动打招呼或介绍自己。这可以通过在创建会话时,使用特殊的提示词实现:更灵活的 VAD
如果你使用 server_vad 模式,但每次 append 的音频片段较长,可能会导致系统响应延迟较高。这是因为 VAD 需要积累足够长的音频数据才能做出判断,建议以20ms 左右的间隔提交音频,以保证检测的实时性。 此外,VAD 判断用户停止说话的依据是检测到连续若干帧的空白或低音量音频。如果你提交的音频末尾没有包含足够的静音帧,VAD 可能无法准确识别语音结束点,从而导致系统未能及时触发自动回复。为避免该问题,应确保在语音段后保留一定时长的静音音频。 最佳实践建议:- 音频分段提交:尽量以小块(如 20ms~30ms)为单位频繁提交音频数据;
- 如果你用音频文件输入,务必在文件确保有一定的静音段;
网页中播放声音示例代码
为了支持流式 pcm16 的播放,你的播放逻辑需要支持多次 append 动作。另外,为了可以及时打断,最好可以实现及时清空缓冲区的功能。 这里是一份简易的示例代码,用 typescript 写成,适用于浏览器环境。错误处理
服务器在会话期间遇到错误情况时,会发出error事件。有时,这些错误可以追溯到您的应用发出的客户端事件。
与HTTP请求和响应不同(其中响应隐式关联到客户端的请求),我们需要使用客户端事件上的event_id属性来确定其中某个事件是否在服务器上触发了错误情况。下面的代码展示了这种方法,客户端尝试发出不支持的事件类型。