한 사용자가 어제 오후 에이전트가 "이상한 짓"을 했다고 보고했습니다. 로그를 열어보니 다음과 같은 내용이 있었습니다:
INFO agent run started
INFO calling tool: updateOrder
INFO tool returned 200
INFO agent run completed
에이전트는 updateOrder를 호출했습니다. 어떤 인수를 사용했는지, 어떤 주문에 대해 호출했는지, 왜 그 도구를 선택했는지, 어떤 결과가 반환되었는지 알 수 없습니다. 기록된 모든 측정치에 따르면 실행은 성공했으며, 에이전트가 내린 단 하나의 결정도 재구성할 수 없습니다.
에이전트 시스템은 나중에야 이해되는 방식으로 실패하며, 이는 로그가 바로 그 결과물임을 의미합니다. 이 가이드는 모든 도구 호출 시 무엇을 기록해야 하는지, 모델의 결정을 생성된 HTTP 요청과 어떻게 연관시키는지, 무엇을 삭제해야 하는지, 그리고 트레이스를 테스트로 전환하는 방법을 다룹니다. API 가시성에 대한 저희 게시물은 서비스 측면을 다루고, 이 게시물은 그 위에 있는 에이전트 계층을 다룹니다.
Apidog은 트레이스가 있을 때 유용합니다. 잘못된 호출을 이해하는 가장 빠른 방법은 동일한 엔드포인트에 대해 다시 실행하고 무슨 일이 일어나는지 지켜보는 것이기 때문입니다.
세 가지 계층, 하나의 트레이스
에이전트는 세 가지 수준에서 이벤트를 생성하며, 대부분의 팀은 중간 수준만 기록합니다.
추론 계층(reasoning layer)은 모델이 결정을 내리는 곳입니다. 어떤 컨텍스트에 있었는지, 어떤 도구가 제공되었는지, 어떤 도구를 선택했는지, 그리고 어떤 인수를 사용했는지.
도구 계층(tool layer)은 실행자입니다. 인수를 검증하고, 정책을 적용하고, 호출을 HTTP 요청에 매핑하며, 결과를 처리합니다.
HTTP 계층(HTTP layer)은 네트워크 전송입니다. 메서드, URL, 헤더, 본문, 상태, 지연 시간.
디버깅은 거의 항상 계층을 넘나듭니다. "에이전트가 잘못된 고객 ID를 보냈다"는 HTTP 계층에서만 보이는 추론 문제입니다. "API가 빈 본문과 함께 200을 반환했다"는 세 단계 후에 이상한 추론으로 나타나는 HTTP 문제입니다. 세 가지 계층이 공유 식별자로 연결되어 있지 않으면 타임스탬프로 상관 관계를 찾아야 하는데, 이는 두 번의 실행이 겹치는 순간 작동을 멈춥니다.
따라서 첫 번째 규칙: 에이전트 실행당 하나의 트레이스 ID, 도구 호출당 하나의 스팬 ID, 그리고 모든 계층의 모든 기록에 둘 다 스탬프를 찍습니다. OpenTelemetry 트레이스는 이미 이 형태를 정확히 모델링하며, 데이터 이식성을 위해 속성 이름을 지정하기 위한 GenAI 시맨틱 규칙이 증가하고 있습니다.
모든 도구 호출에서 기록할 내용
실제 질문에 답하는 기록은 대략 다음과 같은 형태를 가집니다:
{
"trace_id": "run_01J8ZK3M2Q",
"span_id": "call_004",
"parent_span_id": "call_003",
"timestamp": "2026-08-26T14:03:11.482Z",
"agent": "billing",
"step": 4,
"tool_name": "refundOrder",
"tool_args": { "orderId": "ord_92", "amount": 1200, "reason": "duplicate" },
"tools_available": ["getOrder", "listOrders", "refundOrder", "voidInvoice"],
"http": {
"method": "POST",
"url": "/v1/orders/ord_92/refund",
"request_body_hash": "sha256:1f4c...",
"status": 200,
"duration_ms": 412,
"retry_count": 1,
"idempotency_key": "9f2b7c14-6d3a-4b18"
},
"outcome": "success",
"tokens": { "prompt": 8420, "completion": 96 },
"policy": { "approval_required": true, "approved_by": "user_31", "dry_run": false }
}
다섯 가지 필드가 막대한 역할을 합니다.
tool_args는 가장 자주 누락되는 필드이며, 항상 필요한 필드입니다. 실행자가 인수를 정규화하기 전에 모델이 생성한 인수를 기록하세요. 에이전트가 잘못된 ID를 보냈을 때, 이것이 보이는 곳입니다.
tools_available은 선택을 설명합니다. 모델이 이상한 도구를 선택했다면, 첫 번째 질문은 다른 어떤 선택지가 있었는지입니다. 이 필드는 몇 바이트의 비용으로 즉시 답을 제공합니다.
retry_count는 "API가 느렸다"와 "API가 두 번 실패하고 나서 작동했다"를 구분합니다. 이것이 없으면 세 번의 시도가 하나의 호출처럼 보입니다.
outcome은 상태 코드에서 추론하는 것이 아니라 명시적인 열거형이어야 합니다. success, failed, timed_out, blocked_by_policy, rejected_by_human. 마지막 두 가지가 중요한 이유는 차단된 호출은 오류가 아니라 작동하는 안전장치이며, 이들을 혼합하면 실패율이 왜곡되기 때문입니다.
policy는 감사 추적입니다. 누군가 파괴적인 행동이 승인되었는지 물을 때, 이것이 답입니다. 이는 AI 에이전트 가드레일에 대한 저희 게시물에 설명된 강제 사항과 짝을 이룹니다.
결정을 기록하고, 행동만 기록하지 마십시오
가장 어려운 에이전트 버그는 선택이므로, 이를 재구성할 수 있을 만큼 충분히 기록하십시오.
실행에 사용된 도구 정의 또는 그 해시를 보관하십시오. 선택 정확도가 변동할 때, 가장 먼저 의심되는 것은 누군가가 편집한 설명이며, 해시는 좋은 실행과 나쁜 실행 사이에 도구 세트가 변경되었는지 여부를 즉시 알려줍니다. 도구 스키마 설계에 대한 저희 게시물은 해당 텍스트가 왜 그렇게 행동에 많은 영향을 미치는지 다룹니다.
모델과 설정을 기록하십시오. 모델 ID, 온도, 프롬프트 버전은 실행 기록에 속합니다. 모델 버전 간에 동작이 변경되며, 이 필드가 없으면 자체 코드 조사를 하루 종일 하게 될 것입니다.
모델이 본 것, 또는 최소한 그 크기를 기록하십시오. 전체 프롬프트 덤프는 저장 비용이 많이 들고 종종 민감한 정보입니다. 토큰 수와 해시는 대부분의 진단 가치를 제공합니다. 프롬프트 크기가 평소의 두 배인 실행은 추가되어서는 안 될 무언가가 추가된 실행입니다.
잘라내기 전의 원본 도구 결과를 기록하십시오. 실행자가 모델에 전달하기 전에 응답을 축소하는 경우(컨텍스트 창에서 도구 응답을 제외하는 게시물 참조), 전체 페이로드를 트레이스에 저장하십시오. 그렇지 않으면 데이터가 누락되었는지 아니면 당신이 삭제했는지 알 수 없습니다.
저장하기 전에 삭제하십시오
에이전트 트레이스는 요청과 그에 대한 추론을 모두 포함하고, 프롬프트는 개인 데이터를 수집하는 경향이 있어 매우 위험합니다.
네 가지 규칙이 이를 관리할 수 있게 합니다.
자격 증명을 절대 저장하지 마십시오. Authorization, API 키, 쿠키 및 서명된 URL을 제거하십시오. 값 대신 키 ID와 같은 자격 증명의 식별자를 기록하십시오. 에이전트를 위한 최소 권한 API 키에 대한 저희 게시물은 해당 식별자가 필요한 이유를 다룹니다: 어떤 에이전트가 행동했는지 알려줍니다.
쿼리에서가 아니라 경계에서 삭제하십시오. 읽기 시점에 필터링하는 것은 비밀이 디스크에 기록되고, 복제되고, 백업되었다는 것을 의미합니다. 기록이 프로세스를 떠나기 전에 로깅 미들웨어에서 삭제하십시오.
저장할 수 없는 본문은 해시하십시오. 요청 본문 해시는 두 호출이 동일했음을 증명할 수 있게 해주며, 페이로드를 보관하지 않고도 중복 조사에 필요한 대부분의 정보를 제공합니다.
민감도에 따라 보존 기간을 설정하십시오. 일주일 동안은 전체 트레이스, 1년 동안은 삭제된 요약. 대부분의 디버깅은 며칠 이내에 발생하며, 대부분의 감사 질문은 몇 달 이내에 발생합니다.
트레이스를 테스트로 전환하기
좋은 트레이싱의 장점은 더 빠른 디버깅뿐만이 아닙니다. 현실적인 테스트 케이스의 공급원입니다.
모든 실패한 실행은 시나리오입니다. 잘못된 트레이스에서 도구 호출을 가져와 API에 대해 다시 실행하면 재현이 됩니다. 수정 사항이 적용되면 재생을 회귀 테스트로 유지하십시오. Apidog에서는 실패한 요청을 저장된 케이스로 재구성하고, 수정된 동작을 어설션하고, CI에서 실행할 수 있습니다. 이것이 일회성 사건이 영구적인 커버리지로 바뀌는 방법입니다.
트레이스는 또한 무엇을 모의해야 하는지도 알려줍니다. 에이전트가 가장 많이 호출하는 엔드포인트와 실제로 발생하는 실패 상태는 추측이 아닌 데이터에서 직접 나옵니다. 생산 환경 대신 모의 환경에서 에이전트 실행에 대한 저희 게시물을 따라 이를 중심으로 모의를 구축하십시오.
그리고 트레이스는 놓칠 수 있었던 느린 변화를 드러냅니다. 매주 몇 가지 숫자를 추적하십시오: 도구 선택 분포, 엔드포인트별 재시도율, 완료된 작업당 호출 수, 정책에 의해 차단된 실행 비율. 이들 중 어떤 것이라도 변화하면 사건이 되기 전에 신호가 됩니다. API 계약 테스트 가이드에서와 같은 계약 수준 검사는 일반적으로 이를 유발한 상류의 변경 사항을 잡아냅니다.
트레이스가 견뎌야 할 세 가지 조사
"에이전트가 잘못된 고객에게 청구했습니다." 모델이 생성한 인수, 해결된 URL, 그리고 그 이전 단계를 알아야 합니다. 10번 중 9번은 ID가 여러 일치를 반환한 이전 도구 결과에서 왔고 모델이 첫 번째를 선택한 경우입니다. 트레이스는 이전 결과, 모호성, 그리고 선택을 보여줍니다. tool_args가 없으면 200과 매우 불만족스러운 고객만 남게 됩니다.
"화요일부터 작동하지 않습니다." 좋은 실행과 나쁜 실행을 필드별로 비교하십시오. 모델 ID, 도구 세트 해시, 프롬프트 버전, 평균 응답 크기. 무언가가 변경되었고, 이 네 가지 중 하나가 보통 원인을 지목합니다. 이것이 실행 기록이 이벤트뿐만 아니라 구성을 포함하는 이유입니다: 두 측면 모두 동일한 필드를 기록했을 때만 차이점을 파악할 수 있습니다.
"누군가 이것을 승인했습니까?" 정책 블록은 전체 답변이며, 나중에 재구성하는 것이 아니라 결정 시점에 작성되어야 합니다. approval_required, approved_by, 그리고 타임스탬프는 긴장된 대화를 검색으로 바꿉니다.
이것들의 공통점을 살펴보십시오. 이들 중 어느 것도 "도구가 200을 반환했다"는 말로 답할 수 없습니다. 세 가지 모두 기록하는 데 거의 비용이 들지 않지만 사후에는 복구할 수 없는 필드들로 답해집니다.
샘플링, 그리고 절대 샘플링해서는 안 되는 것
모든 실행에 대한 고정밀 트레이싱은 볼륨이 커질수록 비용이 많이 들기 때문에 팀은 샘플링을 합니다. 에이전트 트래픽은 균일하지 않으므로 신중하게 샘플링하십시오.
실패한 모든 실행, 정책 블록에 도달한 모든 실행, 쓰기 작업을 포함하는 모든 실행은 항상 보관하십시오. 이들은 누군가가 질문할 실행들입니다. 성공적인 읽기 전용 실행은 볼륨의 대부분을 차지하고 개별적으로는 가장 흥미롭지 않지만, 기준선을 계산하기 위해 충분한 양은 여전히 필요하므로 샘플링하십시오.
구글의 SRE 책의 모니터링 챕터는 볼륨이 아닌 신호를 위해 샘플링하는 이유에 대해 가장 명확하게 설명하고 있으며, 그 추론은 직접적으로 적용됩니다.
페이로드를 삭제하더라도 실행 기록은 보관하십시오. 도구 이름, 결과, 지속 시간이 포함된 스켈레톤 트레이스는 작으며 위의 네 가지 메트릭을 여전히 지원합니다. 비용이 많이 드는 부분은 본문과 프롬프트이며, 이 부분은 먼저 삭제할 수 있습니다.
테일 샘플링에 대한 한 가지 경고: 실행이 완료된 후 무엇을 유지할지 결정하는 경우, 결과가 알려진 후에 결정이 이루어지는지 확인하십시오. 3단계에서 괜찮아 보였지만 9단계에서 실패한 실행은 전체를 보관해야 하며, 이는 진행 중에 버리는 대신 버퍼링해야 함을 의미합니다.
트레이스가 보관되어야 할 곳
위의 모든 내용은 저장소를 소유하고 있다는 가정을 전제로 합니다. 에이전트가 자체 API를 호출하는 자체 서비스일 때는 올바른 가정입니다. 에이전트가 개발자 머신의 코딩 런타임일 때는 적합하지 않습니다. 왜냐하면 트레이스가 해당 실행을 담당한 터미널에 존재하기 때문입니다.
Sharkly는 다른 접근 방식을 취합니다: 실행 트레이스는 에이전트에게 할당된 작업에 첨부됩니다. 실행 기록, 실행 로그, 결과는 목표, 상태 및 사람이 작업을 검토한 댓글 스레드 옆에 있습니다. 실질적인 차이점은 검색입니다. "에이전트가 왜 그렇게 했지?"라는 질문은 기계, 세션, 스크롤백을 찾는 대신 작업을 열어 답하는 질문이 됩니다.

