AI 에이전트의 자가 복구 루프 설계 (테스트 실패 → 원인 분석 → 자동 수정 구현)
요약
본 기사는 테스트 실패를 자동으로 감지하고 원인을 분석하여 코드를 수정하는 '자가 복구 루프(self-healing loop)' 설계 및 구현을 소개합니다. DebuggerAgent, PostmortemAgent, GuardianAgent 세 에이전트가 협력하며, 오류 시그니처 생성과 지식 기반 활용을 통해 효율적인 자동화 개발 프로세스를 구축합니다.
핵심 포인트
- 테스트 실패 감지부터 수정까지의 자가 복구 루프 설계
- DebuggerAgent는 과거 오류를 학습한 지식 기반으로 즉시 패치 제공
- PostmortemAgent는 오류로부터 '시그니처'와 근본 원인을 분석하여 지식 축적
- 민감 정보 유출 방지를 위한 3단계 정제(redact 등) 과정 필수
AI에게 코드를 생성하게 하면 반드시 오류가 발생합니다. 테스트가 실패하거나 예상과 다른 동작을 하기도 합니다. 사람이 오류를 확인하고 수정 지시를 내리는 것은 수고가 많이 듭니다.
본 기사에서는 테스트 실패를 자동으로 감지하고, 원인을 분석하며, 수정을 생성하고, 재테스트하는 '자가 복구 루프(self-healing loop)'의 설계와 구현을 소개합니다.
세 가지 에이전트가 협력하여 자가 복구를 실현합니다.
-
DebuggerAgent: 오류 분석 및 수정 패치 생성 -
-
PostmortemAgent: 실패의 근본 원인 분석 및 지식 축적 -
-
GuardianAgent: 수정 후 코드 리뷰
-
테스트 실패 출력(stdout/stderr)을 받습니다.
-
로컬 지식 기반에서 알려진 해결책을 검색합니다.
-
알려진 경우 즉시 적용하고, 알 수 없는 경우 LLM으로 분석합니다.
-
통일 차분 형식(unified diff)으로 패치를 생성합니다.
DebuggerAgent는 과거의 실패로부터 학습한 지식 기반을 참조합니다.
# 지식 기반 구조
{
"error_signature": "ImportError: No module named 'src.nexuscore'",
...
오류 메시지를 정규 표현식으로 매칭하여, 과거에 해결된 문제라면 즉시 수정안을 제시합니다. 이를 통해 동일한 오류로 LLM에 문의하는 비용을 절감할 수 있습니다.
LLM이 생성하는 수정은 통일 차분 형식으로 출력됩니다.
--- a/src/nexuscore/core/retry_policy.py
+++ b/src/nexuscore/core/retry_policy.py
@@ -42,7 +42,7 @@
...
상대 경로로 출력함으로써 리포지토리의 어느 위치에서든 적용 가능하게 했습니다.
수정이 생성되면 자동으로 GitHub PR을 생성하는 것도 가능합니다. DebuggerAgent는 브랜치 생성, 커밋, PR 생성까지 일괄적으로 실행할 수 있습니다.
Auto-PR은 편리하지만, 리뷰 없는 자동 병합(auto merge)은 프로덕션 환경에 악영향을 줄 위험이 있습니다. 반드시 인간의 승인 흐름(human approval flow)을 거치는 것을 권장합니다.
PostmortemAgent에게 전달되는 입력은 3단계의 정제(sanitizing)를 거칩니다.
- truncate: 컨텍스트 상한에 맞춰 잘라냄 -
- redact: API 키나 시크릿을 마스킹 -
- validate_and_normalize: JSON 정규화 및 문자 인코딩 검증
목적은 LLM에게 과도하게 긴 컨텍스트를 전달하지 않는 것과 기밀 정보 유출 방지입니다.
API 키나 시크릿의 누출은 LLM 학습 데이터에 포함될 위험이 있습니다. redact 처리는 반드시 LLM 호출 전단에서 실행하며, GuardianAgent가 패치의 차분에도 기밀 정보가 포함되어 있지 않은지 검사합니다.
PostmortemAgent는 오류로부터 고유한 '시그니처(signature)'를 생성합니다.
입력: ImportError: No module named 'src.nexuscore.core.errors'
시그니처: "ImportError:module-not-found:src.nexuscore.*"
정규 표현식 패턴으로 변환함으로써, 동일하지 않아도 동종의 오류를 매칭할 수 있습니다.
- error_signature: 정규 표현식 패턴. 다음 DebuggerAgent가 대조에 사용 -
- root_cause: 왜 오류가 발생했는지에 대한 분석 -
- solution_pattern: 권장되는 해결책. 수정 타입(config/code/test)과 대상 파일을 포함
{
"error_signature": "AssertionError.*expected.*but got",
"root_cause": "테스트의 기대값이 구현 변경을 따라가지 못함",
...
2회차부터는 LLM 호출 없이 해결할 수 있으므로, 비용과 시간을 대폭 절감할 수 있습니다.
무한 루프를 방지하기 위해 자가 복구 재시도에는 상한선을 두고 있습니다.
DECISION_TABLE = {
ModelRateLimitError: {"max_attempts": 5, "backoff": "exponential"},
ModelTimeoutError: {"max_attempts": 3, "backoff": "linear"},
...
오류의 종류에 따라 재시도 횟수와 백오프 전략을 다르게 적용합니다:
429 속도 제한: 지수 백오프(Exponential Backoff) 방식으로 5회까지 (복구 가능성이 높음)
타임아웃: 선형 백오프(Linear Backoff) 방식으로 3회까지
보안 오류: 즉시 중단 (재시도해서는 안 됨)
에러는 크게 두 가지로 분류됩니다.
재시도 가능: 속도 제한, 타임아웃, 연결 오류, 잘못된 출력
재시도 불가: 샌드박스 실행 오류, 보안 위반, 패치 적용 실패, 예상치 못한 시스템 오류
재시도 불가 에러는 즉시 사람에게 통지합니다.
LLM에 전달되는 컨텍스트에는 최대 토큰 수 제한이 있습니다. PostmortemAgent의 _truncate 메서드에서는 에러 출력이 너무 길 경우 중요한 부분(스택 트레이스의 끝 등)을 우선하여 남깁니다.
1. TesterAgent: 테스트 실행 → ImportError 발생
2. DebuggerAgent: 지식 기반 검색 → 해당 없음
3. DebuggerAgent: LLM으로 분석 → PYTHONPATH 설정 오류로 특정
...
1. TesterAgent: 테스트 실행 → AssertionError: expected 200 but got 404
2. DebuggerAgent: 지식 기반 검색 → 해당 없음
3. DebuggerAgent: LLM으로 분석 → 라우팅 설정 변경이 테스트에 반영되지 않음
...
지식 기반의 비대화: 장기 운영으로 인해 지식 기반이 커지고, 검색 비용이 증가하는 문제
잘못된 수정의 위험: LLM이 생성하는 패치가 반드시 올바르지는 않습니다. GuardianAgent가 차이점의 타당성(구문 오류, 의도치 않은 삭제, 기밀 정보 혼입)을 검사하지만, 논리적인 오류까지는 감지하지 못할 때가 있습니다.
- 컨텍스트 제약: 대규모 에러 출력은 LLM의 컨텍스트 창에 담기지 않을 수 있습니다.
자가 복구 루프의 핵심은 '실패를 지식으로 바꾸는 것'입니다. 에러를 단순히 재시도하는 것에 그치지 않고, 그 원인과 해결책을 구조화하여 저장함으로써 시스템이 점진적으로 똑똑해집니다.
DebuggerAgent(수정) → PostmortemAgent(학습) → 지식 기반(축적)의 3단계 구조를 통해, 동일한 에러에 대한 대응 비용을 단계적으로 제로에 가깝게 만들 수 있습니다.
본 기사는 개인 Zenn에서도 공개하고 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기