에이전트가 스스로를 개선하는 날, 4회 크래시 끝에 수료증 QA 통과

26년 06월 18일

bash timeout이 8.3시간이 될 수 있다

이날은 에이전트가 스스로를 개선한 날이다.

내가 쓰는 코딩 에이전트의 확장을 7종 새로 짜고 다른 플랫폼에서 스킬 20개를 포팅했다.

그러는 사이 회사 프로젝트는 모델 장애로 4번 크래시 났다가 마지막에 통과했다.

가장 인상적인 발견은 bash timeout의 단위였다.

에이전트가 bash 명령을 실행할 때 timeout이 있다.

기본 30초다.

근데 timeout 단위가 초다.

30000을 넣으면 30000초, 즉 8.3시간이 된다.

밀리초라고 생각하고 30000을 넣으면, 안전망이 8.3시간이 된다.

안전망이 무력화되는 거다.

명령이 멈춰도 8.3시간을 기다려야 한다.

이걸 발견하고 확장을 만들었다.

매 턴마다 시스템 프롬프트로 단위를 교육하고 도구 호출에서 빈 timeout에 30을 주입한다.

이중 방어다.

설정 키가 있다고 동작하는 건 아니다

또 하나 중요한 발견이 있었다.

설정에 bash 차단 설정이라는 키가 있었다.

bash 사용을 막는 키인 줄 알았다.

근데 아무 확장도 이 키를 안 읽고 있었다.

설정 키가 있다고 동작하는 건 아니다.

누군가 소비해야 한다.

설정 키가 존재하면 동작한다고 가정하면, 안전망이 없는 상태로 돌아가는 거다.

“설정이 있으니까 되겠지”가 아니라, “누가 이 설정을 읽고 있나”를 확인해야 한다.

스킬 20개 포팅

다른 플랫폼에서 쓰던 스킬을 내 에이전트로 포팅했다.

노션, 피그마, 지라 분석 스킬 14개를 벌크로 옮겼다.

깃 커밋, PR 리뷰, 스킬 생성 스킬도 만들었다.

포팅하면서 일관된 원칙을 발견했다.

스킬 매칭은 시맨틱하게 된다.

키워드가 아니라 의미로 매칭된다.

그러니까 description에 “언제 쓸지”를 적어야 한다.

본문은 매칭에 안 참여한다.

description만 참여한다.

그리고 환경 차이를 매핑해야 한다.

명령어 위치, 스킬 구조, 파일 경로 규칙이 플랫폼마다 다르다.

이 차이를 하나씩 매핑해서 변환했다.

수료증 4회 크래시

회사 프로젝트에서 수료증 기능을 만들고 있었다.

근데 4번이나 크래시가 났다.

처음 세 번은 같은 원인이었다.

분석 에이전트 4개를 병렬로 돌리는데, 전부 같은 모델을 썼다.

그 모델이 일시적으로 429 에러를 냈다.

4개가 동시에 실패한 거다.

이때 “모델 설정이 잘못됐나”라고 오진했다.

모델을 바꿔보려고 했다.

근데 원인은 일시적 환경 장애였다.

잠시 후 자가 복구됐다.

같은 모델 쓰는 에이전트가 동시에 실패하면

핵심 교훈은 이거다.

같은 모델을 쓰는 에이전트 여러 개가 동시에 실패하면, 설정 문제가 아니라 환경 신호다.

설정이 잘못됐으면 처음부터 안 됐을 거다.

갑자기 동시에 실패하면, 모델 서버가 일시적으로 장애난 거다.

이걸 구분하지 못하면 설정을 만지느라 시간을 낭비한다.

“잠시 기다려 보자”가 먼저다.

네 번째 시도에서는 유일하게 끝까지 갔다.

QA에서 몇 가지 실패가 나왔지만 수정해서 최종 13개 전부 통과했다.

토스증권 CLI 새 프로젝트

틈틈이 새 프로젝트도 시작했다.

토스증권 Open API를 감싸는 TypeScript CLI다.

이전에 만든 한국투자증권 CLI의 컨벤션을 그대로 썼다.

OAuth 인증, 속도 제한 버킷, Zod 스키마까지. 빌드랑 테스트 전부 통과했다.

마무리

이날의 핵심은 “에이전트가 스스로를 개선했다”는 거다.

bash timeout 함정을 발견하고 확장을 만들었다.

설정 키가 동작하지 않는 걸 발견하고 확인 습관을 정립했다.

스킬 20개를 포팅하면서 환경 매핑 원칙을 세웠다.

그리고 수료증 4회 크래시에서 “같은 모델 동시 실패는 환경 신호”라는 교훈을 얻었다.

이건 일반적인 원칙이다.

같은 의존성을 가진 컴포넌트들이 동시에 실패하면, 의존성 자체의 문제다.

개별 컴포넌트의 문제가 아니다.

자가 개선은 이런 식으로 일어난다.

함정을 발견하고 확장으로 막고 원칙으로 일반화한다.

다음에 같은 함정을 만나면, 이미 막혀 있다.