Skip to main content
A common voice agent architecture is to use a state machine in the form of a graph to track the state of the current call. Let’s take the example of a simple customer support call agent which has 3 stages: support triage, then billing, then a person. A corresponding graph describes how the call moves among these states. The process of the voice agent determining the next stage is called “Graph routing”. The usual way is to transcribe the audio and ask an LLM. With Tazo you can use the audio itself to make this decision. In this cookbook we will try to build the backend of a call router over a small graph with three states using the Tazo Python SDK.

Setup

Each caller turn is a WAV clip of at most 30 seconds.

Define the graph

Every turn asks one question: Which next step does the caller want? Its options are only the nodes reachable from the current node, additionally we define 3 built-in answers: The model only picks from this bounded list. Your application moves the call, so the model can never send it somewhere the graph does not allow. Each node has a label, a description that tells Tazo when to choose it, and routing instructions for that node. The instructions are the most useful tuning lever: they say what should and should not count as a request to move.

Build the question for a node

The question is rebuilt for the current node on every turn: the state describes where the call is, and the options are the outgoing edges plus the built-in answers. Descriptions are clipped, and the function checks the total size, because a request has a text budget for the state, question and options together.

Decide where the call goes

A route is applied only when the answer is confident (at least 65% and a 12-point lead over the runner-up), is not UNCERTAIN, CURRENT_STEP or NO_TOOL, and is a node reachable from the current one. Everything else stays put, so an unclear reply never moves the call.

Run a call

Call.turn sends one caller recording and moves the call. Pass the caller’s turns in order:
With a billing question first and then a request for a person, the output is a path like TRIAGE → BILLING → HUMAN.

Build on it

  • Add a node. Add it to NODES, connect it in EDGES, and describe when to choose it.
  • Act on arrival. When turn moves the call, run your own side effect, such as a transfer.
  • Sub-graph per graph node. A node such as BILLING will most likely have multiple sub-steps in real life, which can be represented as a sub-graph for that node. This works as long as the main routing keeps the call at CURRENT_STEP for every new reply from the customer, and the sub-graph decides what happens inside the node. Feel free to experiment with different graph representations and nested graphs.
  • Live audio. For a call that streams audio, see Speculative tool calling.

Limitations

  • The 65% and 12-point thresholds are starting points, not calibrated guarantees.
  • The size check raises an error rather than silently dropping options, so very connected nodes need shorter descriptions or fewer edges.
  • A node with no outgoing edges ends the route: only CURRENT_STEP, UNCERTAIN and NO_TOOL remain.