iBetter Books
수정

프로비넌스와 추적

멀티 에이전트 시스템은 출력 하나가 어느 모델·어느 호출·어느 스레드에서 나왔는지 추적할 수 있어야 한다. 이것이 프로비넌스(provenance)다. 비용 귀속, 디버깅, 감사, 재현이 모두 여기에 달려 있다. 추적의 메커니즘은 실행 표면에 따라 갈린다. 워크플로우(내가 루프를 도는 경우)에서는 응답 객체의 필드를 내가 직접 기록하고, Managed Agents에서는 이벤트 스트림 자체가 트레이스다. 이 절은 추측이 정확도를 망치는 영역이므로 필드 이름을 정확히 외워야 한다.

워크플로우에서의 추적

Claude API를 직접 호출하는 경우, 추적에 필요한 정보는 응답 객체에 들어 있고 그것을 로그로 남기는 것은 내 책임이다. 핵심 필드는 네 가지다.

# tracing/log.pyresp = client.messages.create(    model="claude-opus-4-8",    max_tokens=16000,    thinking={"type": "adaptive"},    messages=messages,)log.info(request_id=resp._request_id)   # req_... 식별자, 장애 신고 시 동봉log.info(served_by=resp.model)          # 실제 응답을 생성한 모델log.info(usage=resp.usage)              # input/output·캐시 토큰 회계messages.append({"role": "assistant", "content": resp.content})  # 전체 content 보존

여기서 자주 출제되는 포인트가 마지막 줄이다. 다음 턴으로 이어갈 때는 텍스트만 떼어 붙이지 말고 resp.content 전체를 보존해야 한다. thinking 블록과 tool_use 블록을 잃으면 같은 모델에서 턴을 이어갈 수 없고, 컴팩션을 쓸 때는 컴팩션 블록을 잃어 상태가 깨진다. _request_id는 밑줄 접두사에도 불구하고 공개 프로퍼티이며 장애를 Anthropic에 보고할 때 함께 보낸다.

서버 측 폴백(server-side fallback)이 개입해 거부된 요청이 다른 모델로 재실행된 경우, 시도별(per-attempt) 회계의 기준은 응답 객체의 usage.iterations다. 이는 Messages API 응답 필드이며, 어느 시도가 어떤 모델에서 돌았는지를 담는다. 최상위 usage는 최종 응답을 만든 시도만 다루므로, 폴백 비용을 정확히 귀속하려면 usage.iterations를 읽어야 한다.

Managed Agents에서의 추적

세션의 이벤트 스트림이 곧 트레이스다. 요청별 비용과 효율을 분석하려면 span.model_request_end 이벤트의 model_usage 필드를 읽는다. 이것이 Managed Agents 세션에서 모델 요청 한 건의 비용을 얻는 정식 경로이며, 재스케줄은 session.status_rescheduled 이벤트로 드러난다. 내가 보낸 이벤트(사용자 메시지·도구 결과)의 처리 여부는 processed_at로 구분한다. 큐에만 들어가고 아직 처리되지 않았으면 null, 에이전트가 처리하면 타임스탬프가 채워진다. 같은 이벤트가 스트림에 두 번 나타나는 이유가 이것이다.

멀티 에이전트 세션에서는 스레드 단위 추적이 더해진다. 서브에이전트 스레드는 session.thread_created로 생성되고, 스레드 간 메시지는 agent.thread_message_sentagent.thread_message_received로 흐른다. 컨텍스트가 길어 요약되면 agent.thread_context_compacted가 발생한다.

웹훅과 SSE의 네임스페이스 차이

가장 까다로운 함정이 이것이다. 상태 변화를 폴링이나 스트림 대신 웹훅으로 받을 수 있는데, 웹훅의 data.type 값은 SSE 이벤트 타입과 별개의 네임스페이스다. 예를 들어 에이전트가 입력을 기다리는 상태를, SSE 스트림에서는 session.status_idle로, 웹훅에서는 session.status_idled로 표기한다. 둘을 섞어 쓰면 핸들러가 작동하지 않는다. 또한 웹훅 페이로드는 얇아서 ID와 타입만 담기므로, 현재 상태는 리소스를 다시 조회해 얻어야 하고, 재시도는 같은 event.id로 오므로 그 ID로 중복을 제거한다.

시험에서 어떻게 나오는가

  • 함정 1. "다음 턴에 텍스트만 이어 붙인다"는 오답이다. thinking·tool_use·컴팩션 블록을 잃지 않으려면 resp.content 전체를 보존한다.
  • 함정 2-1. Messages API에서 서버 측 폴백이 개입한 비용 회계의 기준을 묻는 문제에서 정답은 최상위 usage가 아니라 usage.iterations다.
  • 함정 2-2. Managed Agents 세션에서 모델 요청 한 건의 비용을 묻는 문제에서 정답은 usage.iterations가 아니라 span.model_request_end.model_usage다. 두 필드는 서로 다른 표면에 속한다.
  • 함정 3. 웹훅 session.status_idled와 SSE session.status_idle을 같은 것으로 취급하면 오답이다. 두 네임스페이스는 분리되어 있다.
  • 핵심 포인트. processed_atnull이면 큐 대기, 타임스탬프가 있으면 처리 완료다.

정리

  • 프로비넌스는 출력의 출처(모델·호출·스레드)를 추적하는 능력이며 비용 귀속·디버깅·감사·재현의 토대다.
  • 워크플로우에서는 _request_id, resp.model, resp.usage를 직접 로깅하고 resp.content 전체를 보존해 thinking·tool_use 블록을 지킨다.
  • Managed Agents에서는 이벤트 스트림이 트레이스이며 요청별 비용은 span.model_request_end.model_usage로 얻는다. 서버 측 폴백 시도별 회계인 usage.iterations는 Messages API 응답 필드로 표면이 다르다.
  • processed_at은 큐 대기(null)와 처리 완료(타임스탬프)를 구분한다.
  • 웹훅 data.type은 SSE 이벤트 타입과 별개의 네임스페이스이며(session.status_idledsession.status_idle) 혼용은 시험의 핵심 함정이다.
04. 프로비넌스와 추적 — 합격하는 Claude Certified Architect 자격증 | iBetter Books