> ## Documentation Index
> Fetch the complete documentation index at: https://daily-main.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenAIDecisionsClassifier

> OpenAIDecisionsClassifier and OpenAIDecisionsClient answer classifier questions through OpenAI's Decisions API.

## Overview

`OpenAIDecisionsClassifier` answers [classifier questions](/api-reference/server/classifiers/overview) through OpenAI's Decisions API. All the questions about one state go to OpenAI in one request. The API takes only text, so structured state, instructions, and descriptions are sent as JSON.

An `OpenAIDecisionsClassifier` asks through an `OpenAIDecisionsClient`, which holds the HTTP/2 connection, adds the auth header, retries when OpenAI is busy, and counts tokens. Build the classifier with an API key to give it a client of its own, or pass an `OpenAIDecisionsClient` to share one connection between several classifiers.

## Installation

```bash theme={null}
uv add "pipecat-ai[openai]"
```

## Prerequisites

An OpenAI API key, usually set as an environment variable:

```bash theme={null}
OPENAI_API_KEY=...
```

## Configuration

### OpenAIDecisionsClassifier

```python theme={null}
from pipecat.classifiers.openai.decisions.classifier import OpenAIDecisionsClassifier
```

<ParamField path="api_key" type="str | None" default="None">
  OpenAI API key, when the classifier should have a client of its own. One of
  `api_key` and `client` is required.
</ParamField>

<ParamField path="client" type="OpenAIDecisionsClient | None" default="None">
  A client to share with other classifiers. One of `api_key` and `client` is
  required.
</ParamField>

<ParamField path="model" type="str" default="gpt-6-luna">
  The decision model a client of its own asks.
</ParamField>

<ParamField path="base_url" type="str" default="https://api.openai.com/v1">
  Where a client of its own sends its questions.
</ParamField>

<ParamField path="timeout" type="float" default="10.0">
  Seconds a client of its own waits for an answer before raising
  `ClassifierError`.
</ParamField>

<ParamField path="name" type="str | None" default="None">
  Name of the classifier, as it appears in logs and metrics.
</ParamField>

### OpenAIDecisionsClient

```python theme={null}
from pipecat.classifiers.openai.decisions.client import OpenAIDecisionsClient
```

<ParamField path="api_key" type="str" required>
  OpenAI API key.
</ParamField>

<ParamField path="base_url" type="str" default="https://api.openai.com/v1">
  Where the API is served, such as `https://eu.api.openai.com/v1` for data
  residency in Europe.
</ParamField>

<ParamField path="model" type="str" default="gpt-6-luna">
  The decision model to ask.
</ParamField>

<ParamField path="timeout" type="float" default="10.0">
  Seconds to wait for a reply before raising `ClassifierError`.
</ParamField>

<ParamField path="max_retries" type="int" default="3">
  How many times to retry a request OpenAI refused because it was busy (HTTP 429
  or 503), with exponential backoff.
</ParamField>

## Usage

### Basic Usage

```python theme={null}
import os

from pipecat.classifiers.base_classifier import YesNoQuestion
from pipecat.classifiers.openai.decisions.classifier import OpenAIDecisionsClassifier

classifier = OpenAIDecisionsClassifier(api_key=os.getenv("OPENAI_API_KEY"))

results = await classifier.yes_no(
    "Hi, you've reached Dana. Leave a message.",
    {"voicemail": YesNoQuestion(instructions="is this a voicemail?")},
)
results["voicemail"].is_yes
results["voicemail"].probability
```

Most of the time you don't call the classifier yourself: you pass it to a component that asks it, such as [`VoicemailDetector`](/api-reference/server/extensions/voicemail) or [`UIWorker`](/api-reference/server/workers/ui-worker).

### Sharing a Client

Several classifiers can share one `OpenAIDecisionsClient`, and with it one connection pool and one token count:

```python theme={null}
from pipecat.classifiers.openai.decisions.classifier import OpenAIDecisionsClassifier
from pipecat.classifiers.openai.decisions.client import OpenAIDecisionsClient

client = OpenAIDecisionsClient(api_key=os.getenv("OPENAI_API_KEY"))

voicemail = VoicemailDetector(classifier=OpenAIDecisionsClassifier(client=client))
ui_worker = MyUIWorker("ui", llm=ui_llm, classifier=OpenAIDecisionsClassifier(client=client))
```

A client the classifier created is closed in the classifier's `cleanup()`. A shared client is left open, so close it yourself with `await client.close()` when every classifier using it is done.

### Opening the Connection Early

`setup()` opens the connection to OpenAI ahead of the first question, so the first answer does not pay for the TLS handshake. Components that own a classifier, such as `VoicemailDetector`, call it for you. If the connection cannot be opened at setup, a warning is logged and the first question opens it instead.

## OpenAIDecisionsClassifier Properties

| Property | Type | Description |
| - | - | - |
| `client` | `OpenAIDecisionsClient` | The client this classifier asks through. |
| `model` | `str` | The decision model the questions go to. |

## OpenAIDecisionsClient Reference

### Properties

| Property | Type | Description |
| - | - | - |
| `model` | `str` | The decision model the questions go to. |
| `usage` | `OpenAIDecisionsUsage` | Tokens used so far over every request, as `input_tokens` and `output_tokens`. |

### Methods

#### connect

```python theme={null}
await client.connect()
```

Opens the connection to OpenAI by looking up the model, a cheap request that also checks the key and its access to the model. It connects once: a client shared by several classifiers is connected by each of them, and only the first call sends anything. Raises `ClassifierError` if OpenAI could not be reached or refused the request.

#### close

```python theme={null}
await client.close()
```

Closes the connection pool.

## Metrics

After every call, an `OpenAIDecisionsClassifier` reports the time it took as `ProcessingMetricsData` and the tokens used as `LLMUsageMetricsData` through its [`on_metrics`](/api-reference/server/classifiers/overview#on_metrics) event.

## Notes

* **Limits**: a choice question takes at most 255 options, available as `OPENAI_DECISIONS_MAX_CHOICE_OPTIONS` in `pipecat.classifiers.openai.decisions.classifier`. A question with more raises `ClassifierError` before anything is sent.
* **Errors**: a rejected request, a busy OpenAI after every retry, an unreachable server, a refusal to answer a question, or a reply missing an answer all raise `ClassifierError`.
* **Idle connections** are kept open for 240 seconds, so a gap between questions does not cost a new TLS handshake.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.