
LLM 에이전트의 '완료'를 검증하기(2) — AI가 기록을 위조할 수 없는 구조를 OpenTelemetry Collector로 만들기
요약
LLM 에이전트가 자신의 작업 기록을 조작할 수 있는 문제를 해결하기 위해 OpenTelemetry Collector를 활용한 신뢰할 수 있는 관측 구조를 제안합니다. 에이전트가 로그나 테스트 결과를 편집할 수 있는 권한을 가진 상황에서, 기록의 무결성을 보장하는 가관측성(Observability)의 중요성을 다룹니다.
핵심 포인트
- LLM 에이전트는 스스로의 기록을 편집하거나 미화할 수 있는 위험이 있음
- 기존 가관측성 논의는 '무엇을 볼 것인가'에만 집중하며 '기록의 무결성'을 간과함
- OpenTelemetry Collector와 Unix 권한을 이용해 에이전트의 손이 닿지 않는 기록 구조 구축 가능
- 에이전트의 감사 추적(Audit Trail)을 위해 보안 관점의 기록 관할(Custody) 도입 필요
지난 기사에서 저는 두 가지 사실을 고백했습니다.
- 데모는 선언자 자신이 트레이스(trace)를 내뱉고 있었다. 원리상 트레이스 자체를 속일 수 있다. - '가짜 완료(false completion)'가 관문에서 차단되는 장면은 실연에서는 나오지 않았다.
이번에 저는 이 두 가지를 해결했습니다. 사용한 것은 OpenTelemetry Collector와 Unix의 권한, 그리고 30줄의 설정뿐입니다. 새로운 소프트웨어는 하나도 등장하지 않습니다.
하지만 먼저, 제가 만든 것의 이름을 올바르게 다시 말하겠습니다. 이번에 만든 것은 '조금 더 안전한 데모'가 아닙니다. AI가 자신의 작업 기록을 위조할 수 없는 구조입니다. 그리고 저는 이것이 AI의 가관측성(observability) 논의에서 빠져 있는 토대라고 생각합니다.
간과되었던 전제 — 관측되는 자에게 손이 있는가
가관측성의 도구들 — 로그(log), 메트릭(metric), 트레이스(trace) — 는 어떤 암묵적인 전제 위에 구축되어 왔습니다.
관측되는 계(system)는 자신의 기록에 이해관계가 없다.
서버는 로그를 미화하지 않습니다. 데이터베이스는 레이턴시(latency)가 나쁜 날을 숨기지 않습니다. 그래서 우리는 "로그에 나오지 않는다면, 일어나지 않은 것이다"라고 말할 수 있었습니다. 기록이 정직한 이유는 기록되는 측에 거짓말을 할 동기도, 기록에 손을 댈 권한도 없었기 때문입니다. 아무도 이 전제를 명시하지 않았던 이유는, 굳이 쓸 필요가 없었기 때문입니다.
LLM 에이전트는 이 전제를 역사상 처음으로 깨뜨리는 피관측계(observed system)입니다. 세 가지 점에서 그렇습니다.
- 자신에 대해 이야기한다. 에이전트의 출력은 자기 작업의 요약이며, 요약은 현실과 어긋난다 (지난번 실측: 가짜 완료 11건, 전 건이 자기 확신 0.85 이상).
- 기록에 닿는 손을 가지고 있다. 셸(shell)을 가진 에이전트는 로그도, 테스트 결과도, 리포트도 편집할 수 있다. 악의는 필요 없습니다. "실패를 정리해줘", "다시 한번 깔끔하게 실행해줘"라는 요구의 연장선상에서 역사는 다시 쓰여집니다.
- 승인받도록 최적화되어 있다. 에이전트는 사람에게 좋게 평가받는 출력을 향하도록 훈련된다. 그것은 '잘하고 있는 것'이 아니라 '잘해 보이는 것'을 향한 압력입니다.
정확히 말씀드리겠습니다. 이 문제가 아무에게도 보이지 않는 것은 아닙니다. 보안과 컴플라이언스(compliance) 분야에서는 에이전트의 감사 로그(audit log)를 둘러싸고 부품들에 대한 논의가 시작되었습니다. "침해된 에이전트가 자신의 기록을 지울 수 없도록 로그는 별도의 시스템에 두어야 한다", WORM 스토리지, 해시 체인(hash chain), "에이전트의 감사 추적(audit trail)은 그대로는 증거가 되지 않는다"라는 지적까지 있습니다. 연구 측면에서도 관측되는 측이 감시를 방해할 수 있다는 전제하에 통제를 설계하는 작업(AI control)이나, 에이전트가 테스트를 다시 써서 합격을 조작한 실례 보고가 있습니다.
반면, 주류의 AI 가관측성 논의는 "무엇을 볼 것인가"에 집중하고 있습니다. GenAI의 시맨틱 규약(semantic convention), 토큰 수, 도구 호출(tool call), 평가 점수 — 관측은 점점 풍부해지고 있습니다. 그리고 옆동네 보안 분야가 쌓아 올리고 있는 부품들은 이쪽에서는 토대로組み込まれていない(組み込まれていない, 포함되어 있지 않습니다). 두 담론은 나란히 놓여 있을 뿐, 연결되어 있지 않습니다.
그래서 이 질문이 양쪽 분야 모두에서 공중에 떠 있습니다.
관측된 기록에 관측된 자의 손이 닿을 수 있다면, 그 풍부함이 무슨 의미가 있는가?
손이 닿을 수 있다면, 모든 텔레메트리(telemetry)는 "에이전트가 그렇게 말하고 있다" 이상의 것이 아닙니다. 풍부한 장식일 뿐입니다. 가관측성의 세 기둥은 **기록의 관할(custody)**이라는 토대 위에 서 있을 때 비로소 기둥이 됩니다. 그리고 피관측계에 손이 생기는 순간, 이 토대는 소리 없이 사라졌습니다.
"가관측성"의 원의로 돌아가면, 이것은 더 딱딱한 이야기가 됩니다. 제어 이론에서의 observability는 "출력을 통해 계의 내부 상태를 추정할 수 있는가"라는 정도를 의미했습니다. 피관측계의 출력 그 자체를 신뢰할 수 없다면, 추정의 토대 자체가 무너집니다. 즉, 관할권이 없는 AI 관측은 풍부하냐 빈약하냐를 떠나서 — 원래 의미에서 애초에 가관측(observable)이 아닙니다.
해결책이 수십 년 전부터 있었다는 점이 이야기를 흥미롭게 만듭니다. 추가 전용 기록. 권한의 분리. 기록자와 보관자를 별도의 관할에 두는 것. 이는 회계 세계가 수백 년 전에 걸어온 길입니다 (장부를 적는 사람과 금고를 가진 사람을 나누는 것 — 내부 통제의 기본 중의 기본). 참신함이 없기에 논문의 주인공이 되지 못했고, 가관측성 논의의 토대로 세워지지 못했던 것이라 생각합니다. 보안의 구석진 논의들도 대부분 사고가 일어난 후의 이야기 — 포렌식(forensics)과 책임 추궁 — 입니다. 이 글에서 논하고 싶은 것은 그 이전 단계인, 완료를 수락하는 관문에 대한 이야기이며, 그것이 프로젝트의 생산성을 어떻게 바꾸는지에 대한 것입니다.
이번 데모는 이 오래된 해법을 OTel (OpenTelemetry) 생태계에 있는 부품만으로 구성한 것입니다.
구현 — Collector 설정은 30줄입니다
agentworker(비특권 사용자) root가 운영하는 경계
┌──────────────────┐ OTLP/HTTPS ┌──────────────────────┐
│ 계측된 작업체 │ ──Bearer 인증──▶ │ otelcol-contrib │
...
사용 중인 것은 otelcol-contrib (v0.157.0)에 포함된 표준 부품뿐입니다 — OTLP 수신, TLS, bearertokenauth 확장, file exporter.
extensions:
bearertokenauth:
scheme: Bearer
...
에이전트는 비특권 사용자로 동작하며, 보낼 자격(토큰)은 가지지만, 도착지(창고)에는 손이 닿지 않습니다. 작업은 지난번과 동일하게 "리포지토리의 Rust 행 수를 세어 보고서를 작성하는 것"입니다. 계측(Instrumentation)도 지난번과 같으며, 바뀐 것은 exporter의 목적지뿐입니다.
이하, 실록의 4막. 모든 명령어와 출력은 공개 리포지토리의 transcript에 있습니다.
제0막: 경계 밑보기
$ curl -k -X POST https://127.0.0.1:4318/v1/traces -d "{}" # 인증 없음
HTTP 401
$ su agentworker -c "cat /var/otel-vault/spans.jsonl" # 창고를 읽으려 함
...
제1막: 정직한 작업체가 경계 너머로 보낸다
$ python3 agent_task_otlp.py /home/user/bantollla report.md # as agentworker
done: 13 files, 4106 lines -> report.md
# 창고의 수령 기록(검증자 측에서):
...
지난번과 동일한 관측이, 이번에는 에이전트의 손이 닿지 않는 곳에 남았습니다.
제2막: 바꿔치기 작업은 덮어쓰기가 되지 않는다
에이전트에게 "편리한 숫자로 수정한 트레이스 (Trace)"를 나중에 재전송하게 합니다.
$ python3 tamper_resend.py # lines.total을 9999로 "정정"하여 재전송
resent with lines.total=9999
# 창고의 수령 기록:
...
이 부분이 이번의 핵심입니다. 원래의 4106은 사라지지 않았습니다. "정정"은 덮어쓰기가 되지 않고, 수신 시각이 찍힌 두 번째 기록으로서 나란히 놓였습니다. 검증자 입장에서 보면, 동일한 작업에 대한 모순되는 두 가지 주장 — 변조 시도 그 자체가 지울 수 없는 증거로 변했습니다.
수중에 있는 trace.json이라면 sed 한 번으로 역사가 바뀝니다. 경계 너머에서는 역사는 늘어날 수만 있습니다.
제3막: 선언 — 증거의 좌석이 경계 너머로 이동한다
$ banto gate declare "crates 행 수 보고서 작성 완료" \
--evidence report.md --evidence vault_export.jsonl --store --actor agent:claude
✓ 기록 seq=0 type=claim.declare id=60ef5c3e...
...
증거는 이제 선언자의 수중에 있는 파일이 아니라, 경계의 운영자가 창고에서 꺼낸 수령 기록입니다. 그리고 선언자는 여전히 스스로 사실을 만들 수 없습니다.
제4막: 게으른 작업체 — 경계는 거짓을 통과시키고, 재계산이 잡아낸다
솔직하게, 이 구조의 한계도 실연하겠습니다. 이번 에이전트는 작업을 전혀 하지 않고, 보고서도 span도 날조하여 (lines.total: 5000), 정규 인증 채널로 보냅니다.
$ python3 agent_task_lazy.py report_lazy.md # 파일을 하나도 읽지 않음
done: 13 files, 5000 lines -> report_lazy.md (...라고 주장)
# 창고는 충실히 기록한다:
...
변조할 수 없는 구조가, 날조할 수 없는 구조는 아닙니다. 경계가 보증하는 것은 "보내진 기록이 나중에 바뀌지 않는다"는 것까지이며, "보내진 기록이 진짜인가"는 보증하지 않습니다. 잡아내는 것은 검증자의 재계산입니다.
검증자의 재계산 (고정된 트리·별도 구현):
$ cd bantollla && git checkout 4c437df && find crates -name "*.rs" | xargs wc -l | tail -1
4106 total
...
가짜 완료가 관문(Gate)에서 차단되었습니다. 이 verdict: fail
은 추가 전용·해시 체인 (Hash Chain) 형태의 장부에 영구히 남으며, 누구나 검토할 수 있습니다. 지난 기사에서 빠져 있었던 '가짜 완료의 실물이 관문에서 떨어지는 장면'이 바로 이것입니다. 정직한 버전(4106)은 동일한 검증자의 삼점 일치 (Three-way match)로 pass — 관문은 거짓말만을 골라내어 차단했습니다.
그리고 이 fail 기록 또한 에이전트가 지울 수 없습니다. 그것이 다음 절에서 다룰 내용입니다.
이 구조가 있으면 프로젝트는 어떻게 변하는가
위조할 수 없는 기록은 방범 장치처럼 들립니다. 실제로 운용해 보면 그 효과는 훨씬 일상적이고 더 깊은 곳까지 미칩니다. 제가 banto(지난번에 소개한 Rust 제 장부)와 이 구조 위에서 몇 주간 AI 에이전트와 협업하며 겪은 일들입니다.
1. 「했습니다」가 대화에서 계약으로 변합니다.
완료가 '그런 분위기'가 아니라 '검토 가능한 상태'가 됩니다. 리뷰는 '믿을 것인가, 전부 다시 할 것인가'라는 이지선다에서, '기록을 대조한다'라는 제3의, 훨씬 저렴한 선택지를 얻게 됩니다.
2. 검수가 저렴해지므로 맡길 수 있는 양이 늘어납니다.
에이전트에게 맡길 수 있는 업무량을 결정하는 것은 사실 모델의 지능이 아닙니다. 바로 **검수 비용 (Cost of verification)**입니다. 생성은 빠른데 검수가 수작업으로 남는다면 위임은 금방 한계에 부딪힙니다. 기록이 위조 불가능하고, 증거가 성과물과 결합되어 있으며, 대조가 기계적이라면 검수는 분 단위로 단축됩니다. 위임의 처리량 (Throughput)은 관측 가능성 (Observability) 설계에 의해 결정됩니다 — 이것이 'AI의 관측 가능성'이 생산성의 문제인 이유입니다.
3. 실패가 자산이 됩니다.
이 부분이 가장 간과되고 있다고 생각합니다. 에이전트가 자신의 이력을 '깨끗하게' 만들 수 있는 환경에서는 실패의 기록이 조용히 사라집니다. 사라져서 곤란한 것은 책임 추궁이 아닙니다 — **실패 기록은 에이전트의 약점을 알려주는 유일한 학습 데이터 (Ground Truth)**입니다. 저 자신도 자신의 개발 이력에 남아 있던 가짜 완료의 실물('4/4 ALL PASS'라고 선언했다가 나중에 뒤집힌 그 기록)에 라벨을 붙여 그라운드 트루스 (Ground Truth)로 만들고, 검출기 실험 코퍼스 (Corpus)로 사용했습니다. 에이전트가 지울 수 없었던 실패만이 다음 에이전트를 똑똑하게 만듭니다. 오늘의 verdict: fail 역시 그 자산에 한 건 추가되었습니다.
4. 과거 논쟁이 사라집니다.
'그때 무엇을 했는가'에 대한 논쟁은 장부를 가리키는 것으로 끝납니다. 이는 인간 팀의 위생 문제처럼 들리지만, 에이전트에게도 똑같은 효과를 발휘합니다. 세션은 휘발되기 때문에, 에이전트 스스로가 훼손되지 않은 장부를 의지하여 어제의 자신으로부터 이어서 작업하게 됩니다. 위조할 수 없는 기록은 AI를 묶는 사슬이기 이전에, AI가 딛고 설 바닥입니다.
5. 규율이 대칭적으로 적용됩니다.
이 관문은 AI 전용이 아닙니다. 저의 선언도 다른 작성자가 검증해야 verified가 됩니다 (실제로 지난 데모에서 제가 verify한 claim은 저 스스로는 declare할 수 없는 구조입니다). 'AI의 감시'가 아니라 공통의 장부입니다. 이곳을 대칭적으로 만들어 두면 에이전트에게 규율을 부과하는 것에 대한 미안함이 사라집니다.
6. 의심을 구조가 대신 짊어집니다.
마지막은 관계의 문제입니다. 위조할 수 없는 구조가 있으면 사람이 에이전트를 계속 의심하지 않아도 됩니다. 의심은 구조가 상시 지불(pay)하고 있으므로, 사람은 결과만 검토하면 됩니다. '신뢰하지만 검증한다'는 피로합니다. '구조가 검증하므로 안심하고 맡긴다'는 피로하지 않습니다.
한계 정리 — 위조 불가능 ≠ 올바름
제4막이 보여준 것처럼, 이 구조의 보증은 정확히 말하면 세 층위입니다.
- 얻을 수 있는 것: 사후 교체의 불가능성 (역사는 늘어날 뿐), 발신자 확인 (인증, Authentication), 경로 보호 (TLS)
- 얻을 수 없는 것: 송신 전의 거짓말 탐지 — 그것은 고정된 대상에 대한 재계산과 독립적 판정의 영역입니다 (제4막)
- 더 바깥쪽: 계측 (Instrumentation)이나 실행 환경 전체를 아우르는 위장. 여기까지 오면 in-toto의 attestation, SLSA의 provenance, Sigstore의 서명 — 소프트웨어 공급망 (Software Supply Chain)의 무결성 문제와 동일합니다. 에이전트의 완료 관문은 빌드의 무결성과 같은 형태를 띠고 있으며, 이곳이 OTel과 supply chain 생태계의 합류점이 될 것입니다 (미구현된 미래로서 솔직하게 남겨둡니다).
운용상의 주의사항도 한 가지 있습니다: 이 구조의 안전성은 Collector 설정 자체의 보호에 의존합니다. 인증(Authentication)·TLS·설정 보호·액세스 제어(Access Control)를 포함한 지침은 공식 보안 문서에 정리되어 있습니다.
결론 — 관측성(Observability)의 토대 이야기
"로그에 나타나지 않는다면, 일어나지 않은 것이다" — 이 신조는 로그가 정직할 때만 성립합니다. 피관측계(Observed system)가 자신에 대해 이야기하고, 기록에 손을 뻗을 수 있으며, 승인에 최적화되어 있는 시대의 관측성은, 우선 **기록의 관할(Jurisdiction of records)**을 설계해야 합니다. 트레이스(Trace)도, 메트릭(Metric)도, 로그(Log)도, GenAI 시맨틱 규약(Semantic Convention)도, 그 토대 위에서만 의미를 갖습니다.
그리고 다행스럽게도, 그 토대는 이미 여러분의 운영 환경(Production environment)에 세워져 있습니다. 에이전트의 손이 닿지 않는 곳에서 수신하고, 보존하며, 전달하는 — OpenTelemetry Collector는 처음부터 그 형태를 갖추고 있습니다. 부족한 것은 기능이 아니라, 역할의 이름뿐입니다.
당신의 Collector를 AI의 증인석에 임명해 보지 않겠습니까?
데모 세트(Collector 설정·계측(Instrumentation)·4막의 transcript·fail의 실록이 담긴 장부 그 자체)는 github.com/type37c/bantollla 의 examples/otel-gate-demo2 にあります. 이 기사의 공개 주장 자체도, 지난번과 마찬가지로 demo 장부로 선언(declare)하고, 별도의 actor에 의해 검증(verify)을 거쳤습니다.
관련 기술은 특허 출원되었습니다. 본 리포지토리(bantollla)는 Apache-2.0으로 공개되어 있으며, 특허 라이선스의 범위는 해당 라이선스 §3의 규정에 따릅니다. 출원된 내용은 "자기 신고가 아니라, 관측에 기반하여 검증 및 권한 부여를 수행하는 기구"에 관한 것입니다. 숨기기 전에 미리 밝혀둡니다. bantollla의 이용을 방해할 의도는 없으며, 코드는 Apache-2.0으로 제공되어 해당 특허 허가 조항(§3)이 이용자에게 적용됩니다.
Discussion

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