|

AI 에이전트 실전 설계 시리즈 (7) – 에이전트 실패는 어떻게 로그로 남겨야 할까

에이전트 실패 로그와 tracing 구조 대표 이미지
에이전트 실패는 최종 답변이 아니라 실행 경로 전체를 남겨야 원인을 찾을 수 있다.

AI agent observability는 에이전트가 틀렸을 때 “왜 틀렸는지”를 다시 볼 수 있게 만드는 설계입니다. 최종 답변만 저장하면 문제 원인을 거의 찾을 수 없습니다.

6편에서 Agent workflow를 plan, execute, review, retry, human approval로 나누는 기준을 봤다면, 7편은 그 각 단계가 남겨야 할 증거를 정리하는 글입니다.

핵심은 에이전트 실패를 답변이 아니라 실행 경로 단위로 기록하는 것입니다. trace로 전체 실행을 묶고, retrieval, tool, memory, guardrail은 span으로 나누어 남겨야 합니다.


AI agent observability는 왜 필요할까

AI 에이전트 trace와 span 로그 구조도
trace_id로 전체 실행을 묶고 retrieval, tool, memory, guardrail을 span으로 나누어 기록한다.

OpenAI Agents SDK의 Tracing 문서는 agent run 중 LLM generation, tool call, handoff, guardrail, custom event를 기록할 수 있다고 설명합니다. 이 단위들은 에이전트 실패를 분석할 때 그대로 디버깅 단위가 됩니다.

최종 답변이 틀렸다는 사실만으로는 부족합니다. 검색이 잘못됐는지, 도구 인자가 틀렸는지, memory가 오염됐는지, guardrail이 막지 못했는지 구분할 수 있어야 다음 수정 방향이 나옵니다.


에이전트 trace와 span을 먼저 나눈다

trace는 하나의 사용자 요청이 끝날 때까지의 전체 실행 단위입니다. span은 그 안에서 벌어진 개별 단계입니다. 로그를 이 두 층으로 나누면 “이번 답변이 왜 이렇게 나왔는가”를 시간순으로 다시 볼 수 있습니다.

trace:
  trace_id: tr_20260713_001
  user_request: "지난달 매출 요약해줘"
  spans:
    - type: retrieval
      selected_documents: ["sales_policy_v3", "monthly_report_2026_06"]
    - type: tool_call
      name: query_sales_db
      args_summary: { month: "2026-06" }
      result_status: success
    - type: guardrail
      name: pii_check
      result: passed

여기서 중요한 것은 원문을 전부 저장하는 것이 아닙니다. 원인 분석에 필요한 ID, 버전, 상태, 요약을 남기는 것입니다. 그래야 보안과 비용을 키우지 않으면서도 재현 가능성을 확보할 수 있습니다.


각 단계에는 다른 로그가 필요하다

4편의 RAG context layer, 2편의 Tool calling 안전 기준, 5편의 Memory policy는 모두 observability와 연결됩니다. 단계가 다르면 남겨야 할 증거도 다릅니다.

  • retrieval: query, 문서 ID, 문서 버전, score, 실제 context에 들어간 chunk를 남긴다.
  • tool: tool 이름, 위험도, 인자 요약, 결과 상태, 오류 코드, 다음 승인 필요 여부를 남긴다.
  • memory: 읽은 memory key, 답변에 영향을 준 memory, 새로 저장한 이유, 저장하지 않은 민감 정보를 남긴다.
  • guardrail: 검사한 정책 이름, 입력/출력 검사 여부, 통과/수정/차단 결과, 차단 이유 코드를 남긴다.
tool_span:
  name: create_wordpress_draft
  risk_level: medium
  args_summary:
    title: "..."
    category: "AI 랩"
  result_status: success
  output_ref: "post_id:3379"
  approval_required_for_next_step: ["publish"]

특히 외부 상태를 바꾸는 도구는 결과만 보면 늦습니다. 호출 전 위험도, 호출 인자 요약, 호출 후 상태, 다음 단계 승인 필요 여부가 같이 남아야 합니다.


실패 원인을 5칸으로 나누어 본다

로그 설계가 부실하면 모든 문제가 “모델이 틀렸다”로 뭉개집니다. 실제로는 검색 실패, 도구 실패, 추론 실패, 기억 실패, 출력 검증 실패를 나누어 봐야 합니다.

failure_map:
  retrieval_error: "필요한 문서를 못 찾았거나 오래된 문서를 선택함"
  tool_error: "tool 인자, 권한, 외부 API 응답이 잘못됨"
  reasoning_error: "근거는 맞지만 모델이 결론을 잘못 냄"
  memory_error: "잘못 저장된 memory를 다시 사용함"
  guardrail_error: "막아야 할 출력이나 행동을 통과시킴"

이렇게 나누면 개선 작업도 달라집니다. retrieval 실패는 chunking이나 reranker를 봐야 하고, tool 실패는 schema와 권한을 봐야 하며, memory 실패는 저장 정책을 다시 봐야 합니다.


작은 업무 자동화 예시

블로그 운영 에이전트를 예로 들면, 좋은 로그는 “글을 만들었다”에서 끝나지 않습니다. 어떤 큐 항목을 골랐고, 어떤 출처를 확인했고, 어떤 검토를 통과했고, publish는 승인 대기인지까지 이어져야 합니다.

blog_agent_trace:
  queue_item: "AI-AGENT-701"
  workflow_step: "wordpress_draft"
  factpack:
    source_count: 2
    unresolved_claims: 0
  review:
    package_validation: passed
    yoast_readiness: "10/12"
  publish:
    status: "blocked_until_user_approval"

많이 남기는 로그도 위험하다

LangSmith의 Observability 문서는 trace부터 production-wide performance metrics까지 LLM application의 가시성을 제공한다고 설명합니다. 하지만 observability는 로그를 무한히 쌓는 일이 아닙니다.

개인정보, API 응답 원문, 내부 문서 전문을 그대로 저장하면 보안과 비용 문제가 생깁니다. 원문 전체보다 trace_id, document_id, tool name, status, latency, token 사용량, 오류 코드처럼 원인 분석에 필요한 최소 단위를 우선 남기는 편이 안전합니다.


실무 체크리스트

  1. trace_id와 conversation_id를 분리했는가?
  2. retrieval, tool, memory, guardrail을 span으로 나누었는가?
  3. 문서 원문 대신 document_id, version, score를 남길 수 있는가?
  4. 도구 호출 전후의 위험도와 결과 상태를 기록하는가?
  5. 민감 정보는 마스킹하거나 저장하지 않는가?
  6. 실패 케이스를 eval dataset으로 다시 보낼 수 있는가?

정리

AI agent observability는 운영자용 장식 대시보드가 아닙니다. 에이전트가 틀렸을 때 prompt, retrieval, tool, memory, guardrail 중 어디에서 흔들렸는지 되짚기 위한 기록 설계입니다.

좋은 7편의 결론은 단순합니다. 로그를 많이 남기는 것이 아니라, 나중에 원인을 찾을 수 있는 단위로 남겨야 합니다. 6편에서 workflow를 나누었다면, 이번 편에서는 그 workflow가 남길 증거를 정하는 단계입니다.

함께보면 좋은 글