관측 단위는 왜 모델 호출이 아니라 Run인가

AI 에이전트의 응답이 20초 걸렸다고 해서 모델 API가 20초 동안 일한 것은 아닙니다. 모델 호출은 2초 만에 끝났지만 검색 결과를 기다리는 데 4초, 외부 도구의 타임아웃과 재시도에 10초, 사람의 승인을 기다리는 데 나머지 시간이 쓰였을 수 있습니다.

반대 상황도 있습니다. 에이전트가 2초 안에 응답했지만 오래된 문서를 검색했거나, 쓸 수 있는 도구 중 잘못된 도구를 선택했거나, 도구가 실패했는데도 성공한 것처럼 최종 답을 만들 수 있습니다. 이 경우 시스템 지연과 HTTP 상태는 정상으로 보입니다.

따라서 AI 에이전트의 관측 단위는 개별 모델 호출이 아니라 사용자 요청이 들어온 시점부터 최종 결과가 전달되거나 작업이 중단될 때까지의 한 Run이어야 합니다. 그 Run 안에서 Retrieval, Model Call, Tool Selection, Tool Execution, Retry, Guardrail, 외부 의존성, 비용과 사용자 결과를 연결해야 어디에서 문제가 시작됐는지 판단됩니다.[3]

원문 Prompt와 Completion을 모두 저장하는 것이 출발점도 아닙니다. 먼저 구조와 결과를 기록하고 원문은 명확한 필요와 보호 정책이 있을 때만 제한적으로 수집하는 편이 안전합니다.

OTel GenAI 규약은 지금 Stable인가

2026년 8월 27일 기준 OpenTelemetry의 코어 Semantic Conventions 문서는 1.44.0입니다.[7] 하지만 GenAI 관련 규약은 코어 문서에서 별도의 semantic-conventions-genai 저장소로 이동했습니다.[6] 별도 저장소에서 GenAI 전체 규약, 모델·클라이언트 Span, 에이전트·프레임워크 Span, Metrics, Events는 모두 Development 상태입니다. Events는 언어별 구현이 아직 제공되지 않을 수도 있습니다.

OpenTelemetry를 쓰지 말아야 한다는 뜻은 아닙니다. 현재 규약은 invoke_agent, plan, retrieval, execute_tool처럼 서로 다른 런타임의 작업 이름을 맞추는 유용한 출발점입니다.[1] 다만 다음 두 가지가 필요합니다. 첫째, Telemetry Schema Version과 Instrumentation Version을 함께 기록해야 합니다. 둘째, 운영 대시보드와 데이터 분석을 실험적 Attribute 이름에 직접 결합하기보다 내부 Canonical Schema로 한 번 정규화해야 합니다. 규약이 바뀌더라도 기존 Run과 새 Run을 비교할 수 있어야 하기 때문입니다.

서비스 작동 방식

관측에서 복구와 개선까지 이어지는 운영서비스 지표와 경보를 기준으로 대응하고 변경 이력과 사후 보고를 다음 개선에 연결합니다.

Session·Run·Span·Event는 어떻게 다른가

주요 에이전트 런타임은 서로 다른 이름을 쓰지만 구조는 비슷합니다. OpenAI Agents SDK는 같은 대화를 group_id로 묶고 한 작업을 Trace, 그 안의 생성·도구·Guardrail 작업을 Span으로 남깁니다. Google ADK는 Session 안에서 한 사용자 요청을 invocation_id로 묶고 모델 호출·도구 호출·상태 변경을 Event로 기록합니다. Amazon Bedrock AgentCore는 Session 아래에 요청·응답 단위의 Trace를 두고 내부 처리와 외부 호출을 Span으로 나눕니다. LangSmith는 개별 작업을 Run, Run의 트리를 Trace, 여러 Trace가 이어지는 대화를 Thread로 표현합니다. 이를 런타임 중립적으로 정리한 것이 위 표입니다.

session_id와 run_id를 같은 값으로 쓰면 다중 Turn 문제를 분석하기 어렵습니다. 반대로 모델 호출마다 새로운 Run을 만들면 하나의 사용자 요청이 여러 개의 독립 작업처럼 흩어집니다. 권장 경계는 Session 아래에 Run / Trace를 두는 구조입니다. 그 안에 Retrieval, Plan / Tool Selection, Model Call, Tool Execution을 Span으로 둡니다. Tool Execution 아래에는 HTTP / DB / Queue / External API Span이 붙습니다. Retry / Loop Event, Guardrail / Policy Event, Human Intervention, User Outcome도 같은 Run 안에 둡니다.[2]

