OpenAI Agents SDK: 핸드오프, 가드레일, 트레이싱 (OpenAI Agents SDK: Handoffs, Guardrails, Tracing)
OpenAI Agents SDK는 Responses API 위에 만들어진 가벼운 멀티 에이전트 프레임워크(multi-agent framework)입니다. 다섯 가지 원시 요소(primitives)는 Agent, Handoff, Guardrail, Session, Tracing입니다. 핸드오프(Handoff)는 transfer_to_<agent>라는 이름의 도구로 표현됩니다. 가드레일(Guardrail)은 입력 또는 출력에서 트립(trip)됩니다. 트레이싱(Tracing)은 기본으로 켜져 있습니다.
유형: Learn + Build
언어: Python (stdlib)
선수 학습: Phase 14 · 01 (에이전트 루프(Agent Loop)), Phase 14 · 06 (도구 사용(Tool Use))
소요 시간: 약 75분
학습 목표
- OpenAI Agents SDK의 다섯 가지 원시 요소를 말할 수 있습니다.
- 핸드오프(Handoff)가 왜 도구로 모델링되는지, 모델이 보는 도구 이름의 형태가 어떤지, 맥락이 어떻게 전달되는지를 설명할 수 있습니다.
- 입력 가드레일(input guardrail), 출력 가드레일(output guardrail), 도구 가드레일(tool guardrail)을 구분하고,
run_in_parallel 방식과 블로킹(blocking) 모드의 차이를 설명할 수 있습니다.
- 핸드오프, 가드레일, 스팬(span) 기반 트레이싱을 갖춘 표준 라이브러리(stdlib) 런타임을 직접 구현할 수 있습니다.
문제
깔끔하게 위임(delegate)하지 못하는 에이전트는 결국 모든 일을 하나의 프롬프트(prompt)에 욱여넣게 됩니다. 가드레일이 없는 에이전트는 개인정보(PII), 정책을 위반하는 출력, 또는 끝없는 루프(loop)를 그대로 내보냅니다. OpenAI SDK는 멀티 에이전트 작업을 실제로 다룰 만하게 만들어 주는 세 가지 원시 요소를 코드로 정형화한 것입니다.
개념
다섯 가지 원시 요소
- Agent. LLM + 지시문(instructions) + 도구(tools) + 핸드오프(handoffs)로 구성됩니다.
- Handoff. 다른 에이전트로 위임하는 동작입니다. 모델 입장에서는
transfer_to_<agent_name>이라는 이름의 도구로 보입니다.
- Guardrail. 입력(첫 번째 에이전트만), 출력(마지막 에이전트만), 또는 도구 호출(function tool 단위)에 대한 검증입니다.
- Session. 여러 턴(turn) 사이의 대화 이력을 자동으로 이어 줍니다.
- Tracing. LLM 생성, 도구 호출, 핸드오프, 가드레일에 대한 내장 스팬(span)입니다.
도구로서의 핸드오프
모델은 자신의 도구 목록에서 transfer_to_billing_agent 같은 항목을 보게 됩니다. 모델이 이 도구를 호출하면 런타임은 다음과 같이 동작합니다.
- 대화 맥락을 그대로 복사하거나, 베타(beta) 기능인
nest_handoff_history를 사용해 압축합니다.
- 대상 에이전트를 해당 지시문(instructions)으로 초기화합니다.
- 대상 에이전트로 실행(run)을 이어 갑니다.
이는 13강과 28강에서 다룬 슈퍼바이저 패턴(supervisor pattern)을 제품화한 형태입니다.
가드레일(Guardrails)
가드레일에는 세 가지 형태가 있습니다.
- 입력 가드레일(Input guardrails). 첫 번째 에이전트의 입력 단계에서 실행됩니다. LLM 호출이 일어나기 전에, 안전하지 않거나 범위를 벗어난 요청을 거부합니다.
- 출력 가드레일(Output guardrails). 마지막 에이전트의 출력 단계에서 실행됩니다. 개인정보(PII) 유출, 정책 위반, 형식이 잘못된 응답을 잡아냅니다.
- 도구 가드레일(Tool guardrails). 함수 도구(function tool)마다 따로 실행됩니다. 인자를 검증하고, 권한을 확인하고, 실행 자체를 감사(audit)합니다.
모드는 두 가지가 있습니다.
- 병렬(Parallel) 모드 (기본값). 가드레일 LLM이 본 LLM과 동시에 실행됩니다. 꼬리 지연(tail latency)이 낮아지는 대신, 가드레일이 트립되면 본 LLM이 한 작업은 버려집니다. 그만큼 토큰이 낭비됩니다.
- 블로킹(Blocking) 모드 (
run_in_parallel=False). 가드레일 LLM이 먼저 실행됩니다. 트립되면 본 호출(main call)에 토큰을 쓰지 않습니다.
트립와이어(tripwire)는 InputGuardrailTripwireTriggered / OutputGuardrailTripwireTriggered 예외를 발생시킵니다.
트레이싱(Tracing)
기본으로 켜져 있습니다. 모든 LLM 생성, 도구 호출, 핸드오프, 가드레일이 스팬(span)을 남깁니다. OPENAI_AGENTS_DISABLE_TRACING=1 환경 변수로 끌 수 있습니다. add_trace_processor(processor)를 사용하면 OpenAI 측 백엔드와 함께 직접 만든 백엔드로도 스팬을 내보낼(fan out) 수 있습니다.
세션(Sessions)
Session은 대화 이력을 백엔드(SQLite, Redis, 사용자 정의 저장소)에 보관합니다. Runner.run(agent, input, session=session)은 이력을 자동으로 불러오고, 새 메시지를 뒤에 덧붙입니다.
이 패턴이 잘못 사용되는 지점
- 핸드오프 표류(Handoff drift). Agent A가 Agent B로 넘기고, Agent B가 다시 Agent A로 돌려보내는 식으로 도는 경우입니다. 홉 카운터(hop counter)를 추가해 막으세요.
- 가드레일 우회(Guardrail bypass). 도구 가드레일은 함수 도구(function tool)에 대해서만 실행됩니다. 파일 리더(file reader), 웹 요청(web fetch) 같은 내장 도구는 별도의 정책이 필요합니다.
- 과도한 트레이싱(Over-tracing). 민감한 내용이 스팬에 그대로 담길 수 있습니다. 23강의 OTel GenAI 콘텐츠 캡처 규칙(content-capture rules)과 함께 사용하세요. 본문은 외부 저장소에 보관하고, 스팬에서는 ID로만 참조하는 방식을 권장합니다.
만들어보기
code/main.py는 SDK의 형태를 표준 라이브러리(stdlib)만으로 구현합니다.
Agent, FunctionTool, Handoff를 정의합니다. 여기서 핸드오프는 위임 의미(transfer semantics)를 가진 함수 도구(function tool)처럼 다룹니다.
- 입력/출력/도구 가드레일, 핸드오프 디스패치(handoff dispatch), 홉 카운터(hop counter)를 갖춘
Runner를 제공합니다.
- 스팬 트리(span tree)의 모양을 보여주는 간단한 스팬 출력기(span emitter)를 포함합니다.
- 트리아지(triage) 에이전트가 사용자 질의에 따라 빌링(billing) 또는 지원(support) 에이전트로 핸드오프하고, 한 입력에서는 가드레일이 트립되도록 구성되어 있습니다.
다음과 같이 실행합니다.
python3 code/main.py
실행 추적을 보면 성공한 핸드오프 두 건, 입력 가드레일 트립 한 건, 그리고 실제 SDK가 내보내는 형태를 닮은 스팬 트리가 함께 출력됩니다.
사용해보기
- OpenAI Agents SDK는 OpenAI 중심(OpenAI-first) 제품을 만들 때 사용합니다.
- Claude Agent SDK(17강)는 Claude 중심(Claude-first) 제품을 만들 때 사용합니다.
- LangGraph(13강)는 명시적인 상태(state)와 영속적인 재개(durable resume)가 필요할 때 선택합니다.
- Custom(직접 구현)은 음성, 다중 제공자(multi-provider), 분산 배포(federated deployments)처럼 정확한 통제가 필요할 때 선택합니다.
산출물 만들기
outputs/skill-agents-sdk-scaffold.md는 트리아지 에이전트, 핸드오프, 입력/출력/도구 가드레일, 세션 저장소(session store), 트레이스 프로세서(trace processor)를 갖춘 Agents SDK 앱의 골격을 자동으로 짜냅니다(scaffold).
연습문제
- (쉬움) 핸드오프 홉 카운터(hop counter)를 추가해 보세요. N번 위임이 일어난 뒤에는 거부하도록 만들고, 그 동작이 트레이스에 어떻게 남는지 확인합니다.
- (중간)
nest_handoff_history 옵션을 구현해 보세요. 위임 직전에 이전 메시지들을 하나의 요약으로 접도록 만듭니다.
- (중간) 블로킹(blocking) 방식의 출력 가드레일을 작성해 보세요. 트립되는 프롬프트와 통과하는 프롬프트의 지연 시간을 비교해 봅니다.
- (어려움)
add_trace_processor를 JSON 로거(logger)에 연결해 보세요. 스팬마다 어떤 모양으로 출력이 남는지 살펴봅니다.
- (어려움) SDK 공식 문서를 읽고, 표준 라이브러리로 만든 장난감 예제를
openai-agents-python으로 옮겨 보세요. 어떤 부분을 잘못 모델링하고 있었는지 정리해 봅니다.
핵심 용어
| 용어 | 흔한 설명 | 실제 의미 |
|---|
| Agent | "LLM + 지시문(instructions)" | SDK의 Agent 타입입니다. 도구(tools)와 핸드오프(handoffs)를 소유합니다. |
| Handoff | "이관(Transfer)" | 다른 에이전트로 위임하기 위해 모델이 호출하는 도구입니다. |
| Guardrail | "정책 검사(Policy check)" | 입력 / 출력 / 도구 호출에 대한 검증입니다. |
| Tripwire | "가드레일 트립(Guardrail trip)" | 가드레일이 거부할 때 발생시키는 예외입니다. |
| Session | "이력 저장소(History store)" | 여러 실행 사이에 지속되는 대화 메모리입니다. |
| Tracing | "스팬(Spans)" | LLM, 도구, 핸드오프, 가드레일 전반에 걸친 내장 관찰성(observability)입니다. |
| Blocking guardrail | "순차 검사(Sequential check)" | 가드레일이 먼저 실행되며, 트립되어도 토큰이 낭비되지 않습니다. |
| Parallel guardrail | "동시 검사(Concurrent check)" | 가드레일이 본 LLM과 함께 실행되어 지연이 줄지만, 트립 시 토큰이 낭비됩니다. |
더 읽을거리