이것은 여기서 설명하는 트레이싱을 대체하지 않으며, 런타임도 대체하지 않습니다. Claude Code와 Codex는 여전히 작업을 수행합니다. 이것이 변경하는 것은 에이전트가 배포한 서비스가 아닐 때 기록이 어디에 저장되는가입니다.
네 가지 숫자 주시하기
트레이스는 누군가가 볼 때만 유용합니다. 이 네 가지는 대시보드에 있어야 합니다.
- 완료된 작업당 호출 수. 가장 명확한 효율성 측정 지표입니다. 증가하면 에이전트가 더 많이 탐색하고 있다는 의미이며, 보통 설명이 나빠졌거나 엔드포인트가 실패하기 시작했기 때문입니다.
- 엔드포인트별 재시도율. 가장 신뢰할 수 없는 종속성을 순위를 매기고 하나가 저하될 때를 보여줍니다. 에이전트 오류 복구에 대한 저희 게시물은 목록의 맨 위에 있는 항목에 대해 무엇을 해야 하는지 다룹니다.
- 정책에 의해 차단된 비율. 낮고 안정적이어야 합니다. 급증은 에이전트가 하지 말아야 할 일을 시도하고 있거나, 정책이 너무 엄격하여 병목 현상이 발생하고 있음을 의미합니다.
- 첫 도구 호출까지의 시간. 시작이 느리다는 것은 보통 비대한 프롬프트를 의미하며, 프롬프트 크기는 누구도 의도하지 않게 증가하는 것입니다.
체크리스트
- 실행당 하나의 트레이스 ID, 도구 호출당 하나의 스팬 ID, 세 가지 계층 모두에 스탬프 표시.
- 정규화 전에 기록된 모델 인수.
- 모든 호출에서 사용 가능한 도구 목록 기록.
- 정책 차단을 포함하여 명시적 열거형으로 기록된 결과.
- 호출 횟수와 별도로 재시도 횟수.
- 실행 기록에 모델, 온도, 프롬프트 버전 및 도구 세트 해시 포함.
- 잘라낸 버전만 모델에 전달하는 대신 원본 도구 결과 저장.
- 미들웨어에서 자격 증명 제거, 저장할 수 없는 본문은 해시.
- 민감도에 따라 계층화된 보존 정책.
- 실패한 트레이스를 다시 재생 가능한 테스트 케이스로 전환 가능.
목표는 간단하게 명시할 수 있습니다: 누군가 에이전트가 왜 그렇게 했는지 물을 때, 추측이 아닌 기록에서 답할 수 있어야 합니다. Apidog을 다운로드하여 트레이스의 호출을 재생하고 재현된 내용을 테스트로 보관하십시오.
자주 묻는 질문
OpenTelemetry를 사용해야 하나요 아니면 목적에 맞는 에이전트 관찰성 도구를 사용해야 하나요? 상관 관계를 이미 처리하고 인프라가 이를 지원할 가능성이 높으므로 전송 및 트레이스 모델에는 OpenTelemetry를 사용하십시오. 에이전트 전용 도구는 그 위에 유용한 뷰를 추가합니다. 밑에 있는 데이터는 여전히 이식 가능해야 합니다.
전체 트레이싱 저장 비용은 얼마나 드나요? 계층화하면 사람들이 예상하는 것보다 적게 듭니다. 며칠 동안은 전체 페이로드, 더 오랜 기간 동안은 본문이 없는 구조화된 기록을 유지하면 대부분의 볼륨을 낮출 수 있습니다. 프롬프트 덤프는 비용이 많이 드는 부분이므로 기본적으로 저장하는 대신 해시하고 크기를 기록하십시오.
모델의 추론 텍스트를 기록해야 하나요? 보통은 아닙니다. 선택한 도구, 생성한 인수, 가졌던 옵션이 대부분의 결정을 설명합니다. 제공자가 추론 콘텐츠를 노출하는 경우, 실패한 실행에 대해서만 저장하고 민감한 정보로 취급하십시오.
여러 에이전트에서 어떻게 트레이스하나요? 전체 작업에 대해 하나의 트레이스 ID를 유지하고 각 에이전트에 자체 스팬을 부여하며, 핸드오프를 이벤트로 기록하십시오. 다중 에이전트 핸드오프에 대한 저희 게시물은 해당 핸드오프 기록에 무엇이 속하는지 다룹니다.
에이전트가 고객의 컴퓨터에서 실행되는 경우 어떻게 해야 하나요? 로컬에 기록하고, 공격적으로 삭제하며, 사용자가 동의하지 않는 한 집계된 메트릭만 전송하십시오. 도구 이름, 결과, 지속 시간은 일반적으로 페이로드가 장치를 벗어나지 않고도 플릿 수준 모니터링에 충분합니다.
요청 본문 해시가 실제로 유용한가요? 예, 가장 일반적인 질문에 대해 유용합니다. 두 호출이 동일했음을 증명하며, 이는 페이로드 자체를 보관하지 않고도 대부분의 중복 쓰기 조사를 해결합니다. 중복을 방지했어야 할 멱등성 키와 함께 사용하십시오.