비동기 작업, Queue Worker, 다른 Agent, 외부 Tool로 실행이 넘어가더라도 같은 Trace Context를 전달하거나 Span Link로 연결해야 합니다. 그렇지 않으면 에이전트 Trace는 Tool을 호출했다는 사실까지만 보여 주고 실제로 어느 외부 시스템에서 시간이 소모됐는지는 보여 주지 못합니다.

계층
의미
답해야 하는 질문
Session여러 Turn이 이어지는 대화나 작업 맥락같은 사용자가 여러 번 요청하는 동안 문제가 누적됐는가
Run·Trace한 사용자 요청부터 최종 결과까지이 요청은 전체적으로 성공했는가, 얼마나 걸렸는가
Span시작과 끝이 있는 개별 작업Retrieval, 모델, Tool, 외부 API 중 어디에서 지연·실패했는가
Event특정 시점의 결정이나 상태 변화Tool이 언제 선택됐는가, Retry가 왜 발생했는가, 승인이 언제 요청됐는가
Session·Run·Span·Event 네 계층 — OpenAI Agents SDK, Google ADK, Amazon Bedrock AgentCore, LangSmith의 구조를 런타임 중립적으로 정리한 것

Telemetry Model에는 무엇이 들어가나

위 표의 모델은 현재 OpenTelemetry GenAI 규약과 주요 런타임의 공통 구조를 정규화한 런타임 중립적 제안 모델입니다. OpenTelemetry의 확정된 Stable Schema 자체로 오해해서는 안 됩니다. identity, request, execution의 Span(model·retrieval·tool·dependency), events, usage_and_cost, outcome, privacy 일곱 그룹으로 이루어집니다.

모든 조직이 이 필드를 한 번에 구현할 필요는 없습니다. 다만 다음 정보는 가능한 한 첫 단계부터 남기는 편이 좋습니다. session_id, run_id, trace_id. Agent·Workflow·Prompt·Tool·Data Source의 Version. 단계별 시작·종료 시각과 상태. Model Call·Tool Call·Retry 횟수. 최초 오류와 최종 오류의 구분. Token Usage와 비용 산정 기준. Human Intervention 여부와 대기 시간. 기술적 성공과 사용자 작업 성공. Content Capture Mode입니다.

run_id나 session_id처럼 값의 종류가 계속 늘어나는 식별자는 개별 Trace와 Log에 두고 집계 Metric의 Label로 쓰지 않는 편이 낫습니다. 고유 ID를 Metric Attribute로 쓰면 Cardinality와 저장 비용이 빠르게 증가합니다.

