Open turn-taking model for voice agents
Knows when you're
done talking.
voxturn listens to the last 8 seconds of a conversation and answers the questions a voice agent actually has — finished? about to go on? just a cough? — in a single forward pass.
English eot-bench
best among open models
on one GPU
than Pipecat's default
Live replay
Same framework. Same VAD. Different turn model.
Real user turns from eot-bench, streamed through Pipecat's Silero VAD — once with Pipecat's default Smart Turn v3, once with voxturn. Press play and watch who jumps in too early.
The same forward pass also answers (voxturn, at the playhead)
How it works
A speech LLM that doesn't talk — it decides.
Questions, not labels
Every decision is a multiple-choice question for Qwen3-ASR-0.6B. No text is generated: a tiny head scores the hidden state of each option, and a softmax gives calibrated probabilities.
eotresumestate4intentinvalidOne pass, many answers
Questions sit after a shared audio prefix, each in its own block of the attention mask — so one pass equals asking them one by one. Four questions: 9.0 ms instead of 33.2 ms.
Learned from real pauses
Real phone calls and face-to-face talk, with the decision time drawn anywhere inside each pause. voxturn grows more certain as a silence goes on — so we keep asking every 250 ms and reply the moment it's sure.
eot-bench
Commercial-grade in English. Best open model in 14 languages.
False cut-offs (the agent replies while the user is only pausing) at each mean-latency budget. Lower is better. Hover the chart.
English: false cut-offs vs latency budget
Every language, 300 ms budget (open models)
Drop it in
Three lines to stop interrupting people.
from huggingface_hub import snapshot_download
import sys; sys.path.insert(0, snapshot_download("AustinXiao/voxturn-v1"))
from voxturn import VoxTurn
model = VoxTurn.from_pretrained("AustinXiao/voxturn-v1")
model.predict(audio, sample_rate=16000, questions=["eot", "resume", "invalid"])
# {'eot': {'yes': 0.93, 'no': 0.07}, 'resume': {...}, 'invalid': {...}}
from pipecat_voxturn import VoxTurnAnalyzer
from pipecat.turns.user_stop import TurnAnalyzerUserTurnStopStrategy
from pipecat.turns.user_turn_strategies import UserTurnStrategies
strategies = UserTurnStrategies(stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=VoxTurnAnalyzer())])
from livekit_voxturn import VoxTurnDetector
from livekit.agents import AgentSession
from livekit.plugins import silero
session = AgentSession(vad=silero.VAD.load(min_silence_duration=0.3),
turn_handling={"turn_detection": VoxTurnDetector()})