OpenAI

OpenAI

OpenAI 호출을 추적·평가하고 싶을 때, 단독으로 쓰든 큰 애플리케이션의 구성 요소로 쓰든 Confident AI가 도와줘요. confident-trace를 쓰면 공식 OpenAI 클라이언트를 그대로 유지하고, init()을 한 번 호출하면 모든 Chat Completions·Responses 호출이 Observatory에서 LLM 스팬으로 나타나요. 메시지, 토큰 사용량·비용, 지연 시간, 오류까지 함께 보이죠.

출처: 문서

본문

개요

Confident AI는 OpenAI 호출을 — 단독으로든 큰 애플리케이션의 구성 요소로든 — 추적·평가할 수 있게 해 줘요.

OpenTelemetry 네이티브 추적 SDK인 confident-trace를 쓰면 공식 OpenAI 클라이언트를 그대로 유지할 수 있어요. init()을 한 번 호출하면 모든 Chat Completions·Responses 호출이 Observatory에서 LLM 스팬으로 나타나죠. 메시지, 토큰 사용량과 비용, 지연 시간, 오류까지 보여요.

이 페이지는 공식 OpenAI 클라이언트를 다룹니다. OpenAI Agents SDK로 에이전트를 만든다면 OpenAI Agents 통합을 보세요. LangChain이나 Vercel AI SDK 같은 프레임워크에는 자체 통합 페이지가 있어요.

Runtime Requirements Supported calls
Python Python 3.10+ Sync and async Chat Completions and Responses create, including streaming
TypeScript Node.js 22+, openai >=7.10.0 <8 Chat Completions and Responses create, including streaming

자동 계측

의존성 설치

confident-trace를 OpenAI SDK와 함께 설치하는 명령을 실행하세요.

Python

pip install confident-trace openai

TypeScript

tsx는 TypeScript 소스를 직접 실행할 때만 필요해요.

npm install confident-trace 'openai@>=7.10.0 <8'
npm install -D tsx
yarn add confident-trace 'openai@>=7.10.0 <8'
yarn add -D tsx

API 키 설정

Confident AI Project API key를 받아 OpenAI 키와 함께 환경 변수로 설정하세요.

export CONFIDENT_API_KEY="<your-confident-project-key>"
export OPENAI_API_KEY="<your-openai-key>"

EU 리전이거나 자체 호스팅 배포라면, 트레이스가 우리 US 서버로 가지 않도록 CONFIDENT_OTEL_ENDPOINT도 설정하세요 — init() 구성을 참고하세요.

OpenAI 계측

모델 호출을 하기 전에 init()을 한 번 호출하세요. 설치된 OpenAI SDK를 감지해 계측해 줘요 — openai에서 클라이언트를 평소처럼 가져오면 되고, 래퍼는 필요 없어요.

Python

from confident_trace import init, shutdown
from openai import OpenAI

init()
client = OpenAI()

try:
    response = client.responses.create(
        model="gpt-4.1-mini",
        input="Explain OpenTelemetry in one sentence.",
    )
    print(response.output_text)
finally:
    shutdown()

TypeScript

import OpenAI from "openai";
import { init } from "confident-trace";

const runtime = init();
const client = new OpenAI();

try {
  const response = await client.responses.create({
    model: "gpt-4.1-mini",
    input: "Explain OpenTelemetry in one sentence.",
  });
  console.log(response.output_text);
} finally {
  await runtime.shutdown();
}

TypeScript에는 한 가지가 더 필요합니다. Node가 openai 패키지를 로드할 때 SDK가 훅할 수 있도록 엔트리포인트를 confident-trace/register preload로 실행하세요. init()은 export를, preload는 계측을 처리합니다 — 둘 다 필요해요.

preload 없이 init()을 호출하면 설정 경고가 나오고 스팬이 없어요. 반대로 preload만 있고 init()이 없으면 스팬은 만들어지지만 아무것도 내보내지지 않습니다.

장기 실행 서버에서는 시작 시 init()을 한 번, 프로세스 종료 시 진행 중인 요청이 끝난 뒤 shutdown()을 한 번 호출하세요 — 요청마다 하지 마세요. 한 번 초기화를 참고하세요.

OpenAI 실행

스크립트를 실행해 트레이스를 Confident AI로 보내세요.

Python

python main.py

TypeScript

# Running TypeScript source directly
node --import tsx --import confident-trace/register src/index.ts

# Running compiled JavaScript
node --import confident-trace/register dist/index.js

이걸 평소 시작 명령으로 만들려면 package.json scripts에 추가하세요.

{
  "scripts": {
    "start": "node --import confident-trace/register dist/index.js",
    "dev": "node --import tsx --import confident-trace/register src/index.ts"
  }
}

