ling-baseling-base

Realtime 实时对话

8 个 provider,全双工 ASR+LLM+TTS WebSocket 语音助手

在线 Playground

在浏览器中直接体验本页相关 API,无需本地安装 Go 环境。

Realtime 实时对话

voice/realtimeASR + LLM + TTS 合并为单一全双工 WebSocket 会话,适合语音助手、实时客服等低延迟场景。与 recognizer(仅 ASR)、synthesizer(仅 TTS)并列,按场景选用。

架构

voice/realtime/
├── types.go        # Agent、Options、Event、EventType
├── factory.go      # NewAgentFromCredential
├── openai/         # GPT-4o Realtime
├── gemini/         # Gemini Live
├── aliyunomni/     # 阿里云 Omni
├── volcdialogue/   # 火山对话
├── minimax/        # MiniMax
├── iflytek/        # 讯飞
├── stepfun/        # 阶跃
└── tencentsts/     # 腾讯 STS

安装

go get github.com/LingByte/ling-base/voice/realtime
go get github.com/LingByte/ling-base/voice/realtime/openai

应用入口 blank import 注册 provider:

import (
    _ "github.com/LingByte/ling-base/voice/realtime/openai"
    _ "github.com/LingByte/ling-base/voice/realtime/gemini"
)

Agent 接口

type Agent interface {
    Start(ctx context.Context) error       // 建立 WS,等待 session.ready
    PushAudio(pcm []byte) error            // 推送 PCM16LE mono 输入
    CommitInputAudio() error               // 手动结束一轮(关闭 server VAD 时用)
    Cancel() error                         // 打断当前 AI 回复(barge-in)
    Close() error                          // 关闭会话
    UpdateInstructions(instructions string) error
}

事件模型

所有事件通过 Options.OnEvent 回调(在 WS 读 goroutine 中触发,勿阻塞):

EventType说明
session.open握手完成,可开始推音频
session.close连接关闭
user.speech.started服务端 VAD 检测到用户开口 → 立即停止播放 AI 音频
user.speech.ended用户说完
user.transcript用户 ASR 文本(Final 表示本句结束)
assistant.textAI 文本片段
assistant.audioAI 音频 PCM(Event.AudioPC,24kHz 常见)
assistant.turn.endAI 一轮回复结束
error错误(Fatal=true 不可恢复)
type Event struct {
    Type    EventType
    Text    string
    Final   bool
    AudioPC []byte
    Err     error
    Fatal   bool
    Vendor  string
}

OpenAI Realtime 完整示例

package main

import (
    "context"
    "fmt"
    "os"
    "sync"

    "github.com/LingByte/ling-base/voice/realtime"
    _ "github.com/LingByte/ling-base/voice/realtime/openai"
)

func main() {
    events := make(chan realtime.Event, 64)
    var wg sync.WaitGroup

    agent, err := realtime.NewAgentFromCredential(map[string]any{
        "provider": "openai_realtime",
        "apiKey":   os.Getenv("OPENAI_API_KEY"),
        "model":    "gpt-4o-realtime-preview",
        "voice":    "alloy",
    }, realtime.Options{
        SystemPrompt:     "你是一个简洁的中文语音助手。",
        InputSampleRate:  16000,
        OutputSampleRate: 24000,
        OnEvent: func(ev realtime.Event) {
            events <- ev // 转发到 worker,避免阻塞 WS
        },
    })
    if err != nil {
        panic(err)
    }

    ctx := context.Background()
    if err := agent.Start(ctx); err != nil {
        panic(err)
    }
    defer agent.Close()

    wg.Add(1)
    go func() {
        defer wg.Done()
        for ev := range events {
            switch ev.Type {
            case realtime.EventUserTranscript:
                if ev.Final {
                    fmt.Println("用户:", ev.Text)
                }
            case realtime.EventAssistantAudio:
                playPCM(ev.AudioPC, 24000)
            case realtime.EventAssistantText:
                fmt.Print(ev.Text)
            case realtime.EventUserSpeechStarted:
                stopPlayback() // barge-in
            case realtime.EventError:
                fmt.Printf("error (fatal=%v): %v\n", ev.Fatal, ev.Err)
            }
        }
    }()

    pcm, _ := os.ReadFile("mic_chunk.pcm")
    _ = agent.PushAudio(pcm)

    wg.Wait()
}

凭证驱动工厂

租户控制面存储 JSON,NewAgentFromCredentialprovider 字段解析,调用方无需 import 具体 vendor

cfg := map[string]any{
    "provider": "gemini",           // 或 aliyun_omni, volc_dialogue, minimax, ...
    "apiKey":   "...",
    // vendor 特定字段见各子包 Config
}
agent, err := realtime.NewAgentFromCredential(cfg, opts)
// 列出已注册 slug
for _, slug := range realtime.AllProviders() {
    fmt.Println(slug)
}

支持的 Provider

Slug(示例)说明
openai_realtimerealtime/openaiGPT-4o Realtime
geminirealtime/geminiGemini Live
aliyun_omnirealtime/aliyunomni阿里云 Omni
volc_dialoguerealtime/volcdialogue火山对话
minimaxrealtime/minimaxMiniMax
iflytekrealtime/iflytek讯飞
stepfunrealtime/stepfun阶跃
tencent_stsrealtime/tencentsts腾讯 STS

各包在 init() 中调用 realtime.Register(...) 注册多个别名。

Options 配置

字段默认说明
SystemPrompt模型 instructions
Voicevendor 默认音色
InputSampleRate16000输入 PCM 采样率
OutputSampleRate24000输出 PCM 采样率
OnEvent必填事件回调
DisableServerVADfalse关闭服务端 VAD 时需手动 CommitInputAudio
Modalitiesvendor 默认输出模态 ["text","audio"]
Temperaturevendor 默认采样温度
Tools / ToolHandlerFunction calling

工具调用(Function Calling)

agent, _ := realtime.NewAgentFromCredential(cfg, realtime.Options{
    OnEvent: handleEvent,
    Tools: []realtime.Tool{
        {Name: "get_weather", Description: "查询天气", Parameters: weatherSchema},
    },
    ToolHandler: func(ctx context.Context, name string, args json.RawMessage) (string, error) {
        if name == "get_weather" {
            return `{"temp": 25}`, nil
        }
        return "", fmt.Errorf("unknown tool")
    },
})

音频契约

  • 输入:PCM16LE mono,Options.InputSampleRate(通常 16000)
  • 输出EventAssistantAudio 为 PCM16LE mono,OutputSampleRate(通常 24000)
  • 并发PushAudio 建议单 goroutine 调用;Cancel / Close 任意 goroutine 安全

生命周期

NewAgentFromCredential → Start → PushAudio (循环) → Cancel (可选) → Close

                    session.open 后才开始推流

错误

  • ErrUnknownProviderprovider 未注册或拼写错误
  • Options.OnEvent 为 nil:构造失败
  • EventError + Fatal=true:需重建 Agent

On this page