> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://poly-ai.ferndocs.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://poly-ai.ferndocs.com/_mcp/server.

# Tutorial: Flow fundamentals

> PolyAcademy Level 3 – Use flows to enforce multi-step sequences where order matters.

> **Info**
>
> **Level 3 – Lesson 2 of 5** – Understand flows, steps, and transitions for structured multi-turn interactions.

> **Lesson**
>
> Level 3 · Advanced · 20 min

Flows enforce a specific sequence of steps – the step prompt stays anchored at the end of conversation history, preventing the model from improvising and keeping it focused on collecting, validating, and acting on information reliably.

Use flows when order matters: collecting a booking reference, verifying identity, routing based on input. Without flows, the LLM guesses the sequence, which leads to inconsistent outcomes.

For reference documentation on flows, see the [Flows overview](/agent-studio/flows/overview). This lesson focuses on how flows work and when to use them.

## When to use flows vs other tools

#### FAQs

Simple question-and-answer. No sequencing needed.

#### Functions

Single actions: fetch data, call an API, save a value.

#### Flows

Multi-step sequences where order matters and the model must stay on track.

If the interaction takes more than 2–3 turns and the steps must happen in a specific order, you probably need a flow.

## How flows work

A flow is a sequence of **steps**. Each step contains:

* **A prompt** – instructions the model follows for this step
* **Functions** – scoped to this step only, used for transitions and actions
* **A transition** – how the flow moves to the next step (or exits)

#### Enter the flow

A start function calls `conv.goto_flow("flow_name")`. This can be triggered from agent behavior, a knowledge topic, or another function.

#### Step activates

The step prompt is injected as a system message at the end of the conversation history. The model follows these instructions.

#### Model interacts with the user

The model asks for information, confirms details, or takes actions according to the step prompt.

#### Flow function transitions

When the model has what it needs, it calls a flow function. That function can save data, call an API, and then move to the next step or exit the flow.

## The persistent prompt

The step prompt is always the **last message** in the conversation history. This is the most important thing to understand about flows.

Unlike content returned from a function (which appears at a specific point in history and becomes less relevant as more turns happen), the step prompt is re-injected on every turn. It cannot be "forgotten" by the model.

#### Function content

```
assistant: "Hi, how can I help?"
user: "I want to register"
function: "Ask the user for their phone number"    ← fades over time
assistant: "Sure, what's your phone number?"
user: "Actually, what are your opening hours?"
assistant: "We're open 9 to 5. Now, about that phone number..."  ← model may drift
```

The function result moves further back in history with each turn.

#### Flow step

```
assistant: "Hi, how can I help?"
user: "I want to register"
assistant: "Sure, what's your phone number?"
user: "Actually, what are your opening hours?"
system: "Ask the user for their phone number"    ← always last, always fresh
```

The step prompt stays anchored at the end, keeping the model on task.

This persistent control is why flows are more reliable than prompting alone for multi-turn interactions.

## Check your understanding

#### Why is the flow step prompt more persistent than content returned from a function?

* It uses a special LLM mode that locks behavior
* It is always re-injected as the last message in conversation history
* It overrides all other prompting
* It is stored in a separate memory system

**Answer:** It is always re-injected as the last message in conversation history

The step prompt is always appended as the last system message. This means it stays relevant regardless of how many turns pass – unlike function content, which moves further back in history over time.

## Creating and entering a flow

There are two ways to create a flow:

1. Go to **Flows** and create one directly
2. Create one from any behavior menu (e.g., inside a managed topic action)

When you create a flow, Agent Studio generates:

* The flow itself (with a start step)
* A corresponding **start function** that contains `conv.goto_flow("flow_name")`

The start function is what triggers entry into the flow. You must expose it somewhere – in agent behavior, a knowledge topic, or another function. If a flow has no entry point, it exists but cannot be reached.

> **Warning**
>
> A common mistake: creating a flow but forgetting to expose the start function. The flow exists but is never entered because nothing triggers `conv.goto_flow`.

## Step transitions

Each step shows only its own functions to the model. When the model calls a flow function, that function can:

* Save data (to `conv.state`)
* Call an API
* Move to the next step using `flow.goto_step("step_name")`
* Exit the flow using `conv.exit_flow()`

When transitioning between steps:

* The previous step prompt is removed
* The new step prompt is injected
* Only the new step's functions are visible

