[개발 깨알 상식_Tips]/[바이브코딩 Tips] / 종료 코드가 빠진 에이전트 재시도.md

종료 코드가 빠진 에이전트 재시도

조회

2026년 6월 27일 | 바이브코딩 Tips


에이전트에게 실패를 다시 맡길 때 가장 자주 빠지는 숫자는 exit code다. 화면에는 빨간 에러가 크게 보이고, 로그 마지막 줄도 꽤 설득력 있어 보인다. 그래서 나도 예전에는 traceback 끝부분이나 실패한 assertion만 복사해서 “이거 고쳐줘”라고 던질 때가 많았다. 그런데 그렇게 주면 에이전트가 문제를 꽤 자주 넓게 잡았다. 실패가 난 명령이 실제로는 2를 반환했는지, 1을 반환했는지, 출력은 어디까지 정상으로 찍혔는지, 경고는 stderr에만 있었는지 구분하지 못한 채 바로 수정 후보를 만들기 때문이다.

에이전트 재시도 전에 exit code, stdout, stderr, next action을 나누는 도식
실패 로그를 한 문단으로 요약하기보다 종료 코드, 표준 출력, 표준 에러, 다음 행동을 분리하면 재시도 범위가 작아진다.

로그 전체보다 구조가 먼저다

코딩 에이전트는 긴 로그를 읽을 수 있다. 문제는 길이가 아니라 구조다. 한 덩어리로 붙인 로그에는 정상 출력, 진행 중 메시지, 경고, 실제 실패, 셸 wrapper의 실패가 한꺼번에 들어간다. 사람은 대충 색깔과 위치를 보고 구분하지만, 자연어 요청 안에서는 그 경계가 금방 흐려진다. 특히 “마지막 줄이 에러”라는 습관이 강하면, 에이전트는 앞에서 이미 깨진 전제를 놓치고 마지막 assertion 근처만 만질 수 있다.

내가 요즘 실패를 넘길 때 먼저 보는 것은 명령 결과의 모양이다. 어떤 명령을 실행했는지, 종료 코드는 무엇이었는지, stdout에는 어느 단계까지 찍혔는지, stderr에는 어떤 경고와 traceback이 있었는지 나눈다. 이 네 칸이 있으면 에이전트가 바로 패치로 뛰어들기보다 “실패가 테스트 코드에서 난 건지, 실행 환경에서 난 건지, 애플리케이션 로직에서 난 건지”를 좁혀 보기 시작한다.

이건 대단한 디버깅 방법론이라기보다 복사 습관에 가깝다. 실패 원문을 더 많이 주는 것이 아니라, 원문이 어떤 통로에서 나온 것인지를 잃지 않는 쪽에 가깝다. 같은 메시지도 stdout에 있으면 상태 보고일 수 있고, stderr에 있으면 경고나 예외일 수 있다. exit code가 0인데 stderr에 경고만 있는 경우와, exit code가 1인데 stdout이 중간까지 정상인 경우는 다음 요청이 달라져야 한다.

내가 붙이는 네 칸

가장 가벼운 형태는 네 줄이면 충분하다. 명령, 종료 코드, stdout 요약, stderr 원문이다. 여기에 “다음 행동”을 한 줄 붙이면 더 좋다. 다음 행동은 해결책이 아니라 권한이다. 예를 들어 “원인 후보를 세 개로 좁히고, 수정은 아직 하지 말라”거나 “가장 작은 파일 하나만 고치고 같은 명령으로 재확인하라”처럼 적는다. 실패 직후에는 수정 권한을 바로 크게 열지 않는 편이 낫다.

command: python -m pytest tests/test_export.py -q
exit_code: 1
stdout: 7개 테스트 중 6개 통과, export_missing_field만 실패
stderr: AssertionError: expected column order ['id', 'name', 'tags'] ...
next_action: 원인 후보를 먼저 적고, export 컬럼 순서 관련 파일 하나만 제안

이 정도만 줘도 대화가 달라진다. “테스트가 실패했다”는 말은 너무 넓다. 반면 “6개는 통과했고 컬럼 순서 하나만 실패했다”는 말은 변경 반경을 바로 줄인다. stderr의 원문을 남기면 에이전트가 내가 요약한 표현을 다시 해석하지 않아도 된다. stdout 요약은 정상 범위를 보여 주고, stderr 원문은 실패 표면을 보여 준다. 둘이 같이 있어야 다음 패치가 작아진다.

