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

# Python

> Integrate Glass with your Python application

<Note>
  Requires Python 3.9 or higher.
</Note>

## Installation

```bash theme={null}
pip install glass-ai
```

## Quick Start

```python theme={null}
from glass import init, trace, interaction
from openai import OpenAI

# Initialize Glass
init(api_key="your-glass-api-key")

# Your AI calls are now automatically traced
client = OpenAI()

@trace()
def generate_response(prompt: str) -> str:
    response = client.chat.completions.create(
        model="gpt-4",
        messages=[{"role": "user", "content": prompt}]
    )
    return response.choices[0].message.content

# Track user interactions
with interaction(user_id="user_123", session_id="sess_abc") as ctx:
    result = generate_response("What is the meaning of life?")
    ctx.finish(output={"response": result})
```

That's it. All your OpenAI, Anthropic, and Google Generative AI calls are now traced automatically.

***

## API Reference

### `init()`

Initializes the Glass SDK. Call this once at application startup.

```python theme={null}
from glass import init

# Basic initialization
init(api_key="your-api-key")

# With debug mode (logs traces to console)
init(api_key="your-api-key", debug=True)
```

<ParamField path="api_key" type="string">
  Your Glass API key. Falls back to `GLASS_API_KEY` environment variable if not provided.
</ParamField>

<ParamField path="debug" type="boolean" default="False">
  Enable console output for local development.
</ParamField>

<ParamField path="skip_default_instrumentations" type="boolean" default="False">
  Disable automatic tracing of AI providers. See [Instrumentations](/sdk/instrumentations) for details.
</ParamField>

<ParamField path="instrumentations" type="list">
  Custom OpenTelemetry instrumentors. See [Instrumentations](/sdk/instrumentations) for details.
</ParamField>

***

### `@trace()`

Decorator that wraps any function with tracing. Automatically records arguments, return values, and exceptions.

```python theme={null}
from glass import trace

# Basic usage
@trace()
def process_data(data: dict) -> dict:
    return {"processed": True, **data}

# Custom span name
@trace(name="custom-operation")
def my_function():
    pass

# With attributes
@trace(attributes={"model": "text-embedding-3-small"})
def create_embedding(text: str) -> list[float]:
    return [0.1, 0.2, 0.3]
```

Works with async functions too:

```python theme={null}
@trace()
async def async_process(data: str) -> str:
    await asyncio.sleep(0.1)
    return f"processed: {data}"
```

<ParamField path="name" type="string">
  Custom span name. Defaults to the function name.
</ParamField>

<ParamField path="attributes" type="dict">
  Additional attributes to attach to the span.
</ParamField>

***

### `interaction()`

Context manager for tracking user interactions. Propagates user context to all nested traces.

```python theme={null}
from glass import interaction, trace

@trace()
def call_llm(prompt: str) -> str:
    return "LLM response"

with interaction(user_id="user_123", session_id="sess_abc", project="conversational-chat", input="Hello!") as ctx:
    result = call_llm("Hello!")
    ctx.finish(output={"response": result})
```

Also works with async:

```python theme={null}
async with interaction(user_id="user_123") as ctx:
    result = await async_call_llm("Hello!")
    ctx.finish(output={"response": result})
```

<ParamField path="user_id" type="string">
  Identifier for the user.
</ParamField>

<ParamField path="session_id" type="string">
  Session identifier.
</ParamField>

<ParamField path="project" type="string">
  In which project to classify traces.
</ParamField>

<ParamField path="input" type="string">
  The user's input/query.
</ParamField>

<ParamField path="service" type="string">
  Service name for routing.
</ParamField>

**Methods on the context:**

| Method                        | Description                                |
| ----------------------------- | ------------------------------------------ |
| `finish(output)`              | Record the final output of the interaction |
| `set_attribute(key, value)`   | Set a custom attribute                     |
| `record_exception(exception)` | Record an exception                        |

***

### `task_span()`

Context manager for creating task spans with explicit input/output recording.

```python theme={null}
from glass import task_span

with task_span("embedding-task", attributes={"model": "ada-002"}) as task:
    task.record_input({"text": "Hello, world!"})
    embedding = compute_embedding("Hello, world!")
    task.record_output({"embedding": embedding, "dimensions": 1536})
```

<ParamField path="name" type="string" required>
  The name of the task span.
</ParamField>

<ParamField path="attributes" type="dict">
  Additional attributes for the span.
</ParamField>

**Methods on the task:**

| Method                        | Description            |
| ----------------------------- | ---------------------- |
| `record_input(data)`          | Record input data      |
| `record_output(data)`         | Record output data     |
| `set_attribute(key, value)`   | Set a custom attribute |
| `record_exception(exception)` | Record an exception    |

***

## Full Example: RAG Pipeline

Here's how the primitives compose together:

```python theme={null}
from glass import init, trace, interaction, task_span
from openai import OpenAI

init(api_key="your-api-key")
client = OpenAI()

@trace()
def retrieve_context(query: str) -> list[str]:
    return ["context 1", "context 2"]

@trace()
def generate_response(query: str, context: list[str]) -> str:
    response = client.chat.completions.create(
        model="gpt-4",
        messages=[
            {"role": "system", "content": f"Context: {context}"},
            {"role": "user", "content": query}
        ]
    )
    return response.choices[0].message.content

@trace(name="rag-pipeline")
def rag_query(query: str) -> str:
    with task_span("retrieval") as task:
        task.record_input({"query": query})
        context = retrieve_context(query)
        task.record_output({"num_docs": len(context)})
    
    return generate_response(query, context)

# Track the full user interaction
with interaction(user_id="user_123", input="What is quantum computing?") as ctx:
    result = rag_query("What is quantum computing?")
    ctx.finish(output={"answer": result})
```

This creates a trace hierarchy like:

```
interaction (user_id=user_123)
└── rag-pipeline
    ├── retrieval (task_span)
    │   └── retrieve_context
    └── generate_response
        └── OpenAI chat.completions.create (auto)
```

***

## Environment Variables

| Variable        | Description                                         |
| --------------- | --------------------------------------------------- |
| `GLASS_API_KEY` | Your Glass API key (alternative to passing in code) |

```bash theme={null}
export GLASS_API_KEY="your-api-key"
```

```python theme={null}
from glass import init

# API key is read from environment
init()
```
