AI 에이전트가 돈을 다룰 때, "작동했다"는 것만으로는 충분하지 않습니다
요약
AI 에이전트가 자산(ETH)을 다루는 환경에서 관찰 가능성(Observability)의 중요성을 강조합니다. OpenTelemetry와 SigNoz를 활용해 에이전트 간 합의 과정과 네트워크 타임아웃을 추적하는 실무적인 계측 방법을 소개합니다.
핵심 포인트
- AI 에이전트 시스템에서 관찰 가능성은 선택이 아닌 필수 제품 요소임
- OpenTelemetry를 활용한 상세한 스팬(Span) 계측으로 로그로 찾기 힘든 타임아웃 감지
- 합의 루프 및 피어 브로드캐스트 과정의 가시성 확보를 통한 안정성 강화
- FHE 및 스마트 컨트랙트를 결합한 자율적 마일스톤 검증 시스템 구축 사례
세 명의 검증 에이전트. 하나의 마일스톤(Milestone). 실제 ETH가 걸려 있습니다.
트레이싱(Tracing) 없이 합의 루프(Consensus loop)를 처음 실행했을 때, 피어 브로드캐스트(Peer broadcast)에서의 조용한 타임아웃으로 인해 두 개의 노드는 투표를 했지만 세 번째 노드는 유휴 상태로 남아 있었습니다. 정족수(Quorum)는 어쨌든 통과되었지만(3명 중 2명), 40분이 지나 수동으로 로그를 확인하기 전까지는 세 번째 노드가 고장 났다는 사실을 전혀 알지 못했습니다.
그때 저는 관찰 가능성(Observability)을 있으면 좋은 기능이 아니라, 제품 그 자체로 취급하기 시작했습니다.
제가 만든 것
Weft는 자율적인 마일스톤 검증기(Milestone verifier)입니다. 빌더(Builders)는 프로젝트 결과물에 대해 ETH를 스테이킹(Stake)하며, 마감 기한이 지나면 세 명의 독립적인 AI 에이전트가 증거(계약 배포, 온체인 사용량, GitHub 커밋 등)를 수집하고, 암호화된 채널을 통해 이를 상호 확인하며, 온체인에서 판결을 실행합니다. 자본은 자동으로 해제되거나 환불됩니다.
기술 스택:
Python 검증 데몬 (Verifier daemon)
0G Chain 스마트 컨트랙트 (Smart contracts)
Zama FHE (봉인된 투표 프라이버시를 위한 완전 동형 암호화)
AXL (피어 투 피어 메시징을 위한)
SigNoz (전체 관찰 가능성 레이어를 위한)
실제로 중요했던 계측(Instrumentation)
저는 OpenTelemetry의 Python SDK를 사용하여 데몬을 계측했습니다. 처음에는 검증 사이클당 하나의 루트 스팬(Root span), 각 증거 수집 단계별 자식 스팬(Child spans)을 두는 표준적인 방식을 사용했습니다. 하지만 유용한 계측은 처음에 트레이싱할 생각을 하지 못했던 곳에서 나왔습니다.
- 피어 브로드캐스트 (The peer broadcast)
각 검증기는 서명된 판결 봉투(Verdict envelope)를 HTTP POST를 통해 다른 두 노드에 브로드캐스트합니다. 저는 브로드캐스트 호출을 peer.address, envelope.evidence_root, response.status 속성을 가진 스팬(Span)으로 감쌌습니다.
python
with tracer.start_as_current_span(
"axl.broadcast_verdict",
attributes={
"peer.address": peer_url,
"milestone.hash": milestone_hash,
"envelope.evidence_root": evidence_root,
},
) as span:
resp = requests.post(f"{peer_url}/send", json=envelope, timeout=10)
span.set_attribute("http.status_code", resp.status_code)
세 번째 노드가 타임아웃(timeout)이 발생하고 있었을 때, span은 30초의 지속 시간과 deadline_exceeded 상태를 보여주었습니다. 이는 stdout 로그에서는 절대 찾을 수 없었을 정보인데, 데몬(daemon)의 재시도(retry) 로직이 조용히 다음 단계로 넘어갔기 때문입니다.
- 합의 대기 (The consensus wait)
AXL_WAIT_FOR_PEERS=1일 때, 데몬은 투표하기 전에 일치하는 피어(peer) 엔벨로프(envelope)가 있는지 인박스(inbox)를 폴링(poll)합니다. 저는 합의가 형성되는 데 얼마나 걸렸는지와 얼마나 많은 고유 서명자(unique signers)가 기여했는지를 추적하는 span을 추가했습니다. SigNoz에서는 이것이 워터폴(waterfall) 차트에서 가변 너비의 막대로 나타납니다. 이를 통해 합의가 빨랐는지(모든 노드가 정상) 아니면 느렸는지(한 노드가 지연됨)를 즉시 확인할 수 있습니다.
- FHE 투표 암호화 (The FHE ballot encryption)
Zama의 FHEVM 연산은 계산 비용이 많이 듭니다. submit_encrypted_weighted_verdict를 감싸는 span을 통해 확인한 결과, 호출당 4~6초가 소요되고 있었습니다. 이는 일반적인 submitVerdict보다 10배나 더 긴 시간이었습니다. 이 사실을 알고 나면 괜찮지만, span이 없었다면 전체 사이클 시간은 명확한 병목 현상(bottleneck) 없이 그저 "느리다"고만 느껴졌을 것입니다.
로그가 주지 못한 SigNoz의 가치
제가 실제로 상주하며 확인했던 대시보드에는 8개의 패널이 있었습니다:
- 검증 사이클 지속 시간 (Verification cycle duration, p50/p95) — 성능 저하 여부를 알려주는 하나의 지표
- 증거 소스 가용성 (Evidence source availability) — GitHub API, RPC 노드, 0G 인덱서(indexer)를 위한 3개의 게이지(gauge)
- 피어 합의 형성 시간 (Peer consensus formation time) — 첫 브로드캐스트(broadcast)부터 정족수(quorum) 달성까지 걸린 시간
- 트랜잭션 성공률 (Transaction success rate) — 온체인(on-chain) 투표 결과가 실제로 반영되었는지 여부
- 노드별 투표 상태 (Per-node vote status) — 어떤 검증기(verifier)가 투표했는지, 어떤 것이 멈춰 있는지
- FHE 암호화 지연 시간 (FHE encryption latency) — 특히 Zama 호출 관련
- 활성 마일스톤 수 (Active milestone count) — 대기 중인 마감 기한(deadline)에 걸친 작업량
- span별 에러율 (Error rate by span) — 어떤 연산이 가장 많이 실패하는지
실제 디버깅이 이루어지는 곳은 트레이스 워터폴(trace waterfall)입니다. 단일 검증 사이클은 15~25개의 span을 생성합니다:
deadline_scheduler.poll
→ indexer_client.get_milestone
→ metadata_reader.read
→ github_client.collect
→ eth_rpc.get_code
→ mvp_verifier.count_callers
→ kimi_client.generate_narrative
→ axl_client.broadcast
→ peer_inbox.wait_for_consensus
→ keeperhub_client.execute_verdict
무언가 고장 나면, 트레이스 (trace)를 클릭하여 정확히 어디인지 확인할 수 있습니다.
나를 놀라게 했던 점은: 내가 예상했던 것보다 트레이스-로그 상관관계 (trace-to-logs correlation)를 더 많이 사용했다는 것입니다. 데몬 (daemon)은 트레이스 ID (trace ID)가 포함된 구조화된 JSON 로그를 방출하므로, SigNoz에서 의심스러운 스팬 (span)을 클릭하면 해당 작업의 정확한 로그 라인으로 바로 이동할 수 있습니다. 이는 증거 수집 (evidence-gathering)은 통과했지만 증명 (attestation) JSON이 잘못된 형식(malformed)이었던 사례를 디버깅할 때 매우 귀중했습니다. 스팬은 "성공"이라고 표시했지만, 로그에는 하위 단계 (downstream)에서만 중요한 누락된 필드가 나타났기 때문입니다.
과거의 나에게 해주고 싶은 말
내부 로직이 아닌 경계 (boundaries)를 계측(instrument)하세요. 나는 비즈니스 로직의 개별 라인을 추적하는 데 시간을 낭비했습니다. 유용한 스팬은 시스템 경계에 있었습니다: 피어 (peers)로의 HTTP 호출, 체인 (chain)으로의 RPC 호출, GitHub/Kimi/0G로의 API 호출 등입니다. 내부 함수 호출은 부모 스팬 (parent span)과 상관관계가 있는 로그를 통해 처리하는 것이 더 낫습니다.
스팬 속성 (span attributes)을 공격적으로 설정하세요. milestone.hash, verifier.address, evidence.type, consensus.signer_count — 이러한 속성들은 일반적인 폭포수 (waterfall) 형태의 데이터를 쿼리 가능한 데이터셋으로 바꿔줍니다. "지난주에 어떤 마일스톤 (milestone)의 검증이 가장 오래 걸렸는가"라는 질문에 답해야 했을 때, 그것은 grep이 아니라 SigNoz 쿼리였습니다.
나를 구해준 알림 (alert): 단순한 조건인 '검증 주기 (verification cycle) > 120s'가 0G 인덱서 (indexer) RPC가 오래된 데이터 (stale data)를 반환하던 회귀 (regression) 문제를 잡아냈습니다. 데몬은 아직 전파되지 않은 메타데이터에 대해 계속해서 읽기 재시도를 반복하고 있었습니다. 나는 상한선이 있는 지수 백오프 (exponential backoff)를 추가했지만, 알림이 없었다면 알아차리기 전까지 몇 시간 동안 속도 제한 (rate limits)을 다 써버렸을 것입니다.
샘플링 (sampling)을 고려하지 않고 프로덕션 (production)에서 트레이싱을 하지 마세요. 3개의 검증자 노드 (verifier nodes)가 각각 60초마다 폴링 (polling)하고, 각 노드가 주기당 15개 이상의 스팬을 생성한다면 — 최소 시간당 약 2,700개의 스팬이 발생합니다. 해커톤에서는 괜찮습니다. 프로덕션에서는 폴링 주기에 대해 헤드 기반 샘플링 (head-based sampling)을 적용하고, 판결 실행 (verdict-execution) 경로에 대해서는 100% 샘플링을 적용해야 합니다.
핵심 요약 (The Takeaway)
Weft의 핵심은 돈을 다루는 자율 에이전트(autonomous agents)는 반드시 관찰 가능(observable)해야 한다는 점입니다. 이는 규제 기관이 요구하기 때문이 아니라(물론 요구하게 되겠지만), 판결(verdict)이 내려지지 않고 실제 자본이 걸려 있는 상황에서 새벽 2시에 디버깅(debug)을 해야 할 상황이 반드시 오기 때문입니다.
SigNoz는 "세 번째 노드가 고장 난 것 같다"는 문제를 로그를 40분 동안 뒤지는 작업에서 트레이스 워터폴(trace waterfall)을 10초간 훑어보는 작업으로 바꾸어 놓았습니다.
만약 여러분이 트랜잭션(transactions), 배포(deployments), 승인(approvals)과 같이 중대한 영향을 미치는 작업을 수행하는 에이전트를 구축하고 있다면, 제품을 출시하기 전에 의사결정 경로(decision path)를 엔드 투 엔드(end-to-end)로 계측(instrument)하십시오. 무언가가 소리 없이 실패하는 첫 번째 상황을 맞이했을 때, 과거의 자신에게 감사하게 될 것입니다.
Weft는 오픈 소스입니다: github.com/thisyearnofear/weft. SigNoz 대시보드는 agent/scripts/weft_signoz_provision.sh에 있는 OpenTofu를 통해 프로비저닝(provisioned)됩니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기