Tracing
Tracing (추적)
Agents SDK에는 내장 tracing이 포함돼 있어요. 에이전트 실행 중 발생하는 이벤트(LLM 생성, 도구 호출, handoff, guardrail, 심지어 커스텀 이벤트까지)의 종합적인 기록을 수집하죠. Traces 대시보드를 쓰면 개발 중과 프로덕션에서 워크플로를 디버깅·시각화·모니터링할 수 있어요.
Note: Tracing은 기본적으로 켜져 있어요. 흔히 쓰는 세 가지 끄는 방법이 있어요.
- 환경 변수
OPENAI_AGENTS_DISABLE_TRACING=1로 전역으로 끄기- 코드에서
set_tracing_disabled(True)로 전역으로 끄기agents.run.RunConfig.tracing_disabled를True로 설정해 단일 실행에 대해 끄기
ZDR(Zero Data Retention) 정책으로 OpenAI API를 쓰는 조직에서는 tracing을 사용할 수 없어요.
출처: 문서
본문
Traces와 Spans
- Traces — "워크플로"의 단일 end-to-end 연산을 나타내요. Spans로 구성되며 다음 속성을 가져요.
workflow_name— 논리적 워크플로 또는 앱의 이름. 예: "Code generation", "Customer service"trace_id— trace의 고유 ID. 넘기지 않으면 자동 생성돼요.trace_<32_alphanumeric>형식이어야 해요.group_id— 같은 대화의 여러 trace를 연결하는 선택적 그룹 ID. 예를 들어 채팅 스레드 ID를 쓸 수 있어요.disabled—True면 trace가 기록되지 않아요.metadata— trace용 선택적 메타데이터.
- Spans — 시작·종료 시간이 있는 연산을 나타내요. Span은 다음을 가져요.
started_at와ended_at타임스탬프- 소속 trace를 나타내는
trace_id - 이 Span의 부모 Span을 가리키는
parent_id(있으면) - Span에 관한 정보인
span_data. 예를 들어AgentSpanData는 Agent에 관한 정보를 담고,GenerationSpanData는 LLM 생성에 관한 정보를 담아요.
기본 tracing
기본적으로 SDK는 다음을 추적해요.
Runner.{run, run_sync, run_streamed}()전체를trace()로 감싸요.- 각 러너 호출을
task_span()으로 감싸요. - 각 모델 턴을
turn_span()으로 감싸요. - 에이전트가 실행될 때마다
agent_span()으로 감싸요. - LLM 생성은
generation_span()으로 감싸요. - function tool 호출은 각각
function_span()으로 감싸요. - guardrail은
guardrail_span()으로 감싸요. - handoff는
handoff_span()으로 감싸요. - 오디오 입력(speech-to-text)은
transcription_span()으로 감싸요. - 오디오 출력(text-to-speech)은
speech_span()으로 감싸요. - SDK는 관련 오디오 span을
speech_group_span()아래에 부모로 둘 수 있어요.
기본적으로 trace 이름은 리터럴 문자열 Agent workflow예요. trace를 쓰면 이 이름을 설정할 수 있고, RunConfig로 이름과 다른 속성을 구성할 수도 있어요.
더 간결한 계층을 원하면 실행에 대해 자동 task·turn span을 끄세요. Agent·generation·function·guardrail·handoff·커스텀 span은 여전히 기록돼요.
from agents import RunConfig, Runner
result = await Runner.run(
agent,
"Hello",
run_config=RunConfig(tracing={"include_task_and_turn_spans": False}),
)
게다가 커스텀 trace processor를 설정해 trace를 다른 목적지로(대체 또는 보조 목적지로) 밀어낼 수 있어요.
장기 실행 워커와 즉시 내보내기
기본 BatchTraceProcessor는 몇 초마다 또는 인메모리 큐가 크기 트리거에 도달하면 백그라운드에서 trace를 내보내고, 프로세스가 종료될 때 최종 flush도 수행해요. Celery·RQ·Dramatiq·FastAPI 백그라운드 작업 같은 장기 실행 워커에서는 특별한 코드 없이 trace가 대개 자동으로 내보내지지만, 각 작업이 끝난 직후 Traces 대시보드에 나타나지 않을 수 있어요.
단위 작업 끝에 즉시 전달 보장이 필요하다면 trace 컨텍스트가 끝난 뒤 flush_traces()를 호출하세요.
from agents import Runner, flush_traces, trace
@celery_app.task
def run_agent_task(prompt: str):
try:
with trace("celery_task"):
result = Runner.run_sync(agent, prompt)
return result.final_output
finally:
flush_traces()
from fastapi import BackgroundTasks, FastAPI
from agents import Runner, flush_traces, trace
app = FastAPI()
def process_in_background(prompt: str) -> None:
try:
with trace("background_job"):
Runner.run_sync(agent, prompt)
finally:
flush_traces()
@app.post("/run")
async def run(prompt: str, background_tasks: BackgroundTasks):
background_tasks.add_task(process_in_background, prompt)
return {"status": "queued"}
flush_traces()는 현재 버퍼링된 trace와 span이 내보내질 때까지 블록하므로, 부분적으로 만들어진 trace를 flush하지 않도록 trace()가 닫힌 뒤 호출하세요. 기본 export 지연이 수용 가능하면 이 호출은 건너뛸 수 있어요.
tracing을 비활성화하면 기본 프로바이더가 새 trace·span을 만들지 않지만, 프로세서가 이미 버퍼링한 데이터를 버리지는 않아요. set_tracing_disabled(True)나 OPENAI_AGENTS_DISABLE_TRACING=1로 tracing을 끈 뒤에도 flush_traces()는 그 버퍼링된 데이터를 계속 flush해요.
더 높은 수준의 trace
때로는 여러 번의 run() 호출을 단일 trace의 일부로 만들고 싶을 수 있어요. 전체 코드를 trace()로 감싸면 됩니다.
from agents import Agent, Runner, trace
async def main():
agent = Agent(name="Joke generator", instructions="Tell funny jokes.")
with trace("Joke workflow"): # (1)!
first_result = await Runner.run(agent, "Tell me a joke")
second_result = await Runner.run(agent, f"Rate this joke: {first_result.final_output}")
print(f"Joke: {first_result.final_output}")
print(f"Rating: {second_result.final_output}")
- 두
Runner.run호출이with trace()로 감싸져 있으므로, 각각 별도 trace를 만드는 대신 두 실행 모두 하나의 전체 trace의 일부가 돼요.
Trace 만들기
trace() 함수로 trace를 만들 수 있어요. trace는 시작·종료해야 해요. 두 가지 방법이 있어요.
- 권장: trace를 컨텍스트 매니저로 사용하기, 즉
with trace(...) as my_trace. 이러면 적절한 시점에 trace를 자동으로 시작·종료해요. trace.start()와trace.finish()를 수동으로 호출하기.
현재 trace는 Python contextvar로 추적돼요. 즉 동시성과 자동으로 잘 동작한다는 뜻이에요. 수동으로 trace를 시작·종료한다면 start()에 mark_as_current를, finish()에 reset_current를 넘겨 현재 trace를 갱신하세요.
Span 만들기
여러 *_span() 메서드로 span을 만들 수 있어요. 일반적으로 span을 수동으로 만들 필요는 없어요. 커스텀 span 정보 추적에는 custom_span() 함수가 있어요.
Span은 자동으로 현재 trace의 일부가 되고, Python contextvar로 추적되는 가장 가까운 현재 span 아래에 중첩돼요.
민감 데이터
일부 span은 잠재적으로 민감한 데이터를 담을 수 있어요. generation_span()은 LLM 생성의 입력/출력을 저장하고, function_span()은 함수 호출의 입력/출력을 저장해요. 민감한 데이터를 포함할 수 있으니 RunConfig.trace_include_sensitive_data로 캡처를 끌 수 있어요.
승인 게이트가 있는 function tool에서, 승인을 위해 일시 중지되는 span은 SDK의 내부 결과 래퍼를 도구 출력으로 저장하지 않아요. 애플리케이션이 커스텀 거부 메시지로 호출을 거부하면, function span은 trace_include_sensitive_data가 True일 때만 그 메시지를 출력·오류 텍스트로 저장해요. 이 설정이 False면 span은 출력을 생략하고 일반 오류 텍스트 Tool execution rejected를 사용해요.
마찬가지로 오디오 span은 기본적으로 입력·출력 오디오의 base64 인코딩된 PCM 데이터를 포함해요. 이 오디오 데이터 캡처는 VoicePipelineConfig.trace_include_sensitive_audio_data로 끌 수 있어요.
기본적으로 trace_include_sensitive_data는 True예요. 앱 실행 전에 OPENAI_AGENTS_TRACE_INCLUDE_SENSITIVE_DATA 환경 변수를 true/1 또는 false/0로 export해 코드 없이 기본값을 설정할 수 있어요.
trace_include_sensitive_data가 False면 Responses 모델 span은 요청 입력·응답 출력을 생략해요. 공식 OpenAI 엔드포인트 호출에서 span은 여전히 상관 메타데이터로 Responses API response_id를 포함해요. SDK는 커스텀 엔드포인트의 편집된 span에서 그 식별자를 생략해요.
커스텀 tracing 프로세서
tracing의 높은 수준 아키텍처:
- 초기화 시 trace를 만드는 책임을 가진 전역
TraceProvider를 만들어요. TraceProvider를 trace/span을 배치로BackendSpanExporter에 보내는BatchTraceProcessor로 구성하고, exporter가 span·trace를 OpenAI 백엔드에 배치로 내보내요.
이 기본 설정을 커스터마이즈해 대체·추가 백엔드로 보내거나 exporter 동작을 바꾸려면 두 가지 옵션이 있어요.
add_trace_processor()— 준비된 대로 trace·span을 받을 추가 trace processor를 더해요. OpenAI 백엔드로 보내는 것 외에 자체 처리를 할 수 있게 해줘요.set_trace_processors()— 기본 프로세서를 자체 trace 프로세서로 교체해요. 그렇게 하면 OpenAI 백엔드로 보낼TracingProcessor를 포함하지 않는 한 trace가 OpenAI 백엔드로 전송되지 않아요.
내보내기 전 편집(Redaction)
Trace 프로세서는 독립적인 관찰자예요. 기본 프로바이더는 프로세서의 콜백 예외를 잡고 등록된 다른 프로세서를 계속 호출해요. 따라서 exporter 앞에 등록된 redaction 프로세서는 redaction이 실패해도 그 exporter가 데이터를 받는 것을 막지 못해요. add_trace_processor()로 프로세서를 추가해도 기본 OpenAI exporter는 등록된 채로 남아요.
내보내기가 성공적인 redaction에 의존할 때는 redaction과 전달을 같은 애플리케이션 소유 exporter 안에 두세요. set_trace_processors()로 기본 프로세서를 그 exporter로 구성된 BatchTraceProcessor로 교체하세요. exporter는 직렬화된 페이로드를 복사하고, 복사본을 편집한 다음, 편집된 결과만 목적지에 넘겨야 해요. 직렬화·복사·redaction이 실패하면 목적지를 호출하기 전에 배치를 버려요. 페이로드·예외 텍스트·traceback 없이 고정된 실패 메시지를 로그로 남기세요.
trace redaction 예제는 기존 tracing API를 써서 이 구성을 보여줘요. 그 예제는 로컬 콘솔에 이벤트 카테고리와 trace/span 연관 ID만 출력하고 API 호출은 하지 않아요. 그 allowlist는 이름·메타데이터·오류·span 데이터를 생략해요. 호출자가 공급한 ID는 민감 정보를 담으면 안 되고, 애플리케이션이 그 ID를 안전한 값으로 매핑해야 해요. 이 진단 출력은 OpenAI tracing ingest 스키마가 아니에요. 백엔드로 데이터를 보내는 애플리케이션은 그 백엔드와 호환되는 redaction 정책과 목적지를 제공해야 해요.
redactor와 목적지는 신뢰하는 애플리케이션 코드예요. 그것들은 원본 데이터를 독립적으로 로그하거나 보내면 안 돼요. batch processor는 백그라운드 export·명시적 flush·종료 중에 exporter를 호출할 수 있으니, 콜백이 그 실행 컨텍스트에서 안전해야 해요. 실패한 배치는 버려지고 이후 배치는 여전히 내보낼 수 있어요. 교체는 미래 프로세서 콜백에 영향을 주고, 이전에 등록된 프로세서가 이미 버퍼링한 데이터를 지우지 않아요. trace를 만들거나 에이전트를 실행하기 전에 교체를 구성하세요.
비-OpenAI 모델로 tracing
비-OpenAI 모델을 쓸 때 OpenAI API 키를 tracing exporter에 제공하면 tracing을 비활성화하지 않고 OpenAI Traces 대시보드에서 무료 tracing을 켤 수 있어요. 어댑터 선택·설정 주의 사항은 Models 가이드의 Third-party adapters 섹션을 참고하세요.
import os
from agents import set_tracing_export_api_key, Agent
from agents.extensions.models.any_llm_model import AnyLLMModel
tracing_api_key = os.environ["OPENAI_API_KEY"]
set_tracing_export_api_key(tracing_api_key)
model = AnyLLMModel(
model="your-provider/your-model-name",
api_key="your-api-key",
)
agent = Agent(
name="Assistant",
model=model,
)
단일 실행에 다른 tracing 키만 필요하다면 전역 exporter를 바꾸는 대신 RunConfig로 넘기세요.
from agents import Runner, RunConfig
await Runner.run(
agent,
input="Hello",
run_config=RunConfig(tracing={"api_key": "«redacted:sk-…»"}),
)
추가 메모
- 무료 trace는 OpenAI Traces 대시보드에서 볼 수 있어요.
생태계 통합
다음 커뮤니티·벤더 통합이 OpenAI Agents SDK의 tracing API 표면을 지원해요.
외부 tracing 프로세서 목록
- Weights & Biases
- Arize Phoenix
- Future AGI
- MLflow (self-hosted/OSS)
- MLflow (Databricks hosted)
- Braintrust
- Pydantic Logfire
- AgentOps
- Scorecard
- Respan
- LangSmith
- Maxim AI
- Comet Opik
- Langfuse
- Langtrace
- Okahu-Monocle
- Galileo
- Portkey AI
- LangDB AI
- Agenta
- PostHog
- Traccia
- PromptLayer
- HoneyHive
- Asqav
- Datadog
- Latitude
- DProvenanceKit
- Tuning Engines
- Laminar
더 알아보기 (Learn more)
- OpenAI Agents SDK 문서에서 더 많은 가이드를 확인하세요.