> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mutagent.io/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenAI (Python)

> Automatic tracing for the OpenAI Python SDK

# OpenAI Integration (Python)

The `mutagent-openai` package provides a drop-in wrapper around the official OpenAI Python client that automatically traces all chat completion calls.

## Installation

<Warning>
  This package is coming soon to PyPI. The install command below will work once published.
</Warning>

```bash theme={null}
pip install mutagent-openai
```

This installs `mutagent-openai` along with its dependencies. Tracing transport is provided by `mutagent-sdk` via the `mutagent.tracing` module. The `openai` SDK (>= 1.0.0) is also required and installed automatically.

## Quick Start

<Steps>
  <Step title="Initialize tracing">
    ```python theme={null}
    from mutagent.tracing import init_tracing

    init_tracing(api_key="mt_xxxxxxxxxxxx")
    ```
  </Step>

  <Step title="Use MutagentOpenAI instead of OpenAI">
    ```python theme={null}
    from mutagent_openai import MutagentOpenAI

    client = MutagentOpenAI(api_key="your-openai-key")

    response = client.chat.completions.create(
        model="gpt-4",
        messages=[{"role": "user", "content": "Hello!"}],
    )

    print(response.choices[0].message.content)
    ```
  </Step>
</Steps>

Every call to `client.chat.completions.create()` is automatically traced and sent to MutagenT. No additional code changes required.

## Full Example

```python theme={null}
import os
import asyncio
from mutagent.tracing import init_tracing, shutdown_tracing
from mutagent_openai import MutagentOpenAI

# Initialize MutagenT tracing
init_tracing(
    api_key=os.environ["MUTAGENT_API_KEY"],
    environment="production",
)

# Create the traced OpenAI client
client = MutagentOpenAI(api_key=os.environ["OPENAI_API_KEY"])

# Use exactly like the standard OpenAI client
response = client.chat.completions.create(
    model="gpt-4",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "What is the capital of France?"},
    ],
    temperature=0.7,
)

print(response.choices[0].message.content)

# Flush remaining spans on exit (shutdown_tracing is async)
asyncio.run(shutdown_tracing())
```

## Streaming

Streaming responses are fully supported. The wrapper accumulates streamed content and records the complete response in the span when the stream finishes.

```python theme={null}
stream = client.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "Write a haiku about Python."}],
    stream=True,
)

for chunk in stream:
    if chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)
```

<Note>
  Streaming spans capture the accumulated output text after the stream completes. Token usage metrics are recorded when available from the model response.
</Note>

## What Gets Traced

Each call to `chat.completions.create()` generates a span with:

<CardGroup cols={2}>
  <Card title="Input Messages" icon="arrow-right">
    All messages sent to the model (system, user, assistant)
  </Card>

  <Card title="Output Messages" icon="arrow-left">
    The model's response content
  </Card>

  <Card title="Token Usage" icon="coins">
    Input tokens, output tokens, and total tokens
  </Card>

  <Card title="Model Info" icon="microchip">
    Model name and provider (`openai`)
  </Card>

  <Card title="Latency" icon="clock">
    Request duration in milliseconds
  </Card>

  <Card title="Errors" icon="triangle-exclamation">
    Error messages with stack traces on failure
  </Card>
</CardGroup>

### Span Details

| Field                   | Description         | Example                |
| ----------------------- | ------------------- | ---------------------- |
| `kind`                  | Span type           | `llm.chat`             |
| `name`                  | Model name          | `gpt-4`                |
| `input.messages`        | Input chat messages | System + user messages |
| `output.messages`       | Response messages   | Assistant response     |
| `metrics.model`         | Model identifier    | `gpt-4-0613`           |
| `metrics.provider`      | Provider name       | `openai`               |
| `metrics.input_tokens`  | Prompt tokens       | `150`                  |
| `metrics.output_tokens` | Completion tokens   | `50`                   |
| `metrics.total_tokens`  | Total tokens        | `200`                  |

## Constructor Options

`MutagentOpenAI` accepts the same parameters as the official `openai.OpenAI` client:

| Parameter      | Type            | Description                                             |
| -------------- | --------------- | ------------------------------------------------------- |
| `api_key`      | `str \| None`   | OpenAI API key (falls back to `OPENAI_API_KEY` env var) |
| `organization` | `str \| None`   | OpenAI organization ID                                  |
| `base_url`     | `str \| None`   | Custom API base URL                                     |
| `timeout`      | `float \| None` | Request timeout in seconds                              |
| `max_retries`  | `int \| None`   | Maximum retry count for failed requests                 |

## Error Handling

When an API call fails, the span is automatically recorded with an `ERROR` status and the error message is captured:

```python theme={null}
try:
    response = client.chat.completions.create(
        model="gpt-4",
        messages=[{"role": "user", "content": "Hello!"}],
    )
except Exception as e:
    # Span is already recorded with status=ERROR
    print(f"Request failed: {e}")
```

## Nested Spans

`MutagentOpenAI` works with the core tracing SDK's context propagation. If you create a parent span, OpenAI calls will automatically nest under it:

```python theme={null}
from mutagent.tracing import start_span, end_span, SpanOptions, SpanEndOptions

# Create a parent span
parent = start_span(SpanOptions(kind="chain", name="my-pipeline"))

# This call is automatically nested under the parent span
response = client.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "Hello!"}],
)

# End the parent span
if parent:
    end_span(parent, SpanEndOptions(status="ok"))
```

## TypeScript Equivalent

For the TypeScript/Node.js OpenAI integration, see the [TypeScript Integrations](/integrations/overview).