그룹
필드
답하는 질문
identitytrace_id · run_id · session_id · parent_run_id · workflow_name · workflow_version · agent_name · agent_version · telemetry_schema_version · instrumentation_name · instrumentation_version · environment어떤 Agent·Workflow·Schema Version이 이 Run을 만들었는가
requeststarted_at · channel · use_case · turn_number · prompt_template_id · prompt_template_version · input_size_bytes · input_language · input_content_ref어떤 경로로 들어온 몇 번째 Turn이며 어떤 Prompt Template을 썼는가
execution.spansspan_id · parent_span_id · stage(retrieval, plan, model_call, tool_selection, tool_execution, guardrail, human_wait, external_dependency) · sequence_no · attempt_no · loop_iteration · started_at · ended_at · duration_ms · wait_duration_ms · status(ok, error, cancelled, interrupted) · error_type · recovered어느 단계가 얼마나 걸렸고 실패했으며 복구됐는가
execution.spans.modelprovider · requested_model · response_model · time_to_first_chunk_ms · input_tokens · output_tokens · cache_read_tokens · finish_reasonProvider 대기인가, 생성 지연인가, Output 제한인가
execution.spans.retrievaldata_source_id · data_source_version · query_fingerprint · top_k · result_count · document_refs · score_summary어떤 Data Source의 어떤 Version에서 실제 결과가 있었는가
execution.spans.toolavailable_toolset_version · selection_source · selected_tool · tool_name · tool_version · tool_call_id · argument_schema_valid · side_effect_class · result_status · argument_content_ref · result_content_ref어떤 Tool이 제공·선택·실행됐고 결과는 무엇인가
execution.spans.dependencyservice_name · operation · protocol_status · timeoutAgent 바깥의 어느 의존성이 Critical Path에 있었는가
eventsevent_id · span_id · occurred_at · event_type(tool_selected, retry_scheduled, loop_detected, guardrail_decision, policy_decision, human_approval_requested, human_approved, human_rejected, run_resumed, state_changed, output_delivered) · reason_code · policy_name · policy_version · decision어느 시점에 어떤 결정·상태 변화가 있었는가
usage_and_costmodel_call_count · tool_call_count · retry_count · total_input_tokens · total_output_tokens · estimated_cost · actual_cost · currency · price_book_version · priced_at · cost_is_estimate얼마가 들었고 그 값은 추정인가 실제인가
outcometerminal_state(completed, partial, failed, cancelled, abandoned, awaiting_human) · technical_success · task_success · final_output_present · user_visible_latency_ms · human_intervention_required · human_wait_duration_ms · user_feedback · user_corrected_result · user_undid_action · business_outcome_ref사용자가 실제 목적을 달성했는가
privacycapture_mode(metadata_only, redacted, external_reference, temporary_debug) · data_classes_detected(pii, secret, customer_data, untrusted_instruction) · redaction_profile_version · content_storage · retention_class · expires_at원문을 어떤 범위로 얼마 동안 보관하는가
Agent Run Telemetry Model — 현재 OpenTelemetry GenAI 규약과 주요 런타임의 공통 구조를 정규화한 런타임 중립적 제안 모델(OpenTelemetry의 Stable Schema가 아님)

Retrieval은 검색 시간만 보면 왜 부족한가

Retrieval Span에는 지연 시간 외에도 어떤 Data Source를 어떤 조건으로 조회했는지가 남아야 합니다. 현재 OpenTelemetry GenAI 규약은 Retrieval에 data_source.id, top_k, 검색된 문서의 ID와 Score를 표현할 수 있도록 하고 있습니다.[1] 다만 문서 목록과 Query Text는 Opt-In이며 Query Text에는 민감한 정보가 들어갈 수 있다고 경고합니다.

운영 환경에서는 다음 정도를 기본값으로 삼으면 됩니다. Data Source ID와 Index·Snapshot Version, 요청한 top_k, 실제 반환 문서 수, 문서의 비식별 Reference와 Score 요약, Filter 적용 여부와 결과 수, Cache Hit 여부입니다. 여기에 Retrieval Latency, Empty Result 여부, Query 길이·언어·분류와 같은 파생 정보, 필요할 때만 원문 Query를 가리키는 별도 Content Reference를 더합니다.

문서 전체를 Span에 복사하지 않아도 "새 배포 이후 특정 Data Source에서 결과가 비기 시작했는가", "잘못된 Index Version이 선택됐는가", "검색은 성공했지만 관련도 점수가 낮았는가"를 판단할 수 있습니다. 서로 다른 Retriever나 Embedding Model의 Score를 그대로 비교해서도 안 됩니다. Score의 의미는 검색기와 Index 구성에 따라 달라지므로 Data Source Version, Retriever Version과 함께 해석해야 합니다.

Tool 선택과 Tool 실행은 왜 다른 단계인가

에이전트가 잘못된 도구를 선택한 문제와 올바른 도구를 선택했지만 실행에 실패한 문제는 수정 위치가 다릅니다.

Tool Selection에서는 다음을 봅니다. 선택 가능한 Tool Set의 Version 또는 Hash, 선택된 Tool, Tool을 선택한 주체(Model, Plan, Rule, Human)입니다. Tool을 선택하지 않은 경우의 상태, tool_call_id, Guardrail이나 Approval에 의해 선택이 거부·변경됐는지도 남깁니다.

Tool Execution에서는 다음을 봅니다. Tool 이름과 Version, 동일한 tool_call_id, Argument Schema Validation 결과, 시작·종료 시각, 실행 상태와 error_type, 실제 호출한 외부 서비스와 Operation입니다. 결과가 없었는지, 일부만 처리됐는지, Side Effect 발생 여부, Retry 또는 중복 실행 여부도 함께 남깁니다.