완료 ✅. Confident AI 프로젝트에서 Observatory를 열면 그 안에 LLM 스팬이 담긴 트레이스를 찾을 수 있어요.

트레이스가 안 보이면 99.99% 프로그램이 스팬을 보낼 기회가 생기기 전에 종료됐기 때문이에요. 종료 전에 반드시 shutdown()(장기 실행 프로세스에선 flush())을 호출하세요 — 트러블슈팅 페이지를 참고하세요.

무엇이 포착되나

지원되는 각 모델 호출은 LLM 스팬이 됩니다. 활성 스팬이 있으면(예: span으로 만든 것) 그 호출이 아래에 중첩되고, 부모가 없는 호출은 자체 새 트레이스를 시작해요.

  • 모델·응답 상세 — 요청된 모델, 응답 ID, 타이밍, 상태, 토큰 사용량
  • 메시지 — 입출력 메시지, 완료 사유, 모델이 반환한 도구 호출 데이터
  • 스트리밍 출력 — 앱이 스트림을 소비하는 대로 기록되며, 미리 읽지 않음

포착되는 콘텐츠는 콘텐츠 정책을 따릅니다. 크기 제한은 기본적으로 꺼져 있지만, export 전에 제한을 구성하거나 콘텐츠를 삭제할 수 있어요.

모델의 도구 요청은 LLM 스팬의 출력에 기록됩니다. 통합은 도구를 실행하는 코드는 추적하지 않아요 — 프레임워크 통합을 쓰거나, 내 도구 함수를 도구 스팬으로 직접 감싸세요.

Chat Completions, 스트리밍, 비동기

빠른 시작은 Responses API를 사용했지만, 지원되는 모든 호출은 같은 방식으로 추적됩니다. 이 예제들은 빠른 시작의 init()과 클라이언트 설정 이후, shutdown() 전에 이어집니다.

Chat Completions

completion = client.chat.completions.create(
    model="gpt-4.1-mini",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "What is the weather in France?"},
    ],
)
print(completion.choices[0].message.content)
const completion = await client.chat.completions.create({
  model: "gpt-4.1-mini",
  messages: [
    { role: "system", content: "You are a helpful assistant." },
    { role: "user", content: "What is the weather in France?" },
  ],
});
console.log(completion.choices[0].message.content);

스트리밍

with client.responses.create(
    model="gpt-4.1-mini", input="Write a short poem.", stream=True
) as stream:
    for event in stream:
        if event.type == "response.output_text.delta":
            print(event.delta, end="", flush=True)
const stream = await client.responses.create({
  model: "gpt-4.1-mini", input: "Write a short poem.", stream: true,
});
try {
  for await (const event of stream) {
    if (event.type === "response.output_text.delta") {
      process.stdout.write(event.delta);
    }
  }
} finally {
  stream.controller.abort();
}

플러시·종료 전에 스트림을 마치거나 명시적으로 닫기·중단하세요. 버려진 스트림은 최종 콘텐츠를 잃고 트레이스가 불완전해져요. flush와 shutdown을 참고하세요.

비동기 (Python)

공식 AsyncOpenAI 클라이언트를 같은 init() 설정과 함께 사용하세요. 평소처럼 호출을 await 하고, async for로 스트림을 소비하면 돼요.

import asyncio
from openai import AsyncOpenAI

async_client = AsyncOpenAI()

async def generate_response(input: str) -> str:
    response = await async_client.responses.create(
        model="gpt-4.1-mini",
        instructions="You are a helpful assistant.",
        input=input,
    )
    return response.output_text

print(asyncio.run(generate_response("What is the weather in France?")))

이 통합의 지원 범위 밖: OpenAI의 별도 responses.stream 헬퍼, 임베딩, 실시간, 배치 API, 이미지·오디오 생성. 그 호출들은 여전히 동작하지만 스팬을 만들지는 않아요.

트레이스 스팬 속성 설정

호출이 시작되기 전에 아는 속성을 추가하려면 트레이스 컨텍스트를 사용하세요. 추가 스팬은 만들지 않아요. client.responses.create()가 시작한 트레이스가 태그, 메타데이터, 사용자 ID, 고객 ID를 상속받습니다.

Python

from confident_trace import init, trace_context
from openai import OpenAI

init()

client = OpenAI()

with trace_context(
    tags=["support"],
    metadata={"release": "2026-09"},
    user_id="user-42",
    customer_id="customer-7",
):
    response = client.responses.create(
        model="gpt-4.1-mini",
        input="Explain OpenTelemetry in one sentence.",
    )

TypeScript

import { init, traceContext } from "confident-trace";
import OpenAI from "openai";

init();

const client = new OpenAI();

