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

# Observability for Pydantic AI with Opik

> Start here to integrate Opik into your Pydantic AI-based genai application for end-to-end LLM observability, unit testing, and optimization.

[Pydantic AI](https://ai.pydantic.dev/) is a Python agent framework designed to
build production grade applications with Generative AI.

Pydantic AI's primary advantage is its integration of Pydantic's type-safe data
validation, ensuring structured and reliable responses in AI applications.

## Account Setup

[Comet](https://www.comet.com/site?from=llm\&utm_source=opik\&utm_medium=colab\&utm_content=pydantic-ai\&utm_campaign=opik) provides a hosted version of the Opik platform, [simply create an account](https://www.comet.com/signup?from=llm\&utm_source=opik\&utm_medium=colab\&utm_content=pydantic-ai\&utm_campaign=opik) and grab your API Key.

> You can also run the Opik platform locally, see the [installation guide](https://www.comet.com/docs/opik/self-host/overview/?from=llm\&utm_source=opik\&utm_medium=colab\&utm_content=pydantic-ai\&utm_campaign=opik) for more information.

## Getting Started

### Installation

To use the Pydantic AI integration with Opik, you will need to have Pydantic AI
and logfire installed:

```bash
pip install --upgrade pydantic-ai logfire 'logfire[httpx]'
```

### Configuring Pydantic AI

In order to use Pydantic AI, you will need to configure your LLM provider API keys. For this example, we'll use OpenAI. You can [find or create your API keys in these pages](https://platform.openai.com/settings/organization/api-keys):

You can set them as environment variables:

```bash
export OPENAI_API_KEY="YOUR_API_KEY"
```

Or set them programmatically:

```python
import os
import getpass

if "OPENAI_API_KEY" not in os.environ:
    os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter your OpenAI API key: ")
```

### Configuring OpenTelemetry

You will need to set the following environment variables to make
sure the data is logged to Opik:

#### Opik Cloud

If you are using Opik Cloud, you will need to set the following environment
variables:

```bash
export OTEL_EXPORTER_OTLP_ENDPOINT=https://www.comet.com/opik/api/v1/private/otel
export OTEL_EXPORTER_OTLP_HEADERS='Authorization=<your-api-key>,Comet-Workspace=default'
export OTEL_METRICS_EXPORTER=none
```

To log the traces to a specific project, you can add the `projectName` parameter to the `OTEL_EXPORTER_OTLP_HEADERS` environment variable:

```bash
export OTEL_EXPORTER_OTLP_HEADERS='Authorization=<your-api-key>,Comet-Workspace=default,projectName=<your-project-name>'
```

You can also update the `Comet-Workspace` parameter to a different value if you would like to log the data
to a different workspace.

#### Enterprise deployment

If you are using an Enterprise deployment of Opik, you will need to set the following
environment variables:

```bash wordWrap
export OTEL_EXPORTER_OTLP_ENDPOINT=https://<comet-deployment-url>/opik/api/v1/private/otel
export OTEL_EXPORTER_OTLP_HEADERS='Authorization=<your-api-key>,Comet-Workspace=default'
export OTEL_METRICS_EXPORTER=none
```

To log the traces to a specific project, you can add the
`projectName` parameter to the `OTEL_EXPORTER_OTLP_HEADERS`
environment variable:

```bash wordWrap
export OTEL_EXPORTER_OTLP_HEADERS='Authorization=<your-api-key>,Comet-Workspace=default,projectName=<your-project-name>'
```

You can also update the `Comet-Workspace` parameter to a different
value if you would like to log the data to a different workspace.

#### Self-hosted instance

If you are self-hosting Opik, you will need to set the following environment variables:

```bash
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:5173/api/v1/private/otel
export OTEL_METRICS_EXPORTER=none
```

To log the traces to a specific project, you can add the `projectName` parameter to the `OTEL_EXPORTER_OTLP_HEADERS` environment variable:

```bash
export OTEL_EXPORTER_OTLP_HEADERS='projectName=<your-project-name>'
```

## Using Opik with Pydantic AI

To track your Pydantic AI agents, you will need to configure logfire as this is
the framework used by Pydantic AI to enable tracing.

```python
import logfire

logfire.configure(
    send_to_logfire=False,
)
logfire.instrument_pydantic_ai()
```

## Practical Example

Now that everything is configured, you can create and run Pydantic AI agents:

```python
import nest_asyncio
from pydantic_ai import Agent

# Enable async support in Jupyter notebooks
nest_asyncio.apply()

# Create a simple agent
agent = Agent(
    "openai:gpt-4o",
    system_prompt="Be concise, reply with one sentence.",
)

# Run the agent
result = agent.run_sync('Where does "hello world" come from?')
print(result.output)
```

![Pydantic AI tracing](https://fdr-prod-docs-files-public.s3.us-east-1.amazonaws.com/opik.docs.buildwithfern.com/73c02d4146fc064daa08becefe9c96a940e72926386e34148f7301fa4084ff6f/img/cookbook/pydantic-ai_trace_cookbook.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIA6KXJSKKNFOCF7G4B%2F20260914%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260914T013202Z&X-Amz-Expires=604800&X-Amz-Signature=c95e943a1a6a91b4ffd467ca6b9f6fb85d61a35580d83cea7b11dc1b678efd2b&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject)

## Logging threads

You can group multiple agent calls into a conversation thread by setting `thread_id` as a span attribute on the root Logfire span. Opik's OTEL ingestion recognizes this attribute and maps it directly to the trace's `thread_id` field:

```python
# Logfire wraps OTEL - thread_id becomes a span attribute automatically
with logfire.span("chat_turn", thread_id=thread_id):
    result = agent.run_sync("What is machine learning?")
```

## Combining with `@track`

If you wrap your agent call in an `@track`-decorated function — for example to capture a clean entrypoint with its own input/output — the Pydantic AI / logfire spans and the `@track` span would normally land in two separate traces, since logfire produces OpenTelemetry spans while `@track` keeps its own context.

Register `OpikSpanProcessor` on logfire's tracer provider to merge them into a single trace. The processor links the OpenTelemetry spans to the active `@track` span automatically — no header propagation or per-call wiring needed:

```python
import opik
import logfire
from pydantic_ai import Agent
from opik.integrations.otel import OpikSpanProcessor

logfire.configure(
    send_to_logfire=False,
    additional_span_processors=[OpikSpanProcessor()],
)
logfire.instrument_pydantic_ai()

agent = Agent("openai:gpt-4o")

@opik.track
def run(question: str) -> str:
    return agent.run_sync(question).output

run('Where does "hello world" come from?')
```

The result is one trace with the `run` entrypoint as the root and the `agent run` / model spans nested underneath. See [Linking OpenTelemetry spans to an existing Opik trace](/integrations/opentelemetry-python-sdk#linking-opentelemetry-spans-to-an-existing-opik-trace) for the general mechanism.

## Further improvements

If you would like to see us improve this integration, simply open a new feature
request on [Github](https://github.com/comet-ml/opik/issues).