OpenTelemetry는 execute_tool Span에 Tool Name, Tool Type, Tool Call ID와 오류 유형을 기록하도록 정의합니다.[6] Tool Argument와 Result는 Opt-In이며 민감한 정보가 포함될 수 있다고 경고합니다. 자동 계측에서 빠진 Tool은 애플리케이션이 직접 계측해야 할 수도 있습니다. 도구 선택을 설명하기 위해 모델의 내부 추론 원문을 저장할 필요는 없습니다. 어떤 Tool Set이 제공됐고 무엇이 선택됐으며 어떤 정책 결정과 실행 결과가 뒤따랐는지를 구조화하면 운영 진단에 필요한 대부분의 정보를 얻게 됩니다.

Retry와 Loop에는 왜 별도 Event가 필요한가

현재 OpenTelemetry의 모델 Span 규약은 일시적 문제로 요청이 자동 재시도된 경우 여러 시도를 포함한 하나의 논리적 Operation Duration을 기록하도록 권고합니다.[1] 이 방식은 최종 지연을 계산하기에는 유용하지만 개별 시도의 실패 원인을 자동으로 보여 준다는 뜻은 아닙니다.

따라서 Retry를 진단해야 한다면 다음 정보를 Event나 하위 Span으로 추가해야 합니다. attempt_no, Retry 이유, Backoff 시간, 이전 오류 유형, 같은 Provider·Model·Tool을 다시 호출했는지, 이전 시도가 외부 시스템에 도달했을 가능성, Retry 후 복구됐는지, 전체 Run을 종료시킨 마지막 실패인지입니다.

Loop는 단순 Retry와도 구분합니다. Retry는 같은 작업의 일시적 실패를 다시 시도하는 것이고 Loop는 에이전트가 상태를 충분히 바꾸지 못한 채 Model Call과 Tool Call을 반복하는 현상입니다. Loop 탐지에는 다음 신호가 유용합니다. Run당 Model Call 수, Run당 Tool Call 수, 같은 Tool과 유사한 Argument의 반복, 동일한 Retrieval Query의 반복, 반복되는 State Fingerprint입니다. 토큰과 비용은 늘지만 Outcome은 변하지 않는 상태, 최대 Iteration 도달, Human Intervention이나 강제 중단 여부도 봅니다. OpenTelemetry의 현재 GenAI Metrics에도 Agent Invocation당 Inference Call 수와 Tool Call 수, Agent Duration, Tool Execution Duration이 제안돼 있습니다.[6]

Guardrail과 Policy는 무엇을 함께 남겨야 하나

Guardrail은 실행됐다는 사실만으로 충분하지 않습니다. 어느 단계에서 어떤 결정을 내렸고 그 결정이 최종 결과에 어떤 영향을 줬는지가 필요합니다. 최소한 다음을 기록합니다. 검사 시점(Input, Retrieval, Model Output, Tool Selection, Tool Result)과 Policy·Rule 이름과 Version입니다. 결정(Allow, Block, Modify, Retry, Escalate), 위반 Category, 검사 Latency도 적습니다. Human Review로 전환됐는지, 최종 Run이 완료됐는지, 원문 대신 비식별 Content Reference가 있는지도 남깁니다.

Guardrail이 요청을 차단하면 보안 관점에서는 정상 작동일 수 있습니다. 그러나 사용자가 이유를 이해하지 못하고 작업을 완료하지 못했다면 사용자 결과는 실패 또는 부분 성공일 수 있습니다. 그래서 Policy Decision과 User Outcome을 분리해 기록해야 합니다.

이 글의 범위는 Policy와 Authorization의 결과를 관측하는 것까지입니다. MCP Token Audience, Token Passthrough, Tool Allowlist, Secret Boundary, Tenant Isolation과 Revocation을 어떻게 설계할지는 별도의 Security Control 문제입니다.[4]

Human Intervention은 지연인가 정상 흐름인가

사람의 승인을 기다리는 시간은 Model Latency도 Tool Latency도 아닙니다. 이를 분리하지 않으면 사용자가 느끼는 지연 전체가 에이전트의 성능 문제로 집계됩니다. Human Intervention에는 다음 상태가 필요합니다. 승인 요청 시각, 승인 대상 작업과 tool_call_id, 승인·거절·수정·만료, 역할 기반 Reviewer 식별자, 대기 시간, 승인 이후 Run 재개 시각, 재개 후 최종 결과, 사람이 결과를 직접 수정했는지입니다.

