Missio 구축하기: SigNoz를 활용한 증거 기반의 Remediation Agent
요약
SigNoz를 활용하여 운영 환경의 에러를 분석하고 해결하는 증거 기반 Remediation Agent 'Missio'를 소개합니다. 추측이 아닌 관측 데이터(Telemetry)를 바탕으로 근본 원인을 파악하고 안전하게 PR을 생성하는 워크플로우를 제안합니다.
핵심 포인트
- SigNoz의 관측 데이터를 증거로 활용하여 에이전트의 추측 방지
- Slack 인시던트 발생부터 PR 생성까지의 자동화된 파이프라인 구축
- 에이전트가 실제 소스 리비전과 텔레메트리를 연결하는 체인 형성
- 사람의 승인을 포함한 안전한 코드 패치 및 배포 프로세스 설계
운영 환경(Production)에서의 에러는 AI 에이전트가 창의성을 가장 발휘해서는 안 되는 순간입니다.
이 문장은 제가 Agents of SigNoz 해커톤을 위해 구축한 터미널 미션 컨트롤 시스템인 Missio의 설계 원칙이 되었습니다. Missio는 Slack에 보고된 실제 인시던트(Incident)로 시작하여, SigNoz로부터 발생 상황을 재구성하고, 실패를 일으킨 정확한 소스 리비전(Source revision)을 찾아내며, 에이전트에게 엄격하게 제한된 변경 사항을 요청한 뒤, 사람이 해당 작업을 승인한 후에만 초안 Pull Request(PR)를 생성합니다.
전체 과정은 하나의 Rust TUI(Terminal User Interface) 내에서 가시적으로 유지됩니다:
SIGNAL → EVIDENCE → CODE → PATCH → HUMAN → PR → CI → HANDOFF
이것은 옆에 AI 요약이 붙어 있는 대시보드가 아닙니다. 모든 단계는 시스템이 실제로 관찰하거나 완료한 무언가를 나타냅니다. 증거(Evidence)가 누락되면 미션은 중단됩니다. GitHub가 운영 리비전을 해결할 수 없으면 중단됩니다. 모델이 안전하지 않은 패치(Patch)를 반환하면 중단됩니다.
인시던트 에이전트에게 필요한 것은 확신이 아니라 증거인 이유
관측성(Observability) 도구들은 이미 요청이 실패했다는 것을 보여주는 데 능숙합니다. 더 어려운 질문은 에이전트가 다음에 무엇을 하도록 허용해야 하는가입니다.
에러 메시지만으로는 어떤 코드가 배포되었는지 확립할 수 없습니다. 리포지토리(Repository)의 기본 브랜치는 장애 발생 이후 변경되었을 수 있습니다. 모델은 파일의 잘못된 버전을 사용하여 설득력 있는 설명을 만들어낼 수 있습니다. 또한 누락된 컨텍스트를 추측으로 조용히 채워 넣을 수도 있습니다.
저는 그 반대의 동작을 원했습니다. Missio는 운영 시그널(Production signal)로부터 특정 소스 코드 조각까지의 체인을 구축할 수 있을 때만 유용해야 합니다. 에이전트의 역할은 그 체인 안에서 추론하는 것이지, 체인을 발명하는 것이 아닙니다.
그렇기에 SigNoz는 단순한 장식용 통합 도구가 아닌, 기록을 위한 증거 시스템(Evidence system of record)이 되었습니다.
실제 결제 실패를 미션으로 전환하기
데모를 위해 저는 계측된(Instrumented) 결제 서비스를 사용합니다. 잘못된 할인 요청이 실제 HTTP 엔드포인트에 도달하여 실패하는 OpenTelemetry 스팬(Span)을 생성합니다. 이 스팬은 일반적인 서비스 및 에러 필드와 함께, Missio가 런타임 동작을 소스에 연결하는 데 필요한 세부 정보를 포함하여 SigNoz로 내보내집니다:
- 영향을 받은 리소스 (The affected resource);
- 환경 (The environment);
- 코드 파일 및 함수 (The code file and function);
- 리포지토리 URL (The repository URL);
- 프로덕션에서 실행 중인 전체 Git 커밋 (The full Git commit running in production).
그 후 운영자가 허용 목록(allowlisted)에 포함된 Slack 채널에서 인시던트(incident)를 엽니다:
/missio-sev SEV1 service production/checkout checkout requests are failing
Slack은 단지 진입점(admission point)일 뿐입니다. 메시지는 에이전트에게 근본 원인(root cause)이 무엇인지 알려주지 않으며, Missio는 해당 문구를 증거로 취급하지 않습니다. 대신 리소스와 인시던트 윈도우(incident window)를 사용하여 SigNoz의 해당 텔레메트리 (telemetry)를 쿼리합니다.
설계를 바꾼 인덱싱 지연 (Indexing Delay)
Missio를 구축하며 얻은 가장 유용한 교훈은 문서를 읽어서 얻은 것이 아니었습니다. 그것은 모든 개별 구성 요소가 정상적으로 보임에도 불구하고 실패한 데모에서 얻은 것이었습니다.
체크아웃 서비스는 스팬 (span)을 성공적으로 내보냈습니다. SigNoz는 텔레메트리 (telemetry)를 수락했습니다. 하지만 Missio가 즉시 쿼리를 보냈을 때는 일치하는 행이 없었습니다. 잠시 후, 동일한 쿼리를 실행하자 예상했던 대로 실패 결과가 반환되었습니다.
수집 수락 (Ingestion acceptance)과 쿼리 가능성 (query availability)은 동일한 시점이 아닙니다.
이 차이는 작게 들릴 수 있지만, 자율 워크플로 (autonomous workflow)의 동작을 변화시킵니다. 만약 첫 번째 빈 응답이 "인시던트가 없음"을 의미한다면, 에이전트는 실제 프로덕션 장애를 폐기해 버릴 수 있습니다.
반대로 시스템이 영원히 기다린다면, 운영자는 작업이 진행 중인지 알 수 없습니다.
이제 Missio는 제한된 범위 내에서 증거 획득 (bounded evidence acquisition)을 수행하며, TUI에서 대기 상태를 시각화합니다. SigNoz가 스팬 (span)을 인덱싱하는 동안 제한된 기간 동안 재시도합니다. 만약 유효한 증거 번들 (evidence bundle)을 여전히 형성할 수 없다면, 증거 (EVIDENCE) 단계는 실패로 종료(fails closed)됩니다. 애니메이션을 계속 돌리기 위해 누락된 텔레메트리 (telemetry)를 조작된 인시던트로 대체하는 일은 절대 하지 않습니다.
이것이 제가 인터페이스 하단에 시그널 호라이즌 (signal horizon)을 유지한 이유이기도 합니다. 운영자는 Missio가 경청 중인지, 증거를 획득 중인지, 아니면 관찰이 불완전하여 대기 중인지를 확인할 수 있습니다.
텔레메트리가 소스를 선택하게 하기
트레이스(trace)가 사용 가능해지면, Missio는 스팬(span)에서 저장소(repository)와 배포된 전체 커밋(commit)을 추출합니다. 이 커밋은 기본 브랜치(default branch)의 현재 상태보다 더 중요합니다. 왜냐하면 관찰된 장애를 실제로 발생시킨 코드를 식기하기 때문입니다.
Missio는 해당 불변 리비전(immutable revision)에서의 저장소 트리(repository tree)를 읽고, 관찰된 코드 위치와 연결된 소스(source)를 선택합니다. 모노레포(monorepo) 환경에서는 조사를 영향을 받은 서비스 내부로 유지할 수 있습니다. 오직 해당 경계 컨텍스트(bounded context)만이 에이전트(agent)에게 전달됩니다.
이를 통해 모델은 훨씬 더 정직한 질문을 받게 됩니다:
"관찰된 이 장애와 이를 발생시킨 정확한 소스를 고려할 때, 작은 수정(small fix)을 위한 충분한 증거가 있는가?"
모델은 미션(mission)을 유지하거나, 제공받은 소스에 대한 교체 콘텐츠를 제안할 수 있습니다. 모델은 관련 없는 파일을 추가하거나, CI 워크플로우(workflow)를 편집하거나, 서비스 경계 외부로 접근하거나, 외부 작업이 성공했다고 주장할 수 없습니다. 이러한 결정은 모델이 응답한 후 Rust에 의해 강제됩니다.
Missio는 에이전트 런타임(agent runtime)으로 Rig를 사용하며, OpenRouter를 통해 명시적으로 구성된 모델을 사용합니다. 모델은 Slack, SigNoz 또는 GitHub 자격 증명(credentials)을 절대 받지 않습니다.
TUI를 권한 경계로 만들기
처음에 저는 인터페이스를 프로젝트의 시각적 정체성, 즉 카드와 테이블로 이루어진 흔한 그리드 대신 미션 컨트롤 궤도(mission-control orbit)로 생각했습니다. 하지만 실제 워크플로우를 구축하면서 이는 더 유용한 무언가가 되었습니다.
TUI는 현재 누가 권한을 가지고 있는지를 보여줍니다.
SigNoz는 증거를 제공할 수 있습니다. 에이전트는 패치(patch)를 제안할 수 있습니다. 하지만 둘 다 풀 리퀘스트(pull request)를 생성할 수는 없습니다. 제안된 변경 사항이 정책을 통과하면, 미션은 HUMAN 단계에서 일시 중지되며 대상 저장소를 보여줍니다. 운영자는 반드시 하나의 초안 PR(draft-PR) 시도를 명시적으로 승인해야 합니다.
그 승인은 의도적으로 좁게 설정되었습니다. 그것은 머지(merge)나 배포(deployment)를 승인하는 것이 아닙니다. 만약 GitHub가 요청을 거부하면, Missio는 미션을 보존하고 변이(mutation)를 조용히 반복하는 대신 제어권을 인간에게 반환합니다.
복구를 가장하는 것이 아니라, 인계(Handoff)에서 종료하기
승인이 완료되면, Missio는 SigNoz에 의해 식별된 프로덕션 리비전(production revision)으로부터 브랜치와 초안 풀 리퀘스트(draft pull request)를 생성합니다. 증거 요약(evidence digest)은 풀 리퀘스트로 전달되어, 제안된 변경 사항을 해당 변경을 유발한 인시던트(incident)와 다시 연결합니다.
그 후 Missio는 정확한 초안 커밋(draft commit)을 위해 GitHub CI를 모니터링합니다. 체크(checks)가 통과되면, 최종 상태는 HANDOFF가 됩니다.
이러한 용어 선택은 의도된 것입니다. Missio는 초록색 체크 표시가 프로덕션이 복구되었음을 의미한다고 가장하지 않습니다. 대신 운영자에게 증거에 기반한 초안이 일반적인 리뷰, 머지(merge) 및 배포를 위해 준비되었음을 알려줍니다. 풀 리퀘스트는 엔지니어가 변경 사항을 검사하고 최종 결정을 내릴 수 있는 장소로 남습니다.
자동 배포를 통해 데모를 확장하는 것도 고려해 보았으나, 이는 제품의 신뢰 모델을 약화시킬 수 있었습니다. 해커톤 애니메이션은 실제 시스템이 갖지 못한 권위를 조작해서는 안 됩니다.
SigNoz가 가능하게 한 것
SigNoz가 없었다면, 이것은 Slack 메시지에 의해 트리거되는 코드 에이전트(code agent)에 불과했을 것입니다. SigNoz와 함께라면, 에이전트는 관찰된 리소스(resource), 시간 범위(time window), 트레이스(trace), 코드 위치(code location), 저장소(repository) 및 배포된 리비전(deployed revision)에 근거를 둡니다.
이러한 컨텍스트(context)는 이후의 모든 단계에 영향을 미칩니다:
- 미션(mission)의 존재 여부를 결정합니다.
- 어떤 소스(source)를 읽을 수 있는지 결정합니다.
- 에이전트가 변경할 수 있는 범위를 제한합니다.
- 초안 풀 리퀘스트를 프로덕션 증거와 다시 결합합니다.
저에게 가장 깊은 교훈은 에이전트 관측성(observability)이 단순히 모델이 무엇을 했는지 추적하는 것만이 아니라는 점이었습니다. 관측성은 모델이 다음에 무엇을 할 수 있는지 제어할 수도 있습니다.
Missio는 여전히 최종 운영 결정을 사람에게 맡깁니다. Missio의 역할은 소란스러운 인시던트를 과정 중의 공백을 숨기지 않으면서, 검토 가능하고 증거에 기반한 변경 사항으로 전환하는 것입니다.
GitHub의 Missio에서 확인해 보실 수 있습니다.
제가 구축한 요소들의 근간을 추적하고 싶다면, 가장 유용한 참고 자료는 SigNoz 가이드였습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기