OpenAI SDK

The OpenAI SDK is the official client for OpenAI’s APIs, available for both Python and TypeScript/JavaScript. It supports Chat Completions and the Responses API. Respan gives you full observability over every OpenAI call, streamed response, and tool invocation — and gateway routing to 250+ models with prompt management.

Create an account at platform.respan.ai and grab an API key. For gateway, also add credits or a provider key.

Run npx @respan/cli setup to set up with your coding agent.

Setup

1

Install packages

$pip install respan-ai respan-instrumentation-openai openai
2

Set environment variables

$export OPENAI_API_KEY="YOUR_OPENAI_API_KEY"
$export RESPAN_API_KEY="YOUR_RESPAN_API_KEY"

OPENAI_API_KEY is used for OpenAI requests. RESPAN_API_KEY is used to export traces to Respan.

3

Initialize and run

1from openai import OpenAI
2from respan import Respan
3from respan_instrumentation_openai import OpenAIInstrumentor
4
5respan = Respan(instrumentations=[OpenAIInstrumentor()])
6
7client = OpenAI()
8
9response = client.chat.completions.create(
10 model="gpt-4.1-nano",
11 messages=[{"role": "user", "content": "Say hello in three languages."}],
12)
13print(response.choices[0].message.content)
14respan.flush()
4

View your trace

Open the Traces page to see your auto-instrumented LLM spans.

Configuration

ParameterTypeDefaultDescription
api_keystr | NoneNoneFalls back to RESPAN_API_KEY env var.
base_urlstr | NoneNoneFalls back to RESPAN_BASE_URL env var.
instrumentationslist[]Plugin instrumentations to activate (e.g. OpenAIInstrumentor()).
customer_identifierstr | NoneNoneDefault customer identifier for all spans.
metadatadict | NoneNoneDefault metadata attached to all spans.
environmentstr | NoneNoneEnvironment tag (e.g. "production").

Attributes

In Respan()

Set defaults at initialization — these apply to all spans.

1from respan import Respan
2from respan_instrumentation_openai import OpenAIInstrumentor
3
4respan = Respan(
5 instrumentations=[OpenAIInstrumentor()],
6 customer_identifier="user_123",
7 metadata={"service": "chat-api", "version": "1.0.0"},
8)

With propagate_attributes

Override per-request using a context scope.

1from openai import OpenAI
2from respan import Respan, propagate_attributes
3from respan_instrumentation_openai import OpenAIInstrumentor
4
5respan = Respan(instrumentations=[OpenAIInstrumentor()])
6client = OpenAI()
7
8def handle_request(user_id: str, question: str):
9 with propagate_attributes(
10 customer_identifier=user_id,
11 thread_identifier="conv_abc_123",
12 metadata={"plan": "pro"},
13 ):
14 response = client.chat.completions.create(
15 model="gpt-4.1-nano",
16 messages=[{"role": "user", "content": question}],
17 )
18 print(response.choices[0].message.content)
AttributeTypeDescription
customer_identifierstrIdentifies the end user in Respan analytics.
thread_identifierstrGroups related messages into a conversation.
metadatadictCustom key-value pairs. Merged with default metadata.

Decorators (optional)

Decorators are not required. All OpenAI calls are auto-traced by the instrumentor. Use @workflow and @task (Python) or withWorkflow and withTask (TypeScript) to add structure when you want to group related calls into a named workflow with nested tasks.

1from openai import OpenAI
2from respan import Respan, workflow, task
3from respan_instrumentation_openai import OpenAIInstrumentor
4
5respan = Respan(instrumentations=[OpenAIInstrumentor()])
6client = OpenAI()
7
8@task(name="generate_outline")
9def outline(topic: str) -> str:
10 response = client.chat.completions.create(
11 model="gpt-4.1-nano",
12 messages=[
13 {"role": "system", "content": "Create a brief outline."},
14 {"role": "user", "content": topic},
15 ],
16 )
17 return response.choices[0].message.content
18
19@workflow(name="content_pipeline")
20def pipeline(topic: str):
21 plan = outline(topic)
22 response = client.chat.completions.create(
23 model="gpt-4.1-nano",
24 messages=[
25 {"role": "system", "content": "Write content from this outline."},
26 {"role": "user", "content": plan},
27 ],
28 )
29 print(response.choices[0].message.content)
30
31pipeline("Benefits of API gateways")
32respan.flush()

Examples

Streaming

Streaming responses are auto-traced like regular completions.

1stream = client.chat.completions.create(
2 model="gpt-4.1-nano",
3 messages=[{"role": "user", "content": "Write a haiku about Python."}],
4 stream=True,
5)
6
7for chunk in stream:
8 content = chunk.choices[0].delta.content
9 if content:
10 print(content, end="", flush=True)

Tool calls

Function calling is auto-traced. Wrap the workflow with @workflow and @task decorators for a structured trace tree.

1import json
2from openai import OpenAI
3from respan import Respan, workflow, task
4from respan_instrumentation_openai import OpenAIInstrumentor
5
6respan = Respan(instrumentations=[OpenAIInstrumentor()])
7client = OpenAI()
8
9tools = [
10 {
11 "type": "function",
12 "function": {
13 "name": "get_weather",
14 "description": "Get the weather for a city.",
15 "parameters": {
16 "type": "object",
17 "properties": {"city": {"type": "string"}},
18 "required": ["city"],
19 },
20 },
21 }
22]
23
24@task(name="get_weather")
25def get_weather(city: str) -> str:
26 return f"Sunny, 72F in {city}"
27
28@workflow(name="weather_assistant")
29def run(question: str):
30 messages = [{"role": "user", "content": question}]
31
32 response = client.chat.completions.create(
33 model="gpt-4.1-nano",
34 messages=messages,
35 tools=tools,
36 )
37 message = response.choices[0].message
38
39 if message.tool_calls:
40 messages.append(message)
41 for tc in message.tool_calls:
42 args = json.loads(tc.function.arguments)
43 result = get_weather(**args)
44 messages.append(
45 {"role": "tool", "tool_call_id": tc.id, "content": result}
46 )
47
48 final = client.chat.completions.create(
49 model="gpt-4.1-nano",
50 messages=messages,
51 tools=tools,
52 )
53 print(f"Answer: {final.choices[0].message.content}")
54
55run("What's the weather in Paris?")
56respan.flush()

Structured output

JSON mode with Pydantic models is auto-traced.

1from pydantic import BaseModel
2from openai import OpenAI
3
4client = OpenAI()
5
6class MovieReview(BaseModel):
7 title: str
8 rating: int
9 summary: str
10 pros: list[str]
11 cons: list[str]
12
13response = client.beta.chat.completions.parse(
14 model="gpt-4.1-nano",
15 messages=[
16 {"role": "system", "content": "You are a film critic. Rate movies 1-10."},
17 {"role": "user", "content": "Review: The Matrix"},
18 ],
19 response_format=MovieReview,
20)
21result = response.choices[0].message.parsed
22print(f"{result.title} - {result.rating}/10")