OpenAI Agents SDK의 HITL 구조도 Tool Call 전에 Run을 중단하고 Pending Approval을 Interruption으로 노출한 뒤 직렬화된 Run State에서 승인·거절 후 원래 Run을 재개합니다. 이와 같은 흐름에서는 Human Wait를 독립 단계로 기록해야 합니다.

Human Intervention Rate가 높다고 항상 나쁜 것은 아닙니다. 위험한 Side Effect에 승인이 의도된 설계라면 정상입니다. 대신 승인 대기 시간이 사용자 여정 목표를 초과하는지, 불필요한 승인 요청이 반복되는지, 사람이 자주 결과를 수정하는지를 함께 봐야 합니다.

단계마다 어떤 신호와 진단 질문을 두어야 하나

위 표는 Session·Run 시작부터 Cost까지 열네 단계에 대해 남길 Signal, 대표적인 Failure Example, 그 단계에서 던질 Diagnostic Question을 정리한 것입니다. 각 행의 질문에 답할 수 있는 신호가 없다면 그 단계의 문제는 사용자 신고로만 발견됩니다.

Stage
Signal
Failure Example
Diagnostic Question
Session·Run 시작session_id, run_id, Agent·Workflow Version한 사용자 요청이 여러 독립 Trace로 분리됨같은 사용자 작업의 모든 단계가 하나의 Run으로 연결됐는가
RetrievalData Source Version, top_k, Result Count, Score Summary, Latency오래된 Index에서 관련 없는 문서를 검색어떤 Data Source와 Version이 사용됐고 실제 결과가 있었는가
PlanPlan Span, Agent Version, Child Model Call계획 단계가 반복되지만 실행으로 넘어가지 않음계획이 몇 번 생성됐고 이전 계획과 무엇이 달라졌는가
Model CallProvider, Requested·Response Model, TTFC, Duration, Token, Finish Reason응답 시작이 늦거나 길이 제한으로 중단Provider 대기인가, 생성 지연인가, Output 제한인가
Tool SelectionTool Set Version, Selected Tool, tool_call_id, Selection Source검색 Tool 대신 데이터 변경 Tool을 선택어떤 Tool이 제공됐고 어떤 Tool이 선택·거부됐는가
Tool ExecutionTool Version, Schema Validation, Duration, Status, Dependency Span올바른 Tool이 외부 API Timeout으로 실패선택은 맞았지만 실행이 실패한 것인가
RetryAttempt, Reason, Backoff, RecoveredProvider 오류가 세 번 재시도돼 지연 증가몇 번째 시도에서 어떤 오류가 발생했고 복구됐는가
LoopIteration, Repeated State, Model·Tool Call Count같은 검색과 Tool Call을 반복하며 비용 증가상태가 변하지 않은 반복이 어디에서 시작됐는가
Guardrail·PolicyPolicy Version, Stage, Decision, Category, Latency정상 요청이 반복 차단되거나 검사 시간이 급증어떤 정책이 어느 단계에서 결과를 변경했는가
Human InterventionRequest·Decision Time, Wait Duration, Resume ResultAgent는 빨랐지만 승인 대기에 수십 분 소요실제 실행 시간과 사람을 기다린 시간은 각각 얼마인가
External DependencyService, Operation, Status, Timeout, Trace ContextTool은 성공으로 보이지만 하위 DB가 지연Agent 바깥의 어느 의존성이 Critical Path에 있었는가
FailureFirst Error, Terminal Error, Recovered, User-visible Failure중간 오류는 복구됐지만 마지막 결과는 부분 완료최초 실패와 최종 실패는 같은가
User OutcomeTechnical Success, Task Success, Feedback, Correction, UndoHTTP 200과 답변은 있었지만 사용자가 작업을 다시 수행사용자가 실제 목적을 달성했는가
CostUsage, Estimated·Actual Cost, Price Book Version실패한 Run이 성공 Run보다 많은 Token과 Tool 비용 사용비용이 어느 단계에서 늘었고 성공 결과로 이어졌는가
Stage → Signal → Failure Example → Diagnostic Question — Run의 열네 단계에서 남길 신호와 진단 질문

느린 Agent는 왜 Critical Path부터 찾는가

