A voice assistant that can only talk is not an agent. This model listens, speaks, plans, and calls tools on a single 160 ms chunk timeline — so it can switch on your air conditioning in the middle of a sentence without going silent, stuttering, or waiting for you to finish.
You are driving. The cabin is freezing. You say, mid-conversation, without stopping the conversation: "It's too cold in here — turn up the AC, put on something relaxing, and I'm getting hungry, find me a restaurant."
A human co-driver would have already reached for the climate dial before you finished the word "cold". They would keep talking to you while they did it. They would not say "please hold" and then go quiet for two and a half seconds.
Every deployed voice assistant you have used does exactly that. And the reason is not that the language model behind it is weak. The reason is architectural: the assistant's mouth and the assistant's hands are on different clocks, and neither is on yours.
Open any production voice-assistant architecture diagram from the last decade and you will find the same four boxes in the same order. The paper names them in its first paragraph of Section 1, and it is worth drawing before we criticize it, because most of this lesson is a rebuttal to this picture:
This is called a turn-based or cascaded pipeline: each box waits for the previous box to finish a unit of work. It is easy to build, easy to debug, and every component can be swapped independently. Those are real virtues, and it is why the architecture dominates production.
It also has two structural problems in duplex spoken interaction — and the word structural is doing heavy lifting. These are not bugs you fix with a better VAD or a better LLM. They follow from the shape of the pipeline itself.
An energy-based VAD sees one number over time: how loud is the microphone right now. From that number it must decide whether the floor has been yielded. But four completely different conversational events produce nearly identical energy traces:
| What the human is doing | What the microphone shows | What the assistant should do |
|---|---|---|
| Finishing a turn — "…so what do you think?" | Speech, then silence | Answer, promptly |
| Hesitating mid-thought — "I want to go to… um…" | Speech, then silence of the same length | Stay silent. Keep listening. Do not barge in |
| Backchanneling — "mm-hmm", "you're right" | A short energy burst while the assistant is talking | Keep talking. Do not reset the answer |
| Interrupting — "you're right, but the schedule is tight…" | A short energy burst while the assistant is talking — that keeps going | Stop. Immediately. Yield the floor |
Look at the last two rows. The first 800 milliseconds are acoustically identical. "You're right." followed by silence is a backchannel; "You're right, but the project schedule is tight, I don't really have a choice" is an interruption. Nothing in the energy envelope distinguishes them at the moment you must decide. The difference is semantic, and it only exists in meaning, not in loudness.
The industry's answer has been to bolt a second model on top: a semantic VAD — typically a small classifier or an ASR-plus-LLM turn detector that reads the partial transcript and predicts whether the turn is really over. The paper's Section 1 concedes this "recovers part of this nuance", and then makes two objections that you should hold onto for the rest of the lesson:
Now the part this lesson is really about. Suppose the assistant, mid-conversation, needs to do something — raise the AC, start music, start navigation. Where in the turn loop does that tool call go?
There are exactly three options in a turn-based pipeline, and the paper's introduction dispatches all three in a single sentence. Sit with each one, because the fact that all three are bad is the entire motivation for the architecture:
| Option | What happens | Why it fails |
|---|---|---|
| A. Emit tool calls before the assistant speaks | LLM plans, calls tools, waits, then generates the spoken reply | Adds wall-clock delay to everything the user hears. The user's experience of "the assistant is thinking" is dead air, and dead air in speech is far more punishing than a slow web page. |
| B. Emit tool calls after the assistant finishes | Speak first, dispatch side-effects at the end of the turn | Delays the side-effect by a full turn. The assistant says "I've turned up the AC" and the AC turns up three seconds later — a lie that becomes true eventually. Worse for multi-second replies. |
| C. Emit tool calls mid-utterance, on the same channel that drives speech | Interleave JSON tokens with the tokens that generate audio | Breaks the spoken response. The channel that must produce a smooth 25-tokens-per-second audio stream is suddenly asked to produce {"function": "set_car_setting"… instead. The voice stutters, pauses, or garbles — exactly where the user is listening hardest. |
Option C is the interesting failure. It fails not because the model cannot produce the JSON, but because one channel cannot carry two things that both need the clock. Speech is a real-time signal: every 40 milliseconds of audio requires its token, on time, or the waveform has a hole in it. Tool-call JSON is bursty and long. Multiplexing them onto one lane means the audio starves whenever the JSON is talking.
Once you see the problem this way, the solution names itself, and the paper says so directly: what is missing is "a model that can listen, speak, think, and act on one synchronized timeline." Not one channel — one timeline, with enough channels that nothing has to starve.
Before any machinery, watch the phenomenon. The simulation below runs one user request — "It's too cold in the car, turn up the AC" — through the cascaded pipeline and through DuplexSLA, on the same wall clock, and marks the moment the AC actually changes.
Do not read the code or the architecture yet. Just watch when the orange marker lands in each lane, and notice what the assistant's voice is doing at that moment.
Press play. Top lane: the user speaks. Middle: a turn-based VAD→ASR→LLM→TTS cascade. Bottom: DuplexSLA. The diamond marks the instant the tool call is dispatched. Delay figures are the paper's measured averages on the tool-call benchmark (Table 5): cascade 2.77 s, DuplexSLA 0.64 s — roughly a 4× gap.
Three things the sim is showing you, in order of how much they should bother you:
The name is DuplexSLA: Speech, Language, Action. Plenty of systems claim two of those. The paper is explicit about what makes the third non-trivial, and this sentence is the one to memorize:
interrupt, backchannel, response) a dedicated, time-stamped textual lane co-decoded with assistant audio, instead of either competing for slots in the assistant text channel or being relegated to a post-hoc cascade." Two failure modes named and rejected in one clause — that is options C and A/B from the table above.Notice the scope: the action lane carries both tool calls and turn-taking decisions. That is a design unification most readers miss on the first pass. "Should I stop talking because the user interrupted?" and "should I call navigate()?" are, in this architecture, the same kind of event: a discrete, time-stamped decision emitted on a dedicated lane by the same backbone that is producing the voice. Interruption handling is not a special case — it is a tool call with an empty argument list.
Here is everything this lesson will explain and justify, with the paper's numbers attached, so you know what the destination looks like. Do not try to absorb it now — return to this table after Chapter 9 and check that every row means something to you:
| Quantity | Value | Chapter |
|---|---|---|
| Conversational clock (chunk size) | 160 ms | 1 |
| Per-chunk model output | 5 assistant TA4 tokens (always) + up to 10 action tokens | 1, 5 |
| Channels on the model interface | 3 (user audio, assistant TA4, action text) | 2 |
| Backbone | 7B speech-LM, initialized from Step-Audio 2 mini | 8 |
| Continued pretraining audio | ~500k hours (~320k duplex dialogue + 2×90k dual-side ASR) + ~1.92M text samples | 8 |
| Post-training audio | ~50k hours (~36k interaction control + ~14k tool call) | 8 |
| Benchmark | DuplexSLA-Bench, 2,100 cases (1,200 turn-taking + 900 tool-call) | 9 |
| Turn-taking delay (normal / pause / interrupt / backchannel) | 0.27 / 0.27 / 0.40 / 0.32 s | 9 |
| Backchannel accuracy vs best baseline | 98.33% vs 40.00% | 9 |
| Tool-call delay vs cascade (average of 3 patterns) | 0.64 s vs 2.77 s | 9 |
| Tool-call accuracy vs cascade (average) | 85.56% vs 91.33% — the honest trade | 10 |
| Tool schema coverage | 50 cabin and smart-home functions + 3 control labels | 7 |
Two rows in that table point in opposite directions, and that tension is the intellectual spine of the lesson. DuplexSLA is dramatically faster and it is slightly less accurate on tool calls. Chapter 10 refuses to paper over that; the interesting question is not "who wins" but "what did the speed cost, mechanically, and is the trade the right one for a voice interface?"
| Field | Value |
|---|---|
| Title | DuplexSLA: A Full-Duplex Spoken Language Model with Synchronized Speech, Language, and Action |
| Authors | Haoyang Zhang and Jun Chen (equal contribution), Donghang Wu, Yuxin Li, Yuxin Zhang, Xiangyu Tony Zhang, Che Liu, Qingjian Lin, Yizhou Peng, Hexin Liu, Eng Siong Chng, Chao Yan, Boyong Wu, Yechang Huang, Xuerui Yang, Fei Tian (corresponding) |
| Affiliations | StepFun; Peking University; Nanyang Technological University; Shanghai Jiao Tong University; UNSW; Imperial College London |
| Identifier | arXiv:2605.20755v2 [eess.AS], 11 June 2026 |
| Type | Systems / foundation-model technical report, with a companion benchmark |
| Artifacts | Project page, interactive demos, and the DuplexSLA-Bench evaluation suite (github.com/hyzhang24/DuplexSLA) |
One editorial note on how to read a report like this. It is not a proof-heavy theory paper — there is exactly one piece of notation in the whole thing (the chunk index) and no theorems. It is a systems paper, which means the intellectual content lives in the design decisions and the numbers that justify them. Our job in the next eleven chapters is to make every decision feel inevitable and every number feel earned.
One habit to install before Chapter 1. Every time this paper quotes a latency, convert it into chunks by dividing by 0.16. A 0.27 second delay is 1.7 chunks. A 1.18 second delay is 7.4 chunks. Once you think in chunks, the numbers stop being abstract benchmark scores and become statements about how many grid squares of hesitation the user perceives. That conversion is the single most useful reading aid in this lesson, and it is why the next chapter is entirely about the clock.
The term is borrowed from telephony, where a full-duplex line carries audio in both directions simultaneously, as opposed to a half-duplex walkie-talkie where one party transmits at a time. Applied to spoken dialogue models, the paper's abstract gives the operational definition: a full-duplex design is one "where the model continuously listens to the user while generating responses."
Read that carefully. Continuously listens — not "listens, then generates, then listens again." At every instant, the model is consuming user audio and producing assistant audio. There is no moment where the microphone is logically closed.
backchannel label: the model noticed something and chose to keep talking. A cancel-on-energy system cannot express "I heard you and I am deliberately continuing."This distinction is worth a moment because it explains a result you will meet in Chapter 9 that otherwise looks like a typo. On the backchannel scenario, one commercial system scores 0.33% and another 13.00%. Those are not broken systems; they are systems whose architecture has no way to represent "acknowledged, continuing." Every short user utterance is either ignored entirely or treated as a turn. The label does not exist, so the behavior cannot exist.
DuplexSLA does not appear from nowhere. Its introduction sketches three converging lines of work, and knowing the shape of each will make Chapter 3 much easier:
| Line of work | What it established | What it left open |
|---|---|---|
| Native full-duplex speech models (the paper cites fourteen, including Moshi, Freeze-Omni, SALMONN-omni, Mini-Omni, LLaMA-Omni, OmniFlatten, SpiRit-LM, Voila, PersonaPlex) | That one backbone can learn to listen and speak inside a single model, with the two audio streams modelled jointly | No native lane for planning or tool calls — agentic behaviour stays tied to turn boundaries or an external cascade |
| Chunk-aligned reasoning (Chronological Thinking; Mind-Paced Speaking; The Silent Thought) | That a model can think on the same timeline as its audio — internal cognition that does not stop the voice | Thinking is not acting: an internal rationale has no schema, no arguments, and no dispatchable side-effect |
| Audio-aware foundation models (Qwen2-Audio, Qwen3-Omni, GLM-4-Voice, Step-Audio 2, VITA, MiniCPM-o…) | Strong general audio understanding and instruction following, with LLM-grade world knowledge | Mostly turn-based; the duplex clock is bolted on afterwards, if at all |
DuplexSLA sits precisely at the intersection: it takes a strong audio foundation model (Step-Audio 2 mini, 7B), puts it on a duplex clock, and then adds the thing none of the three lines had — a rate-limited textual lane for actions, co-decoded with the voice. The paper's own framing of its novelty is careful and worth quoting: "We focus on a combination that existing duplex backbones and benchmarks do not jointly stress: semantic-driven turn-taking control plus in-conversation tool calling."
The word jointly matters. Turn-taking benchmarks exist. Tool-calling benchmarks exist. Nothing measured them on the same timeline, which is why Section 5 has to build a new benchmark before it can report a result.
Let us do the conversion habit once, together, on the headline numbers, so that the rest of the lesson can lean on it. One chunk is 0.16 s. Divide:
Now stare at that last pair. DuplexSLA answers within roughly one and a half to two chunks of the moment the user's turn ends. Since the model can only act at chunk boundaries, and a semantic anchor lands uniformly at random inside a chunk, even a hypothetical perfect model pays an expected half-chunk (80 ms) of quantization latency before it can do anything at all. DuplexSLA's 270 ms is therefore not "fast for a neural system" — it is within about 190 ms of the architectural floor imposed by its own clock.
Figure 1 of the paper is a chunk-level architecture diagram, and its worked example is the one we will keep returning to. The user, sweating, says: "The heat is killing me! I feel like I'm going to get heatstroke." Here is what the three lanes carry, aligned on the same clock:
<|toolcall_begin|>{"function": "decrease_car_setting", "arguments": "air-conditioner: 26 degree"}<|toolcall_end|> then <action_end>. At most ten tokens in any single chunk.Four observations that will each become a chapter:
decrease_car_setting with argument "air-conditioner: 26 degree" — the user is hot, so the AC temperature setting goes down. A small detail that reveals the schema is about setting values, not about comfort semantics.It is worth being blunt about the deployment target, because it explains several design choices that look arbitrary in the abstract. All 50 tool schemas in this paper are cabin and smart-home functions: climate, windows, seats, navigation, media, on-device search, phone calls. The training data is Chinese-language dialogue synthesized with 18 voice-clone speakers. The examples are people who are cold, hungry, or heading somewhere.
Why is this a good laboratory rather than a limitation to apologize for? Because the in-car setting is the environment where the failure modes of turn-based voice hurt most:
| Property of the setting | Consequence for the architecture |
|---|---|
| The user's hands and eyes are busy | Voice is not a convenience layer, it is the only interface. A two-second dead-air gap is not a small annoyance; it is the whole product. |
| Requests are naturally multi-intent | "Turn up the AC, put on music, find a restaurant" in one breath is normal speech, not an edge case — and it is exactly the pattern where the cascade's delay balloons to 4.71 s. |
| The environment is noisy and conversational | Energy-based endpointing is at its worst. Semantic turn-taking is at its most valuable. |
| Side-effects are physical and immediate | "The AC is now warmer" is verifiable by the user's skin within seconds. Latency between claim and effect is felt, not merely measured. |
Keep this in mind, and Chapter 10's scope discussion will land properly: the cabin is where the argument is strongest, which is both why the results are convincing and why we should be careful about extrapolating them to open-domain agentic tool use.
Four notes on method, because a systems paper rewards a particular reading posture:
Good. Here are the five most common ones, with where each is answered:
| Objection | Short answer | Full treatment |
|---|---|---|
| "Just make the cascade faster — better endpointing, faster ASR, a smaller LLM." | You can shave the constants, but you cannot fire a tool call before the endpoint, because the ASR final hypothesis is gated on it. The structural bound stays. | Ch 4, multi-action |
| "Streaming ASR gives partial transcripts — feed those to the LLM continuously." | Now you have re-invented a duplex model with worse coupling: the LLM still cannot see the assistant's state, and you pay a full LLM forward pass per partial. | Ch 3 |
| "A 7B model doing four jobs will be worse at all of them than four specialists." | Partly true, and the paper's own numbers show it — the cascade wins on tool-call accuracy. The question is what the latency is worth. | Ch 10 |
| "Ten tokens per chunk is nothing. You cannot plan in ten tokens." | You do not have to. Tokens spill across chunks; the budget bounds the rate, not the total. | Ch 5 |
| "This only works because it is a car with fifty buttons." | Largely fair as a scope limit, and the paper's conclusion says as much. | Ch 10 |
The bar for this lesson, stated as capabilities rather than topics. After Chapter 11 you should be able to:
One last framing note before the clock. Throughout this lesson, "action" means something narrower and sharper than in agent literature generally. An action here is an object emitted on a textual lane at a specific chunk index: a name, optional planning text, optional JSON arguments, and a trigger offset. It is not a plan, not a policy, not a rollout. Its entire ambition is to be the right object at the right millisecond — and, as we will see, that ambition turns out to be enough to make voice feel agentic.
The problem statement, compressed. Two structural failures of the turn-based pipeline, and what each one costs:
| Failure | Root cause | Cost, measured | Fixed in Ch |
|---|---|---|---|
| Silence is ambiguous | An energy VAD sees loudness, not meaning; hesitation, backchannel, and interruption share an envelope | Baselines score 63.67–79.00% on interrupt and 0.33–40.00% on backchannel | 6 |
| Semantic VAD is external | Another chain to run, and it cannot see the assistant's state | 1.57–1.68 s response delay in the semantic-VAD configuration | 2, 6 |
| No place for a tool call | Before speech delays the voice; after speech delays the effect; inside the speech channel breaks the audio | 2.33–4.71 s tool-call delay | 2, 4, 5 |
| No clock | The pipeline is event-driven, so latency is emergent rather than designed | — | 1 |
If you remember one thing: a voice agent's mouth and hands are on different clocks, and putting them on the same one is an architectural change, not an optimization.
Three exercises before Chapter 1:
A language model has no idea what time it is. It has an order — token 1, token 2, token 3 — and nothing else. Order is not time. A transformer will happily spend a hundred milliseconds on one token and a microsecond on the next, and nothing in the architecture notices or cares.
Speech does care. Air pressure has to arrive on schedule. If the assistant's waveform needs a sample at t = 3.240 s and the model has not produced it, the user hears a hole. There is no "buffer more" escape hatch in a conversation, because buffering is latency and latency is the thing we are trying to kill.
So the first thing a full-duplex spoken language model must do is nail token order to wall-clock time. That nail is the conversational clock, and in DuplexSLA it ticks every 160 milliseconds.
That is the paper's entire notation. Time t in seconds; chunk index c as the floor of t divided by the chunk size. Everything else in this paper is a statement about what happens inside chunk c.
Concretely: chunk 0 covers [0.00, 0.16) seconds. Chunk 1 covers [0.16, 0.32). Chunk 37 covers [5.92, 6.08). An event at t = 4.31 s belongs to chunk 26, because 4.31 / 0.16 = 26.9 and the floor of that is 26. Do that conversion three times by hand right now; the rest of the lesson assumes it is automatic.
At every chunk, the model receives one user audio segment and one assistant audio segment, and produces two outputs: an assistant audio segment and an action segment, both indexed by the same c. Here is the full inventory, straight from Section 2.1:
| Channel | Per chunk | Stride | Produced by the model? |
|---|---|---|---|
| User | 2 continuous causal audio features | 80 ms each | No — observed only, never generated |
| Assistant | 1 text anchor T + 4 discrete audio tokens A (the TA4 layout) | 40 ms per audio token | Yes — always, every chunk, no exceptions |
| Action | Up to 10 text tokens, possibly zero | No stride — text, not signal | Yes — rate-limited |
Check the arithmetic yourself, because the number 160 is not arbitrary — it is the number that makes the three granularities line up:
The chunk is the smallest window in which every stream completes a whole number of its own units. Choose 120 ms and the user features (80 ms apart) no longer tile it. Choose 100 ms and neither stream tiles it. The clock is the least common multiple of the physical rates the model is built on, and everything else — the action budget, the latency floor, the benchmark's delay resolution — is downstream of that choice.
Convert everything to per-second quantities, because that is the unit in which hardware is specified:
| Quantity | Per chunk | Per second (÷ 0.16) |
|---|---|---|
| Chunks | 1 | 6.25 Hz |
| User audio features consumed | 2 | 12.5 features/s |
| Assistant audio tokens produced | 4 | 25 tokens/s |
| Assistant text anchors produced | 1 | 6.25 anchors/s |
| TA4 total (always paid) | 5 | 31.25 tokens/s |
| Action tokens (maximum) | 10 | 62.5 tokens/s |
| Model output, worst case | 15 | 93.75 tokens/s |
Appendix D states the middle rows as a serving fact: "Per-chunk model output: 5 assistant TA4 tokens (always) plus up to 10 action text tokens." The words always and up to are the whole story. The voice is a floor; the actions are a ceiling.
Real-time full-duplex interaction requires the per-chunk decoding cost to fit inside one 160 ms chunk on the actual inference hardware. Let us make that requirement quantitative, by hand, with every intermediate step. This is the arithmetic that determines the number 10.
Setup. Let N be the number of tokens the model must autoregressively decode in one chunk, and let ttok be the wall-clock time to decode one token on your accelerator. Define the real-time factor:
The system is real-time capable exactly when RTF ≤ 1. Now push numbers through it.
Step 1 — the floor. The TA4 unit is unconditional: 5 tokens every chunk whether the assistant is speaking or silent (silence still needs its anchor and its four silence audio codes). So N ≥ 5 always.
Step 2 — the ceiling. Add the action channel's maximum:
Step 3 — the per-token time this allows. Set RTF = 1 and solve for ttok:
Equivalently, the decoder must sustain 1000 / 10.667 = 93.75 tokens per second of autoregressive throughput, sustained, with no gaps.
Step 4 — what happens if you miss. Suppose your accelerator decodes at 12 ms per token. Then:
Read that last line again. A 12.5% overshoot on token latency does not degrade quality by 12.5%. It makes the assistant fall progressively further behind, one fifth of a second for every second of talking, until the conversation is unusable. Real-time systems do not degrade gracefully; they diverge. This is why the budget has to be a hard cap rather than a soft preference.
Step 5 — solve for the action budget. Turn the equation around. Given a measured ttok, how many action tokens can you afford?
| Measured ttok | Total token budget Δ/ttok | Action budget (minus TA4) | Verdict at cap 10 |
|---|---|---|---|
| 8 ms | 20.0 | 15 | Comfortable — 5 tokens of headroom |
| 10 ms | 16.0 | 11 | Fits, 1 token of margin |
| 10.67 ms | 15.0 | 10 | Exactly at the cap, zero margin |
| 12 ms | 13.3 | 8 | Cap of 10 is unsafe — retune to 8 |
| 16 ms | 10.0 | 5 | Half the action bandwidth |
| 32 ms | 5.0 | 0 | Voice only. No actions are affordable at all |
That last row is the sobering one and it is worth stating as a principle: on slow enough hardware, the action channel simply cannot exist. The third letter of "SLA" is purchased with decoding throughput. This is not a metaphor — it is the literal accounting the paper does in Section 2.3, which says the throughput of a 7B backbone "leaves room for only a small number of action-channel tokens per chunk", and settles on 10 "with a safe margin against the per-chunk wall-clock budget."
python — the budget, as code def action_budget(chunk_ms=160, tok_ms=10.0, ta_tokens=5, margin=1): """How many action tokens per chunk can this accelerator afford?""" total = int(chunk_ms / tok_ms) # tokens we can decode in one chunk return max(0, total - ta_tokens - margin) action_budget(tok_ms=10.0) # -> 10 (the paper's setting) action_budget(tok_ms=12.0) # -> 7 (retune down, no retraining needed) action_budget(tok_ms=6.0) # -> 20 (spend it on longer planning text)
Here is a consequence of having a clock at all, which the paper does not spell out but which its numbers quietly respect.
A semantic event — the moment the user's request becomes clear, the moment an interruption really starts — happens at some continuous time t★. The model can only act at a chunk boundary. So the earliest possible response time is the end of the chunk containing t★:
So a perfect model on this clock averages 80 ms of unavoidable delay. Now compare with the measured numbers from Chapter 9: DuplexSLA's normal-turn delay is 270 ms and its interrupt delay 400 ms. Subtract the floor:
Two chunks to recognize a semantic interruption and switch the voice to silence. That is the actual claim hidden inside "0.40 s", and it is a much more impressive number when you strip out the clock's own contribution.
The obvious next thought: if 160 ms costs 80 ms of average quantization latency, why not use 80 ms chunks? Work it through — this is a derivation the paper does not do, so treat it as our extension of its accounting, not as its claim.
At Δ = 80 ms, the assistant channel would carry 2 audio tokens (still 40 ms each) plus its anchor, so a "TA2" unit of 3 tokens. The user channel would carry 1 feature. The per-chunk decode budget scales down with the chunk:
| Δ | Audio tokens | TA unit size | Budget at 10 ms/token | Action tokens affordable | Action tokens per second |
|---|---|---|---|---|---|
| 320 ms | 8 | 9 | 32 | 23 | 71.9 |
| 160 ms | 4 | 5 | 16 | 11 | 68.8 |
| 80 ms | 2 | 3 | 8 | 5 | 62.5 |
| 40 ms | 1 | 2 | 4 | 2 | 50.0 |
Notice what the last column does: action bandwidth per second falls as chunks shrink, even though the audio rate is unchanged. The reason is fixed overhead. Every chunk pays for its text anchor and its boundary markers regardless of length, so shrinking the chunk raises the fraction of the budget spent on framing rather than content. Halve the chunk and you halve the quantization latency, but you also squeeze the lane that carries the tool calls — and, at 40 ms, you can no longer fit even a short JSON fragment inside a single chunk.
160 ms is the compromise: fast enough that the quantization floor (80 ms average) is below human turn-taking sensitivity, slow enough that ten action tokens fit alongside the voice. That is the whole justification, and now you can reproduce it from first principles.
Drag the chunk size and the per-token decode time. The bar shows one chunk of wall clock: the TA unit is paid first (always), the action budget takes what is left, and the red zone is overshoot. Watch RTF, the drift-per-second, and the latency floor move together. The paper's operating point is 160 ms with a 10-token action cap.
Things to try, in order. (1) Start at the paper setting and push the token time up until the bar turns red — note that it happens at 10.67 ms, exactly where the Step 3 arithmetic said it would. (2) Set the chunk to 40 ms and watch the action budget collapse to a couple of tokens while the latency floor drops to 20 ms — the trade made visible. (3) Set the chunk to 320 ms and notice you can afford twenty-three action tokens but the user now waits 160 ms on average before anything can happen. Somewhere in the middle is a product decision, and 160 ms is the paper's.
Here is a design decision that looks wasteful and is not. Section 2.2 says: "Whenever the chunk has nothing to say, T is predicted as a special anchor token (<vad_silence> or <tts_pad>) and the four A tokens are predicted as the corresponding silence audio codes."
So a silent chunk costs five tokens, the same as a speaking chunk. Over a ten-minute conversation:
Why pay for silence? Three reasons, each of which becomes visible later:
<vad_silence> is a choice, scored by the loss, conditioned on everything the user is currently doing. That is precisely what lets Chapter 6's pause behaviour exist: the model actively decides to keep quiet while the user hesitates, rather than passively not being invoked.Two distinct silence anchors are worth distinguishing now, because they mean different things. <vad_silence> is "there is nothing to say here" — the assistant is genuinely not speaking. <tts_pad> is "the text has run out but the audio has not" — the text anchors for an utterance were consumed earlier than the audio that renders them, and the remaining chunks pad the anchor slot while the audio tokens finish. You will see both in the appendix traces in Chapter 2, and the difference will matter in Chapter 7 when we ask why assistant-side ASR is necessary at all.
Let us practise the conversion on a concrete scenario — the multi-intent request from Figure 3b. Suppose the user says, starting at t = 0:
"It's too cold in the car [1.9 s], turn up the AC [3.1 s], play some relaxing music [4.6 s]. I'm feeling a bit hungry now, please navigate to a nearby restaurant [8.2 s]."
The bracketed times are the moments each intent becomes semantically unambiguous — the semantic trigger offsets that Chapter 7 will show are exactly what the data pipeline annotates. Convert each to a chunk index:
| Event | t (s) | t / 0.16 | Chunk c = floor | Chunk window |
|---|---|---|---|---|
| Complaint is clear ("too cold") | 1.9 | 11.875 | 11 | [1.76, 1.92) |
| AC intent clear | 3.1 | 19.375 | 19 | [3.04, 3.20) |
| Music intent clear | 4.6 | 28.750 | 28 | [4.48, 4.64) |
| Navigation intent clear | 8.2 | 51.250 | 51 | [8.16, 8.32) |
| User finishes speaking | 8.6 | 53.750 | 53 | [8.48, 8.64) |
Now the punchline of the whole architecture, expressed purely in this table. A cascaded system cannot emit any of these tool calls before chunk 53 — the endpoint — and in practice fires several chunks after that, once ASR finalizes and the LLM plans. DuplexSLA can emit the AC call at chunk 19, the music call at chunk 28, and the navigation call at chunk 51: 34 chunks (5.4 s), 25 chunks (4.0 s), and 2 chunks (0.3 s) earlier respectively, all while the assistant's voice is doing something else entirely.
That is where the paper's 4.71 s versus 0.68 s multi-action delay comes from. It is not a better model being faster; it is an architecture that is allowed to act before the sentence ends.
Everything downstream of this chapter is a statement about chunks, so here is the forward index:
| Chapter | What the clock does there |
|---|---|
| 2 | The chunk is terminated by an explicit <|action_end|> token — the grid is enforced in the token stream, not by a timer |
| 5 | Action objects that overflow 10 tokens spill into the next chunk; the trigger time stays anchored to the first |
| 6 | "Switches the assistant TA4 to silence within a small number of chunks" is the paper's own unit for interruption latency |
| 7 | Annotated semantic trigger offsets are snapped to a chunk index at training time — the label itself is quantized |
| 9 | The evaluation protocol streams test audio in 160 ms chunks and timestamps events as tk = 0.16 k |
Cover the right-hand column and work each one. Every number in the rest of the lesson is one of these five operations.
| # | Question | Answer |
|---|---|---|
| 1 | An event at t = 6.55 s belongs to which chunk? | 6.55 / 0.16 = 40.9 → chunk 40, window [6.40, 6.56) |
| 2 | Chunk 87 covers what time range? | 87 × 0.16 = 13.92 → [13.92, 14.08) s |
| 3 | A measured delay of 1.02 s is how many chunks? | 1.02 / 0.16 = 6.4 chunks |
| 4 | How many assistant audio tokens in 4 seconds of speech? | 4 × 25 = 100 tokens (or 25 chunks × 4) |
| 5 | An action object of 52 tokens takes how long to transmit at the paper's budget? | ⌈52/10⌉ = 6 chunks = 960 ms |
If question 5 surprised you — nearly a full second to clock out one tool call — hold that reaction. It is the subject of Chapter 5, and the resolution (the trigger time is the first token, not the last) is one of the more elegant details in the design.
There are actually three notions of time floating around this system, and keeping them apart prevents most confusion later:
| Clock | Ticks on | Who guarantees it | What breaks if it slips |
|---|---|---|---|
| Conversational clock | Chunk boundaries, every 160 ms of content | The serialization — one <|action_end|> per chunk | Nothing, internally: token position is still a valid index. But it no longer maps to reality |
| Wall clock | Real time, in the room, where the user is | Physics | — |
| Token clock | One decode step at a time | The accelerator | If N×ttok > Δ, the conversational clock drifts away from the wall clock — and the gap never closes on its own |
The RTF calculation above is precisely the statement "the token clock must be able to keep the conversational clock synchronized with the wall clock." When people say a duplex model is "real-time", that equation is what they mean, whether or not they can write it down.
One practical corollary: a single slow step — a garbage collection pause, a scheduling hiccup, a cold cache — is not recoverable by running fast afterwards, because there is no buffer to catch up into. The audio for chunk c was needed at time 0.16 c and that moment has passed. Real-time speech systems therefore care about tail latency, not mean latency, in a way that batch inference never does. The paper's phrase "with a safe margin against the per-chunk wall-clock budget" is doing exactly this work: the margin is there to absorb the tail.
A short honesty note, so the chapter does not oversell its own idea. Having a clock guarantees that events are indexed consistently. It does not guarantee that they are indexed correctly. A model can emit a perfectly well-formed action token at chunk 40 when the intent actually became clear at chunk 26 — the format is satisfied, the timing is wrong, and nothing in the serialization will notice.
Correct timing has to come from supervision, which is why Chapter 7's dual-side ASR slices exist and why Chapter 9's benchmark scores trigger time as a correctness criterion. The clock is the coordinate system. Learning where things go in it is a separate problem, and it is the harder one.
One closing thought to carry into Chapter 2. The clock is what makes the phrase "synchronized speech, language, and action" mean something checkable rather than aspirational. Two events are synchronized here in a precise sense: they carry the same chunk index, and therefore they were produced in the same autoregressive step, conditioned on the same context, and they will be executed against the same 160 ms window of the world. That is a much stronger notion of synchrony than "both happened around the same time", and it is what a shared clock buys.
We have a clock. Now we need to decide what the model actually sees and produces at each tick — and, crucially, in what order, because a transformer consumes a single flat sequence and nothing else. There are no parallel tapes inside an autoregressive decoder. Whatever "three channels on one timeline" means, it has to be expressible as one string of tokens.
This chapter builds that string, token by token, until you could write it out from memory.
The paper's name for the design is a mouthful with a precise meaning:
Unpack the two halves.
Two physical streams. In the world, there are exactly two sounds: the user's voice and the assistant's voice. A microphone captures one; a speaker plays the other. This is the "dual-stream" formulation inherited from earlier full-duplex models — the model conditions on both simultaneously instead of alternating.
Three semantic channels. On the model's interface, however, there are three things to represent, because the assistant's timeline carries two different kinds of content: the audio it is emitting, and the decisions it is making. The action channel is text-only. It has no waveform. It does not play through a speaker. It rides on the assistant's timeline as a parallel annotation.
| User channel | Assistant channel | Action channel | |
|---|---|---|---|
| Physical? | Yes — sound in the room | Yes — sound in the room | No — text only |
| Representation | Continuous features (2 per chunk, 80 ms stride) | Discrete tokens (TA4: 1 text anchor + 4 audio) | Discrete text tokens (≤10 per chunk) |
| Direction | Input only | Output (and fed back as input) | Output (and fed back as input) |
| Supervised in training? | No — observed only | Yes | Yes |
| Rate discipline | Fixed by the encoder | Fixed, always paid | Capped, may be empty |
| Consumer | The model | The speaker, and the user's ears | The host application — and the evaluation harness |
That last row deserves attention. The action channel's consumer is not the user. Nobody hears it. It exists to be read by the software around the model — the thing that actually turns the AC dial — and, as Chapter 9 shows, by the benchmark harness, which reads backchannel labels directly off the lane even when there is no audible change at all. A channel whose output no human perceives is a strange object in a speech model, and it is the single most important structural idea in this paper.
Note an asymmetry that is easy to skim past. The assistant's audio is discrete tokens; the user's audio is continuous features. Why not tokenize both?
Because they are used for different things. The assistant's audio must be generated, and generation from an autoregressive language model requires a finite vocabulary — you cannot sample a real-valued waveform from a softmax. The user's audio only needs to be understood, and for understanding, discretization is pure loss: quantizing to a codebook throws away prosody, hesitation cues, and the fine acoustic detail that distinguishes "you're right." (agreeing) from "you're right," (about to object).
So the design keeps the user side continuous. Appendix D adds the constraint that matters for latency: "User audio is encoded by a causal speech front end; no future user audio is required to advance one chunk." Causal means the encoder for chunk c looks only at audio up to the end of chunk c. No lookahead, no bidirectional attention over the utterance, no waiting for the next 200 ms to disambiguate.
TA4 is the paper's name for the per-chunk assistant unit: one text anchor T followed by four audio tokens A. Written out, the assistant stream looks like this across chunks:
Three questions, answered in order.
What is the text anchor for? It carries the word the assistant is saying — a text token, interleaved with the audio tokens that render it. This is the "text-guided speech generation" pattern that runs through modern speech LMs: generating text alongside audio keeps the model's language ability engaged and gives the audio something semantically stable to hang on. Without it, an audio-only decoder drifts into fluent nonsense.
What are the audio tokens? Discrete speech units, four per chunk at 40 ms each, produced by the backbone and rendered to a waveform by the codec's decoder. Four tokens at 40 ms is 25 tokens per second of audio — the rate the whole clock was built around.
Why one anchor and four audio tokens, rather than a matched number? Because text and speech run at different natural rates. A Chinese character or an English word takes rather more than 40 ms to say. One anchor per 160 ms is roughly a comfortable speaking rate of about six units per second; the audio needs 25 tokens per second to reconstruct. The ratio 1:4 is the paper's chosen alignment between those two rates, and it is exactly why the timing of the text is imprecise — a point that will detonate in Chapter 7.
Now the string. Within a chunk, the three channels are interleaved into a single token stream consumed by the backbone. Section 2.2 gives it as:
the per-chunk serialization
<|user_audio_begin|> U U <|user_audio_end|>
<|assistant_audio_begin|> T A A A A <|assistant_audio_end|>
<action text> <|action_end|>
Read it as one flat sequence, left to right, top to bottom. That is literally the order the tokens arrive in. Walk through it:
| # | Token(s) | Role | Model produces it? |
|---|---|---|---|
| 1 | <|user_audio_begin|> | Frame marker: the next items are user features | No |
| 2–3 | U U | Two causal user audio features for this chunk | No — injected from the encoder |
| 4 | <|user_audio_end|> | Frame marker: user segment closed | No |
| 5 | <|assistant_audio_begin|> | Frame marker: the assistant unit starts | No |
| 6 | T | Text anchor — a word, or <vad_silence>, or <tts_pad> | Yes |
| 7–10 | A A A A | Four discrete audio tokens (or silence codes) | Yes |
| 11 | <|assistant_audio_end|> | Frame marker: assistant unit closed | No |
| 12… | action text (0 to 10 tokens) | Planning text, control labels, tool-call JSON — or nothing | Yes |
| last | <|action_end|> | Chunk terminator — emitted whether or not any action text was produced | Yes |
Two properties of this ordering are load-bearing, and both are easy to miss.
The user segment comes first. Within chunk c, the model sees this chunk's user audio before it must produce this chunk's assistant audio and action text. That is what makes the reaction latency as low as it is: the response to what you just said is conditioned on what you just said, in the same tick, not one tick later.
The action text comes last. The assistant's TA4 unit is decoded before the action segment. So the model has already committed to this chunk's audio when it writes the action tokens. This ordering is why a long action burst cannot starve the voice: the voice is already paid for. Reverse the order and the failure mode of option C from Chapter 0 comes right back.
One token deserves its own section: <|action_end|>. The paper is emphatic: it "terminates the chunk regardless of whether any action text was emitted, which keeps every chunk strictly aligned to the 160 ms clock."
Think about what would happen without it. The action segment is variable length — sometimes zero tokens, sometimes ten. If nothing marked its end, the decoder would have no way to know whether the next token it sees is more action text or the start of the next chunk's user segment. The sequence would become ambiguous, and the alignment between token position and wall-clock time — the entire premise of Chapter 1 — would dissolve.
So the terminator is what turns a variable-length text lane into a fixed-rate lane. Every chunk emits exactly one <|action_end|>, at 6.25 Hz, forever. It is a heartbeat.
This also means the empty case is explicit. A chunk with nothing to do looks like:
a completely idle chunk
<|user_audio_begin|> U U <|user_audio_end|>
<|assistant_audio_begin|> T(<vad_silence>) A A A A <|assistant_audio_end|>
<|action_end|>
Eleven tokens, no content, still fully specified. The model is silent, listening, and has decided not to act — and every one of those decisions was made explicitly, scored by the loss, and time-stamped. In a cascaded pipeline, the equivalent moment is nothing happening, which is not a decision anyone can supervise or measure.
Section 2.2 lists a small set of structured markers alongside free text. The full vocabulary of the lane:
| Content type | Form | Purpose |
|---|---|---|
| Planning text | Free-form natural language, kept short | A short rationale fragment: "The user feels cold, I should turn on the air conditioning." |
| Turn-taking labels | response / interrupt / backchannel | The VAD-like decisions, made natively (Chapter 6) |
| Tool call | <|toolcall_begin|>{"function": …, "arguments": …}<|toolcall_end|> | A named function with structured arguments |
| Delayed transcript text | Plain text, lagged by a fixed number of chunks | ASR supervision for both sides (Chapter 7) |
| Nothing | (empty, followed by the terminator) | The common case |
The canonical abstract form for a chunk carrying planning plus one call, exactly as the paper writes it:
one action segment, abstract form planning<|toolcall_begin|>{"function": "function_name", "arguments": "arguments"}<|toolcall_end|>
And the concrete instance from Figure 1, which we met in Chapter 0:
the heatstroke example, action lane The user is feeling hot, so I should switch on the air conditioning and set it to a nice temperature. <|toolcall_begin|>{"function": "decrease_car_setting", "arguments": "air-conditioner: 26 degree"}<|toolcall_end|> <action_end>
Count the tokens in that block and you will immediately see the problem Chapter 5 solves: it is far more than ten. The action lane's per-chunk cap means this single object cannot fit in the chunk that triggered it. That is not a bug; it is the reason the FIFO spill rule exists.
Here is the payoff of putting the action lane on the same grid, and it is the sentence to underline in Section 2.2:
No separate timing model. No alignment step. No timestamp prediction head. The chunk index is the timestamp, because the serialization guarantees that the n-th <|action_end|> in the stream occurs at time 0.16 n. Reading a time off this model costs a count.
Section 2.6 explains why this matters twice over: the timestamp is "needed both for downstream execution and for the latency-oriented evaluation in Section 5." Downstream execution needs it because a car that receives "turn up the AC" wants to know whether that instruction is current or three seconds stale. Evaluation needs it because the entire benchmark in Chapter 9 is built on comparing realized action times to annotated semantic anchors — and you cannot compute that difference without a clock on both sides.
Pick what this chunk should contain and watch the exact token stream assemble in order, with the running token count and the real-time budget bar from Chapter 1. Notice that the frame markers and the TA4 unit are present in every single configuration — including the idle one.
Two things to check in the sim. First, cycle from "idle" to "speaking" and confirm that the token count of the assistant channel does not change — silence is not cheaper. Second, select "tool call" and watch the action lane blow past the 10-token cap and turn red: the surplus is what spills into the next chunk under the rule we derive in Chapter 5.
Appendix A of the paper gives chunk-by-chunk traces of actual training samples, and reading one is the fastest way to make the format concrete. Here is the user-channel ASR trace from Appendix A.1, transcribed into a table. The user says 今天天气很好 ("the weather is nice today"); the assistant is silent for most of it and then begins to reply.
| Chunk | t (s) | User audio | Assistant TA4 anchor | Action segment |
|---|---|---|---|---|
| 0 | 0.00 | 今天 ("today") | <vad_silence> | — |
| 1 | 0.16 | 天气很 ("weather very") | <vad_silence> | — |
| 2 | 0.32 | 好 ("good") | <vad_silence> | 今天 |
| 3 | 0.48 | — | <vad_silence> | 天气很 |
| 4 | 0.64 | — | 确 (assistant starts speaking) | 好 |
| 5 | 0.80 | — | 实 | — |
| 6 | 0.96 | — | <tts_pad> | — |
| 7–8 | 1.12+ | — | <vad_silence> | — |
Four things this trace teaches that no prose description can:
<vad_silence>. This is what most of a conversation looks like from the assistant's side, and the model is being explicitly supervised on all of it.<tts_pad> — the text has run out mid-utterance while the audio finishes rendering — while chunks 7 and 8 are <vad_silence>, genuine "not speaking". The model must learn the difference, because one means "I am still talking" and the other means "I have stopped."Do the same conversion in reverse as an exercise. If you saw an action segment appear at chunk 17, what user audio produced it? Chunk 15, at t = 2.40 s to 2.56 s. That inference — from lane position to source time — is exactly what the evaluation harness in Chapter 9 does, and it is only possible because every lane shares one index.
To feel the budget pressure that motivates Chapter 5, count what a tool call actually costs. Take the Figure 1 example and break it into rough token groups (exact counts are tokenizer-dependent; the shape is what matters):
| Fragment | Approx. tokens | Chunks at 10/chunk |
|---|---|---|
| Planning: "The user is feeling hot, so I should switch on the air conditioning and set it to a nice temperature." | ~20 | 2 |
<|toolcall_begin|> | 1 | — |
{"function": "decrease_car_setting", | ~8 | ~1 |
"arguments": "air-conditioner: 26 degree"} | ~10 | 1 |
<|toolcall_end|> + <action_end|> | 2 | — |
| Total | ~41 | ~5 chunks = ~800 ms |
So a single complete action object takes roughly five chunks — nearly a second of clock — to transmit through a 10-token pipe. And yet the paper reports a tool-call delay of 0.64 seconds on average. How can the delay be shorter than the transmission?
Because the trigger time is the time of the first token, not the last. Appendix D states it exactly: "tool-call closing markers can land in a later chunk than the opening marker, but the trigger time of the action object is always anchored to the chunk where the planning text starts." The action is timestamped at its birth. Its body arrives over the following chunks like a message over a serial line — and, critically, the assistant's voice keeps flowing the entire time, because the TA4 unit was already paid for in every one of those chunks.
The paper's comparison sentence deserves a table, because "compared with backbones that work with two streams only" is doing a lot of work in one clause:
| Two-stream duplex backbone | DuplexSLA's three channels | |
|---|---|---|
| Where does planning text go? | Interleaved with assistant text, or nowhere | Dedicated lane, time-stamped |
| Where does a tool call go? | Assistant text channel (breaks audio) or an external cascade (breaks timing) | Dedicated lane, atomic JSON block |
| Where does "the user interrupted" live? | Implicitly, as the model switching to silence — unlabelled and unreadable | Explicitly, as an interrupt label with a chunk index |
| Can an evaluator read a decision with no audible effect? | No — only audio-derived events exist | Yes — this is why backchannel delay is measurable at all |
| Cost | Zero extra tokens | ≤10 tokens per chunk |
The fourth row is quietly the most consequential and reappears in Chapter 9's Table 6, where the backchannel delay column reads N/A for every closed-source baseline. Not "worse" — not measurable. If a system's only output is audio, then a decision that produces no audible change produces no observable event, and the metric has nothing to time. Adding a channel did not just improve the model; it made a category of behaviour legible.
Before moving on, kill the obvious objection. The assistant channel already carries text (the anchors). Why not let tool calls ride there and skip the third channel entirely?
Section 2.6 answers directly: "Embedding planning and tool calls into the same channel as assistant text would force that channel to alternate between TA4 audio tokens and tool-call JSON, which breaks the smoothness of the assistant audio."
The mechanism, spelled out: the anchor slot T occurs once per chunk and is consumed by the word currently being spoken. To insert JSON there you must either (a) displace the word — the audio then has no text to hang on, and pronunciation degrades — or (b) insert extra T slots — which breaks the fixed TA4 rate and hence the clock. There is no third option. The channel is rate-locked by construction, and a rate-locked channel has no spare capacity by definition.
The cost of the extra lane, meanwhile, is bounded and small: "at most 10 tokens per chunk", which Chapter 1's arithmetic showed is affordable at typical decoding speeds. A dedicated channel that costs at most two-thirds of the token budget and never touches the audio path is a much better deal than a shared channel that occasionally destroys the voice.
Everything readers reliably ask at this point, in one place. If any answer surprises you, that is the part of the chapter to re-read.
<|action_end|> tokens have gone by. Which is exactly why the alignment supervision in Chapter 7 matters so much.That last question is the interesting one to sit with. The three-channel design is not a fundamental truth about speech; it is the smallest set of lanes that covers listening, speaking, and acting. The framework generalizes, and its currency is tokens per chunk.
The format, as a checklist you should be able to reproduce blind:
If you remember one thing: an ordering is an architecture. Putting the action segment last in the chunk is what makes the priority scheduler work, and it is a one-line design decision with the entire real-time behaviour of the system riding on it.
Three exercises:
<|action_end|> emitted even in chunks where the action channel produced nothing at all?DuplexSLA did not invent full duplex. It inherited it. The dual-stream idea — one backbone modelling both sides of a conversation simultaneously — was established by a line of work the paper cites fourteen references deep, and understanding what was already solved is the only way to see clearly what this paper adds.
This chapter is the lineage. It is also the chapter where this lesson connects to its siblings: if you have read the Moshi veanor or the Qwen2.5-Omni veanor, you already own most of the substrate and can read this chapter as a diff. If you have not, everything you need is built here from zero.
We dismantled the turn-based pipeline in Chapter 0, so here we only need its epitaph — and a fair one, because the cascade is not stupid. It is the reference system in this paper's own tool-call evaluation, and it wins on accuracy (91.33% vs 85.56%). Its virtues are real:
| Virtue of the cascade | Why the duplex model gives it up |
|---|---|
| Every stage is independently swappable and testable | One backbone means one thing to train and one thing to debug — you cannot fix the tool caller without touching the voice |
| The LLM sees clean text and can be a frontier model | The duplex backbone is 7B, and is doing four jobs at once with a 10-token-per-chunk planning budget |
| Transcripts are auditable and compliance-friendly | The action lane provides an audit trail, but the acoustics never become text unless ASR supervision produces one |
| Failures are localized ("the ASR misheard") | A duplex failure is a model failure, full stop |
Hold that first column when you reach Chapter 10. The accuracy gap this paper reports is not a mystery — it is the price of collapsing four specialized stages into one 7B model that must also stay on a metronome.
The key move, made by the models the paper cites as [1–14], is to stop treating the conversation as an alternation and start treating it as two simultaneous time series that one model predicts jointly. Concretely: at every step, the model is conditioned on the user's audio so far and its own audio so far, and it predicts its own next audio.
Three capabilities fall out of this that a cascade cannot express, and each is worth naming because DuplexSLA assumes all three:
pause behaviour is impossible without this.The paper's own bibliography is a decent map of this generation: a full-duplex scheme based on an LLM (2405.19487), synchronous LLMs as full-duplex agents (2409.15594), Moshi (2410.00037), Freeze-Omni (2411.00774), SALMONN-omni (2411.18138), Mini-Omni and Mini-Omni2, LLaMA-Omni, OmniFlatten, SpiRit-LM, Voila, and — from 2026 — PersonaPlex (2602.06053) and Covo-Audio (2602.09823).
Two of these appear as measured baselines in Chapter 9's Table 7, so they are not just citations: Freeze-Omni and PersonaPlex are evaluated head to head on the turn-taking benchmark, and their results are among the most instructive numbers in the paper.
Worth naming the cost of the dual-stream move as well, since nothing is free: you now train one model on a joint distribution over two speakers, which is strictly harder than modelling one, and you pay tokens for silence forever. Generation 1 accepted both costs because the capabilities on the list above are unreachable otherwise.
Moshi is the anchor reference for this generation and the direct architectural ancestor of the dual-stream half of DuplexSLA. Its contribution, in the terms this lesson needs:
| Moshi's idea | What it bought | How DuplexSLA uses it |
|---|---|---|
| Model the assistant's own audio stream and the user's audio stream jointly in one transformer | Full duplex without an external turn manager | Directly inherited — this is the "dual-stream" in dual-stream three-channel |
| Interleave text tokens with the audio tokens the model generates | The language ability of the LLM stays engaged while speaking; speech stops drifting into fluent nonsense | This is the "T" in TA4 — the text anchor that precedes the four audio tokens |
| Discrete audio tokens from a neural codec, generated autoregressively | Speech becomes a language-modelling problem | The "A4" — four discrete assistant audio tokens per chunk |
Read the middle row again with Chapter 2's TA4 in hand. The text anchor is not a DuplexSLA invention; it is the inner-monologue pattern, adopted and given a fixed rate. What DuplexSLA adds is the observation that this text channel is already fully occupied by the words being spoken — which is precisely why planning and tool calls need somewhere else to live.
The other parent is the omni-modal streaming line, of which Qwen2.5-Omni is the cleanest example, and which the paper cites through its "audio-aware foundation models" group [18–32] — Qwen2-Audio, Qwen3-Omni, GLM-4-Voice, VITA-1.5, VITA-Audio, MiniCPM-o, and the Step-Audio family.
| Qwen2.5-Omni's idea | Relevance here |
|---|---|
| Thinker–Talker: a text brain that reasons and a speech mouth that renders, sharing context | The clean separation between "what to say" and "how to say it" — DuplexSLA collapses this into one backbone but keeps the lane separation |
| Time-aligned multimodal position encoding | The recognition that in streaming multimodal models, time must be a first-class citizen of the representation — DuplexSLA's answer is the chunk index |
| Block-wise streaming through the whole stack | Encoder, backbone, and codec all operate on blocks so nothing waits for a complete utterance — exactly the causal front end of Chapter 2 |
MiniCPM-o also appears as a measured baseline in Table 7, scoring 82.00% average accuracy at 0.61 s delay in the no-prefill setting — respectable accuracy, roughly double DuplexSLA's latency.
A caution about lineage tables generally: they compress a messy literature into a tidy sequence, and the tidiness is partly an illusion. Several of these systems were developed concurrently, solve overlapping problems, and cite each other in both directions. Treat the three generations as a way of organizing capabilities, not as a chronology — the useful question is never "who was first" but "which capability does this system assume, and which does it add."
There is a third line, and it is the one closest to DuplexSLA's actual contribution. Three papers by overlapping authors — Chronological Thinking in Full-Duplex Spoken Dialogue Language Models (2510.05150), Mind-Paced Speaking: A Dual-Brain Approach to Real-Time Reasoning in Spoken Language Models (2510.09592), and The Silent Thought: Modeling Internal Cognition in Full-Duplex Spoken Dialogue Models via Latent Reasoning (2603.17837) — ask how a duplex model can reason without stopping to think.
This matters because it isolates the exact gap DuplexSLA fills. Thinking on the clock gives you an internal rationale that does not interrupt the voice. But a rationale is not an action:
| Chunk-aligned thinking | DuplexSLA's action channel | |
|---|---|---|
| Output | Free-form internal text | Free-form planning text plus a structured object |
| Schema | None | Function name from a fixed set, JSON arguments |
| Consumer | The model itself, next step | The host application — something in the world changes |
| Timestamp | Implicit | Explicit: the chunk index, evaluated against an annotated anchor |
| Failure mode | Bad reasoning | Wrong function, wrong arguments, or right call at the wrong time |
The last row is the interesting one. Once your model can act, a new kind of error exists: the temporally wrong action. Calling navigate() correctly but four seconds late is a failure that has no analogue in text agents, and it is why Chapter 9's evaluation protocol has to treat trigger time as a correctness criterion rather than a performance metric.
Put differently: the thinking line asks "can the model reason without going silent?" and this paper asks "can the model act without going silent?" Those turn out to be the same architectural question with different payloads — which is why the action lane carries planning text as well as JSON, and why a system that solved one is most of the way to solving the other.
DuplexSLA is not trained from scratch. Section 4 states: "DuplexSLA is initialized from Step-Audio 2 mini, a 7B-scale audio language model." Table 1 repeats it: "7B speech-LM, initialized from Step-Audio 2 mini."
Why does this matter enough to state twice? Because it determines what continued pretraining has to teach versus what it can assume:
| Already present in the initialization | Must be installed by DuplexSLA's training |
|---|---|
| World knowledge and language ability | The chunked dual-stream three-channel serialization |
| Audio understanding — mapping acoustics to meaning | Strict time alignment between assistant audio and action text |
| Speech generation from discrete units | Silence behaviours on both the TA4 anchor and the action channel |
| Instruction following | Turn-taking control: pause, interrupt, backchannel |
| — | In-conversation planning and structured tool calls |
That right-hand column is Chapter 8's syllabus, in order. And the left-hand column explains a design pressure that is otherwise invisible: the training mixture includes ~1.92M general text samples explicitly "to preserve world knowledge and reasoning ability" while the speech format changes underneath. You are performing surgery on a model's input format without letting it forget how to think.
Pick an architecture, then pick a conversational event. The panel shows whether that architecture can represent the event at all, how it responds, and where the decision physically lives. "Cannot represent" is a stronger and more interesting failure than "responds badly" — it is why Chapter 9 has N/A cells.
The row to dwell on is "user backchannels" against "dual-stream duplex". A dual-stream model can keep talking through a backchannel — overlap is representable, so the behaviour is available. What it cannot do is say that it did so. There is no label, no timestamp, no object for the host application or the evaluator to read. The behaviour exists; the report does not. Adding the action channel converts an implicit behaviour into an explicit, addressable event, and that conversion is most of what "SLA" means.
The three generations above are about models. It is worth tracing the parallel history of the component they replace, because each step in that history was a reasonable response to the previous one's failure:
| Era | Mechanism | The failure that motivated the next step |
|---|---|---|
| Push-to-talk | The human presses a button to mark the turn boundary | Requires a hand and an eye. Unusable while driving or cooking — the exact settings voice is for |
| Energy VAD | Threshold on frame energy plus a hangover timer (typically 500–800 ms of silence) | Cannot distinguish hesitation from completion; interrupts the user constantly, or feels sluggish if the timer is raised |
| Statistical / neural VAD | A small classifier on acoustic features, trained on speech versus non-speech | Better at rejecting noise, still blind to meaning: silence is silence |
| Semantic VAD / turn detector | A model reading partial transcripts to predict whether the turn is complete | Adds a detector chain's latency (measured: 1.57–1.68 s in the gpt-realtime semantic-vad configuration) and cannot see the assistant's state |
| Native duplex control | The decision is a token on the action channel of the same backbone that drives the voice | — this paper |
Notice the pattern: each generation buys accuracy by adding a stage, and each added stage costs time. The native approach is the first one that buys accuracy by removing a stage — which is only possible because the information the detector needed was already inside the model that was going to run anyway.
The paper cites eleven evaluation suites [33–43]. Knowing roughly what each covers explains why a new one was necessary:
| Benchmark | What it measures | What it does not |
|---|---|---|
| Full-Duplex-Bench | Turn-taking capabilities of full-duplex spoken dialogue models — pause, interruption, backchannel | Tool calling; timing of side-effects |
| Talking Turns | Turn-taking dynamics of audio foundation models | Actions |
| VoiceBench / VocalBench | LLM-based voice assistant quality; vocal conversational ability | Duplex timing |
| AIR-Bench / MMAU / MMSU | Audio understanding and reasoning, generative comprehension | Interaction at all — these are offline |
| SD-Eval / URO-Bench / WildSpeech / Multi-Bench | Spoken dialogue understanding beyond words; end-to-end spoken dialogue; natural conversation; multi-turn emotional intelligence | Sub-second yielding; time-stamped tool calls |
The gap is clear once tabulated. Turn-taking is measured. Understanding is measured. Tool calling is measured elsewhere, in text. Nobody measured tool calling on a duplex timeline, because until this paper there was no system whose tool calls had timestamps to score.
One cited system is worth a paragraph because it takes a different road at a fork DuplexSLA does not even mark. SALMONN-omni (2411.18138) is described in its own title as "a codec-free LLM for full-duplex speech understanding and generation."
Codec-free means the assistant's speech is not represented as discrete codec tokens at all. That choice removes the quantization loss of a codec and the need for a fixed audio-token rate — and it also removes the thing DuplexSLA's whole clock is built on. If your assistant audio is not a fixed number of discrete tokens per chunk, you do not have a TA4 unit, and the tidy "5 tokens always, 10 tokens at most" budget arithmetic of Chapter 1 has no meaning.
| Codec-token duplex (DuplexSLA, Moshi) | Codec-free duplex | |
|---|---|---|
| Assistant audio representation | Discrete tokens from a neural codec | Continuous features, decoded by a separate synthesizer |
| Fixed per-chunk token cost? | Yes — this is what makes the budget computable | Not in the same way |
| Quantization loss | Yes, bounded by the codec | Avoided |
| Can you reason about real-time budget with simple arithmetic? | Yes (Chapter 1) | Harder — the accounting depends on the synthesizer |
Neither road is obviously right. But it is worth noticing that DuplexSLA's clean budget story is downstream of a representational choice, not a universal law of duplex systems. When you read "at most 10 action tokens per chunk", the reason that sentence can even be written is that everything else in the chunk is discrete and counted.
With the lineage in place, the contribution reduces to two bullets, which are the paper's own:
And the two capabilities those contributions are meant to deliver, which will structure the rest of the lesson:
A note on how quickly this moved. The dual-stream duplex line begins in earnest in 2024; the chunk-aligned reasoning line lands in late 2025; this paper is mid-2026. Three years from "a model can listen while it speaks" to "a model can act while it speaks," on a shared clock, with a benchmark to score it. If you are reading this lesson well after publication, assume the neighbourhood has moved again — and use the framework rather than the numbers.
The framework, restated for that purpose: identify the physical rates, derive the clock, count the per-chunk token budget, decide what each lane carries and in what order, then ask what the supervision has to look like for the model to learn the timing. Those five steps outlive any particular set of results, and they apply to any modality that has to run in real time next to a language model.
One honest note about lineage papers before we move on. It is tempting to read a contributions list as "everything before this was inadequate." That is not the right reading here. Every element DuplexSLA uses — discrete audio tokens, text-audio interleaving, dual-stream conditioning, streaming encoders, a strong audio backbone — was built by someone else and works. The contribution is an addition that happens to be cheap: one more lane, ten tokens per chunk, and a data pipeline that knows how to fill it. The best systems papers are usually shaped like this, and recognizing the shape makes them easier to read.
Duplex speech papers use a compact jargon. Decoding it makes the citations above readable:
| Term | What it means | Where it appears here |
|---|---|---|
| Speech-to-speech (S2S) | A model that takes audio in and emits audio out with no text bottleneck in the middle | DuplexSLA is S2S with two text side-channels |
| Cascaded | VAD, ASR, LLM, TTS as separate components | The baseline in Table 5 |
| Barge-in | The user speaking over the assistant, and the assistant yielding | The interrupt scenario |
| Endpointing | Deciding that the user's turn has ended | What the response label replaces |
| Hangover | How long a VAD waits in silence before declaring an endpoint | The source of the baselines' ~1 s delays |
| TTFA / time to first audio | Latency from the user's end of turn to the first sound from the assistant | Essentially the normal delay metric |
| Semantic VAD | A turn detector reading meaning, not energy | The component this architecture removes |
| Inner monologue | Generating text alongside generated audio to keep language ability engaged | The TA4 text anchor |
| RVQ / codec tokens | Discrete units from a residual-vector-quantized neural audio codec | The four A tokens per chunk |
One term deliberately absent from this paper's vocabulary is worth noting: TTFA. Product teams optimize it obsessively, and DuplexSLA's normal delay is essentially that metric under another name. The paper's framing — delay against a semantic anchor — is stricter, because a system can improve TTFA by starting to speak before it has understood, and the anchor-based metric does not reward that.
DuplexSLA is a 2026 paper in a fast-moving area, and several of its neighbours are worth placing because you will meet them in the results tables:
| System | Focus | Relationship to DuplexSLA |
|---|---|---|
| PersonaPlex (2602.06053, NVIDIA) | Voice and role control for full-duplex conversational speech models | Orthogonal axis: who the assistant is, not when it acts. Appears as a baseline in Table 7 |
| Freeze-Omni (2411.00774) | Low-latency speech-to-speech dialogue with a frozen LLM | The opposite design instinct — freeze the language model and wrap it — and a baseline in Table 7 |
| SALMONN-omni (2411.18138) | Codec-free full-duplex understanding and generation | Different representational road; see the contrast section above |
| The Silent Thought (2603.17837) | Internal cognition in full-duplex models via latent reasoning | Thinking on the clock, in latent space rather than on a text lane. Shares an author with this paper |
| Step-Audio 2 / R1 / R1.5 | The StepFun audio foundation-model line | Step-Audio 2 mini is the initialization; the R-series is the reasoning branch of the same family |
| MiniCPM-o | On-device multimodal live streaming | Baseline in Table 7 — 82.00% at 0.61 s, the strongest open system there |
Two things this table makes visible. First, the StepFun lineage is doing something deliberate: an audio foundation model, then a reasoning branch, then a duplex-action branch, sharing authors and a backbone. DuplexSLA is a limb of a programme, not a one-off.
Second, the 2026 duplex frontier has split into at least three axes — who the model is (persona and voice control), how it thinks (latent or chunk-aligned reasoning), and what it does (this paper). They are compatible, and nobody has yet published all three in one system. That is a fairly clear map of where the next paper comes from.
The inheritance, itemized. For each element, where it came from and where it appears in this lesson:
| Element of DuplexSLA | Inherited from | Chapter |
|---|---|---|
| Discrete assistant audio tokens | Neural audio codecs and the audio-as-language line | 2 |
| Text interleaved with generated audio (the anchor) | Moshi's inner monologue | 2 |
| Joint modelling of both audio streams | The dual-stream duplex generation | 3 |
| Causal streaming encoder, no lookahead | Streaming omni-modal models | 2 |
| Strong audio understanding and world knowledge | Step-Audio 2 mini, 7B | 8 |
| Reasoning that does not stop the voice | The chunk-aligned thinking line | 4 |
| A dedicated, time-stamped action lane | This paper | 2, 4, 5 |
| Turn-taking labels co-decoded with speech | This paper | 6 |
| A timing-aware tool-call benchmark | This paper | 9 |
One more framing that helps when reading any paper in this area: ask what the model is allowed to say. A cascade's turn detector may say "turn over" or "not yet". A dual-stream duplex model may say anything it can pronounce. DuplexSLA may additionally say "I am interrupting", "I heard you and I am continuing", and "call this function with these arguments, now". The expressible vocabulary of a system is a surprisingly good predictor of what it can be evaluated on — and, as Table 6's N/A column shows, of what it can be seen to do at all.
If you remember one thing from this chapter: the difference between "the model behaved correctly" and "the model emitted a legible, time-stamped decision." Dual-stream duplex gives you the first. The action channel gives you the second — and the second is what makes a behaviour dispatchable, auditable, and scoreable.
Three exercises, answers in the chapter above:
Everything so far has been static: a clock, a serialization, a lineage. This chapter runs it. By the end you will have spoken into a live conversation, watched a tool call fire while the assistant kept talking, and seen the side-effect fold back into the dialogue — and you will be able to explain, chunk by chunk, why each of those things happened when it did.
This is the chapter to linger in. If you take one thing from this lesson, take the feeling of three lanes moving together.
Before the controls: the sim below is not a video. Every cell you see is computed from the same rules we derived in Chapters 1 and 2 — chunk indices, fixed TA4 allocation, a ten-token action cap — so if you disagree with something it draws, you can check it with arithmetic rather than opinion. That is the standard this lesson holds its simulations to.
Section 2.5 identifies the patterns that a duplex action channel makes possible, and Section 5 turns each into 300 benchmark cases. Learn the three by name, because every result table is organized around them:
| Pattern | What the user does | What the model does | Why a cascade struggles |
|---|---|---|---|
| Single action | One explicit request, one function | Emits planning plus one tool call at the semantic anchor, mid-utterance | Must wait for the endpoint, then ASR, then planning: 2.33 s measured |
| Multi action | One turn, several ordered intents ("AC, music, restaurant") | Emits several time-aligned calls, each anchored to the chunk where its intent became clear | Must hear all intents before planning any: 4.71 s measured |
| Backchannel action | A short, topically unrelated request while the assistant is mid-answer ("play some Beatles songs") | Treats it as a backchannel — keeps speaking — and dispatches the call anyway | Must either ignore it or treat it as an interruption and abandon the answer |
That third row is the one that has no turn-based equivalent at all. Read the paper's description carefully: "A short user utterance that is topically unrelated to the current dialogue (e.g., 'play some Beatles songs' uttered while the assistant is talking about something else) is treated as a backchannel: the action channel emits a planning fragment plus a tool call without interrupting the assistant's spoken thread. The assistant audio thus stays coherent while the side-effect is dispatched."
The second pattern deserves its own paragraph because of a subtle claim. Section 2.5: "Because each tool call is anchored to its own chunk on the action channel, the calls are emitted in semantic order along the user's request, and the assistant audio runs in parallel with each call's planning text."
The ordering is not something the model has to plan. It falls out of the clock. Intent A becomes clear before intent B, so A's anchor chunk precedes B's anchor chunk, so A is emitted first. A turn-based agent has to construct the order at planning time from a completed transcript; a duplex agent inherits it from the passage of time.
That is a genuinely elegant property, and it is worth naming the price: because the model commits to A before hearing B, it cannot revise. If the user says "navigate to the airport — no wait, the train station," the anchor for the first intent has already passed. We will return to this in Chapter 10, and it is one plausible mechanism behind the multi-action accuracy drop.
Here is the instrument. Three lanes on the 160 ms grid: the user's audio on top, the assistant's TA4 stream in the middle, the action channel at the bottom. A dispatch panel on the right shows what has actually been executed and when.
Controls, and what each teaches:
Three lanes, one clock. Filled cells are content; hollow cells are silence anchors. Small squares on the action lane are individual tokens under the 10-per-chunk cap. The teal diamond is a tool dispatch; the grey diamond is where the cascade would have fired. Press 🎤 Speak now while it plays to issue your own mid-conversation request.
A word on why this particular visualization and not a nicer one. The obvious alternative — an animated cartoon of a car and a talking assistant — would be prettier and would teach nothing, because the thing being taught is precisely the grid: discrete chunks, fixed allocations, events with indices. Anything that smooths the timeline away hides the mechanism. Three lanes of cells on a shared clock is not a stylistic choice; it is the paper's Figure 1 rendered honestly.
Single action. The user says "It's freezing in here, turn up the AC." The semantic anchor — the moment the request is unambiguous — arrives several chunks before the user stops talking. Watch the action lane light up there, not at the end. Then watch the assistant lane: it is producing silence anchors while the user speaks (it is listening, correctly), and it begins its reply after the user's turn ends. The tool fired before the reply began.
Multi action. Three intents, three anchors, three dispatches, and the assistant's single fluent sentence "Sure, I've turned up the AC temperature and started the music. I'm now navigating to a nearby restaurant" running across all of them. Note the ordering: the calls come out in the order the intents were spoken, without any planning step deciding that.
Backchannel action. The assistant is mid-sentence about the May Day holiday. The user says "play some Beatles songs." Look at the assistant lane during and after that utterance: unbroken. Look at the action lane: planning text plus search_music. The paper's Figure 3a in motion.
Interrupt. Contrast with the previous one. Same short user utterance shape, different meaning — and now the action lane emits interrupt and the assistant lane switches to silence anchors within a couple of chunks. Same acoustics, opposite behaviour, because the decision is semantic. This is Chapter 6's subject, previewed.
Pause. The user hesitates mid-thought. The assistant lane stays silent through the gap. An energy VAD would have declared the turn over and started talking; the model keeps listening because nothing semantically complete has been said. The absence of a barge-in is the behaviour.
Because this is the pattern with no turn-based equivalent, it is worth writing out as a script — the way you would read a trace in a debugger. This is Figure 3a of the paper, expanded onto the grid with plausible chunk indices.
| Chunk | t (s) | User channel | Assistant TA4 | Action channel |
|---|---|---|---|---|
| 0–5 | 0.00–0.96 | "The May Day holiday is coming up, so no work!" | <vad_silence> × 6 | — |
| 6 | 0.96 | — | "Finally," (assistant takes the floor) | response |
| 7–13 | 1.12–2.08 | — | "…another long-awaited long weekend! I'm so excited." | — |
| 14 | 2.24 | "Play some" (user starts) | "Do you have" | — |
| 15 | 2.40 | "Beatles" | "any travel" | — |
| 16 | 2.56 | "songs." | "plans?" | planning: "The user wants to listen…" |
| 17 | 2.72 | — | <tts_pad> | "…to music and needs to play music by" |
| 18 | 2.88 | — | <vad_silence> | "The Beatles." <|toolcall_begin|>{"function": |
| 19 | 3.04 | — | <vad_silence> | "search_music", "arguments": "play: |
| 20 | 3.20 | — | <vad_silence> | The Beatles"}<|toolcall_end|><action_end> |
Read the assistant column across chunks 14–16. The user interjects, and the assistant finishes its question — "Do you have any travel plans?" — without a hitch. No pause, no restart, no acknowledgment of the interjection in speech at all. Meanwhile the action lane spends five chunks emitting a rationale and a call.
Two design consequences visible only in the trace:
Being explicit about the model's idealizations, so you do not carry a false picture forward:
| In the sim | In reality |
|---|---|
| Semantic anchors are known in advance and fixed | The model must infer them from partial audio, and it is sometimes wrong — that is what the 85.67% single-action accuracy measures |
| Action token counts are round numbers | Tokenizer-dependent, varying with the language and the argument strings |
| The assistant's speech is scripted | Generated token by token, conditioned on everything including the action lane |
| Tool execution is instantaneous and always succeeds | Real tools have latency and failure modes, and the paper describes no return path for either |
| The cascade ghost uses the paper's average delays | A real cascade's delay varies per utterance with endpointer settings and ASR finalization |
The one idealization that matters most is the first. The simulation shows you the mechanism assuming perfect intent detection; the benchmark measures how often detection is right. Keep them separate: this chapter teaches the machine, Chapter 9 grades it.
If you played with the sim properly, three questions should be nagging. Each is answered in a later chapter, and knowing where to look is part of learning to read a systems paper.
Voice-agent engineering has a standard trick for hiding tool latency: acknowledgment filler. The assistant says "Sure, let me check that for you…" while the tool runs, so the user hears something instead of dead air. Every production voice stack does some version of this.
Look closely at what DuplexSLA does instead, in the Figure 3b transcript: the assistant says "Sure, I've turned up the AC temperature and started the music. I'm now navigating to a nearby restaurant."
That is not filler. It is a report of something already done. The difference is worth making precise:
| Cascade with filler | DuplexSLA | |
|---|---|---|
| What the speech is for | Occupying the user's attention while the system works | Describing side-effects that have already been dispatched |
| Is the statement true when spoken? | "Let me check" — true but contentless. "I've turned it up" would be a lie | True: the call was emitted in an earlier or concurrent chunk |
| What if the tool is slow? | The filler must be extended, or an awkward gap appears | The dispatch is decoupled from the speech — the voice never depended on it |
| Cost | Extra generation, extra design, and an honesty problem | Zero — the assistant was going to be talking anyway |
A short pre-registration exercise, which is worth doing honestly before you touch the controls again. Write down your answers, then check them in the sim:
| Question | Your prediction | Where to check |
|---|---|---|
| In the multi-action scenario, does the assistant start speaking before or after the last tool call is dispatched? | — | Watch the assistant lane against the third diamond |
| If you press "Speak now" twice within two chunks, do the two actions interleave or queue? | — | The action lane's colours |
| During the interrupt scenario, how many chunks pass between the label and the first silence anchor? | — | Step one chunk at a time |
| Does the assistant lane ever contain a gap in any scenario? | — | Every scenario, every chunk |
The fourth is the one worth being certain about. The answer is no, by construction — and if you predicted otherwise, re-read Chapter 2's ordering argument before continuing, because everything in Chapter 5 depends on it.
The chapter brief for this sim says the tool's result "folds back into the dialogue," and the simulation shows exactly that: the call dispatches, the world changes, and the assistant's later speech reflects it. You should know precisely how much of that is in the paper.
What the paper specifies in detail: the emission path. How an action object is represented, when it is emitted, how it is timestamped, how it queues, how it is scored.
What the paper does not specify: the return path. There is no described channel for a tool result to re-enter the model. Section 2.6 says the timestamp is "needed both for downstream execution and for the latency-oriented evaluation", and Section 2.5 says "the side-effect is dispatched" — the language throughout is of dispatch, not of round trip. Appendix E's action-object schema has name, planning, parameters, and offset. There is no result field.
query_arrival_time, query_weather, and search_food are all in the 50-function schema, and every one of them produces an answer the assistant must then say out loud. How that answer re-enters the model on the 160 ms clock is left to the host application. Chapter 10 returns to this; the simulation labels the return leg as host-side so you never confuse it with the paper's contribution.If you were building this system, the natural completion is nearly free: results arrive as text injected into the action channel's input side at the chunk they return, exactly like user audio features are injected on the user channel. The model is already trained to condition on action-channel tokens. Nothing in the architecture forbids it. But "nothing forbids it" is not the same as "the paper did it", and this lesson holds that line.
The ledger in the simulation reports four numbers. Each corresponds to something in Chapter 9's evaluation protocol, so learn to read them now:
| Ledger field | Meaning | Where it reappears |
|---|---|---|
chunk | The index c; wall clock is 0.16 c | The protocol's tk = 0.16 k |
anchor | The annotated semantic trigger time of the current intent | The ground-truth offset in the tool-call scoring rule |
emitted | When the first token of the action object appeared | The realised trigger time — anchored to the first token, not the last |
delay | emitted − anchor | Exactly the paper's delay metric (averaged over matched actions) |
One deliberate detail in the sim: the delay never goes below the quantization floor from Chapter 1, because it cannot. If you find a configuration where the ledger reports a delay under 80 ms on average, you have found a bug in the simulation, not a faster model.
One more reading of the ledger worth doing: run the single-action scenario twice, once with the cascade ghost on and once off, and watch only the assistant lane both times. It is identical. The entire difference between the two architectures lives on a lane the user never hears — which is exactly why this capability was invisible until somebody gave it a channel.
The best way to internalize an architecture is to push it past its assumptions. Three experiments, in increasing order of interest:
Notice what never happens in any configuration: the assistant lane never has a hole in it. Not while planning text drains, not while JSON clocks out, not while a second action waits in the queue. Five tokens per chunk, every chunk, no exceptions. That invariant is the whole design, and once you have watched it hold under pressure, the rest of the paper reads as a set of consequences.
The single-action scenario, written out as the ledger reports it, so you can check the sim against arithmetic you did yourself. The user says "It's freezing in here, turn up the AC" from t = 0 to t = 2.4 s; the intent is clear at t = 1.5 s; the action object is 38 tokens.
| Chunk | t (s) | User | Assistant TA4 | Action lane | Ledger |
|---|---|---|---|---|---|
| 0–8 | 0.00–1.28 | "It's freezing in here," | <vad_silence> | — | listening |
| 9 | 1.44 | "turn" | <vad_silence> | — | anchor at 1.50 s → chunk 9 |
| 10 | 1.60 | "up the" | <vad_silence> | — | accumulating evidence |
| 11 | 1.76 | "AC" | <vad_silence> | planning begins (10 tok) | emitted 1.76 s · delay 0.26 s |
| 12 | 1.92 | — | <vad_silence> | planning + open marker (10) | draining 20/38 |
| 13 | 2.08 | — | <vad_silence> | JSON body (10) | draining 30/38 |
| 14 | 2.24 | — | <vad_silence> | JSON close (8) + terminator | arrived — host may execute |
| 15 | 2.40 | (user ends) | <vad_silence> | response | floor taken |
| 16+ | 2.56+ | — | "Sure — I've turned the temperature up." | — | speaking a true sentence |
Three numbers to extract and check against earlier chapters. Trigger delay: 1.76 − 1.50 = 0.26 s — about 1.6 chunks, of which roughly 0.06 s is quantization. Transmission: chunks 11–14, four chunks, 640 ms — matching ⌈38/10⌉ from Chapter 5. Actuation: the AC changes at 2.24 s, while the user is still speaking, and 0.16 s before the assistant says a word.
Compare with the cascade on the same utterance: endpoint at 2.4 s plus hangover plus ASR plus planning puts its dispatch somewhere past 4.5 s. The two systems do the same thing; one does it before the sentence ends and the other after the silence.
Since the chapter is about what the assistant does while acting, it is worth laying out the full space of options a voice system has. Only the last is available to DuplexSLA, and only because of the action lane:
| Strategy | What the assistant says | When the tool fires | Honest? | Requires |
|---|---|---|---|---|
| 1. Dead air | Nothing | After the turn | Yes, and unbearable | Nothing |
| 2. Filler | "Let me check that for you…" | During the filler | Technically — it says nothing false and nothing useful | Engineered stalling phrases per intent |
| 3. Pre-acknowledgment | "Sure, turning that up now" | After the sentence | Borderline — present tense for a future event | Confidence that the call will succeed |
| 4. Concurrent report | "I've turned up the AC and started the music" | Already fired, chunks earlier | Yes — past tense for a past event | A separate action lane on the same clock |
Strategy 4 is what the Figure 3b transcript shows, and it is qualitatively different from the other three. The assistant is not managing the user's perception of latency; there is no latency to manage. It is narrating.
That distinction has a practical consequence worth naming: strategies 2 and 3 both degrade badly when tools are slow or fail, because speech has been committed on a promise. Strategy 4 degrades badly too — but only for the subset of tools whose results the assistant must report, which is exactly the gap Chapter 10 discusses. For pure side-effect tools, it is strictly better than the alternatives.
To fix the showcase in memory, here is one request — "It's freezing, turn up the AC" — traced through four architectures on the same wall clock. Assume the user speaks from t = 0 to t = 2.4 s, with the intent clear at t = 1.5 s.
| Architecture | Tool fires at | Assistant speaks at | What the user experiences |
|---|---|---|---|
| Cascade, energy VAD (800 ms hangover) | ~4.5 s — after endpoint (3.2 s), ASR final, LLM plan | ~4.9 s | Two and a half seconds of silence, then a reply, then the cabin warms |
| Cascade, semantic VAD | ~4.3 s — better turn detection, extra detector latency | ~4.7 s | Slightly better; the silence is still the dominant impression |
| Dual-stream duplex, no action lane | Not expressible in-conversation — either before speaking (delaying the voice) or after the turn | ~2.6 s (fast!) | Fast, natural conversation … that cannot change the temperature without breaking one of the two |
| DuplexSLA | ~1.6 s — at the chunk owning the semantic anchor, mid-utterance | ~2.7 s | The cabin starts warming while you are still finishing the sentence, and then the assistant says so |
The third row is the one to dwell on, because it is the state of the art this paper is arguing against — not the clumsy cascade, but the good duplex model that talks beautifully and cannot do anything. Speed of speech was already solved. Speed of action was not.
One habit to carry out of this chapter: whenever you meet a claim about a voice system's speed, ask what it is fast relative to. Faster than a slow cascade is a low bar. Faster than the semantic anchor is impossible. The interesting quantity is the gap between the measured delay and the architectural floor — and Chapter 1 gave you the tools to compute both halves of it.
If you remember one thing: the assistant lane never has a hole in it. Five tokens per chunk, every chunk, while the action lane does whatever it needs to. Every other property in this chapter — latency masking for free, backchannel-action, multi-action ordering — is a consequence of that invariant plus a shared clock.
| Pattern | The one-sentence version | Measured delay |
|---|---|---|
| Single action | Fire at the anchor, mid-utterance, instead of at the endpoint | 0.67 s vs 2.33 s |
| Multi action | Each call anchored to its own chunk; ordering inherited from time | 0.68 s vs 4.71 s |
| Backchannel action | Act without taking the floor — no turn-based equivalent exists | 0.57 s vs 1.27 s |
Three exercises:
We ended Chapter 2 with an uncomfortable count: one complete action object — planning text plus a JSON tool call — runs to roughly forty tokens. The pipe carries ten per chunk. Something has to give.
What gives is the assumption that an action fits in a chunk. It does not, and the paper builds a small, strict protocol around that fact. This chapter derives that protocol, works a full numerical example by hand, then writes it three ways in code.
Section 3.3 sets it up: "Because every chunk has a hard ≤ 10-token action-channel budget, short bursts of actions cannot always fit into the chunk where they are triggered. The data-construction format therefore turns the action stream into a single FIFO queue keyed by trigger time."
Three words in that sentence carry the design. Single: one queue, not one per action type. FIFO: first in, first out, no priorities. Keyed by trigger time: the ordering is temporal, inherited from when each intent became clear.
And two rules govern it. Here they are, close to the paper's own words, then unpacked:
<|action_end|> marker is emitted only after the last queued action has fully closed, so an open <|toolcall_begin|>…<|toolcall_end|> block is never split by an early <|action_end|>."<|toolcall_begin|>…<|toolcall_end|> block."Both rules protect the same invariant: a <|toolcall_begin|>…<|toolcall_end|> block is never split by a chunk terminator, and never interleaved with another action's tokens.
Think about what a violation would produce. Suppose action A's JSON is halfway out when action B starts emitting. The action lane would read:
what atomicity prevents <|toolcall_begin|>{"function": "navigate", "argu <|toolcall_begin|>{"function": "search_music"… ments": "nearby restaurant"}<|toolcall_end|>
That is not a parsing inconvenience — it is irrecoverable. The host application receiving this stream cannot know which fragment belongs to which call. Worse, the model would have to learn to produce and re-consume interleaved JSON, which is a strictly harder language-modelling problem for no benefit. Atomicity turns the lane into a well-formed message stream: read tokens, accumulate until you see <|toolcall_end|>, parse, execute.
Note the cost, though, and be honest about it: atomicity plus FIFO means an urgent action cannot jump the queue behind a long one. If the assistant is halfway through emitting a verbose search_food call and the user says "stop the car's fan, it's too loud", the fan call waits. Chapter 10 lists this among the design's real limits.
Time to push numbers. This is the arithmetic the data pipeline performs on every training sample, and it is worth doing once by hand until it is boring.
Setup. Budget B = 10 tokens per chunk. Two actions, both from the multi-intent car scenario:
| Action A1 — raise the AC | Action A2 — play music | |
|---|---|---|
| Semantic trigger time | t1★ = 1.83 s | t2★ = 2.20 s |
| Trigger chunk (floor of t/0.16) | ⌊11.44⌋ = 11 | ⌊13.75⌋ = 13 |
| Planning tokens | 14 | 12 |
| Tool-call block tokens (markers + JSON) | 22 | 18 |
| Total tokens | 36 | 30 |
Step 1 — how many chunks does each action need, ignoring interference?
Step 2 — lay A1 out chunk by chunk. It starts at its trigger chunk, 11, and takes ten tokens per chunk until it runs out:
| Chunk | t (s) | A1 tokens emitted | Running total | Free slots |
|---|---|---|---|---|
| 11 | 1.76 | 1–10 | 10 / 36 | 0 |
| 12 | 1.92 | 11–20 | 20 / 36 | 0 |
| 13 | 2.08 | 21–30 | 30 / 36 | 0 |
| 14 | 2.24 | 31–36 | 36 / 36 — closed | 4 |
Step 3 — where does A2 go? Its trigger chunk is 13. But chunk 13 is fully occupied by A1's tokens 21–30, and Rule 2 forbids preemption. So A2 waits. A1 fully drains in chunk 14, which has four free slots.
Here the paper's phrase "starts emitting from the next available chunk" admits two readings, so we compute both and label them honestly:
| Reading A — greedy (fill the free slots) | Reading B — strict (start the next chunk) | |
|---|---|---|
| Chunk 14 | A1 31–36 (6) + A2 1–4 (4) = 10 | A1 31–36 (6), 4 slots idle |
| Chunk 15 | A2 5–14 | A2 1–10 |
| Chunk 16 | A2 15–24 | A2 11–20 |
| Chunk 17 | A2 25–30 — closed | A2 21–30 — closed |
| A2 first token at | chunk 14 (t = 2.24 s) | chunk 15 (t = 2.40 s) |
Step 4 — compute the realised delays. The evaluation protocol timestamps an event at the start of its chunk, tk = 0.16 k, and takes the absolute difference from the annotated anchor. So:
Step 5 — sanity-check against the paper. DuplexSLA's measured multi-action delay is 0.67 s, comfortably above both of our computed values. Good: our arithmetic captures the mechanical component (quantization plus queueing) and the measured number includes everything else — the model's own semantic latency in recognizing the intent, which Chapter 1 estimated at roughly two chunks. Mechanism plus model, and the mechanism is the small part.
The most important consequence of the spill rule is stated in Appendix A.3, and it is easy to misread:
"The strict time-alignment prior installed by dual-side ASR during CPT lets the model treat this multi-chunk spillover as a bounded, budget-induced transmission delay rather than as drift in the offset itself: the first action token still emerges at the chunk that owns the semantic anchor, so the realised trigger time remains aligned with the annotated offset."
Two separate quantities, and the paper insists on keeping them apart:
| Trigger time | Transmission time | |
|---|---|---|
| Definition | The chunk where the action's first token appears | How many chunks the whole object takes to clock out |
| Determined by | The semantic anchor — when the intent became clear | Token count ÷ budget |
| What the benchmark measures | This one | Not measured directly |
| What the host application waits for | — | This one — you cannot execute a half-arrived JSON body |
| Grows with planning length? | No | Yes, linearly |
That fourth row is a small honest caveat on the headline numbers. The benchmark scores the moment the call was born, but the car cannot act until it has fully arrived. For a 40-token object at 10 tokens per chunk, that is roughly 640 ms of additional transmission before execution can begin. The paper's 0.64 s average delay is a measure of the model's timing intelligence, not of end-to-end actuation latency. Both are legitimate quantities; they are just not the same quantity.
Now write the scheduler down. Same computation, three ways — hand arithmetic above, explicit loop, then the vectorized one-liner.
Form 2: the explicit loop. This is the greedy reading (Reading A), written so every rule from Section 3.3 is visible as a line of code:
python — the FIFO action scheduler, step by step def schedule(actions, budget=10): """actions: list of (trigger_chunk, n_tokens), sorted by trigger time. Returns per-chunk fill and the realised first-token chunk per action.""" fill = {} # chunk -> tokens already placed there first = [] # realised trigger chunk per action c = 0 # the queue's write head for (trig, n) in actions: c = max(c, trig) # never emit before the anchor (Rule 2) while fill.get(c, 0) >= budget: # this chunk is full: wait c += 1 first.append(c) # the timestamp that gets evaluated remaining = n while remaining > 0: room = budget - fill.get(c, 0) put = min(room, remaining) fill[c] = fill.get(c, 0) + put remaining -= put if remaining > 0: c += 1 # spill into the next chunk (Rule 2) return fill, first schedule([(11, 36), (13, 30)]) # fill = {11:10, 12:10, 13:10, 14:10, 15:10, 16:10, 17:6} # first = [11, 14] <- matches the hand-worked table exactly
Trace it against Step 2 and Step 3 above and confirm every number. The max(c, trig) line is "never emit before the anchor". The while … >= budget line is "never preempt". The inner loop is the spill. Three rules, three lines.
Form 3: the vectorized version. Once you see that the scheduler is really just "lay tokens end to end and cut every B", the whole thing collapses. For the common case where actions are separated enough that nobody waits — or, more usefully, for a single action — the chunk index of every token is a division:
python / numpy — the same layout, vectorized import numpy as np n_tokens, budget, start = 36, 10, 11 # which chunk does each of the 36 tokens land in? chunk_of_token = start + np.arange(n_tokens) // budget # -> [11 x10, 12 x10, 13 x10, 14 x6] # how many tokens per chunk? np.bincount(chunk_of_token - start) # -> [10, 10, 10, 6] # how many chunks does a whole batch of actions occupy? lens = np.array([36, 30]) chunks_each = -(-lens // budget) # ceil division -> [4, 3] # and the one-liner: cumulative start chunk of each action, back to back starts = start + np.concatenate(([0], np.cumsum(chunks_each)[:-1])) # -> [11, 15] (strict Reading B: each action starts a fresh chunk)
Compare that last output with the hand-worked table: [11, 15] is exactly Reading B. The greedy Reading A needs the loop, because packing partial chunks is a stateful operation that cumsum cannot express. That is a useful lesson in itself — vectorization is free when your allocation is aligned, and expensive when it is not.
Form 4, for completeness: the library one-liner. Once you recognize the shape, the standard-library answer is a single call, because "cut a stream into fixed-size frames" is a solved problem:
python — the whole spill rule in one line from itertools import batched # Python 3.12+ chunks = list(batched(action_tokens, 10)) # [(t1..t10), (t11..t20), ..., (t31..t36)] # len(chunks) == 4; the trigger time is the chunk of chunks[0], the rest is transmission.
That is the entire across-chunk rule: batched(tokens, budget). Everything else in Section 3.3 is bookkeeping about what happens when two of these streams meet.
Set the token budget, the size of each action, and how far apart the triggers are. The grid shows the action lane chunk by chunk, coloured by which action owns each token slot. The ledger reports each action's anchor chunk, first-token chunk, queueing delay, and full-arrival chunk. Try setting the budget to 4 and watch everything back up.
Experiments worth running in the drainer, in order:
Now the multi-intent car request, on a slower accelerator where the budget has been retuned to B = 6 (Chapter 1: this corresponds to roughly 14.5 ms per token). Three actions, sizes 30, 26, and 34 tokens, triggered at chunks 19, 28, and 51 — the anchors we computed in Chapter 1's timeline exercise.
Step 1 — chunks needed each, ignoring interference:
Step 2 — lay them out under FIFO:
| Action | Anchor chunk | Earliest free chunk | First token at | Drains through | Queueing delay |
|---|---|---|---|---|---|
| A1 | 19 | 19 | 19 | 23 | 0 chunks |
| A2 | 28 | 28 (A1 finished at 23) | 28 | 32 | 0 chunks |
| A3 | 51 | 51 | 51 | 56 | 0 chunks |
Step 3 — the conclusion, which is the interesting part. Nobody waits. Even at a budget of 6, the three actions never collide, because their anchors are 9 and 23 chunks apart while each object needs only 5–6 chunks to drain.
That is the general case for real speech. Human intents in a multi-intent utterance are separated by the time it takes to say a clause — typically 1–3 seconds, which is 6–19 chunks — while an action object drains in 3–6 chunks. The queue is usually empty when the next action arrives.
Step 4 — find where it breaks. Set up the collision deliberately. Two intents 2 chunks apart, budget 6, 30 tokens each:
So even a deliberate collision on a degraded budget produces a delay the benchmark tolerates. The FIFO design is more robust than it first appears, and now you can say why rather than taking it on faith.
One more sentence from Section 3.3 closes the loop with Chapter 2's ordering argument: "Because the assistant TA4 channel has its own per-chunk token budget, this FIFO queue on the action channel never blocks assistant speech: while the queue is draining over several chunks, the TA4 stream keeps producing audio in lockstep."
This is why the two-lane split was worth the ten tokens. In a single-lane design, a four-chunk action burst would be four chunks of missing audio — 640 milliseconds of silence in the middle of a sentence, exactly when the user is most attentive. With separate lanes and a fixed TA4 allocation, the burst is invisible to the listener. The queue can be arbitrarily backed up and the voice does not notice.
A closing observation that matters for Chapter 7. All of the above is a data-construction policy: it describes how supervision targets are laid out. The model is never told the rules. It sees millions of examples in which action tokens happen to arrive ten at a time, in trigger order, with atomic JSON blocks, and it learns the distribution.
Which means the rules are learned as statistical regularities, not enforced as constraints. At inference time nothing prevents the model from emitting an eleventh token, or from opening a second tool call before closing the first. The paper does not report how often that happens. Practical deployments would clamp the lane with a decoding constraint — a grammar or a hard cap — and the paper's framing of the cap as a "deployment budget" that can be "re-tuned per accelerator without retraining" is consistent with that reading.
| Concept | Rule | Consequence |
|---|---|---|
| Budget | ≤10 action tokens per chunk | Bounds the rate, not the total — you can still say anything, just not all at once |
| Spill | Surplus goes to following chunks | An action's body is a serial transmission; length becomes time |
| FIFO | One queue keyed by trigger time; no preemption | Later actions inherit the queue; urgency cannot jump ahead |
| Atomicity | Tool-call blocks are never split | The lane is a parseable message stream |
| Trigger vs arrival | Timestamp at the first token; execution needs the last | The benchmark's delay is not the actuation latency |
| Non-blocking | TA4 is paid before any action token | The queue can back up arbitrarily without a hole in the voice |
If you remember one thing: this is a real-time scheduler written in token order. A periodic hard-deadline task (audio) gets a guaranteed reservation; an aperiodic soft-deadline task (actions) runs in the slack. Every rule in the chapter is a standard answer to a standard scheduling problem.
<|toolcall_begin|>…<|toolcall_end|> block never be split by another action's tokens or by an early chunk terminator?Play these two clips in your head. Both are the assistant mid-sentence, giving advice about overwork. Both have the user saying exactly the same three words at exactly the same moment.
| Clip A | Clip B | |
|---|---|---|
| Assistant is saying | "…health is the ultimate priority. Without a healthy body…" | "…health is the ultimate priority. Without a healthy body…" |
| User says | "You are right." | "You are right, but the project schedule is tight, I don't really have a choice…" |
| First 800 ms of user audio | identical | identical |
| Correct assistant behaviour | Keep talking. Do not reset the plan | Stop. Now. Yield the floor |
These are the paper's own Figure 2 examples, and they are the cleanest statement of why turn-taking is a semantic problem. At the moment you must decide, the acoustic evidence is identical. The difference has not been spoken yet.
An energy VAD cannot solve this. Neither, quite, can a semantic VAD that only sees the user's side — because "you are right" is agreement in both clips; what differs is whether the user is done, and that depends on prosody, on the assistant's own state, and on what happens 300 ms later. This chapter is about what it takes to make that decision inside the model.
Section 2.4 names three behaviours and, crucially, describes each in terms of what the two lanes do. Learn them as lane behaviours, not as concepts:
| Phenomenon | What the user is doing | Action channel | Assistant TA4 |
|---|---|---|---|
| Pause | Holding a thought without ending the turn | Stays at response-style continue-listening labels | Keeps emitting silence anchors |
| Interrupt | Starting a new thought while the assistant speaks | Emits an interrupt label near the semantic interruption point | Switches to silence within a small number of chunks |
| Backchannel | Short feedback, not taking the floor | Emits a backchannel label | Continues, without resetting the current speech plan |
The phrase "without resetting its current speech plan" in the last row is doing quiet work. The assistant has committed to a multi-sentence answer. A backchannel must not restart it, must not cause a repetition, must not derail it into responding to "you are right." The model must notice, log the notice, and continue the plan — which is a harder behaviour than either ignoring or stopping.
Appendix A.4 gives an actual chunk-by-chunk trace of the interrupt case. Below it is, with the Chinese transcribed and glossed. The assistant is finishing "…health is the most important thing…"; the user starts with an acknowledgment and rolls into a real objection.
| Chunk | t (s) | User audio | Assistant anchor T | Action segment |
|---|---|---|---|---|
| 0 | 0.00 | 你说 ("you say…") | 身体 ("body") | — |
| 1 | 0.16 | 得对 ("…are right") | 健康 ("health") | — |
| 2 | 0.32 | — | 是 ("is") | — |
| 3 | 0.48 | 但项 ("but the pro…") | 最 ("most") | — |
| 4 | 0.64 | 目很 ("…ject is very") | 重要 ("important") | — |
| 5 | 0.80 | 紧 ("tight") | 的 | 检测到用户插话<interrupt> ("user interruption detected") |
| 6 | 0.96 | 我也 ("I also") | <vad_silence> | — |
| 7 | 1.12 | 没办 ("have no") | <vad_silence> | — |
| 8 | 1.28 | 法 ("choice") | <vad_silence> | — |
Read the timing off the table:
interrupt label fires at chunk 5.Compare with the benchmark: DuplexSLA's measured interrupt delay is 0.40 s. Our trace-derived 0.48 s is the same order, and the difference is exactly the kind of variation you would expect between one illustrative sample and a 300-case average. The trace is not a cartoon; it is what the numbers look like from the inside.
Now Appendix A.5, the same shape with the opposite outcome. The assistant is mid-answer; the user says "没错" ("that's right") and then stays silent.
| Chunk | t (s) | User audio | Assistant anchor T | Action segment |
|---|---|---|---|---|
| 0 | 0.00 | — | 相依为 | — |
| 1 | 0.16 | 没 ("that's…") | 命的 | — |
| 2 | 0.32 | 错 ("…right") | 感觉 | 检测到附和语气<backchannel> ("acknowledging tone detected") |
| 3 | 0.48 | — | 比 | — |
| 4 | 0.64 | — | 直接 | — |
| 5 | 0.80 | — | 撒糖 | — |
| 6 | 0.96 | — | 有意思 | — |
| 7 | 1.12 | — | 多了 | — |
The critical column is the assistant anchor. Compare it with the interrupt trace: there, the anchors turn into <vad_silence> one chunk after the label. Here, the anchors march on — 比 直接 撒糖 有意思 多了 — completing the sentence the assistant had planned. The label was emitted; the plan was not disturbed.
The label fires at chunk 2, inside the user's short utterance (chunks 1–2). The paper's accuracy window for backchannel requires the event to land in [tbc-s − 0.2, tbc-e + 2], and the delay is measured against the end of the backchannel utterance. Measured average: 0.32 s. So the model typically labels a backchannel about two chunks after it ends, which is roughly when the crucial disambiguating evidence — the silence that follows — has arrived.
backchannel label on the action channel and continues speaking." That is why both labels take a couple of chunks: the model is waiting to see what comes next. It is not slow. It is being careful, and the delay is the cost of that care.Appendix B lists the canonical control labels used on the action channel — and a design detail that is easy to overlook but is genuinely clever:
| Action name | Trigger context | Canonical phrase + paraphrases (as trained) |
|---|---|---|
response | User finishes a turn | 用户发言结束 / 检测到表达完毕 / 接收到完整内容 ("user has finished speaking" / "expression complete detected" / "complete content received") |
interrupt | User starts a real new thought during assistant speech | 检测到用户插话 / 识别到插话意图 / 检测到有效发言 ("user interruption detected" / "interruption intent recognized" / "valid speech detected") |
backchannel | Short feedback without taking the floor | 检测到附和语气 / 识别到轻微反馈 / 用户仅做确认 ("acknowledging tone detected" / "slight feedback recognized" / "user is only confirming") |
asr | Duplex ASR supervision | No canonical phrase — the planning text is the delayed transcript |
| tool name | Tool-use scenario | Free planning text plus structured JSON |
Why paraphrase? The paper explains: "During data construction, the same name field is paraphrased by several near-synonyms so that the model is not over-fit to a single surface form."
Think about what over-fitting to one surface form would mean here. The label is emitted as text on a text lane by a language model. If every interruption in training produced the identical eight-character string, the model would learn a brittle template: a high-probability lexical reflex triggered by superficial cues, decoupled from the semantics that should drive it. By varying the surface, the training signal forces the decision to be the invariant and the wording to be the noise.
name field, not on the prose. This is a transferable trick worth stealing for any system where a language model emits control tokens.Pause deserves separate attention because it is the only one of the three whose correct behaviour is nothing happening.
The user says "I want to go to…" and stops. Half a second of silence. An energy VAD, tuned to a typical 500–700 ms endpoint threshold, declares the turn over and the assistant barges in over the user's next word. Everyone has experienced this; it is the single most common failure of deployed voice assistants.
DuplexSLA's response is to keep emitting silence anchors and response-style continue-listening labels. Nothing observable happens. And yet this is a decision the model makes 6.25 times a second, scored by the loss, supervised by a 36,000-hour data slice.
The benchmark reflects the difficulty. In the no-prefill setting, the pause scenario is where the open-source duplex backbones collapse: Freeze-Omni at 11.00% and PersonaPlex at 22.00%, versus DuplexSLA's 93.00%. The paper's caption is blunt about why: "Open-source duplex backbones without targeted post-training collapse on the pause subset, illustrating that pause robustness has to be supervised explicitly."
Read that as the chapter's engineering lesson. Being full-duplex does not give you pause robustness for free. The architecture makes the behaviour expressible; only data makes it reliable.
Choose what the user does. The top row is the energy envelope an old-fashioned VAD sees; the middle is what DuplexSLA's lanes do; the bottom is what a threshold VAD would have done. Drag the "continuation" slider to change how much the user says after the acknowledgment — and watch the model's label flip from backchannel to interrupt while the energy trace stays identical for the first several chunks.
The lab's point is the one the chapter opened with: slide the continuation from 0 to 4 chunks and the energy envelope for the first several chunks does not change at all, while the correct behaviour inverts. Any decision rule that reads only the envelope is making a coin flip. Any decision rule that waits long enough for the envelope to disambiguate has already talked over the user.
Let us be precise about the win, because "no external VAD" can sound like a purity argument rather than an engineering one. Three concrete benefits, in order of how measurable they are:
| Benefit | Mechanism | Evidence in the paper |
|---|---|---|
| Lower latency | No extra detector chain to run: the decision is a token the backbone was going to emit anyway | Delays of 0.27–0.40 s vs 0.62–1.68 s for systems with external VADs (Table 6) |
| Access to the assistant's state | The same representation that drives the response drives the decision | Argued in Section 2.4; supported by the backchannel result, which requires knowing what the assistant is in the middle of |
| An expressible label set | Not bounded by what an external detector was designed to output | Table 6's N/A column: baselines cannot express backchannel at all |
| One thing to train | Turn-taking improves with the same data that improves everything else | Post-training's 36k-hour interaction-control slice (Chapter 8) |
And the honest counter-column, which the paper does not write but which Chapter 10 will: you also lose the ability to tune turn-taking independently of the voice, to swap in a better detector next quarter, or to explain a specific failure without retraining a 7B model. The cascade's modularity was a real asset, and integration spends it.
Make the endpointing dilemma quantitative, because it explains why every voice assistant you have used feels wrong in one of two ways.
An energy VAD declares the turn over after H milliseconds of silence — the hangover. Choosing H is a forced trade:
| Hangover H | In chunks | Added latency on every normal turn | Behaviour on a 600 ms hesitation |
|---|---|---|---|
| 300 ms | 1.9 | +0.30 s to every single response | Barges in, badly — 300 ms into the user's pause |
| 500 ms | 3.1 | +0.50 s | Barges in at 500 ms |
| 800 ms | 5.0 | +0.80 s | Survives this pause — but every turn now waits 0.8 s |
| 1200 ms | 7.5 | +1.20 s | Robust to hesitation, and unbearably sluggish |
There is no good row. The hangover must exceed the longest hesitation you want to survive, and it is paid on every turn including the ones with no hesitation at all. That single trade explains the entire commercial baseline column in Chapter 9: delays of 0.95–1.68 s are what buying pause robustness with a timer costs.
Now compare with DuplexSLA's measured numbers: normal 0.27 s and pause 0.27 s, at 96.00% and 93.33% accuracy. Identical latency on both scenarios. That is the signature of a system that is not using a timer at all — a threshold-based system must show a latency floor equal to its hangover, and this one does not.
Handling an interruption in a cascaded stack is a genuinely fiddly piece of engineering. Enumerating it makes clear how much the duplex design absorbs:
| Step in a cascade | What can go wrong | In DuplexSLA |
|---|---|---|
| Detect that the user has started speaking over the assistant | Echo from the speaker is picked up by the microphone and looks like user speech | Same acoustic problem — but the model has its own audio in context, so it knows what it is saying |
| Decide whether it is a real interruption | The hardest part; usually a threshold plus a duration heuristic | A semantic decision on the action channel |
| Stop audio playback | Buffered audio keeps playing; the user hears a tail | The TA4 stream switches to silence anchors; there is no buffer beyond one chunk |
| Cancel the in-flight LLM generation | Tokens already generated are wasted; cancellation may not be supported | Nothing to cancel — generation is per chunk |
| Cancel in-flight TTS | Same problem one stage later | Not applicable |
| Repair the context: what did the assistant actually say before being cut off? | The LLM's transcript says one thing; the user heard less. Getting this wrong makes the assistant repeat itself or reference unsaid content | Solved by construction: the assistant transcript on the action channel is emitted at the chunk where each character was actually spoken (Chapter 7). What was cut off was never emitted |
That last row is a quiet gift from the dual-side ASR design. Context repair after barge-in is one of the most annoying bugs in production voice agents, and here it falls out of the timing supervision that was added for a different reason.
Human turn-taking is richer than three labels. For honesty, here is what a conversation analyst would say is missing:
None of these are failings of the paper — three labels covering pause, interrupt, and backchannel is already more than any deployed system expresses. They are the map of what a fourth, fifth, and sixth label could be, and the architecture has room for all of them at ten tokens a chunk.
One detail from the evaluation protocol (Section 5.1) reveals something about how this system is meant to be operated: "the assistant audio output is post-processed by an external VAD to obtain speak and stop transitions; for DuplexSLA the action channel is also read directly."
So a VAD does still appear — on the output side, as an instrument for measuring when the assistant starts and stops speaking. That is a fundamentally different role from the input-side VAD the architecture eliminates. One is a decision-maker inside the loop; the other is a measurement device outside it. Removing the first does not mean the second is useless, and conflating them is a common misreading of "no VAD" claims in this literature.
Chapter 4's backchannel-action pattern is the point where this chapter and the tool-calling chapters intersect, and it is worth stating the composition rule explicitly:
| User utterance during assistant speech | Label | Tool call? | Assistant voice |
|---|---|---|---|
| "You are right." | backchannel | No | Continues |
| "Play some Beatles songs." | backchannel | Yes | Continues |
| "You are right, but the schedule is tight…" | interrupt | No | Stops within a few chunks |
| "Actually, forget the music — where are we going?" | interrupt | Unclear — not a case the paper enumerates | Stops |
Rows two and three are the interesting pair: the same label, opposite consequences on the action lane; and different labels, similar user utterances. What determines the split is whether the utterance requires the floor, not whether it requires an action. A request can be dispatched without taking the floor — that is precisely the insight backchannel-action encodes.
Row four is our own construction and the paper does not cover it: an utterance that both takes the floor and implies an action. The architecture can obviously express it (emit interrupt and a tool call in the same chunk), but it is not among the three trained tool-call patterns, so its behaviour is unspecified. A small, concrete gap in the benchmark.
One practical obstacle sits under every duplex system and the paper does not discuss it: the assistant's own voice comes out of a speaker in the same cabin as the microphone. Without treatment, the model hears itself.
Cascaded systems handle this with acoustic echo cancellation — a filter that subtracts an estimate of the played signal from the captured one. It works, imperfectly, and residual echo is a classic source of spurious barge-in: the assistant interrupts itself.
A duplex model has an interesting structural advantage here, which follows from the architecture rather than from any signal processing:
| Cascade | DuplexSLA | |
|---|---|---|
| What the turn detector sees | Microphone audio, echo-cancelled, from an unknown source | Microphone audio plus its own assistant tokens for every chunk, in context |
| Can it tell its own voice from the user's? | Only as well as the canceller performs | It generated one of them, chunk by chunk, and that generation is in the sequence |
| Residual-echo barge-in | A known failure mode | Should be far less likely — the model has a perfect reference for what it is saying |
The paper reports nothing on this — its training audio is synthesized and merged, so there is no acoustic echo in it at all. Which is worth flagging in both directions: the architecture has a natural advantage on echo, and the evaluation contains no evidence that it materializes. A duplex model trained purely on cleanly-merged tracks may never have learned to expect its own voice on the user channel.
Three labels is a small vocabulary for something as rich as turn-taking, and the paper says why: "The label set is kept compact so that turn-taking decisions are decoupled from spoken content." That is a real design principle, and it suggests criteria for adding a fourth:
| Criterion | Question to ask | Why it matters |
|---|---|---|
| Decidable at a chunk | Can the model know this within a chunk or two of the evidence? | A label that needs three seconds of hindsight cannot be emitted on a real-time lane |
| Actionable | Does the assistant's TA4 stream do something different because of it? | A label with no behavioural consequence is a comment, not a decision |
| Observable | Can an evaluator define a window and an anchor for it? | Otherwise it cannot be benchmarked, and unbenchmarked behaviours drift |
| Distinct | Is there audio for which this label and an existing one are both correct? | Overlapping labels make the supervision inconsistent and the model hedge |
| Cheap | Does it fit in a few tokens? | Every label competes with planning text for the same ten-token budget |
Run a candidate through it. "Turn-yielding imminent" — the assistant signalling that it is about to finish — is decidable (the model knows its own plan), actionable (the user could be invited in), observable (anchor at the actual end of the utterance), distinct, and cheap. It passes all five, and it does not exist yet in any system. That is a small research proposal you can now write down.
Now run a bad one. "The user seems frustrated" — decidable, arguably; actionable, only if something downstream changes; observable, poorly (what is the anchor for an emotion?); distinct, no (it can co-occur with all three existing labels). It fails on observability and distinctness, which is precisely why it belongs in the planning text rather than in the label vocabulary.
The three behaviours, as a decision table you could implement — except that no rule engine could evaluate the middle column, which is the point:
| Evidence | Semantic judgement required | Label | TA4 response | Measured |
|---|---|---|---|---|
| User silent mid-turn | "Is this thought finished, or held?" | response (continue listening) | Stay silent | 93.33% at 0.27 s |
| User silent after a complete thought | "Is the floor mine now?" | response | Answer | 96.00% at 0.27 s |
| Short user utterance, then silence | "Feedback, or a new turn?" | backchannel | Keep going, do not reset the plan | 98.33% at 0.32 s |
| Short user utterance, then more content | "Has a real new thought started?" | interrupt | Silence within a few chunks | 99.33% at 0.40 s |
If you remember one thing: the first 800 milliseconds of a backchannel and an interruption are acoustically identical, so the decision cannot be made from the audio alone at the moment it must be made. Everything DuplexSLA does here follows from putting that decision inside the model that already knows what it is saying and what it planned to say next.
Three exercises:
interrupt label fires at chunk 5. Is that a latency problem?Here is the problem that would stop most teams before they started. There is no corpus of chunked, dual-track, three-channel spoken dialogue with time-stamped tool calls. There is no such recording anywhere in the world, because the format is an invention of this paper.
Section 3 opens by saying exactly that: "The chunked, dual-stream three-channel format described in Section 2 does not match the format of conventional dialogue corpora, so building DuplexSLA required a dedicated data-construction effort."
This chapter is that effort. It is the chapter readers skip and the chapter that determines whether the model works — because for a model that must learn when as well as what, the layout of the supervision is the method.
Section 3.1 gives the schema. Every training sample is a chunked dual-track session containing:
| Field | Content | Supervised? |
|---|---|---|
| Task-conditioned system prompt | One of: dialogue, asr_human, asr_assistant, interrupt, backchannel, pause, toolcall | Context only |
| User audio track | Continuous, aligned to the conversational clock | No — observed only |
| Assistant audio track | Discrete speech units, 4 per chunk in TA4 layout | Yes |
| Ordered list of action objects | Each with a function name, optional planning text, optional structured arguments, and a semantic trigger offset snapped to a chunk index | Yes |
And then the sentence that explains why the whole thing is trainable at all: "The same schema covers all task families: they differ only in which channels carry information."
| Task family | What the action channel carries |
|---|---|
ASR families (asr_human, asr_assistant) | Delayed transcript text |
Timing-control families (interrupt, backchannel, pause) | The interrupt / backchannel / response labels |
| Tool-use families | Planning text plus structured tool calls |
Ordinary dialogue | Usually nothing — just the terminator |
Figure 4a shows the annotation stage. Start with an ordinary text dialogue — the kind that does exist in quantity:
raw dialogue (before annotation)
USER: I'm off work, what do you think I should eat tonight?
ASSISTANT: That's a world-class dilemma. Are [It's so cold in the car.]
you planning to cook or eat out?
...
USER: Let's have a light food salad, it's healthier. Help me navigate
to a nearby Wagas, and play some light music.
ASSISTANT: Okay, navigating to a nearby Wagas for you now, and the music
has been turned on too. Let's go.
An LLM, given the tool schemas, annotates each dialogue with tool-call objects. For each one it produces a planning rationale and a structured call:
what the annotator emits 💭 The user feels cold, I should turn on the air conditioning and set it to heating mode. 🛠 {"func": "open_car_setting", "args": "air-conditioner: heat mode"} 💭 The user wants to go to Wagas for a light salad, I need to navigate there. 🛠 {"func": "navigate", "args": "destination: wagas"} 💭 The user wants to listen to light music, I need to open the music player. 🛠 {"func": "search_music", "args": "play: light music"}
The result is a tool-calling augmented dialogue in which each call is inserted at the position in the text where its intent occurs:
tool-calling augmented dialogue (after annotation) USER: Let's have a light food salad, it's healthier. Help me navigate to a nearby Wagas [{"function": "navigate", "arguments": "destination: wagas"}], and play some light music [{"function": "search_music", "arguments": "play: light music"}].
Look at where the brackets sit. They are inside the user's utterance, immediately after the words that make each intent clear. This is the crucial move: the annotation is not "this turn requires these two calls" — it is "this call belongs here, at this point in the speech." Position in text will become position in time.
The same figure shows a backchannel-action example being planted mid-assistant-utterance: "That's a world-class dilemma. Are [It's so cold in the car.[{"function": "open_car_setting", "arguments":"air-conditioner: heat mode"}]] you planning to cook or eat out?" — the user's off-topic remark and its tool call are literally spliced into the middle of the assistant's sentence. That is how you fabricate a training example for a behaviour nobody has ever recorded.
Figure 4b turns the annotated text into audio, and the pipeline has four steps:
Notice how much of this pipeline is timing machinery and how little is language machinery. That ratio is the honest signature of the problem: the hard part of teaching a model to act while speaking is not deciding what to do, it is deciding exactly when the doing should be visible.
Table 9 lists the training-time system prompt per task family. They are short, and reading them tells you exactly how the model is told what game it is playing:
| Task family | System prompt (Chinese) | English gloss |
|---|---|---|
dialogue | (empty) | — |
asr_human | 请记录下你所听到的语音内容,只记录用户说的内容。 | "Write down the speech you hear — only what the user said." |
asr_assistant | 请记录下你所听到的语音内容,只记录助手说的内容。 | "Write down the speech you hear — only what the assistant said." |
interpret | 请翻译用户说的内容。 | "Translate what the user said." |
toolcall | 你是一个专注于与人互动的AI,既能聊天,也能使用工具来解决用户的问题。 | "You are an AI focused on interacting with people — you can chat, and you can use tools to solve the user's problems." |
interrupt / backchannel / pause | 你是一个AI语音助手,用{·}的声音来说话。 | "You are an AI voice assistant. Speak with the voice of {speaker}." |
Two observations. First, the three turn-taking families share a prompt that says nothing about turn-taking — it only sets the voice. The behaviours are taught by the data, not announced by the prompt, which is exactly what you want if the goal is "absorbed into core conversational competence" rather than "activated by an instruction."
Second, the {·} placeholder is filled with one of the 18 canonical speakers at sample-build time. So voice identity is a prompt-level variable throughout training. That is a small hint about how a system like this gets voice control — and a natural connection point to the persona-and-voice-control line of work the paper cites.
Section 3.4 is titled "Dual-side ASR is required for time alignment", and it contains the argument that most repays careful reading. Set it up properly.
The observation. Inside the TA4 layout, the text anchor T is left-aligned within its chunk. The assistant's text stream looks like this, with the trailing chunks padded:
Words get packed into anchor slots as they come, four audio tokens at a time. But a word's audio may not finish in the chunk whose anchor slot holds it. The paper: "a single Chinese word can be packed into the first T slot of a chunk while the corresponding audio is actually played in the next chunk."
The naive fix, and why it fails. If we want the model to learn when its own speech is happening, why not just delay-copy the anchors onto the action channel with a fixed lag, exactly as the user-side ASR does with its 2-chunk lag? Because the anchors are not on time in the first place. Copying an inaccurate timestamp with a constant offset gives you an inaccurate timestamp.
The proof is in the Appendix A.2 trace. Watch the lag vary:
| Chunk | Assistant anchor T | Action channel | Implied lag |
|---|---|---|---|
| 4 | 确 (character 1) | — | |
| 5 | 实 (character 2) | — | |
| 6 | <tts_pad> | 确 | character 1: 2 chunks |
| 7 | <vad_silence> | — | |
| 8 | <vad_silence> | 实 | character 2: 3 chunks |
There it is. Two consecutive characters, two different lags. If the anchors carried true timing, the lag would be constant. It is not, because the action-channel emission is placed "at the chunk where each character is actually being spoken" — and the anchors were packed earlier than that, at different amounts of earliness.
The consequence. Section 3.4's closing sentence is the payoff for the whole architecture: "By forcing the action channel to emit the assistant transcript at the chunk where each character is actually being spoken, we explicitly tie assistant audio to action time. As a result, the model's internal time clock stays consistent across user audio, assistant audio, and action emission, which is what makes sub-second tool-call latency feasible."
Top row: assistant text anchors, packed left into chunk slots as words arrive. Middle: when that word's audio is actually played. Bottom: the action-channel transcript, emitted at the true speaking chunk. Drag the speaking rate to change how far the anchors run ahead of the audio — and watch the lag between the two rows stop being constant.
Switch between "naive delay-copy" and "assistant-side ASR" and compare the error bars. The delay-copy transcript inherits the anchors' packing error; the ASR transcript is anchored to the audio itself. The gap between those two rows is what 90,000 hours of training data buys.
Figure 5 and Table 2 give the proportions. Two stages, seven task families:
| Stage | Family | Scale | Share of stage |
|---|---|---|---|
| Continued pretraining (~500k hours audio) | Duplex dialogue | ~320k hours | 64.0% |
| User-channel ASR | ~90k hours | 18.0% | |
| Assistant-channel ASR | ~90k hours | 18.0% | |
| Text (to preserve language ability) | ~1.92M samples | — | |
| Post-training (~50k hours) | Interrupt + backchannel + pause | ~36k hours | 72.0% |
| Tool call (BC-action, single-action, multi-action) | ~14k hours | 28.0% |
Three ratios worth committing to memory, because each encodes a design belief:
The two stages to scale, sliced by family. Click a slice to see what it teaches, what breaks without it, and where its effect shows up in the results tables. The width of each stage bar is proportional to hours, so you can see how small post-training really is.
Appendix E gives the abstract schema shared by every data family. Four fields, and each one is a design decision:
| Field | Contents | Why it is shaped that way |
|---|---|---|
name | One of the 50 tool schemas, or response, interrupt, backchannel, asr | Control decisions and tool calls share one namespace — the unification from Chapter 0. An interruption is an action with no arguments |
planning | Optional natural-language rationale, "kept short so that it fits within a few chunks" | The length constraint is explicitly a budget constraint. Verbosity here is latency for everything behind it in the queue |
parameters | Optional JSON-style argument dictionary; empty for asr and control-only labels | Optionality is what lets one schema cover both a navigation call and a backchannel label |
offset | Semantic trigger time, snapped to a chunk index at training time | The whole paper in one field. This is the label that teaches when |
Look at what is not there: no priority, no dependency on another action, no result, no confirmation flag, no expiry. The object is deliberately flat. That flatness is what makes the single FIFO queue sufficient — and it is also the boundary of what this design can currently express.
A practical inventory, because "we constructed the data" hides a great deal of work. To reproduce Chapter 7's pipeline you need:
Of those ten, exactly one — item 8 — is specific to this paper. The other nine are standard speech-pipeline components, which is why the data section reads as an engineering inventory rather than a research contribution, and why it is nonetheless the section that determines whether the model works.
Note how much of that is timing infrastructure and how little is modelling. This is the shape of most speech-systems work, and it is why data sections deserve to be read as carefully as method sections.
Appendix C lists the full schema exercised in training and evaluation: 50 functions across four intent families. The distribution is itself informative:
| Family | Count | Examples | Return value needed? |
|---|---|---|---|
| Cabin and hardware control | 9 | open_car_setting, set_car_setting, increase_car_setting, set_pet_car_setting, set_car_alarm | Mostly no — except query_car_setting |
| System settings and apps | 11 | open_app, switch_page, scroll, select_option, disconnect_system_setting | No |
| Navigation | 9 | navigate, add_waypoint, query_arrival_time, search_along_route | Yes for the three query functions |
| Media playback | 7 | play_media, search_music, next_track, play_broadcast | Mostly no |
| Search and queries | 14 | search_food, search_hotel, query_weather, query_stock, make_call | Yes — nearly all of them |
Count the right-hand column. Roughly twenty of the fifty functions produce information the assistant would have to speak back. That is a large fraction of the schema for which the paper's fire-and-forget action lane, as described, does not close the loop. It is not a fatal gap — the host application can inject the answer as ordinary dialogue context — but it is a real one, and Chapter 10 counts it honestly.
Also note what is absent: no web search, no code execution, no email, no calendar writes, no multi-step workflows with dependencies. Every function is a single flat call to a local device. The paper's own conclusion names this as future work: "broader open-domain spoken tool use."
A useful way to see a synthetic pipeline is to ask which knobs are randomized. Here, as far as the paper describes:
| Varied | Range | Prevents the model from over-fitting to… |
|---|---|---|
| Assistant voice | 18 voice-clone speakers, named in the system prompt | A single timbre; also makes voice a controllable variable |
| Control-label wording | Several near-synonymous phrases per label | A fixed surface string standing in for the decision |
| Task family | Seven system prompts | Assuming every session is a dialogue |
| Tool schema | 50 functions across four intent families | A handful of memorized calls |
| Trigger offsets | Wherever the intent lands in the sentence | Turn-final action, the very habit being unlearned |
And what is not varied, as far as the report says: acoustic conditions, language, speaking style beyond the 18 voices, microphone characteristics, and the absence of echo. Those are the axes on which a synthetic corpus is most likely to leave a gap, and they line up exactly with the robustness questions Chapter 10 raises.
The pipeline, end to end, with what each stage contributes to the final model:
| Stage | Input | Output | What the model ultimately learns from it |
|---|---|---|---|
| LLM annotation | Ordinary text dialogue + 50 tool schemas | Dialogue with tool objects inserted inside utterances | Which function, which arguments, and roughly where in the sentence |
| TTS / voice cloning | Annotated text, 18 assistant speakers | Two audio tracks | How the words sound; voice identity as a prompt variable |
| Forced alignment | Audio + text | Word-level times | Position in the sentence becomes position in seconds |
| Time merge | Two tracks + overlap plan | One duplex timeline | What a backchannel, an interruption, and a pause look like on the clock |
| Action merge at the grid | Offsets + FIFO rules | Per-chunk action segments | The budget, the spill, and the trigger-time convention |
| Dual-side ASR pass | Both tracks | Delayed transcripts on the action lane | What time it is — the timing prior everything else depends on |
If you remember one thing: the format of the supervision is the method. A model that must learn when cannot be taught by data that only records what, and no existing corpus records when. Everything DuplexSLA can do that other systems cannot traces back to a decision made in this pipeline.
We have a format and a corpus. Now the question every practitioner actually asks: in what order do you feed it, and what does the loss look like?
Section 4 answers in three parts — two stages, a modified loss, and a short, unusually candid paragraph about why the stages are divided the way they are. That last paragraph is the most useful thing in the section, so we will build up to it.
Read this chapter with one question in mind throughout: which of these decisions would you have gotten wrong? Most of them look obvious in retrospect and are not — particularly the loss reweighting, whose absence would have produced a training run that looked healthy and a model that was quietly worse at everything that mattered.
"DuplexSLA is initialized from Step-Audio 2 mini, a 7B-scale audio language model." Before a single duplex sample is seen, the model already has world knowledge, language ability, audio understanding, speech generation from discrete units, and instruction following.
So the training run is not "learn to talk." It is "learn to talk on a clock, in a format you have never seen, without forgetting anything." That framing explains several choices that would otherwise look odd — particularly the 1.92M general text samples mixed into an audio training stage.
The goal, stated in Section 4.1, is to "make the backbone fluent in the new serialization." The model must learn three things simultaneously:
| # | What must be learned | Which data slice teaches it | What failure looks like |
|---|---|---|---|
| 1 | The chunk-level interleaving of user audio, assistant TA4, and action text | Duplex dialogue (~320k h) | Malformed sequences: missing terminators, wrong token counts per chunk, the grid dissolving |
| 2 | Strict time alignment between assistant audio and action text, via dual-side ASR | User + assistant ASR (2 × 90k h) | The model can act but not when: trigger times drift from anchors, and sub-second latency becomes impossible |
| 3 | Silence behaviours on the TA4 anchor (<vad_silence>, <tts_pad>) and on the action channel | All slices — silence is everywhere | Chattiness, or the inability to stop; padding confusion mid-utterance |
| + | Not forgetting how to think | Text (~1.92M samples) | Degraded planning text, worse world knowledge, weaker argument selection |
And the honest report of what CPT does not achieve: "After CPT, the model becomes comfortable with the duplex serialization, but does not yet exhibit the targeted real-time interaction behaviours, especially when the user pauses, interrupts, or issues short backchannel feedback."
Read that as a strong empirical claim about what generic duplex dialogue data contains. Three hundred and twenty thousand hours of conversation apparently do not teach reliable pause handling. Why not? Because natural dialogue is dominated by the easy case — clean alternating turns — and the interesting cases are rare, unlabelled, and drowned. This is a general lesson about scale: more of the same distribution does not fix a tail behaviour if the tail is what you care about.
Post-training "shifts the data distribution from generic duplex dialogue toward the behaviours we want to evaluate. The mixture is deliberately small, but each slice is highly informative."
| Slice | Hours | What it drives, in the paper's own words |
|---|---|---|
| Interrupt + backchannel + pause | ~36k | "Drive the action channel to emit the right control labels at the right time, and to switch the assistant TA4 to silence within a small chunk-level latency under interruption" |
| Tool call (backchannel-action, single-action, multi-action) | ~14k | "Drives the model to emit planning text plus structured tool calls on the action channel, both in standard turn-taking single- and multi-action requests and in topically unrelated backchannel-action requests that must not break the assistant's spoken thread" |
Two details in the first row are worth separating, because they are different skills. "Emit the right label at the right time" is a detection problem on the action channel. "Switch the assistant TA4 to silence within a small chunk-level latency" is an execution problem on the audio channel. A model could learn to detect interruptions perfectly and still keep talking through them. Post-training has to couple the two, which is only possible because both lanes are outputs of the same backbone in the same step.
And note the composition of the tool-call slice: it is not one tool-calling distribution but three, matched exactly to the three benchmark patterns. The training set and the evaluation set are structured identically. That is standard practice and it is also worth flagging — Chapter 10 returns to what it means for generalization.
Section 4.3 describes a base objective and then a modification. The base:
Standard next-token cross-entropy on the two supervised channels, plus a general text-modelling term. The user audio side is never a target — it is observed only.
Then: "On top of this base loss, we apply additional loss masks and per-token weights to selected state tokens and to specific positions in the chunked dual-stream three-channel sequence, so that the optimisation is better matched to the full-duplex training setting (e.g., silence anchors, channel-boundary markers, and task-conditioned segments are not trained as ordinary content tokens)."
The paper does not give the weights. But it names the three categories, and each one has an obvious motivation you can reconstruct. Let us do that, with arithmetic.
Category 1: silence anchors. Suppose the assistant speaks 40% of the time in a typical duplex session (generous — in a conversation with a talkative user it is much less). Then:
Train those as ordinary content tokens and the majority of your gradient signal teaches the model to predict silence. It will get exceptionally good at that — it is an easy, highly predictable target — and the loss will look wonderful while the speech quality does not improve. Down-weighting silence rebalances the objective toward the tokens that carry information.
Category 2: channel-boundary markers. Count them per chunk: <|user_audio_begin|>, <|user_audio_end|>, <|assistant_audio_begin|>, <|assistant_audio_end|>, <|action_end|> — five markers, all fully deterministic given the position in the chunk.
A perfectly-predictable token contributes near-zero loss once learned, so the argument is not that markers dominate the objective forever — it is that they occupy attention, context, and early-training gradient for no benefit. Masking them is cheap hygiene.
Category 3: task-conditioned segments. The system prompt tells the model which game it is playing. Training the model to generate its own system prompt is not merely useless; it actively encourages the model to model the distribution of tasks rather than to condition on the given one.
The term is overloaded in 2026, so pin it down. In text-LLM practice, post-training usually means instruction tuning followed by preference optimization — a small, alignment-shaped stage measured in millions of tokens.
Here it means 50,000 hours of audio. By Chapter 8's own conversion that is over a billion chunk-decisions, all supervised, all next-token cross-entropy. It is not alignment; it is a second curriculum with a different data distribution.
| Text-LLM post-training | DuplexSLA post-training | |
|---|---|---|
| Purpose | Shape behaviour and preferences on an already-capable model | Install capabilities the pretraining distribution does not contain |
| Size relative to pretraining | Often well under 1% | 10% |
| Method | SFT, then preference optimization | Supervised only, same loss and interface as stage 1 |
| What changes | Style, refusals, formatting | Timing behaviours and structured action emission |
Keeping the distinction straight matters when reading the recipe: nothing here is alignment, and nothing here uses preferences. The behaviours are taught the same way the format was, just with a distribution chosen to concentrate on rare events.
Section 4.4 is short and it is the most transferable paragraph in the paper. Here it is, unpacked:
"A turn-based agent can be improved by adding more text or more tool examples. A duplex spoken agent carries the additional burden of timing."
That is the framing. Turn-based agents have one axis of difficulty: content. Duplex agents have two: content and time. And the two are learned differently — content from examples, timing from a prior that must be stable before anything else can be layered on.
Hence the division: "The CPT stage therefore establishes the timing prior using ordinary duplex dialogue plus dual-side ASR, and the post-training stage sharpens it for pause, interrupt, backchannel, and tool calling."
And then the sentence that reports an actual experiment, compressed to a clause: "This division was the most data-efficient setup in our experiments: pure duplex dialogue alone teaches turn taking but not interaction control, while starting with capability-heavy data without first stabilizing the duplex serialization leads to noticeably worse speech smoothness on the assistant audio."
Three orderings, three outcomes:
| Curriculum | Reported outcome | Mechanism |
|---|---|---|
| Duplex dialogue only (no capability post-training) | Turn taking works; interaction control does not | The tail behaviours are too rare in natural dialogue to be learned from the base distribution |
| Capability-heavy from the start (skip or shorten CPT) | "Noticeably worse speech smoothness on the assistant audio" | The model is asked to learn behaviours before it is fluent in the serialization; capacity goes to the format at the expense of the voice |
| CPT then post-training (the paper's recipe) | Most data-efficient | The timing prior is stable first, so the small capability slices only have to teach decisions, not format |
Pick a curriculum and watch five capability meters fill as training progresses through the stages. The profiles encode the paper's qualitative findings from Section 4.4 (which reports outcomes, not ablation numbers) — treat the bars as an illustration of the argument, not as measured data.
The fourth button is our extrapolation rather than the paper's: remove the dual-side ASR slice and watch the timing meter stall while every other meter fills normally. Section 3.4's argument says this is what should happen — the model would speak beautifully and act at the wrong moments — and it is the single most instructive counterfactual in the recipe.
Write the objective out fully, with the shape of each term, so nothing is hand-waved:
| Term | Target tokens | Count per chunk | Treated how |
|---|---|---|---|
| Assistant TA4 — text anchor | A word, or a silence anchor | 1 | Full weight when it is a word; down-weighted when it is <vad_silence> / <tts_pad> |
| Assistant TA4 — audio tokens | Discrete speech units, or silence codes | 4 | Same pattern: content tokens matter, silence codes are structural |
| Action channel | Planning text, labels, JSON, transcripts | 0 to 10 | Full weight — this is where the capability lives |
| Chunk terminator and boundary markers | Five deterministic markers | 5 | Masked or heavily down-weighted — zero information |
| User audio features | — | 2 | Never a target. Observed only |
| System prompt segment | — | once per sample | Masked — conditioning, not content |
| Text-only slice | Ordinary text tokens | — | Standard language modelling, to preserve reasoning |
Add up the "structural" rows against the "content" rows for an idle chunk and the imbalance is stark: 5 markers plus 5 silence tokens against 0 content tokens. For a speaking chunk with an active action lane: 5 markers against up to 15 content tokens. The mix swings by a factor of several depending on what is happening, which is another argument for masking — without it, the effective learning rate on content varies with how talkative the sample is.
Worth doing roughly, because it explains why the paper cares so much about not wasting supervision. The model has one set of weights and four jobs:
| Job | What it demands | Competes with |
|---|---|---|
| Speak fluently | Precise audio-token modelling at 25 tokens/s, prosody, no artifacts | Everything — it is the highest-rate output |
| Understand continuously | Causal encoding of user audio, semantics without lookahead | Speaking, for attention over the same context |
| Decide turn-taking | Fine-grained temporal judgement about intent completion | Understanding, and the action lane's budget |
| Plan and call tools | World knowledge, schema selection, argument construction | All of the above, in ten tokens a chunk |
The cascade splits these across four specialized components, one of which can be a frontier-scale LLM doing nothing but planning. DuplexSLA runs all four in a 7B model in a 160 ms window. Framed that way, an average tool-call accuracy of 85.56% against a cascade's 91.33% is a remarkably small gap, and Chapter 10's trade analysis becomes easier to reason about.
A natural question given the era: the recipe is entirely supervised — continued pretraining plus supervised post-training, with no preference optimization or RL stage. Some plausible reasons, which the paper does not state:
That said, the obvious application exists: the benchmark's own scoring rule — correct function, correct arguments, legal trigger time — is a ready-made reward. It is a natural next paper, and its risk is equally obvious: optimizing directly for the timing window would push the model toward firing as early as the rule allows, which is exactly the speculation problem Chapter 10 raises.
Being precise about the gaps is part of reading a technical report well. Section 4 does not report:
None of these are damning — industrial technical reports routinely omit them — but a careful reader should know which claims rest on published numbers and which rest on the authors' report of their own experience. In this section, the curriculum argument rests on the latter.
A practical ordering, derived from everything above, for anyone building a duplex action model on a different backbone:
If you were running this, the loss curve would tell you very little — it is dominated by structural tokens that are learned in the first hour. Three better instruments, each derived from something in this lesson:
| Metric | What it detects | Why the loss will not show it |
|---|---|---|
| Format validity rate — the fraction of generated chunks with exactly one terminator, five TA4 tokens, and at most the budget of action tokens | Whether the serialization is actually internalized | Malformed chunks are rare enough to be invisible in an average, and catastrophic at inference |
| Emission-offset error — on held-out ASR samples, the signed difference in chunks between where a transcript token was emitted and where it should have been | Whether the timing prior is forming, and whether it is biased early or late | Cross-entropy on the right token in the wrong chunk is only slightly worse than in the right chunk |
| Speech smoothness — any proxy for audio-token distribution health, or simply listening | The canary for capacity being eaten by format learning — the failure mode of capability-first training | The paper found this degrades first, and it is not in any loss term |
The middle one deserves emphasis because it is the metric that would have made Section 3.4's argument quantitative. A signed offset error tells you not just that timing is wrong but which way, which distinguishes a mis-aligned corpus (constant bias) from an under-trained model (high variance). Neither appears in the paper.
Audio corpora are quoted in hours, but a language model consumes tokens. Convert, because the number reframes the whole training run:
Roughly a hundred billion sequence positions, of which about seventy billion are supervised. That is a pretraining-scale run by any measure — comparable in token count to training a mid-size language model from scratch — being spent on reformatting a model that already knew how to speak.
Two implications. First, "continued pretraining" is not a fine-tune; it is a second pretraining, which is why it can install something as fundamental as a clock. Second, the ~1.92M general text samples that preserve language ability are a tiny fraction of that stream, which makes their placement and weighting a delicate business the paper does not detail.
The post-training stage, by the same arithmetic, is about 1.1 × 109 chunks — still over a billion supervised chunk-decisions for behaviours as narrow as "keep talking through a backchannel." Timing behaviours are apparently expensive to install even when everything underneath them is already in place.
The curriculum makes most sense drawn as dependencies rather than as a timeline. Each capability requires the ones below it:
Read upward and the data proportions stop looking arbitrary: the recipe spends the most on the widest layer and the least on the narrowest, which is what you would do for any skill that composes.
If you remember one thing: a duplex spoken agent carries the additional burden of timing, and timing is a prior that has to be stable before behaviours are layered on. That single sentence explains the stage division, the size of the ASR slices, and the surprising failure mode of capability-first training — which degrades the voice, not the behaviour.
| Question | The recipe's answer |
|---|---|
| What does CPT teach? | The serialization, the timing prior, and silence — not the target behaviours |
| What does post-training teach? | Interaction control and three tool-call patterns, on 10% of the data |
| What does the loss modify? | Silence anchors, boundary markers, and task-conditioned segments are not trained as ordinary content |
| Why that order? | Most data-efficient in the authors' experiments; the reverse harms speech smoothness |
| What is unreported? | Weights, optimizer, schedule, hardware, ablation tables, base-model regression |
Three exercises:
Every claim in this lesson now has to survive contact with numbers. And the first problem the authors faced is that the numbers did not exist: no benchmark measured what they built.
Section 5.1: "Existing duplex benchmarks measure pause, interruption, and backchannel behaviour, but none of them jointly stress sub-second yielding under semantic interruption, backchannel detection inside the action channel, backchannel-triggered tool calling, and multi-action tool calling on a duplex timeline."
So they built one. This chapter reads the protocol carefully — because a benchmark authored by the system's authors deserves careful reading — and then reads the results.
| Subset | Scenario | Cases | What the case contains |
|---|---|---|---|
| Turn-taking 1,200 cases | normal | 300 | Ordinary end-of-turn response |
pause | 300 | Hesitation-rich within-turn silence | |
interrupt | 300 | Semantic interruption mid-assistant-speech | |
backchannel | 300 | Short user feedback without floor transfer | |
| Tool call 900 cases | single-action | 300 | One explicit request, one function |
multi-action | 300 | One user turn, multiple ordered functions | |
backchannel-action | 300 | Topically unrelated function triggered while the assistant keeps speaking |
Each test case is a duplex audio session with semantic anchor times annotated. That annotation is the benchmark's real asset: it is what makes "did it act at the right moment?" a scoreable question rather than a vibe.
Table 4 gives the evaluation as pseudocode in set-theoretic form. Translated:
speak if the model emitted assistant speech else stop, and append every action label the step produced.Four things to notice about this design:
argmin t inside the window. A system that emits several candidate events is scored on the first one that lands in bounds.Table 3 defines, per scenario, what counts as correct and what the delay is measured against. This is where the benchmark's judgment calls live:
| Scenario | Accuracy window | Delay definition | Reading it |
|---|---|---|---|
normal | Assistant speech onset in [tue − 0.2, ∞) | |tspeak − tue| | You may start up to 200 ms before the user's end, and there is no late cutoff — slowness is punished by delay, not by accuracy |
pause | Same as normal, on hesitation-rich audio | |tspeak − tue| | Identical rule; the difficulty is entirely in the audio, which is full of within-turn silences designed to trigger a premature endpoint |
interrupt | Assistant stop time in [tint − 1, tint + 2] | |tstop − tint| | A three-second window around the semantic interrupt anchor. Stop too late and you simply miss |
backchannel | A stop-or-restart event in [tbc-s − 0.2, tbc-e + 2] | |tlabel − tbc-e| | The tricky one — see below |
The backchannel row needs unpacking, because it looks inverted at first read. The accuracy criterion for baselines is relaxed to "any stop-or-restart event inside the window", since closed-source systems emit no backchannel label. But a stop is exactly the wrong behaviour on a backchannel! So what is being scored?
Read the protocol note: "for s = backchannel, accuracy is relaxed to any {stop, speak} event inside Ws, since closed-source baselines emit no backchannel label and DELAY is therefore reported only when one is present." The relaxation exists so that baselines can score at all, by looking for any observable reaction to the backchannel in the audio. DuplexSLA, which does emit a label, is scored on the label directly. That asymmetry is worth flagging, and it is one reason the backchannel column deserves the most scrutiny in the results.
Pick a scenario, then drag the realized event marker along the timeline. The shaded band is the accuracy window; the dashed line is the anchor. The verdict panel reports hit or miss and the delay exactly as Table 3 defines it. Try dragging just outside a window boundary to feel how much slack each scenario actually allows.
Section 5.2 defines a triple condition. A predicted tool call counts as correct when all three hold:
| # | Condition | Why it is there |
|---|---|---|
| 1 | Every ground-truth action has a predicted action with the same function name | Coverage: you must get all the intents, not just the easy one. This is what makes multi-action hard |
| 2 | The arguments match — exact match, both empty, or judged semantically consistent by an LLM with no "core information conflict" | Argument strings are natural language ("air-conditioner: 26 degree"); exact match alone would be absurdly strict |
| 3 | The trigger time is legal: not earlier than the ground-truth offset by more than 1.0 s, and not later than the end of the audio by more than 3.0 s | Timing as correctness, not just as a metric — the innovation of this benchmark |
Condition 3 is the one to study. It is asymmetric and both bounds are interesting:
And then: "Accuracy is the fraction of cases in which all ground-truth actions are matched, and delay is the average gap on matched actions." All-or-nothing per case. Get two of three functions in a multi-action request and you score zero for that case.
Table 5, the 900-case tool-call subset. The baseline is a cascade: "a streaming ASR module whose transcript is fed to an LLM that emits tool calls."
| Model | Single action | Multi actions | Backchannel action | Average | ||||
|---|---|---|---|---|---|---|---|---|
| Acc % | Delay s | Acc % | Delay s | Acc % | Delay s | Acc % | Delay s | |
| ASR + LLM cascade | 89.33 | 2.33 | 89.33 | 4.71 | 95.33 | 1.27 | 91.33 | 2.77 |
| DuplexSLA | 85.67 | 0.67 | 75.00 | 0.68 | 96.00 | 0.57 | 85.56 | 0.64 |
Four readings, in increasing order of interest:
Table 6, all four scenarios, systems that can preload the dialogue history:
| Model | normal | pause | interrupt | backchannel | ||||
|---|---|---|---|---|---|---|---|---|
| Acc % | Delay s | Acc % | Delay s | Acc % | Delay s | Acc % | Delay s | |
| DuplexSLA | 96.00 | 0.27 | 93.33 | 0.27 | 99.33 | 0.40 | 98.33 | 0.32 |
| gemini-3.1-flash-live | 93.67 | 1.18 | 94.33 | 1.17 | 63.67 | 0.62 | 40.00 | N/A |
| gpt-realtime-1.5 (semantic-vad-high) | 91.33 | 1.67 | 90.33 | 1.68 | 79.00 | 0.68 | 0.33 | N/A |
| gpt-realtime-1.5 (server-vad-40ms) | 82.33 | 0.95 | 71.00 | 1.02 | 77.00 | 0.72 | 13.00 | N/A |
This is the paper's strongest table, and it rewards column-by-column reading:
The two gpt-realtime configurations are also an instructive within-system comparison: semantic-vad-high buys accuracy on normal and pause (91.33/90.33 vs 82.33/71.00) at the cost of latency (1.67 vs 0.95 s). That is the semantic-VAD trade the paper predicted in its introduction, measured on a commercial system: the extra detector chain helps the decision and costs the clock.
Table 7 reduces to the two scenarios every system supports, and adds open-source duplex backbones:
| Model | Average | normal | pause | |||
|---|---|---|---|---|---|---|
| Acc % | Delay s | Acc % | Delay s | Acc % | Delay s | |
| DuplexSLA | 94.34 | 0.30 | 95.67 | 0.29 | 93.00 | 0.31 |
| Freeze-Omni | 10.67 | 0.36 | 10.33 | 0.40 | 11.00 | 0.33 |
| PersonaPlex | 22.34 | 0.47 | 22.67 | 0.38 | 22.00 | 0.55 |
| MiniCPM-o | 82.00 | 0.61 | 83.33 | 0.62 | 80.67 | 0.59 |
| gemini-3.1-flash-live | 93.17 | 1.17 | 93.67 | 1.16 | 93.67 | 1.18 |
| gpt-realtime-1.5 (semantic-vad-high) | 96.50 | 1.57 | 96.70 | 1.57 | 96.30 | 1.57 |
| gpt-realtime-1.5 (server-vad-40ms) | 85.50 | 0.83 | 91.30 | 0.83 | 79.70 | 0.83 |
Three observations, one of which should make you cautious:
Every system plotted as accuracy (vertical) against delay (horizontal, lower is better). The upper-left corner is where you want to be. Switch scenarios to watch the field rearrange — especially the jump from normal to backchannel, where three of four baselines fall off the chart entirely.
Before the numbers, one more look at the design. Three quantities a duplex evaluation could have scored and this one does not:
The third is the most surprising omission. In a benchmark built around acting early, spurious action is the natural failure mode, and precision — not just recall — is what a deployment cares about. Nothing in the stated rule appears to count extra calls against a system.
Run the protocol yourself on a single interrupt case, so the tables stop being abstractions.
The case. The assistant is speaking. The user's semantic interruption anchor is annotated at tint = 3.40 s. The audio is 8.0 s long, so K = ⌈8.0 / 0.16⌉ = 50 chunks.
Stage 1 — Init. Reset the model, prefill the history, empty log E.
Stage 2 — Stream. Feed 50 chunks. Suppose the model emits assistant speech through chunk 24 and silence from chunk 25 onward, and emits an interrupt label in chunk 24. The log gains, among others:
Stage 3 — Score. For s = interrupt, the required event type is τ = stop, the anchor is t★ = 3.40, and the window is [tint − 1, tint + 2] = [2.40, 5.40].
stop event in the window: t = 4.00 s (chunk 25)Sanity checks. Would a slower system still hit? A stop at 5.30 s is inside the window — accurate, with a delay of 1.90 s. A stop at 5.50 s is outside — scored as a miss, and its delay is not counted at all. That is the accuracy-versus-delay asymmetry from the protocol, now concrete: late enough and you stop hurting your delay average and start hurting your accuracy instead.
Now do the arithmetic that makes DuplexSLA's 0.40 s average striking. To average 0.40 s, its stop events land, on average, 2.5 chunks after the semantic anchor — and Chapter 6's trace showed why roughly two of those chunks are evidence accumulation rather than lag.
A transferable checklist, derived from reading this protocol carefully. Apply it to the next duplex paper you read:
Section 5.4 states two patterns: "(1) On turn taking, DuplexSLA delivers sub-second responses in all four scenarios and is the only system that cleanly handles backchannel detection. (2) On tool calling, DuplexSLA matches the cascade in accuracy at ~4x lower delay, because the action channel emits planning and tool calls without waiting for a turn boundary or interrupting assistant audio."
Claim (1) is well supported by Table 6. Claim (2) needs a caveat that Chapter 10 supplies: "matches in accuracy" is 85.56 against 91.33 on the average, and 75.00 against 89.33 on multi-action. "Competitive" is the fairer word, and the paper uses it in the abstract ("while remaining competitive on tool-call accuracy") — the summary in Section 5.4 is the looser phrasing.
What both claims do jointly support is the design argument: "Together they validate the central design choice — an explicit action channel on top of a duplex backbone, supervised by the data recipe in Section 3." That is the claim the numbers actually license, and it is a good one.
Tables 6 and 7 differ by one flag: whether the system may preload the dialogue history H before streaming begins. The paper's reason is practical — "Many duplex systems cannot cheaply preload long histories" — but the split is more interesting than a logistics note.
| With prefill (Table 6) | Without prefill (Table 7) | |
|---|---|---|
| What the model knows | The whole conversation so far | Only the current audio |
| Scenarios evaluable | All four | Only normal and pause |
| Why the restriction? | — | Interrupt and backchannel require the assistant to be mid-utterance, which requires a history to be mid-way through |
| Deployment analogue | A continuing session with state | A cold start, or a system whose context cannot be cheaply seeded |
The third row is the substantive one. You cannot test interruption without an utterance to interrupt, and you cannot put the system mid-utterance without giving it the context that produced the utterance. So the no-prefill setting is not a harder version of the same test — it is a strictly smaller test, covering only the two scenarios that need no history.
Which means the headline capabilities of this paper — semantic interruption and backchannel — are demonstrated only in the prefill setting, against three commercial baselines. That is a reasonable evaluation, and it is narrower than a quick reading of "1,200 turn-taking cases" suggests.
Every headline number, with the claim it supports and the caveat it carries:
| Number | Claim it supports | Caveat |
|---|---|---|
| 0.27 / 0.27 / 0.40 / 0.32 s | Sub-second turn-taking in all four scenarios | Includes an unavoidable ~80 ms quantization term from the 160 ms clock |
| 98.33% vs 40.00% backchannel | Only system that can express "acknowledged, continuing" | Baselines are scored on a relaxed audio-only criterion because they have no label |
| 99.33% interrupt | Semantic yielding is a real capability gap | A three-second accuracy window is generous; the delay column is the sharper measure |
| 0.64 s vs 2.77 s tool call | ~4× faster dispatch | Delay is the trigger time; full arrival takes several more chunks |
| 85.56% vs 91.33% | "Competitive" accuracy | Section 5.4's "matches" is looser than the abstract's "competitive" — prefer the latter |
| 94.34% at 0.30 s (no prefill) | Only sub-second system with competitive accuracy | Not the most accurate: gpt-realtime reaches 96.50% at 1.57 s |
| 10.67% / 22.34% | Pause robustness needs explicit supervision | Both systems also collapse on normal, which that explanation does not cover — suspect the harness |
If you remember one thing: this benchmark's contribution is treating when as a correctness criterion, with both an early bound and a late bound. Speed without an early bound rewards guessing; that single asymmetry is what makes the tool-call numbers meaningful.
A lesson that ends at the results table has taught you to be impressed. This chapter is where you learn to be useful.
DuplexSLA makes a genuine architectural contribution and it is not free. Some of the costs are stated in the paper, some are visible in its numbers, and some are absences you have to notice yourself. All three kinds are below.
A note on tone before starting. Everything below applies to a paper whose central results this lesson has spent ten chapters taking seriously. Criticism at this level of detail is a compliment: vague papers cannot be criticized precisely, because there is nothing specific enough to disagree with. Every item here is possible to state only because the paper stated its own design clearly enough to be checked.
Put the numbers next to each other with no rounding and no framing:
| Pattern | Cascade acc | DuplexSLA acc | Δ accuracy | Δ delay | Seconds saved per accuracy point lost |
|---|---|---|---|---|---|
| Single action | 89.33% | 85.67% | −3.66 | −1.66 s | 0.45 s / point |
| Multi action | 89.33% | 75.00% | −14.33 | −4.03 s | 0.28 s / point |
| Backchannel action | 95.33% | 96.00% | +0.67 | −0.70 s | strictly better |
| Average | 91.33% | 85.56% | −5.77 | −2.13 s | 0.37 s / point |
Whether that is a good trade depends entirely on the product. In a car, where a two-second gap is the difference between a usable assistant and an abandoned one, giving up six points of accuracy for two seconds is obviously right. In a banking assistant that executes transfers, it obviously is not. There is no architecture-level answer.
Why is multi-action the weak point? The paper does not analyze it, so here are four mechanisms, ordered from most to least likely, each grounded in something we established earlier:
| Hypothesis | Grounding | Would predict |
|---|---|---|
| 1. Incremental commitment without revision. Each call is emitted at its own anchor, before the rest of the sentence is heard. The model cannot revise an earlier call after later context arrives | Chapter 4: ordering is inherited from the clock, not constructed by a planner | Errors concentrated on the earliest intents in a multi-intent turn, and on turns with corrections |
| 2. All-or-nothing case scoring. Three functions per case, all must match. If each call is independently 91% right, the case-level score is 0.913 = 75.4% | Chapter 9's condition 1 | Almost exactly the observed 75.00% — a suspiciously good fit |
| 3. Budget pressure on planning text. Ten tokens per chunk forces terse rationales; three actions in a short window means the queue is draining continuously | Chapter 5's drainer — verbosity is a latency tax and the cap truncates thought | Degradation that worsens as intents get closer together |
| 4. Capacity. A 7B backbone doing four jobs against a cascade whose LLM does exactly one | Chapter 3's virtue table | A uniform gap across all patterns — which is not what we see, so this is probably not the main cause |
Hypothesis 2 deserves a moment. If per-call accuracy were the same as the single-action rate of 85.67%, the cubed value would be 62.9% — too low. If per-call accuracy is around 91%, the cube is 75.4%, essentially the observed number. So the data are consistent with "each individual call in a multi-action request is about as good as a single-action call, and the case-level score is just the compounding." That is a much less alarming story than "the model gets confused by multiple intents", and it is testable: report per-action accuracy alongside per-case accuracy. The paper does not.
Set how much one second of delay costs you, in units of accuracy points. The bars re-rank every system by that utility. At zero, accuracy is all that matters and the cascade (or gpt-realtime) wins. Slide right and the ranking flips — find the crossing point for each pattern, and notice how differently the three tool-call patterns behave.
Two crossing points worth finding by hand. On the tool-call average, the cascade's 5.77-point lead is worth 2.13 seconds, so the systems tie when one second costs 2.7 accuracy points. On multi-action, the 14.33-point lead is worth 4.03 seconds, so the tie is at 3.6 points per second. In other words: if you believe a second of voice latency is worth more than about three points of tool accuracy, DuplexSLA wins everywhere. Most voice-product intuition says a second is worth far more than that — but now you can argue about a number instead of a vibe.
One nuance on the table above before moving on: the "seconds saved per accuracy point lost" column is not a physical constant, it is a ratio between two things measured on this benchmark with this baseline. Swap in a faster cascade — better endpointing, a smaller planner — and the ratio moves. What does not move is the structural bound: the cascade cannot dispatch before the endpoint, so however fast its components get, the multi-action gap stays large. Optimize the constants and the shape of the trade survives.
Introduced in Chapter 4, now counted properly. The action channel is emit-only, as described. Appendix E's action-object schema has four fields — name, planning, parameters, offset — and no result. Nothing in the paper describes how a tool's output re-enters the model.
Chapter 7's schema audit showed roughly twenty of the fifty functions are queries whose answers the assistant must speak: query_arrival_time, query_weather, query_stock, search_food, search_hotel, query_road_conditions. For all of these, the paper's contribution covers half the round trip.
The consequences, in increasing severity:
set_car_setting) always succeeds; the assistant can safely say "done" concurrently. The paper's showcase examples are all of this kind.One more consequence of the missing return path, easy to miss: it also means there is no latency for tool execution anywhere in the reported numbers. Every delay figure in Chapter 9 measures when the model spoke a call into the void. A real assistant's felt latency is dispatch plus execution plus, for query tools, the time to work the answer into speech. The paper's 0.64 s is a lower bound on an end-to-end quantity nobody has measured yet.
| Dimension | What the paper covers | What is untested |
|---|---|---|
| Language | Chinese (all traces, all canonical labels, all system prompts) | Every other language. Turn-taking cues, backchannel conventions, and hesitation patterns are strongly culture- and language-specific |
| Audio realism | TTS and voice cloning, force-aligned, time-merged (Chapter 7) | Natural conversational recordings: crosstalk, reverberation, road noise, laughter, disfluency, two people |
| Tools | 50 cabin and smart-home functions, flat, single-call, mostly side-effecting | Open-domain tools, web APIs, multi-step workflows with dependencies, tools that need authentication or confirmation |
| Speech quality | Reported qualitatively ("speech smoothness") | No MOS, no listening test, no intelligibility or naturalness metric anywhere in the paper |
| Robustness | — | No results on noisy input, accented speech, code-switching, or overlapping speakers — despite two authors having published on code-switching ASR |
| Long conversations | Single-episode benchmark cases | Context growth over a long drive; how the 6.25 Hz token stream interacts with the context window over tens of minutes |
The context-length point is worth its own arithmetic, because it is a real deployment concern that the paper does not raise. At 11 tokens per idle chunk and 6.25 chunks per second:
A duplex model burns context at a rate no text chat approaches, because it pays tokens for silence. Whatever context-management strategy makes a long drive work — sliding windows, summarization, state carry-over — is unaddressed here, and it interacts badly with the "context prefill" setting that Table 6 depends on.
Worth stating what is not a scope problem, since lists like the one above can leave a false impression. The 160 ms clock, the TA4 layout, the ordering argument, the FIFO queue, and the timestamp-for-free property are all language-independent and domain-independent. They would work identically in English, in a kitchen, or on a phone call. What is scoped is the evidence, not the mechanism.
This is the most important gap for a careful reader, and it takes a moment to see.
The paper's central claim is that a dedicated action channel is the right design. The evidence offered is: DuplexSLA (which has one) beats a cascade and several commercial systems (which do not). But those systems differ from DuplexSLA in every other way too — backbone, training data, language, clock, objective.
The experiment that would isolate the claim is absent: train the same backbone, on the same data, with tool calls embedded in the assistant text channel instead of a separate lane, and measure the speech smoothness and tool accuracy that result. Section 2.6 asserts the outcome — "would force that channel to alternate between TA4 audio tokens and tool-call JSON, which breaks the smoothness of the assistant audio" — but asserts it without a number.
| Claim | Supported by | Strength |
|---|---|---|
| Duplex + action channel is faster than a cascade | Table 5, measured head to head under one protocol | Strong |
| Native turn-taking beats external semantic VAD | Table 6, four scenarios, three baseline configurations | Strong |
| A separate action channel beats a shared text channel | Architectural argument in Section 2.6 | Asserted, not measured |
| The 10-token cap is the right budget | Throughput arithmetic in Section 2.3 | Derived, and honestly labelled a deployment choice |
| The CPT → post-training order is best | "In our experiments" — outcomes reported, no table | Reported, not shown |
None of this makes the paper wrong. The architectural argument in Section 2.6 is a good argument, and it is the kind of thing that is genuinely expensive to ablate at 7B scale on 550k hours. But "obviously right" and "demonstrated" are different epistemic states, and a reader who conflates them will over-generalize the result to settings where the argument does not hold.
A structural point that follows from Chapters 7 and 9 together, and that no single section of the paper states.
The post-training tool-call data has three families: single-action, multi-action, and backchannel-action. The benchmark's tool-call subset has three families: single-action, multi-action, and backchannel-action, 300 cases each. Both are built by the same team, presumably with the same annotation pipeline and the same 50-function schema.
| Component | Training | Evaluation | Shared? |
|---|---|---|---|
| Tool schema | 50 cabin and smart-home functions | The same 50 | Yes |
| Pattern taxonomy | Three tool-call styles | The same three | Yes |
| Scenario taxonomy | Interrupt, backchannel, pause | The same, plus normal | Yes |
| Audio generation | TTS with voice cloning | Duplex audio sessions with annotated anchors — construction not stated to differ | Probably |
| Anchor annotation | LLM annotation, force-aligned | "Semantic anchor times annotated" | Probably |
This is entirely normal for a capability report and it is still worth naming. Matched training and evaluation taxonomies measure whether the capability was successfully installed. They do not measure whether it generalizes to a request pattern nobody enumerated, a function outside the schema, or an anchor annotated by a different process.
The cascade baseline is, ironically, less advantaged here: its LLM was not trained on this schema or these patterns, and it still scores higher on accuracy. That comparison is more favourable to the cascade than the headline framing suggests — and more impressive for DuplexSLA's latency claim, which no amount of distribution matching can fake.
One more absence, and it is a safety-shaped one. The entire value proposition is acting before the user finishes speaking. The benchmark's only guard against acting too early is the legality rule: not more than 1.0 s ahead of the annotated offset.
But the annotated offset is defined as the moment the intent became clear, by an annotator who saw the whole sentence. At inference time, nobody knows the future. Consider:
Each has an early fragment that reads as a clear intent and a later fragment that reverses it. A model rewarded for acting at the earliest defensible moment is a model biased toward acting on the fragment. The paper reports no results on corrections, negations, or retractions, and its 50 functions include no confirmation or undo primitives. Nothing in the design forbids adding them — but a system that turns your car's heat on because it heard "cold" in "I'm not cold" is a product problem, and the benchmark as constituted would not catch it.
Technical reports on capability rarely include one, and this is not a criticism of the authors so much as a note about what a deployment review would have to add. A duplex action model raises questions that neither a speech model nor a text agent raises alone:
| Question | Why duplex action makes it sharper | What would address it |
|---|---|---|
| Consent to act | The system acts before the sentence ends, so the user has not finished authorizing anything | A reversibility tier on the schema; confirmation required above it |
| Retraction | Speech is not undoable, and neither is a dispatched call | A cancel primitive on the action lane, plus supervision for correction utterances |
| Attribution | Who asked for this — the driver, a passenger, the radio? | Speaker identification on the user channel; the paper's single user track has no notion of who is speaking |
| Adversarial audio | An assistant that acts on partial speech can be triggered by a fragment played from any speaker in the cabin | Wake-word gating or speaker verification — both of which reintroduce latency |
| Auditability | Actions now have timestamps but no user-visible record | Log the action lane with chunk indices; it is already a perfect audit trail |
| Voice cloning | 18 cloned speakers are used in training | Provenance and consent for the voices; watermarking of generated speech |
The fifth row is a small bright spot: the architecture happens to produce exactly the artifact an auditor would want. Every action ever taken has a name, arguments, a rationale in natural language, and a millisecond-resolution timestamp, emitted on a dedicated lane. Very few agent architectures give you that for free.
The fourth row is the darkest. A system whose selling point is acting on fragments is, definitionally, easier to trigger with fragments. The mitigations all cost the latency the system exists to save, which makes it a genuine design tension rather than an oversight to patch.
A useful exercise on any technical report: line up how the same result is phrased in the abstract, the body, and the summary. Careful authors hedge in one place and relax in another, and the difference tells you where the evidence is thin.
| Result | Abstract | Section 5.4 summary | Which to quote |
|---|---|---|---|
| Tool-call accuracy | "remaining competitive on tool-call accuracy" | "matches the cascade in accuracy" | The abstract — 85.56 vs 91.33 is competitive, not matching |
| Latency ratio | "sub-second latency" | "~4x lower delay"; the conclusion says "3−4x" | The conclusion's range — it spans the per-pattern variation honestly |
| Turn-taking | "semantic-driven turn-taking control" | "the only system that cleanly handles backchannel detection" | Both hold up; Table 6 is unambiguous |
| Curriculum | — | "the most data-efficient setup in our experiments" | Report as the authors' experience, not as a measured ablation |
| The action channel design | "a dedicated, time-stamped textual lane" | "validate the central design choice" | Note that "validate" here means "the system works", not "the alternative was tried" |
None of this is misconduct — the abstract is the careful version in every case, which is the right way round. But if you are going to cite one sentence of this paper in a design document, cite the abstract's.
Given the failure taxonomy below and the gaps above, a concrete wish list, ordered by how much each would change our understanding:
One reason this architecture is worth studying is that it creates error categories that do not exist in text agents. Naming them is useful whether or not you ever build one:
| Failure | What it looks like | Which mechanism produces it | Measured here? |
|---|---|---|---|
| Wrong function | Opens the window instead of the AC | Ordinary schema-selection error | Yes — condition 1 |
| Wrong arguments | Sets 16 degrees instead of 26 | Argument construction under a token budget | Yes — condition 2 |
| Right call, too late | Navigation starts after the junction | Queueing, budget, or slow recognition | Yes — delay and condition 3 |
| Right call, too early | Acts on "cold" in "I'm not cold" | Incremental commitment; anchored on a fragment | Only crudely — the 1.0 s early bound |
| Un-revised call | User corrects themselves; the first call already fired | No revision path once an anchor has passed | No |
| Orphaned claim | "I'm navigating there now" when the call failed | No return channel | No |
| Starved voice | Audio stutters while the action lane is busy | Would require the ordering or budget to break | Prevented by construction |
| Split JSON | Unparseable action stream | Atomicity violation at inference time | Not reported |
| Clock drift | Everything correct, uniformly late | RTF > 1, or misaligned training labels | Not reported |
Five of the nine are unmeasured. That is not an indictment — it is a map of what a follow-up evaluation suite should cover, and several of them (revision, orphaned claims) are the ones a real user would notice first.
A fair reading of that taxonomy: the four failures the benchmark measures are the four a model can be blamed for, and the five it does not measure are the ones a system can be blamed for. That split is exactly the boundary between a foundation-model report and a product evaluation, and it is worth knowing which document you are holding.
Question 3 deserves emphasis. The paper's fifty functions are almost all recoverable: a wrong AC temperature is fixed by saying so. Add make_call to a stranger, a purchase, or a message send, and "act at the earliest defensible moment" becomes a different risk profile entirely. The architecture makes early action possible; it does not tell you which actions deserve it.
Concretely, the experiments that would most raise or lower confidence in this design:
| Experiment | If it succeeds | If it fails |
|---|---|---|
| Same backbone, tool calls in the assistant text channel | The separate-lane claim is demonstrated, not just argued | The third channel is unnecessary complexity |
| Per-action (not per-case) tool accuracy on multi-action | The 75% is compounding, and each call is fine | The model genuinely degrades with multiple intents |
| Evaluation on natural, non-synthesized duplex audio | The pipeline's synthetic training generalizes | The results are an artifact of clean TTS timing |
| A second language with different backchannel conventions | The behaviours are learned, not memorized | The label set is culture-bound |
| Correction and negation cases in the benchmark | Early commitment is safe | Speed was bought with a real safety cost |
| Long-session evaluation with context management | Deployable for a full drive | The token rate is the real bottleneck |
The five costs, with a one-line statement of each and its severity for a real deployment:
| Cost | One line | Severity | Fixable how? |
|---|---|---|---|
| 1. Accuracy trade | −5.77 points on average, −14.33 on multi-action, for −2.13 s | Depends entirely on the domain | Bigger backbone; per-action rather than per-case reporting to see the real size |
| 2. No return channel | Emit-only; ~20 of 50 schemas are queries needing an answer | High for anything beyond device control | Inject results on the action lane's input side; needs supervision and a benchmark |
| 3. Scope | Chinese, synthetic audio, cabin tools, no MOS, no noise robustness | Medium — limits what generalizes, not what is true | More data, more languages, natural recordings |
| 4. Missing ablation | The separate-lane claim is argued, not measured | Medium for readers, low for users | One controlled training run — expensive but straightforward |
| 5. Acting on fragments | Rewarded for early action; no corrections, negations, or undo in the benchmark | High for irreversible tools | Confirmation primitives, a retraction action, and adversarial benchmark cases |
A closing observation about how to hold all of this. Nothing above argues that DuplexSLA is a weak result — the latency numbers are large, clean, and hard to explain away, and the backchannel result is categorical. What the chapter argues is that the scope of the demonstration is narrower than the framing suggests, in five specific and individually fixable ways. That is the normal condition of a good systems paper, and being able to state the five is what turns reading into engineering judgement.
If you remember one thing: this paper demonstrates that timing is architectural. It does not demonstrate that the specific channel design is uniquely right, that the result transfers outside Chinese in-cabin assistants trained on synthetic audio, or that acting on half-finished sentences is safe. Those three are the next three papers, and knowing which is which is what separates reading a result from using one.
Three exercises:
Step back far enough and this paper is the last move in a sequence that took about four years.
Machines learned to hear meaning when contrastive language-audio pretraining put sound and text in one embedding space, so that a model could recognize a sound it had never been given a label for. They learned to transcribe anything when weak supervision at the scale of hundreds of thousands of hours made robust speech recognition into infrastructure. They learned to treat audio as language when neural codecs turned waveforms into discrete tokens and language models started generating them. They learned to converse when dual-stream duplex models put both voices on one clock and made overlap representable.
And now, with DuplexSLA, they learn to act — on the same clock as the voice.
| Step | The capability unlocked | What remained impossible |
|---|---|---|
| CLAP — contrastive language-audio pretraining | Zero-shot audio classification: open-vocabulary hearing | Anything sequential; anything spoken back |
| Whisper — weakly supervised ASR at scale | Transcription robust enough to be a utility | Understanding beyond the words; speaking; timing |
| EnCodec / AudioLM — audio as tokens | Generation of speech and audio by language modelling | Interaction — the model still spoke in monologue |
| Moshi — dual-stream full duplex | Continuous listening while speaking; barge-in; inner monologue | Doing anything in the world |
| Qwen2.5-Omni — streaming omni-modal | A whole stack that streams, with time as a first-class citizen | A native lane for decisions and side-effects |
| DuplexSLA — speech, language, action | Tool calls and turn-taking decisions on the voice's own clock | Results returning; open-domain tools; safety on unfinished sentences |
Click a node to see what it unlocked, what it still could not do, and which chapter of this lesson depends on it. The connecting edges are capabilities, not citations — each step is only possible because the previous one exists.
Each row of that table is a lesson in this series or a chapter in one, and the column that matters is the third. Progress in this field has not been a march toward one goal; it has been a sequence of specific impossibilities being removed, one at a time, each by a system that assumed everything before it.
Every interface has a cost of use, and the cost is not measured in features. It is measured in what the interface demands of your attention, your hands, and your eyes.
| Interface | Demands | Fails when |
|---|---|---|
| Screen and touch | Eyes on the display, a free hand, spatial memory of the app | You are driving, cooking, carrying something, or your hands are dirty |
| Turn-based voice | You wait for it; it waits for you; you learn to speak in complete, uninterrupted commands | You hesitate, change your mind, or want two things at once |
| Duplex voice that can only talk | Natural conversation, but every request that needs doing falls back to a screen | The moment the conversation needs to change the world |
| Duplex voice that acts | Speak the way you speak to a person | …the frontier this paper opens |
Notice the second row. Turn-based voice assistants trained us. People genuinely learned to speak differently to them — short, complete, unhesitating command sentences, delivered in one breath. That is the tell of a bad interface: when the human adapts to the machine's model of conversation rather than the reverse.
The reason DuplexSLA matters beyond its benchmark numbers is that it removes the two adaptations we were forced into. You may hesitate, because pause is handled. You may say two things at once, because multi-action is handled. You may add a side request in the middle, because backchannel-action is handled. And the assistant may act while it talks, because the action lane exists.
Claims that a new interface has arrived are cheap. Test this one against the transitions that actually stuck, and ask what each of them had in common:
| Transition | What made it stick | The analogous move here |
|---|---|---|
| Command line → graphical UI | Direct manipulation: you point at the thing itself rather than naming it, and the result is immediate and visible | Acting mid-sentence: the effect happens while you are still describing it |
| Mouse → multi-touch | The intermediary disappeared — your finger is the pointer, with no latency between intent and effect | Removing the endpointer: no component stands between the utterance and the action |
| Typed search → instant results | Sub-100 ms feedback changed search from a query into a conversation with the index | Sub-second dispatch changes voice from a command line into a conversation with the car |
| Turn-based voice → duplex voice that acts | this paper's bet | — |
The common thread in the first three is not capability — each of those systems could already do the task. It is the collapse of the gap between intent and effect. That is precisely the quantity DuplexSLA reduces from 2.77 seconds to 0.64, and it is why the latency result matters more than the accuracy result even though the accuracy result is the one that got worse.
The honest counter-argument, which you should hold alongside it: none of the three historical transitions required the interface to guess what you meant before you finished saying it. Direct manipulation is unambiguous by construction; a finger on a button is not a prediction. Acting on a partial utterance is, and Chapter 10's fifth cost is the price of that difference. Whether the bet pays off may depend less on latency numbers than on whether early action can be made safe.
Everything worth remembering, on one screen.
The clock and the channels
| Symbol / term | Meaning | Value |
|---|---|---|
| Δ | Chunk size on the conversational clock | 160 ms |
| c = ⌊t/Δ⌋ | Chunk index — the timestamp of everything | — |
| U | Continuous causal user audio feature | 2 per chunk, 80 ms stride |
| TA4 | Assistant unit: one text anchor + four audio tokens | 5 tokens per chunk, always |
| T | Text anchor: a word, <vad_silence>, or <tts_pad> | Left-aligned, no exact timing |
| A | Discrete assistant audio token | 40 ms each, 25/s |
| Action channel | Text-only lane: planning, labels, tool calls, delayed transcripts | ≤10 tokens per chunk |
| Total model output | TA4 + action | 5 to 15 tokens per chunk = 31.25–93.75 tokens/s |
The serialization
memorize this
<|user_audio_begin|> U U <|user_audio_end|>
<|assistant_audio_begin|> T A A A A <|assistant_audio_end|>
<action text> <|action_end|>
listen → speak → act, all inside one autoregressive step
the terminator fires every chunk whether or not anything was emitted
The rules
| Rule | Statement |
|---|---|
| Budget | ≤10 action tokens per chunk; a deployment budget, retunable without retraining |
| Spill | Surplus tokens go into following chunks; the trigger time is the chunk of the first token |
| FIFO | One queue keyed by trigger time; later actions never preempt earlier ones |
| Atomicity | A <|toolcall_begin|>…<|toolcall_end|> block is never split |
| Termination | <|action_end|> only after the last queued action has fully closed |
| Non-blocking | The TA4 stream keeps producing audio while the action queue drains |
The labels
| Label | Trigger | Assistant TA4 does |
|---|---|---|
response | User finishes a turn (also the continue-listening state during a pause) | Answers — or stays silent during a pause |
interrupt | User starts a real new thought mid-assistant-speech | Switches to silence within a few chunks |
backchannel | Short feedback without taking the floor | Continues, without resetting the speech plan |
asr | Duplex ASR supervision | Unaffected — the transcript rides the action lane |
| tool name | Tool-use scenario (50 schemas) | Unaffected — that is the whole point |
The numbers
| Quantity | Value |
|---|---|
| Backbone | 7B, initialized from Step-Audio 2 mini |
| CPT | ~500k h audio (320k duplex / 90k user ASR / 90k assistant ASR) + ~1.92M text samples |
| Post-training | ~50k h (36k interaction control / 14k tool call) |
| Voices | 18 main voice-clone speakers |
| Benchmark | 2,100 cases: 1,200 turn-taking (300 each) + 900 tool-call (300 each) |
| Turn-taking delay | normal 0.27 · pause 0.27 · interrupt 0.40 · backchannel 0.32 s |
| Turn-taking accuracy | 96.00 / 93.33 / 99.33 / 98.33 % |
| Backchannel, best baseline | 40.00% (gemini-3.1-flash-live); gpt-realtime 0.33–13.00% |
| Tool call vs cascade | 85.56% at 0.64 s vs 91.33% at 2.77 s — ~4× faster, ~6 points less accurate |
| ASR lag on the action channel | 2 chunks (320 ms) for the user side |
| Timing legality window | Not >1.0 s early; not >3.0 s after the audio ends |
Since this lesson ends at the frontier, a small act of forecasting — each falsifiable, each following from something established above:
If all three land, the resulting system is recognizably this architecture with a wider lane and a return path. If none do — if the field instead abandons discrete audio tokens, or collapses the lanes again — then the framework in this lesson was the local optimum of one representational choice, and the interesting lesson will be why it did not hold.
A condensed checklist, assembled from every chapter:
Design the return channel DuplexSLA does not specify. Constraints: the model runs at 6.25 Hz with a ≤10-token action budget; a tool result may arrive at any chunk, with arbitrary latency; the assistant may be mid-sentence when it arrives; and a result may be a failure. Decide (a) which lane the result enters on and whether it is supervised, (b) how the model is told which pending call the result belongs to, (c) what happens to an already-spoken claim ("I'm navigating there now") when the call fails, and (d) how you would benchmark it — what is the anchor, and what is the window? Then sanity-check your design against Chapter 5's budget arithmetic: does your result payload fit, or does it need its own spill rule?
Test the cheat sheet the right way round: cover the values column and reconstruct each number from the design. Four audio tokens at 40 ms forces 25 tokens per second. Five TA4 tokens plus ten action tokens at 160 ms forces 93.75 tokens per second. A 160 ms clock forces an 80 ms expected quantization floor. Numbers you can re-derive are numbers you actually understand; numbers you memorized will be wrong within a year anyway, when the next paper changes the constants.
Every term this lesson introduced, in one place, for the whiteboard test:
| Term | Definition |
|---|---|
| Full duplex | The model continuously listens to the user while generating responses — the microphone is never logically closed |
| Conversational clock | The fixed 160 ms grid on which all three channels are indexed |
| Chunk | One tick of that clock; the unit of everything |
| Dual-stream | Two physical audio streams (user, assistant) modelled jointly by one backbone |
| Three-channel | Three semantic lanes on the model interface: user audio, assistant TA4, action text |
| TA4 | The assistant's per-chunk unit: one text anchor plus four audio tokens |
| Text anchor | The text token accompanying a chunk's audio — a word, <vad_silence>, or <tts_pad>; left-aligned, no exact timing |
| Action channel | The rate-limited text-only lane carrying planning, control labels, tool calls, and delayed transcripts |
| Action object | name + planning + parameters + offset; the unit the action channel transmits |
| Semantic trigger offset | The annotated moment an intent became clear, snapped to a chunk index |
| Trigger time | The chunk in which an action's first token is emitted — what the benchmark scores |
| Spill | Surplus tokens beyond the per-chunk budget deferring to following chunks |
| Backchannel | Short user feedback that does not take the floor; the assistant labels it and keeps talking |
| Semantic VAD | An external turn detector reading meaning rather than energy — the component this architecture removes |
| Real-time factor (RTF) | Decode time for a chunk's tokens divided by the chunk duration; must stay at or below 1 |
| Context prefill | Loading dialogue history before streaming — the evaluation setting that splits Table 6 from Table 7 |
A test of understanding: can you compress it without lying? Here are three versions to compare against your own.
Sixty seconds. Voice assistants can talk but not act — tool calls either delay the speech, arrive a turn late, or break the voice. DuplexSLA puts the assistant's audio and a separate text-only "action" lane on the same 160 millisecond clock, decoded by one backbone in one step. Tool calls and turn-taking decisions ride the action lane with a ten-token-per-chunk budget, so the model can call a function mid-sentence without the voice pausing. Result: sub-second tool dispatch against a cascade's two to five seconds, and the only system that can express "I heard you and I'm continuing."
Five minutes. Add: the chunk is 160 ms because four 40 ms audio tokens and two 80 ms user features both tile it. Each chunk carries user features, a TA4 unit (one text anchor, four audio tokens, always paid), and up to ten action tokens, in that order — so the voice is committed before any action tokens are written and can never starve. Longer actions spill across chunks under a FIFO queue with atomic JSON blocks, and the trigger time is the first token, not the last. Training is two stages from a 7B Step-Audio 2 mini: 500k hours of continued pretraining, a third of which is dual-side ASR that teaches the model what time it is, then 50k hours of capability post-training for pause, interrupt, backchannel, and three tool-call patterns. Evaluated on a purpose-built 2,100-case benchmark that scores when as well as what.
On a whiteboard. Draw the clock. Draw three lanes. Write the serialization in order and circle <|action_end|>. Draw a 40-token action object spilling across four chunks while the TA4 lane keeps ticking. Write two rows of numbers: 0.64 versus 2.77, and 98.33 versus 40.00. Then say the one sentence everything reduces to: the chunk index is the timestamp, and that is what makes "synchronized" a measurable claim.
A note on the compression exercise above. Each version drops something real: the sixty-second version omits the training recipe entirely, and the five-minute version omits the honest limits. Neither is dishonest, but both are incomplete in a way worth being conscious of — the parts that get cut first are always the data section and the caveats, which are also the two parts that determine whether a result transfers. If you find yourself giving the sixty-second version to someone who is about to build something, give them the five-minute version instead, and then Chapter 10.
The paper's own forward look, from its conclusion: "We view DuplexSLA as a step toward duplex spoken agents that combine fluent speech with timely action, and we expect the action-channel design to extend naturally to richer planning signals, multi-turn agentic workflows, and broader open-domain spoken tool use."
Three phrases, three research programmes. Richer planning signals means the lane carries more than a terse rationale — which runs straight into the 10-token budget and Chapter 1's arithmetic. Multi-turn agentic workflows means the return channel, dependencies between calls, and state that survives across turns. Broader open-domain spoken tool use means leaving the cabin, where latency is measured in seconds rather than milliseconds and where a wrong call costs more than a cold seat.
If this lesson made you want to go deeper, the papers in the order that builds the least confusion:
| Read | For |
|---|---|
| Moshi (2410.00037) | The dual-stream backbone and the inner monologue — the "T" and "A4" of TA4 |
| Qwen2.5-Omni (2503.20215) | Streaming through an entire multimodal stack, and time as a first-class citizen |
| Step-Audio 2 (2507.16632) | The exact backbone DuplexSLA initializes from |
| Full-Duplex-Bench (2503.04721) | The turn-taking benchmark DuplexSLA-Bench extends |
| Chronological Thinking (2510.05150) and Mind-Paced Speaking (2510.09592) | Reasoning on the clock — the closest neighbours to the action channel |
| PersonaPlex (2602.06053) | The persona and voice-control axis, and a Table 7 baseline |
| SALMONN-omni (2411.18138) | The codec-free road not taken |
| DuplexSLA (2605.20755) | Re-read it after the above; the design decisions will read as inevitable |
And a note on where this lesson sits in the audio series. It is the terminus of a long arc — hearing, transcribing, tokenizing, conversing, acting — but a terminus only in the sense that a station is: the line continues. The next stop is not a better speech model. It is the engineering around one: the latency ledger of a production voice agent, endpointing and barge-in as product decisions, telephony and transport, evaluation suites that measure conversations rather than utterances, and the safety machinery that acting-while-listening demands.
One last thought to leave with. The most striking thing about this paper is not any single number — it is that "when" turned out to be an architectural property. Not a scheduling problem, not a post-processing problem, not something you fix with a faster VAD. You get correct timing by giving the model a clock, putting every decision on it, and supervising the alignment for ninety thousand hours. Everything else — the labels, the queue, the budget — is bookkeeping around that one idea.
Twelve chapters, twelve sentences. If you can expand each of these into a paragraph, you have the paper.
| Ch | The sentence |
|---|---|
| 0 | A turn-based pipeline cannot fire a tool call before the user stops talking, and it cannot tell a hesitation from an interruption, so a voice agent built on one can talk but not act. |
| 1 | A 160 ms chunk is the smallest window in which four 40 ms audio tokens and two 80 ms user features both tile exactly, and the decoder's per-token latency determines how many action tokens fit alongside them. |
| 2 | Each chunk serializes as user features, then the assistant's TA4 unit, then up to ten action tokens, then an unconditional terminator — and that order is why the voice can never be starved. |
| 3 | Dual-stream duplex was already solved; what was missing was a lane where decisions and side-effects could be emitted legibly and on time. |
| 4 | Because the lanes are independent, the assistant can dispatch a tool call mid-sentence without pausing — and latency masking becomes structural rather than an engineered stalling phrase. |
| 5 | Actions are longer than a chunk, so they spill under a FIFO queue with atomic JSON blocks, and the trigger time is the first token rather than the last. |
| 6 | Backchannel and interruption are acoustically identical when the decision must be made, so the decision has to live inside the model that knows what it is saying. |
| 7 | No corpus of this format exists, so it is manufactured — LLM annotation inside utterances, TTS, forced alignment, and a chunk-grid merge — and the boring ASR slice is what teaches the model what time it is. |
| 8 | Continued pretraining installs the format and the timing prior; a tenth as much post-training installs the behaviours; reversing the order damages the voice. |
| 9 | A new benchmark had to be built because no existing one scored when an action happened, and timing is treated as a correctness criterion with both an early and a late bound. |
| 10 | The speed costs about six points of tool-call accuracy, the return path is unspecified, the scope is one language and one cabin, and the central architectural claim is argued rather than ablated. |
| 11 | The chunk index is the timestamp, which is what turns "synchronized speech, language, and action" from a slogan into a measurable property — and what turns a voice that answers into an interface that acts. |