섞이면 생기는 오해

stdout과 stderr가 섞이면 의외로 흔한 오해가 생긴다. 첫째, 경고를 실패로 읽는다. deprecation warning이나 optional dependency warning이 stderr에 찍혔을 뿐인데, 에이전트가 설정 파일을 고치기 시작하는 식이다. 둘째, wrapper 실패를 애플리케이션 실패로 읽는다. 실제 코드는 정상인데 실행 스크립트의 경로, 권한, 환경변수 때문에 종료 코드가 달라진 경우다. 셋째, 정상 출력 일부를 실패 원인으로 착각한다. 진행률 로그나 캐시 메시지가 traceback과 붙어 있으면 충분히 그럴 수 있다.

그래서 나는 재시도 요청을 할 때 “전체 로그는 아래”라고 쓰더라도, 그 위에 작은 요약 칸을 먼저 둔다. 요약 칸은 에이전트에게 정답을 주는 곳이 아니다. 어디까지가 관찰이고 어디부터가 가설인지 경계를 긋는 곳이다. 특히 exit code는 작은 숫자지만, 실패의 종류를 분류하는 첫 신호다. 이 숫자가 빠지면 에이전트는 로그의 감정적인 부분, 그러니까 가장 길고 빨간 부분에 끌리기 쉽다.

재시도 요청 문장

내가 실제로 자주 쓰는 문장은 길지 않다. 핵심은 “수정해줘”보다 “먼저 분류해줘”가 앞에 오는 것이다. 실패 직후의 첫 요청은 패치 생성보다 진단 모양을 고정하는 쪽이 안전하다.

아래 명령 결과를 exit_code / stdout / stderr 기준으로 먼저 분리해서 읽어줘.
원인 후보를 3개 이하로 줄이고, 수정이 필요하면 파일 1개 범위의 패치만 제안해줘.
stdout에 찍힌 통과 범위는 유지해야 한다.
stderr 마지막 줄만 보고 전체 리팩터링으로 넓히지 말아줘.

이 문장에서 내가 가장 중요하게 보는 부분은 “stdout에 찍힌 통과 범위는 유지”다. 실패만 보면 고칠 것이 많아 보인다. 하지만 이미 통과한 범위는 보존해야 할 기준선이다. 이 기준선을 같이 주면 에이전트가 실패 하나를 고치겠다고 지나치게 많은 코드를 바꾸는 일을 줄일 수 있다.

작은 표로 닫기

넣는 내용 막는 오해
exit code 0, 1, 2 같은 실제 종료 숫자 경고와 실패를 같은 것으로 보는 실수
stdout 정상 출력, 통과 범위, 중간 상태 이미 맞는 부분까지 다시 고치는 패치
stderr 경고, traceback, assertion 원문 요약 때문에 사라진 실패 조건
next action 분류, 제안, 좁은 수정, 중단 조건 재시도 한 번이 전체 리팩터링으로 번지는 상황

이 표를 매번 엄격하게 채우지는 않는다. 작은 오류라면 exit code와 stderr 한 줄만으로도 충분하다. 다만 같은 실패를 두 번 이상 보고 있다면, 그때부터는 표를 만드는 쪽이 빠르다. 에이전트에게 더 강하게 말하는 것보다, 실패가 어떤 통로에서 나온 신호인지 나눠 주는 편이 다음 수정의 품질을 더 안정적으로 만든다.

나는 이 습관을 들인 뒤로 “다시 해봐”라는 말을 덜 쓰게 됐다. 대신 “exit code는 1이고, stdout 기준으로 여기까지는 맞고, stderr의 이 줄부터 깨진다”라고 말한다. 문장은 조금 길어지지만 재시도는 짧아진다. 바이브코딩에서 중요한 건 에이전트를 믿지 않는 태도가 아니라, 에이전트가 믿고 좁힐 수 있는 관찰 단위를 남기는 일이다.

댓글

홈으로 돌아가기

검색 결과

"" 검색 결과입니다.