한 Run 안에 여러 Tool이 병렬 실행될 수 있으므로 Child Span Duration을 모두 더한 값이 사용자 대기 시간과 같지는 않습니다. 진단할 때는 다음을 구분합니다. 사용자 요청부터 첫 응답까지의 시간, 첫 Chunk부터 최종 응답까지의 시간, 실제 실행 시간입니다. Queue·Backoff·Rate Limit 대기, Human Approval 대기, 병렬 작업 중 가장 긴 Critical Path, 결과 전달 이후 비동기 작업 시간도 따로 봅니다.

OpenTelemetry의 현재 GenAI Metrics는 전체 Model Operation Duration뿐 아니라 Streaming 응답의 Time to First Chunk와 이후 Chunk 간 시간을 구분합니다.[6] Agent·Workflow 단위의 End-to-End Duration도 개별 Model Call Duration과 별도로 제안돼 있습니다. 사용자가 "답이 늦게 나오기 시작한다"고 느끼는 문제와 "답은 바로 시작하지만 끝나지 않는다"는 문제는 같은 평균 Latency로 합치면 안 됩니다.

잘못 행동한 Agent는 왜 Outcome에서 거꾸로 추적하나

에이전트가 최종 문자열을 만들었다고 해서 작업이 성공한 것은 아닙니다. 최소한 다음 두 상태를 분리해야 합니다. technical_success는 Run이 오류 없이 끝나고 Final Output이 생성된 상태이고, task_success는 사용자가 원한 실제 작업이 완료된 상태입니다.

Task Success는 사용 사례마다 다르게 정의됩니다. 지원 Agent라면 문의가 해결됐는지, 운영 Agent라면 변경이 실제 적용되고 검증됐는지, 문서 Agent라면 필요한 파일이 생성·전달됐는지입니다. 구매 Agent라면 올바른 대상과 조건으로 주문됐는지, 분석 Agent라면 사용자가 결과를 채택했는지입니다. 사용자 Feedback만으로 판단하기 어려우면 비즈니스 Event, 후속 수정, Undo, 재질문, Human Review, Evaluation Score를 같은 Run ID에 연결하면 됩니다. LangSmith는 Feedback을 Run ID에 연결하고 Google ADK는 실제 Tool Trajectory와 Response를 평가할 수 있는 구조를 제공합니다.

잘못된 결과를 진단할 때는 Outcome에서 시작해 다음 순서로 거슬러 올라가는 편이 효과적입니다. 실제 Task Success가 실패했는가. Final Output이 근거와 일치했는가. Tool Execution 결과를 올바르게 반영했는가. 올바른 Tool을 선택했는가. Retrieval 결과가 적절하고 최신이었는가. 어떤 Model·Prompt·Agent·Tool Version이 사용됐는가.

Token 수와 비용은 왜 같은 뜻이 아닌가

Token Usage는 비용 계산의 중요한 입력이지만 그 자체가 실제 비용은 아닙니다. Provider, Model, Input·Output 구분, Cache Read·Write, 사용 시점의 가격, 할인·계약 조건, Tool이나 Retrieval의 별도 비용에 따라 달라집니다.

Run에는 다음을 구분해 남깁니다. Provider가 반환한 사용량, Input·Output·Cache 등 Token Breakdown, 요청별 사용량, Tool·Retrieval의 별도 Usage입니다. 사용한 Price Book Version과 적용 시점, 계산된 예상 비용, 청구 데이터에서 확인한 실제 비용, 비용이 Estimate인지 Actual인지도 적습니다. OpenTelemetry는 Token Usage Metric을 정의하면서 사용량과 Billable Token을 모두 제공하는 시스템에서는 Billable Token을 보고하도록 합니다.[1] OpenAI Agents SDK는 Run 전체와 개별 요청별 Token Usage를 별도로 보존합니다.

운영 지표는 Run당 비용에서 멈추지 않는 편이 좋습니다. 성공한 작업당 비용, 사람의 수정이 필요 없었던 결과당 비용, 완료된 사용자 여정당 비용으로 연결해야 비용 증가가 실제 가치로 이어졌는지 판단됩니다.

원문은 왜 기본 수집 대상이 아닌가

원문이 있으면 디버깅이 쉬워지는 경우가 있습니다. 그러나 다음 내용도 함께 Telemetry Backend로 들어갈 수 있습니다. 이름·이메일·전화번호 등 PII, 인증정보·API Key·Session Token, 고객 데이터와 영업기밀, 내부 System Instruction, Tool Schema와 내부 API 구조입니다. Tool Argument와 Tool Result, Retrieval Query와 원문 문서, 외부 문서에 삽입된 Prompt Injection Payload도 마찬가지입니다.