This means the model cannot skip ahead, look at future steps, or call functions from a previous step.

```python
def save_phone_number(conv, flow, phone_number: str) -> str:
    conv.state["phone_number"] = phone_number
    flow.goto_step("collect_name")
    return f"Phone number {phone_number} saved. Now ask for their full name."
```

#### Check your understanding

#### You create a flow with three steps but the model skips step 2 and jumps to step 3. What is the most likely cause?

* Step 2's prompt is too short for the model to act on
* Step 2 has no prompt defined
* A flow function in step 1 transitions directly to step 3 via goto_step
* The model can see all steps and chooses the most relevant one

**Answer:** A flow function in step 1 transitions directly to step 3 via goto_step

The model cannot see other steps – it only sees the current step prompt and its functions. If a step is skipped, the transition function must be routing directly past it. Open the flow function in step 1 and check whether its goto_step call jumps to step 3 instead of step 2.

> **Try it**
>
> To move from one flow step to the next, call: flow.\_\_\_\_\_\_("step_name")
>
> **Answer:** `goto_step`

## What happens without transitions

If you tell the model to ask for a phone number but don't define what happens next, the model improvises. It may start asking for names, emails, or other details based on its training patterns.

This is not a model failure – it is a design failure. You did not give it the next step.

> **Warning**
>
> Always define explicit transitions between steps. Never rely on the model to "know what to do next."

## Transition pitfalls

Neither `conv.goto_flow` nor `flow.goto_step` interrupt the execution of your function. If you have multiple conditions, be careful not to overwrite one transition with another.

#### Incorrect

```python
# If condition_1 and condition_2 are both True,
# we set step A, then overwrite with B, then C.
# Final transition is always C.
if condition_1:
    flow.goto_step("A")
if condition_2:
    flow.goto_step("B")
flow.goto_step("C")
```

#### Correct (return)

```python
if condition_1:
    flow.goto_step("A")
    return
if condition_2:
    flow.goto_step("B")
    return
flow.goto_step("C")
```

#### Correct (elif)

```python
if condition_1:
    flow.goto_step("A")
elif condition_2:
    flow.goto_step("B")
else:
    flow.goto_step("C")
```

> **Warning**
>
> This is one of the most common bugs in flow functions. Always use explicit `return` statements or `if/elif/else` chains to prevent unintended transition overwrites.

## Exiting a flow

When `conv.exit_flow()` is called:

* The step prompt disappears from conversation history
* The model returns to normal behavior (behavioral rules, knowledge, global functions)
* Any state saved during the flow persists in `conv.state`

## Try it yourself

#### Challenge: Design a two-step registration flow

Design a flow that collects a phone number and then a full name.

Plan:

1. What is the start step prompt?
2. What flow function transitions from step 1 to step 2?
3. What does the second step prompt say?
4. How does the flow exit?

#### Hint

Each step should have a clear prompt (one instruction) and a flow function that saves the collected value and transitions. The final function should call `conv.exit_flow()`.

#### Example solution

**Step 1 prompt:** "Ask the user for the phone number we can contact them on. Once they provide it, call `save_phone_number`."

**Step 1 function (`save_phone_number`):**

```python
def save_phone_number(conv, flow, phone_number: str) -> str:
    conv.state["phone_number"] = phone_number
    flow.goto_step("collect_name")
    return "Phone number saved."
```

**Step 2 prompt:** "Ask the user for their full name. Once they provide it, call `save_name`."

**Step 2 function (`save_name`):**

```python
def save_name(conv, flow, full_name: str) -> str:
    conv.state["full_name"] = full_name
    conv.exit_flow()
    return f"Registration complete for {full_name}."
```

## Check your understanding

#### After exiting a flow, what happens to values saved in conv.state during the flow?

* They are deleted when the flow exits
* They persist and remain accessible for the rest of the conversation
* They are only available if you re-enter the same flow
* They are moved to a separate flow-specific storage

**Answer:** They persist and remain accessible for the rest of the conversation

conv.state persists across the entire conversation – it is not scoped to the flow. Values saved during a flow (e.g., conv.state.phone_number) remain accessible after the flow exits, so later functions and topics can use them.

#### [← Previous: Code organization](/academy/poly-academy/poly-academy-level-3/code-organization)

Lesson 1 of 5

#### [Next: Flow patterns →](/academy/poly-academy/poly-academy-level-3/flow-patterns)

Lesson 3 of 5