---
title: "Quickstart"
description: Build your first agentic workflow in less than a minute.
icon: rocket
---


Welcome to ControlFlow! This quickstart guide will walk you through the basics of using ControlFlow to create AI-powered workflows. 

You'll learn how to:

1. [Run simple tasks](#running-a-single-task) with `cf.run()`
2. [Create specialized agents](#creating-specialized-agents) for specific tasks
3. [Compose tasks into complex workflows](#composing-tasks-into-a-flow) using flows

## Install ControlFlow

Install ControlFlow with pip:

```bash
pip install controlflow
```

Next, set up your LLM provider. By default, ControlFlow uses OpenAI, so you'll need to configure an OpenAI API key:

```bash
export OPENAI_API_KEY="your-api-key"
```

To use another provider, see the docs on [configuring LLMs](/guides/configure-llms).

## Create some data


In this quickstart, we're going to build an email processing pipelines, so let's create some sample data to work with. Execute this code in your Python interpreter to set up the (very simple) example emails we'll use throughout the quickstart:

<Tip>
Try changing the emails to your own content to see how ControlFlow works with different inputs.
</Tip>

```python
emails = [
    "Hello, I need an update on the project status.",
    "Subject: Exclusive offer just for you!",
    "Urgent: Project deadline moved up by one week.",
]
```
## Running a single task

Let's start with the basics. We're going to create a task that generates a reply to an email.

The `cf.run()` function is the main entry point for ControlFlow. It creates a task, assigns it to the default agent, and runs it to completion.

Here, we create a **task** that generates a simple email reply, and provide the content of an email as additional **context**:

<CodeGroup>
```python Code
import controlflow as cf

# Create a ControlFlow task to generate an reply
reply = cf.run(
    "Write a polite reply to an email",
    context=dict(email=emails[0]),
)

print(reply)
```

```text Result
Dear [Recipient's Name],

Thank you for reaching out. I appreciate your patience.

I wanted to inform you that the project is progressing 
well. We have completed several key milestones and are 
currently working on the next phase. We anticipate 
meeting our deadlines and will keep you updated with 
any new developments.

Please feel free to reach out if you have any further 
questions or need additional information.

Best regards,

[Your Name]
```
</CodeGroup>

### Recap
<Check>
**What we learned:**
- Create and run tasks with `cf.run()`
- Provide additional `context` as necessary
</Check>


## Creating specialized agents

Now let's create a task to identify whether an email is spam. 

For classification tasks, we want to use a smaller, faster LLM. In ControlFlow, `Agents` are used to represent portable LLM configurations, including model choice, tools, specialized instructions, and more.

<Tip>
You may have noticed that in the last example, we didn't assign an agent to the task. In that case, ControlFlow uses a general-purpose [default agent](/guides/default-agent).
</Tip>

Agents are sort of like portable configurations for how to perform tasks, which could include specific LLMs, tools, instructions, and more. For our spam classifier, we'll create a new agent that uses a smaller, faster LLM and specialized instructions.

In addition, note that the `result_type` of this task is a list of labels, indicating that the agent must choose one of the provided options. This is the simplest way to create a classification task, but you can require more complex [output formats](/concepts/tasks/task-results) as well.


<Warning>
This example uses an OpenAI model, but you can use any LangChain-compatible LLM here. Follow the instructions in the [LLM docs](/guides/configure-llms) to learn more.
</Warning>

<CodeGroup>
```python Codem


# Create a specialized agent 
classifier = cf.Agent(
    name="Email Classifier",
    model="openai/gpt-4o-mini",
    instructions="You are an expert at quickly classifying emails.",
)


# Set up a ControlFlow task to classify emails
classifications = cf.run(
    'Classify the emails',
    result_type=['important', 'spam'],
    agents=[classifier],
    context=dict(emails=emails),
)

print(classifications)
```

```python Result
[
    "important",
    "spam",
    "important",
]
```
</CodeGroup>

Our agent correctly identifies the first and third emails as important, and the second as spam.

### Recap
<Check>
**What we learned:**
- Create specialized agents to configure LLMs, tools, or instructions
- Use `result_type` to define the task's output format
- Use `agents` to specify which agent to use for the task
</Check>

## Composing tasks into a flow

Thus far, each of our tasks has run as a one-off operation. To create a more complex workflow, we can use a ControlFlow flow.

A flow provides a shared context and history for all agents, even across multiple tasks. The easiest way to create a flow is to use the `@cf.flow` decorator on a function with ControlFlow agents working inside it.

<CodeGroup>
```python Code
import controlflow as cf


# Create agents
classifier = cf.Agent(
    name="Email Classifier",
    model="openai/gpt-4o-mini",
    instructions="You are an expert at quickly classifying emails. Always "
                 "respond with exactly one word: either 'important' or 'spam'."
)

responder = cf.Agent(
    name="Email Responder",
    model="openai/gpt-4o",
    instructions="You are an expert at crafting professional email responses. "
                 "Your replies should be concise but friendly."
)


# Create the flow
@cf.flow
def process_email(email_content: str):

    # Classify the email
    category = cf.run(
        f"Classify this email",
        result_type=["important", "spam"],
        agents=[classifier],
        context=dict(email=email_content),
    )

    # If the email is important, write a response
    if category == "important":
        response = cf.run(
            f"Write a response to this important email",
            result_type=str,
            agents=[responder],
            context=dict(email=email_content),
        )
        return response

    # Otherwise, no response is needed
    else:
        print("No response needed for spam email.")


# Run the flow on each email
for email in emails:
    response = process_email(email)
    print(response)
```

```text Response to Email 1
Dear [Recipient's Name],

I'm glad to report that the project is progressing well. We have 
completed several key milestones and are currently working on the 
next phase. We anticipate meeting our deadlines and will keep you 
updated with any new developments.

Please feel free to reach out if you have any further questions 
or need additional information.

Best regards,

[Your Name]
```

```text Response to Email 2
<No response needed for spam email.>
```

```text Response to Email 3
Dear [Recipient's Name],

Thanks for letting me know. We'll make sure to adjust our plans accordingly.

Best regards,
[Your Name]
```
</CodeGroup>

### Recap
<Check>
**What we learned:**
- Use `@cf.flow` to create a shared context for multiple tasks
- Use task results to dynamically adjust your workflow
</Check>

## Conclusion
Congratulations! You've completed the ControlFlow quickstart. You've learned how to:

1. Run simple tasks with `cf.run()`
2. Create specialized agents for specific tasks
3. Compose tasks into complex workflows using flows

This email processing example showcases how ControlFlow can be used to create sophisticated AI-powered applications. As you continue to explore ControlFlow, you'll discover even more ways to leverage AI in your projects.