const response = await traceContext(
  {
    tags: ["support"],
    metadata: { release: "2026-09" },
    userId: "user-42",
    customerId: "customer-7",
  },
  () => client.responses.create({
    model: "gpt-4.1-mini",
    input: "Explain OpenTelemetry in one sentence.",
  }),
);

각 ID와 함께 선택적 표시 이름을 설정하려면 사용자와 고객을, 지원되는 모든 트레이스 속성과 갱신 동작은 트레이스 컨텍스트를 참고하세요.

다중 턴 계측

OpenAI 엔트리포인트 호출 하나가 이미 하나의 대화 턴일 때는 turn()이 필요 없어요 — 통합이 그 턴의 트레이스를 자동으로 만들어 주거든요. 경계를 직접 정의하고 싶을 때, 예를 들어 두 번의 연속 OpenAI 호출을 하나의 턴으로 묶고 싶을 때 turn()을 사용하세요. 이후 턴에서 같은 스레드 ID를 재사용해 하나의 대화로 묶으면 돼요.

Python

from confident_trace import init, turn

init()

with turn("support-turn", thread_id="chat-42"):
    context = client.responses.create(model="gpt-4.1-mini", input="Find the relevant account details.")
    answer = client.responses.create(model="gpt-4.1-mini", input=f"Summarize these details: {context.output_text}")

TypeScript

import { init, turn } from "confident-trace";

init();

const answer = await turn({ name: "support-turn", threadId: "chat-42" }, async () => {
  const context = await client.responses.create({ model: "gpt-4.1-mini", input: "Find the relevant account details." });
  return client.responses.create({ model: "gpt-4.1-mini", input: `Summarize these details: ${context.output_text}` });
});

스레드 입출력, 턴 ID, 사용자 ID는 스레드를 참고하세요.

트러블슈팅

Python

  • 스팬 없음: 첫 모델 호출 전에 init()이 실행되고, 프로세스가 shutdown()에 도달해 버퍼링된 스팬이 플러시되는지 확인하세요.
  • 최종 스트림 콘텐츠 누락: shutdown() 전에 스트림을 완전히 소비하거나 닫으세요.
  • 중복 스팬: 같은 클라이언트에 instrumentor가 두 개 붙어 있어요. confident-trace가 활성인 동안 다른 프로바이더 instrumentor로 클라이언트를 감싸지 마세요. 외부 계측이 이미 OpenAI 스팬을 공급한다면 init(instrumentations=())을 전달하세요.
  • 콘텐츠 누락: 마스킹·콘텐츠 제어, 잘림 한도, 호출한 API가 위 지원 범위에 있는지 확인하세요. 이진 다중모달 페이로드는 제외돼요.

TypeScript

  • 스팬 없음: 첫 모델 호출 전에 init()이 실행되고, 시작 명령에 --import confident-trace/register가 포함되며, shutdown()에 도달해 버퍼링된 스팬이 플러시되는지 확인하세요. runtime.getInstrumentationStatus()가 OpenAI 훅이 붙었는지 알려 줘요.
  • 최종 스트림 콘텐츠 누락: shutdown() 전에 스트림을 완전히 소비하거나 중단하세요.
  • 중복 스팬: 같은 클라이언트에 instrumentor가 두 개 붙어 있어요. confident-trace가 활성인 동안 다른 프로바이더 instrumentor로 클라이언트를 감싸지 마세요. 외부 계측이 이미 OpenAI 스팬을 공급한다면 init({ instrumentations: [] })을 전달하세요.
  • 콘텐츠 누락: 마스킹·콘텐츠 제어, 잘림 한도, 호출한 API가 위 지원 범위에 있는지 확인하세요. 이진 다중모달 페이로드는 제외돼요.

일반 설정 문제는 트러블슈팅을 참고하세요.

OpenAI 계측 비활성화

특정 통합만 활성화하려면 init()에 통합 식별자 목록을 전달하세요. OpenAI의 식별자는 Python·TypeScript 모두 "openai"이고, 이를 빼면 이 통합이 비활성화돼요. 빈 목록은 모든 자동 계측을 비활성화합니다.

Python

from confident_trace import init
init(instrumentations=())
# Use ("openai",) to opt in; omit "openai" to disable it.

TypeScript

import { init } from "confident-trace";
init({ instrumentations: [] });
// Use ["openai"] to opt in; omit "openai" to disable it.

이렇게 하면 Confident AI의 자동 계측이 꺼지고, 초기화 이후의 호출은 이 통합으로 계측되지 않아요.

다음 단계

Online Evals

트레이스와 스팬이 Confident AI로 수집되는 실시간으로 평가를 돌려 프로덕션 AI 품질을 모니터링하세요.

Threads

다중 턴 대화를 스레드로 묶고, 턴 입출력을 설정하며, 전체 대화를 하나의 단위로 평가하세요.

더 알아보기