
OpenTelemetry(OTel)로 수집한 에이전트 트레이스에서 이상 감지 시스템 구축하기
요약
OpenTelemetry(OTel)를 활용하여 AI 에이전트의 무한 루프, 과도한 비용 소모, 목적 이탈 등 비정상적인 행동을 실시간으로 감지하는 시스템 구축 방법을 소개합니다. OTel GenAI Semantic 규약을 기반으로 규칙, 행동 시퀀스, 의미론적 분석을 결합한 3계층 감지 모델을 제안합니다.
핵심 포인트
- OpenTelemetry를 통한 AI 에이전트 행동 트레이스 수집 및 활용
- 규칙, Markov 체인, 의미론을 결합한 3계층 이상 감지 메커니즘
- GCP 환경에서의 지속적인 모델 재학습 및 자동 교체 루프 구현
- AI 에이전트의 안전성을 위한 하네스 엔지니어링의 중요성 강조
요약
AI 에이전트의 '폭주'— 무한 루프, 과도한 비용 소모, 목적 이탈, 위험 조작 — 을 OpenTelemetry(OTel)로 수집한 행동 트레이스에서 준실시간으로 감지하는 PoC를 만들었습니다.
- 수집은
OTel GenAI Semantic 규약 + OTel Collector로 진행하고, - 감지는
규칙 + 행동 시퀀스(Markov) + 의미(Semantics)의 3계층을 통합하며, - GCP에서,
재학습하여 자동적으로 교체되는 지속 개선 루프까지 구현했습니다.
대상 독자
- OpenTelemetry에 관심이 있는 분
- 기계 학습의 기초적인 이해가 있는 분
- AI 에이전트의 비정상적인 행동에 우려를 느끼는 분
배경
AI 폭주
AI 에이전트 모델의 성능은 날마다 향상되어 우리의 생활을 풍요롭게 하고 있지만, 때로는 우리가 상상하는 것을 넘어서 위험한 행동을 하기도 합니다. 아래 링크에서 볼 수 있듯이, 최근에는 AI 모델이 타사에 사이버 공격을 가했다는 뉴스를 자주 접할 수 있습니다.
AI 에이전트의 혜택을 누리는 시스템을 구축하는 것만큼이나, 에이전트의 행동을 제약하여 안전하게 움직이게 하는 것(하네스 엔지니어링), 그리고 비정상 행동을 감지하고 즉시 대응하는 것이 중요해지고 있으며, 저자는 '어떤 형태로든 이상 감지 메커니즘을 제품에 도입해야 하지 않을까?'라고 느꼈습니다.
이상 감지와 OpenTelemetry 데이터의 활용
AI 에이전트의 비정상 행동에는 예를 들어 다음과 같은 것들이 있을 수 있습니다.
| 유형 | 예시 |
|---|---|
| 무한 루프/반복 | 승인 대기 상태에서 동일한 확인을 끊임없이 반복하는 경우 |
| ... |
이러한 비정상을 포착할 단서로, OpenTelemetry로 수집된 트레이스가 유효하게 활용될 수 있지 않을까라고 저자는 생각했습니다. OTel에서는 다음과 같은 LLM의 토큰 사용량뿐만 아니라, 어떤 도구가・어떤 순서로 사용되었는지, 어떤 모델이 호출되었는지까지 데이터로 남기 때문입니다.
gen_ai.usage.input_tokens<br> gen_ai.usage.output_tokens<br>gen_ai.tool.name<br><br>예를 들어, AI 에이전트의 특정 태스크에서 토큰 사용량을 수집하고 데이터 분포를 파악할 수 있다면, 통계학적 사고방식을 근거로 하여 토큰 사용량 평균값(비정상)을 감지할 수 있습니다.
최근 AI 뉴스의 배경도 고려하면, 이 OTel 트레이스에 '데이터 활용 가치'가 있다는 것이 보입니다.
AI 에이전트 × OpenTelemetry라고 하면 감사나 모델 평가가 주 전장이지만, **이상 감지에도 활용할 수 있다(요즘 AI 폭주 상황을 고려하면 활용해야 한다)**는 결론에 이르렀습니다.
그래서 이 글에서는, 탐색적인 방식일 수 있지만 OpenTelemetry의 응용 분야 기술 활용, 즉 OTel로 수집된 데이터로부터 이상 감지 모델을 학습하고 구축할 수 있는지 검증하고 그 성능에 대해 서술합니다.
데모 구현은 아래에 있습니다.
방법
앞으로의 시대에 기업의 AI 네이티브화가 진행되는 것을 고려하여, 샘플 주제로 기업 인사부에 AI 에이전트(HR Agent; Human Resource)를 도입하고, 그 AI가 부자연스러운 행동을 했을 때의 시나리오를 구상합니다.
여기서 만들 감지 모델이 그 비정상을 감지할 수 있는지 검증합니다.
AI 에이전트 주제 (인사 업무)
HR 에이전트가 수행하는 태스크는 예를 들어 다음과 같습니다.
- 급여 조회
- 직원 승진 플로우
- 직원 주소 변경
- 그 외 규정 조회(급여 규정・휴가 규정 등)・회의 통지 등 총 10가지
정상과 비정상
예를 들어,
진 플로우
- 직원 주소 변경
- 그 외 규정 조회(급여 규정・휴가 규정 등)・회의 통지 등 총 10가지
정상과 비정상
예를 들어,
| 이상 시나리오 | 발생 내용 | 수치 |
|---|---|---|
| 무한 루프 | 승인이 계속 내려지지 않아, '승인은 완료되었는가?' 확인을 끊임없이 반복함 | 40단계 / 입력 92,554 토큰 / LLM 상한으로 강제 중지 |
| ... | ||
| 다른 이상 데이터로는 **정상적인 행동열을 기계적으로 변이시키는 '변이 합성'(조작의 반복 삽입・승인 절차 삭제・순서 변경・사외 전송 주입・무관 검색 혼입)**도 양산했습니다. 소수의 자연스러운 폭주만으로는 평가 데이터가 부족하기 때문입니다. 이처럼 의도적으로 이상한 트레이스를 포함하여 물량을 늘리는 것은 다음 국제 학회 논문에서도 제안된 방법이며 유효한 방법입니다. |
OTel 의미론 정의 (Semantics)
gen_ai.*의 표준 속성뿐만 아니라, 이 시스템 고유의 속성(app.*)도 정의합니다. 어떤 조작이 이루어졌는지・승인되었는지와 같은 정보도 이상 감지에 활용하기 위해 독자적으로 부여했습니다.
| 속성 | 용도 |
|---|---|
gen_ai.usage.input_tokens / output_tokens | 비용 감지・특징량 |
gen_ai.tool.name | 툴 식별 |
app.operation_type (read/write) | 권한 시스템 규칙 |
app.approval_status (approved/missing) | 승인 없음 write 감지 |
app.external_recipient / app.amount_delta / app.target_is_self | 사외 전송・거액 변경・자신 거래 |
app.task_type | task_type 조건부 모델 |
def _set_context_attributes(span: trace.Span) -> None:
ctx = get_run_context()
span.set_attribute(
예를 들어 '권한/일탈'의 구체적인 예시는 다음과 같습니다.
승인이 필수임에도 불구하고, 승인 상태가 '승인됨(承認済み)'이 아님 →
'미승인 상태로 ◯◯을 실행했습니다'이므로 CRITICAL
### 행동 시퀀스 계층 (Markov)

행동 시퀀스의 이상은 AI 에이전트의 **사물 진행 방식의 이상**을 감지하는 것입니다. '이 작업이라면 보통 이 순서로 툴을 호출한다'는 것을 정상 데이터로부터 학습합니다. **task_type 조건부 트라이그램(2차 마르코프)**으로 직전 2개 액션으로부터 다음 액션의 확률을 측정합니다.
시퀀스 데이터는 `<START> <START> a0 a1 … <END>`
와 양 끝에 채웁니다. 적어도 직전 2개의 액션을 보기 때문입니다. 전이(transition)마다 아래에서 정의되는 **자기 정보량 (Self-Information)**을 계산합니다. 정의식대로, 자기 정보량은 단순히 낮은 확률의 사건일수록 큰 값(정보량이 크다)이 됩니다. 이번 케이스에서는 이
**값이 클수록 이상**하다고 할 수 있습니다.
자기 정보량이라고 해도 이미지가 오기 어려울 수 있으니 여기서는 **서프라이즈 (Surprise)**라고 부르며, '놀라움의 크기/정도'로 해석해 보세요.
확률
빈도 데이터라는 점에서도 이 데이터는 실제로 데이터를 가져가면서 분포를 업데이트하여 이용할 것으로 예상됩니다. 따라서 미관측 사건에서는 데이터가 없으므로 전이 확률이 0이 되어버립니다(소위 제로 빈도 문제). 그래서 전이가 확률 0이 되지 않도록 어휘 수
상의 그림 예시에서는,
## 상세한 이상 판정법에 대하여
트레이스
task_type
으로, AI 에이전트가 새롭게 생성한 트레이스는 행동 시퀀스 계층이 발동하여 이상으로 판단됩니다. 임계값을 '정상의 최대값보다 높게' 설정하므로, 학습 데이터 상의 오탐지는 발생할 수 없습니다. 이 보정 파라미터는 태스크의 종류에 따라 달라지며, 진행 방식의 편차가 큰 태스크는 자연스럽게 임계값이 느슨해지고, 정형적인 태스크는 엄격해집니다.
### 의미 계층
의미 계층에서는 자연어 처리 모델을 사용합니다. 그 모델로 문장의 특징량을 추출하여 이상 감지에 이용합니다. 이 방법 자체는 kaggle 같은 데이터 사이언스 대회 등에서도 이용되는 일반적인 방법입니다.
다국어 문 임베딩 모델 **paraphrase-multilingual-MiniLM-L12-v2(384차원 출력・BERT의 증류 모델)**로 행동 텍스트(툴 이름+인수)를 벡터화합니다.
그리고,
**같은 태스크의 정상 트레이스 그룹 중심(평균 벡터)으로부터의 거리**를 '의미 드리프트'로 점수화합니다.
더 나아가, 의미 드리프트에 OTel로 정의된 구조적 특징량(단계 수・승인 누락・외부 전송 등)을 더한 특징 벡터를 정상 값만으로 학습시킨 IsolationForest에 넣어 판정에 이용합니다.

## 클라우드 아키텍처
PoC(개념 증명)이므로 다음과 같은 간이 아키텍처로 합니다. 이번에는 Google Cloud를 사용합니다. AWS가 아닌 Google Cloud를 채택하는 데 특별한 이유는 없고 단순히 저자가 좋아하는 클라우드이기 때문입니다.
HR agent의 행동 데이터가 Otel Collector에 의해 회수되어, Cloud Trace와 Cloud Run 위에서 동작하는 감지기(Detector)로 전송됩니다. 감지기에서 이상이 감지되면 Cloud Logging에 데이터를 남깁니다. 동시에, Detector에서 판정한 정보와 트레이스 정보를 BigQuery에도 전송하여, 주기 실행 잡(job)으로 이상 감지 모델의 재학습에 이용합니다. 검증 후, 기존 모델 대비 성능이 좋으면, 학습된 데이터를 오브젝트 스토리지인 GCS(Google Cloud Storage)에 저장합니다. 그 후에, 이상 감지 모델이 담긴 Cloud Run에 자동으로 가져오도록 합니다.

주의할 점은 이번에는 PoC이기 때문에 Cloud Run 측의 인메모리에서 데이터를 축적하여 판정하는 스테이트풀(stateful) 구조가 되었다는 것입니다. 대규모 이용을 생각하면 스테이트리스(stateless)로 해야 하지만, 이에 대해서는 후술합니다.
# 실제로 해본 결과
## 데이터
평가를 위해 다음 3종류의 데이터를 사용했습니다. 모두 본 기사의 HR 에이전트를 실제로 구동하여 수집했거나, 또는 그 트레이스를 변이시켜 만든 것입니다.
| 데이터 | 본수 | 제작 방법 |
|---|---|---|
| 정상 트레이스 | 약 230본 | 실제 LLM 실행 60본 + 그 리플레이에 의한 양산 |
| ... |
Hold out 검증을 실시합니다. 검증 데이터의 분할 방법은 다음과 같이 A, B, C의 3가지 패턴을 상정하여 진행했습니다.
B와 C에서는 전체 10개 태스크 중 2개 태스크(급여 인상 플로우 `raise_flow`, 규정 조회 `policy_question`)를 학습 데이터에 포함하지 않고, 성능을 측정하기 위한 검증용으로 따로 떼어두고 진행했습니다. 이는 마치 추가 개발 등으로 인해 AI 에이전트가 개수되어 다른 업무 태스크 등도 수행하게 되는 시나리오를 고려한 것입니다.
| 조건 | 훈련 데이터 | 학습층의 자동 정지 |
|---|---|---|
| A: 랜덤 분할 상당 | 전체 10개 태스크의 정상 (테스트와 동일한 태스크 포함) | — |
| ... | ... | ... |
조건 C의 "**학습층의 자동 정지**"는, **학습하지 않은 태스크에 대해서는 의미층 (Semantic Layer)과 IsolationForest를 발화시키지 않는** 케이스입니다. 미지의 태스크에 대해 스코어를 내버리면, 나중에 살펴보겠지만 오검출(False Positive) 투성이가 되기 때문입니다 (새로운 태스크에 데이터가 없는, 이른바 cold-start 문제에 대한 대책).
이번에 사용하는 메트릭(Metric)은 다음 4가지입니다.
- **FPR**: 정상 18개 중, 잘못하여 이상으로 판정된 비율 (낮을수록 좋음)
- **Recall**: 이상 78개 중, 검출해낸 비율
- **Precision**: 이상이라고 판정한 것 중, 실제로 이상이었던 비율
- **AUPRC**: Precision-Recall 곡선의 아래 면적 (1.0이 최상)
참고: 메트릭의 정의
### 결과
각 데이터셋에 대한 메트릭은 다음과 같습니다.
| 지표 | A: 랜덤 분할 상당 | B: 태스크 분리 | C: 태스크 분리 + 자동 정지 |
|---|---|---|---|
| FPR | 0.0% | 100.0% | 0.0% |
| Recall | 100.0% | 92.3% | 73.1% |
| Precision | 100.0% | 80.0% | 100.0% |
| AUPRC | 1.000 | 0.966 | 0.950 |

다음의 이상에 대해 A, B, C 검증 데이터에서는 다음과 같은 결과가 나왔습니다.
| 이상의 종류 (합성) | 변이 내용 | A | B | C |
|---|---|---|---|---|
| 반복 삽입 | 동일한 조작의 반복을 삽입 | 7/7 | 7/7 | 7/7 |
| ... | ... | ... | ... | ... |
조건 A는 스코어가 완벽하여 언뜻 보기에는 성능이 매우 좋아 보입니다. 하지만 랜덤 분할 상당이기 때문에, 훈련 단계에서 테스트와 동일한 태스크를 이미 본 상태입니다. 이 수치로는 미지의 태스크에 대한 퍼포먼스를 예측할 수 없어 참고하기 어려우므로, 미지의 태스크에 대한 퍼포먼스는 B와 C를 통해 확인해 보겠습니다.
B에서는 이상을 올바르게 이상이라고 판단하여 성능이 높지만 (**Recall이 높음**), 정상 케이스의 데이터를 모두 잘못하여 이상으로 판정하고 있습니다 (**FPR 100%**. 내역은 의미층 10개 + IsolationForest 8개 — 미지의 태스크에 대해 '정상의 기준'을 가지지 못한 학습층의 폭주입니다).
C에서는 정상 데이터를 올바르게 정상이라고 판단하고 있습니다 (FPR 0%). 하지만 의미층에서만 잡을 수 있는 "무관한 검색의 혼입"은 검출하지 못했습니다 (0/21. 구조가 깨지는 다른 4종은 규칙층(Rule Layer)·행동 시퀀스층(Action Sequence Layer)이 모두 검출).
이 약점은 지속적인 개선 루프를 통해 해당 태스크의 데이터가 쌓여 재학습된다면 자동으로 해소됩니다.
## 특징 공간의 시각화
검출기가 사용하는 13차원의 특징량 (구조화 특징 + Surprise + 의미 드리프트 (Semantic Drift))을 **t-SNE로 2차원**으로 축소하면, 이상 데이터와 정상 데이터가 대체로 깔끔하게 군집을 이루고 있음을 알 수 있습니다. 이를 통해서도 의미층에서의 이상 검출이 직관적으로 작동하고 있음을 이해할 수 있습니다.

## 이상의 통지
검출 서비스는 이상을 Cloud Logging에 구조화된 로그로 남기기 때문에, Cloud Monitoring의 로그 일치형 알람(Log-based Alert)을 설정하면 이메일이나 채팅으로 통지를 연결할 수 있습니다. 이번에는 이메일 통지를 설정하고, 클라우드 상에서 의도적으로 이상(승인 없는 급여 업데이트)을 발생시킨 결과, 다음과 같은 이메일이 도착했습니다.

# 요약
OTel로 수집한 데이터를 이용하여, AI 에이전트의 폭주를 검출하는 시스템을 만들어 보았습니다.
- OTel의 GenAI 세맨틱 규약 (GenAI Semantic Conventions) 트레이스는 폭주 검출의 토대로 활용할 수 있을 것 같습니다.
- **룰 기반 (Rule-based) + 행동 시퀀스 (Action Sequence) + 의미 (Semantics)**의 이 다층 방어 구조가 각각의 필터에서 미처 포착하지 못한 정보를 상호 보완하며 더 높은 수준의 검출에 성공했습니다.
앞서 기술한 바와 같이, 이상 패턴은 다른 형태로도 존재할 수 있습니다. 예를 들어, 과도한 권한 위임, 프롬프트 인젝션 (Prompt Injection)을 기점으로 업무로 위장한 조작 등이 있습니다. 이러한 이상 징후로의 확장은 향후 과제입니다.
# 추가 개선안
이번에는 PoC(Proof of Concept) 제작이었으나, 실용적인 측면을 고려하면 다음과 같은 사항들도 검토 대상이 될 것이라 생각합니다.
## 검출 ≠ 차단
이번에 만든 PoC는 AI 에이전트의 이상 행동을 실행 전에 차단하는 것이 아닙니다. OTel의 트레이스는 "실행된 후"에 도달하는 비동기 관측 데이터이므로, 원리적으로 실행 전 차단은 불가능합니다. 차단까지 고려한다면, Tool 사용을 제어하는 동기적인 경로가 필요합니다.
예를 들어 다음과 같이 Tool Gateway를 마련하여, 툴 실행 시마다 이용 가능 여부를 판정하고 리스크가 있다면 차단하는 설계를 생각할 수 있습니다. 본 PoC의 검출 결과(예: "이 태스크에서 이상 경향이 지속되고 있음")를 Gateway의 정책에 반영하면, 검출과 차단이 상호 보완하는 구성이 됩니다.
## AI 에이전트에 의한 판정
의미 계층을 LLM 판정으로 교체하면, 해당 태스크의 정상 여부를 모르더라도 "행동이 태스크에 부합하는가"를 판단할 가능성이 있지만, 비용이 발생합니다. 이번에는 저비용 실현을 우선하여 자연어 처리 (NLP) 모델인 BERT의 증류 모델 (Distilled Model)로부터 특징량 (Feature)을 추출하는 방침을 택했습니다.
## 대규모 스케일링 (Scaling)
현재는 검출 서비스가 트레이스 상태를 인메모리 (In-memory)로 보유하는 스테이트풀 (Stateful)한 상태입니다. 다중 에이전트 및 고부하 요청에 대응하기 위해서는 다음과 같은 검토가 필요할 것으로 보입니다.
- **Collector → Pub/Sub (partition key = trace_id) → 검출 서비스군**
- 동일 트레이스를 동일 인스턴스에 전달하여 (※ 어피니티 (Affinity) 설정), 시퀀스 조립을 깨뜨리지 않고 데이터를 취득
- 트레이스 상태를 Redis로 외부에 분리하여 완전한 스테이트리스 (Stateless)화
# Appendix
## 상정 운영: 카나리 (Canary) + 지속적 개선 루프
AI 에이전트는 나날이 브러시업(Brush-up)되어 갑니다. 따라서 새로운 업무가 추가되거나, 새로운 Tool이 추가되거나, 멀티 에이전트화되는 등 다양한 수정이 이루어질 것입니다. 이에 따라 **카나리 배포 (Canary Deployment)로 새로운 프리뷰 검출기를 공개하여 조금씩 데이터를 수집하고, 이를 다음 모델 학습에 사용하는** 운영을 상정하여 설계하였습니다.
지속적 개선 루프는 다음과 같습니다.
- 검출 서비스가 트레이스를 **BigQuery**에 축적 (판정 결과 포함)
- **Cloud Scheduler**가 일 단위로 재학습 잡 (Job)을 실행
- 현재의 이상 검출기가 "정상" 데이터만을 학습에 채택
- Markov의 확률 빈도 분포, 자연어 모델이 출력하는 의미 특징량 공간의 중심, Isolation Forest를 재학습하여 기존 모델보다 점수가 좋으면 채택
- **GCS**에 새 버전을 publish
- 검출 서비스가 **자동 리로드 (Auto-reload)**
### Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기