OpenTelemetry는 Model Instruction, User Message, Model Output을 기본적으로 기록하지 말고 Opt-In으로 제공할 것을 권고합니다.[1] 운영 환경에서 민감 데이터나 저장량이 문제가 된다면 Content를 별도 저장하고 Span에는 Reference만 두는 방식을 권장합니다. Tool Argument와 Result, Retrieval Query 역시 민감 정보가 들어갈 수 있는 Opt-In 항목입니다. 권장 수집 단계는 위 표의 네 단계입니다.

프레임워크 기본값이 조직 정책과 일치한다고 가정해서도 안 됩니다. OpenTelemetry는 원문 미수집을 기본 패턴으로 제시하지만 OpenAI Agents SDK의 trace_include_sensitive_data 기본값은 현재 true입니다. Microsoft는 개발·디버깅 때 Content Recording을 활성화하고 운영 환경에서는 끄도록 안내합니다. Google ADK도 원문 Prompt, Tool Argument, Session State가 들어간 Debug Output을 민감 데이터로 취급하라고 경고하며 PII가 Span Attribute에 붙지 않도록 하는 설정을 제시합니다. 결국 계측을 활성화하는 것과 원문 수집을 허용하는 것은 별도의 설정과 승인 절차여야 합니다.

단계
기본 용도
수집 범위
Metadata Only운영 기본값ID, Version, 크기, 지연, 상태, Token, Error, Outcome
Redacted·Derived제한적 원인 분석언어, 길이, Schema 적합 여부, PII·Secret 탐지 Category, 비식별 Fingerprint
External Reference프로덕션 심층 분석별도 보호 저장소의 Content Reference, 접근권한·보존기간 분리
Temporary Debug한시적 재현명시적 승인, 제한된 대상, 짧은 TTL, 접근 감사, 종료 후 삭제
원문 수집 네 단계 — 운영 기본값부터 한시적 재현까지 수집 범위와 용도

Telemetry 속 Prompt Injection은 믿어도 되나

외부 문서나 Tool Result에 포함됐던 악성 지시문은 Retrieval·Tool Result·Prompt·Completion과 함께 Telemetry로 복사될 수 있습니다. 이후 다른 AI Assistant가 장애 분석을 위해 이 Log를 읽는다면 Telemetry가 새로운 간접 Prompt Injection 입력이 됩니다.

OWASP는 AI가 소비하는 Log, Link, External Reference를 신뢰할 수 없는 입력으로 취급해야 한다고 지적합니다.[4] 일반 Logging Guidance도 외부 Trust Zone에서 들어온 Event Data를 검증하고 CR·LF와 구분자 등을 정리해 Log Injection을 막도록 권고합니다.

원문 Telemetry를 다룰 때는 다음 원칙이 필요합니다. 원문은 실행 가능한 Instruction이 아니라 비신뢰 데이터로 표시합니다. Dashboard와 Viewer에서 적절히 Escape·Encode합니다. 외부 Link와 Active Content를 자동 실행하지 않습니다. 다른 Agent에 전달할 때 원문과 운영 Instruction의 경계를 분리합니다. Security Event 분석용 Payload는 별도 보존 정책을 적용합니다. Debug가 끝나면 Temporary Capture를 자동 종료합니다. 이는 MCP Authorization을 어떻게 구성할지의 설계가 아니라, Telemetry 자체가 두 번째 데이터 저장소이자 입력 경로가 될 수 있다는 관측 데이터 관리 문제입니다.

대시보드는 왜 Model이 아니라 사용자 결과 중심인가

Agent Dashboard의 첫 화면을 평균 Model Latency와 총 Token 수만으로 구성하면 사용자 영향이 뒤로 밀립니다. 먼저 봐야 할 Run-level 지표는 다음과 같습니다. Task Success Rate, Partial·Failed·Abandoned Run Rate, 사용자 체감 End-to-End Latency입니다. Human Intervention Rate와 Human Wait, Retry·Loop Rate, Run당 Model Call·Tool Call 수가 뒤따릅니다. Guardrail Block·Modify·Escalate Rate, External Dependency Error Contribution, 성공한 작업당 비용, 사용자 수정·Undo·재실행 비율도 같이 둡니다. 그다음 Agent Version, Workflow Version, Prompt Version, Model, Tool Version, Data Source Version, 배포 환경별로 분해합니다.

