服务端在链路各节点打点,输出统一事件流。ts/ts_end 为相对通话起点的毫秒;瞬时事件只填 ts,区间事件加 ts_end。
{
"meta": { "session_id": "call-20260727-001", "started_at": "2026-07-27T14:30:00+08:00" },
"duration_ms": 22000,
"events": [
{ "ts": 560, "track": "vad", "type": "speech_start", "turn": 1 },
{ "ts": 500, "ts_end": 2300, "track": "vad", "type": "speech", "turn": 1 },
{ "ts": 2860, "track": "vad", "type": "speech_end", "turn": 1,
"detail": { "tail_silence_ms": 560 } },
{ "ts": 900, "track": "asr", "type": "partial", "text": "帮我查", "turn": 1 },
{ "ts": 2980, "track": "asr", "type": "final", "text": "帮我查明天去新加坡的航班", "turn": 1 },
{ "ts": 3010, "ts_end": 4650, "track": "llm", "type": "request",
"detail": { "model": "qwen-max", "prompt_tokens": 812 }, "turn": 1 },
{ "ts": 3520, "track": "llm", "type": "first_token", "turn": 1 },
{ "ts": 3730, "ts_end": 3950, "track": "tts", "type": "synthesis",
"text": "为您查到3个航班…", "turn": 1 },
{ "ts": 4020, "ts_end": 7800, "track": "bot_audio", "type": "play", "turn": 1 },
{ "ts": 13560, "track": "ctrl", "type": "barge_in", "turn": 3 }
]
}
speech(区间)、speech_start、speech_end(detail.tail_silence_ms = 尾静音判停耗时)recognizing(区间)、partial、final(附 text)request(区间 请求→生成完)、first_token、sentence(整句下发)synthesis(区间 请求→首帧音频)、first_audioplay(区间 实际播放);ctrl:barge_in、tts_cancel、turn_startsdk/duplex_trace.py(Python)/ sdk/duplex-trace.js(Node/浏览器)单文件零依赖,丢进网关即用;自动写 JSONL + 可选实时上报 collector。tools/trace_convert.py + 映射 profile,把任意系统的 JSONL/文本日志转成本格式(examples/ 有 LiveKit、自研网关两套样例)。--profile otel 转换 OTLP JSON spans。tools/trace_collector.py,事件 POST /ingest,顶部「🔌 实时」连接后通话中即可看时间轴生长。?trace=文件或URL 直接分享某次通话的分析页。完整文档见站点目录 README.md。启动采集器:python3 tools/trace_collector.py · 跑一通演示:python3 examples/simulate_call.py