임계값은 모든 Agent에 공통으로 정하지 않습니다. 사용자가 몇 초 안에 답을 받아야 하는 대화형 Agent와 몇 분 동안 백그라운드 분석을 수행하는 Agent는 같은 Latency 기준을 쓸 수 없습니다. 무엇을 SLI로 삼을지는 해당 Agent가 지원하는 Critical User Journey에서 출발해야 합니다.[5]

구현은 어떤 순서로 해야 안전한가

처음부터 모든 Prompt와 Tool Result를 수집하기보다 위 여덟 단계의 순서가 안전합니다. Run의 시작과 끝을 정의하고 Context를 전파하는 앞 두 단계가 없으면 이후의 세부 계측은 하나의 실행 경로로 조립되지 않습니다. 원문 없이 Span Coverage를 먼저 만들고, Retry·Loop·Human Wait를 Event로 더하고, User Outcome과 비용 모델을 연결한 뒤에야 Content Capture Policy와 Schema Adapter를 별도 승인으로 둡니다.

1. Run의 시작과 끝을 정의한다
한 사용자 요청이 어디에서 시작되고 언제 완료·부분 완료·실패·중단되는지 정합니다. 비동기 작업이라면 결과가 나중에 도착해도 원래 Run과 연결할 수 있어야 합니다.
2. Session·Run·Trace Context를 전파한다
API, Queue, Worker, 다른 Agent, Retrieval System, Tool과 외부 서비스까지 Context를 전달합니다. 이 단계가 없으면 이후의 세부 계측은 하나의 실행 경로로 조립되지 않습니다.
3. 원문 없이 Span Coverage를 만든다
Retrieval, Model Call, Tool Selection, Tool Execution, Guardrail, 외부 의존성을 먼저 Span으로 구분합니다. Version, Duration, Status, Error Type과 Call ID를 남깁니다.
4. Retry·Loop·Human Wait를 Event로 추가한다
자동 계측이 보여 주지 못하는 Attempt, Backoff, 반복 상태와 승인 대기를 구조화합니다.
5. User Outcome을 연결한다
Final Output 생성 여부와 실제 Task Success를 구분합니다. Feedback, Business Event, Correction, Undo와 Human Review를 Run에 연결합니다.
6. Usage와 비용 모델을 붙인다
Token Usage, Tool Usage, Price Book Version, Estimate·Actual 여부를 분리합니다. 비용은 성공한 사용자 결과와 함께 봅니다.
7. Content Capture Policy를 별도로 승인한다
개발·운영 환경, 데이터 등급, Sampling 조건, Redaction, 접근권한, TTL과 삭제 절차를 정합니다. 프레임워크 설정을 명시적으로 덮어씁니다.
8. Schema Adapter와 회귀 검증을 둔다
OpenTelemetry GenAI 규약과 Runtime Telemetry가 Development 상태라는 점을 고려해 내부 Canonical Schema와 Mapping Version을 둡니다. SDK나 계측 라이브러리 업데이트 후 필드가 사라지거나 이름이 바뀌지 않았는지 테스트합니다.

관측성의 목적은 모든 내용을 저장하는 것인가

좋은 Agent Observability는 세 질문에 답할 수 있어야 합니다. 이 Run에서 실제로 무슨 일이 일어났는가. 어느 단계에서 처음 지연되거나 잘못된 경로로 들어갔는가. 그 결과 사용자는 목적을 달성했고 얼마의 시간과 비용이 들었는가. 이 질문에 답할 수 있다면 모든 Prompt, Completion, Tool Argument를 원문으로 보관하지 않아도 됩니다.

반대로 모델 호출 시간과 Token 수만 남기면 시스템이 느렸다는 사실은 알 수 있어도 나머지는 알 수 없습니다. Retrieval이 비었는지, 잘못된 Tool을 골랐는지, Retry Loop에 빠졌는지, Guardrail이 막았는지, 사람이 승인하지 않았는지, 사용자가 실제로 문제를 해결했는지가 그렇습니다.

AI 에이전트의 관측성은 모델을 더 자세히 보는 일이 아닙니다. 한 Run 안의 판단·행동·대기·비용과 사용자 결과를 하나의 실행 경로로 연결하는 일입니다.