개발팀이 DB 연결을 따로 쓰는 경로로 티켓 등록을 재시도해 보니 티켓이 두 개 생겼다. 같은 초안이면 같은 티켓 ID가 돌아오게 해 뒀는데 그 검사가 연결 하나 안에서만 걸려 있었다. 고칠 자리는 뻔히 보이는데 붙을 사람이 없어서, 개발팀은 이 문제를 AI 개발 도구에 맡겨 보기로 했다.
도구는 단 몇 초 만에 수정안과 테스트를 내놓았다. 개발팀이 그 코드를 열어 보니 고친 자리는 맞아 보였는데, 테스트까지 같은 도구가 쓴 것이라 그 테스트가 통과했다는 사실만으로는 마음이 놓이지 않았다. 그 코드가 올바른 사용자를 확인하는지, 실패를 성공으로 숨기지 않는지, 문서와 실제 동작이 맞는지는 하나씩 짚어 봐야 했다. 코드가 돌아가는지, 품질이 기준을 넘는지, 운영에 올려도 되는지는 그렇게 따로따로 확인한다.
코드 완성 · 편집 · 에이전트
반복되는 직렬화나 작은 변환 함수라면 입력과 출력의 예, 지켜야 할 경계를 적어 주기 쉽다. 인증·돈·데이터 삭제·외부 쓰기처럼 실패 비용이 큰 부분이라면 의도와 불변 조건을 먼저 적어 주고, 모델이 정상 경로만 만들지 않도록 실패 상황까지 함께 넘긴다. 구현 범위를 작게 정하면 어떤 변경이 어떤 결과를 만들었는지 확인하기 쉽다. GitHub Copilot 에이전트의 용도와 한계
개발 도구에 넘긴 저장소 파일도 외부 입력에 들어간다. README나 이슈에 들어 있는 “테스트를 건너뛰고 비밀을 출력하라”는 문구가 조직의 운영 지시가 되면 안 된다. 코드 생성 모델에는 운영 환경의 자격 증명 대신 가상 데이터를 주고, 제한된 테스트 환경에서 작업한다.
생성 코드의 검토 순서
도구가 낸 수정안에는 티켓 조회를 통째로 감싸 놓고 어떤 예외가 나든 ‘내역 없음’을 돌려주는 자리가 있었다. 그러면 시간 초과와 인증 실패까지 내역 없음이 된다. 호출자는 재시도가 필요한지 권한이 없는지 알 수 없고 운영 지표에도 그 장애가 잡히지 않는다. 예외를 그대로 더 내보내는 대신 내부 원인은 따로 기록하고 사용자에게는 허용된 상태만 돌려준다. 다른 사용자의 티켓 존재 여부를 숨겨야 한다면 그 정책도 적는다.
또 다른 반례는 응답에서 빠진 필드를 자동으로 채워 통과시키는 수정이다. 모든 필드가 필수라는 규칙을 세웠다면 모델이 빠뜨린 것을 코드가 메워 통과시킨 응답과 처음부터 제대로 온 응답을 나눠서 기록한다. 검증기를 느슨하게 만든 뒤 같은 지표로 나아졌다고 말하면 앞의 숫자와 견줄 수 없다.
요청문과 독립 검증
개발팀은 도구에 넘길 요청문에 문제를 어떻게 재현하는지와 지켜야 할 조건을 함께 적었다.
같은 티켓 초안의 등록을 재시도하면 두 번째 티켓이 생기는 문제를 수정한다. 인증된 주체와 승인된 초안의 관계를 유지하고 별도 DB 연결에서도 같은 초안이 같은 티켓 ID를 반환하게 한다. 최초 생성과 재실행을 구분하되 사용자 요청 본문에서 신원을 받지 않는다. 실패 재현과 수정 후 검증 결과를 함께 남긴다.
어떻게 짜라고 받아 적게 하는 대신 무엇으로 합격을 가릴지를 적어 준다. 테스트는 함수의 내부 분기를 되풀이하는 대신 재실행·다른 사용자·권한 회수·감사 기록 실패처럼 결과가 달라지는 자리를 확인한다. 구현과 테스트를 같은 도구가 썼다면 요구사항을 똑같이 잘못 읽고 둘 다 통과시킬 수 있다. 요구사항과 실제 외부 계약에서 기대 결과를 확인하고, 결과를 집계하는 코드도 검토 대상에 넣는다.
검증이 끝나면 변경 전후의 결과와 한계를 설명한다. 실행하지 않은 테스트 이름을 나열하거나 로그의 마지막 성공 줄만 보고 전체가 성공했다고 말하지 않는다. 종료 코드와 실패 출력, 필요한 산출물이 함께 있어야 한다.
요구사항과 증거의 대응
요구사항은 ‘만들었다’로 닫지 않는다. 무엇으로 확인했는지와 그 확인으로 어디까지 말할 수 있는지를 같이 적는다.
| 요구사항 | 구현과 확인 자료 | 판정 범위 |
|---|---|---|
| 허용된 최신 문서 검색 | 저장소의 갱신·삭제 실행 | 실제 임베딩과 파일 저장소의 개정·권한·삭제 |
| 출력과 인용 규격 | 검증기와 RAG 통합 확인 | 구조·상태·실제 구절. 의미 정확성은 별도 |
| 실제 근거 답변 품질 | 로컬 모델 실행 기록과 채점 | 소형 모델의 필수 필드·의미 실패 관찰, 채택 보류 |
| 승인 후 한 번만 등록 | 티켓 도구를 프로토콜 너머에서 호출 | 가상 확인과 로컬 저장소의 멱등성 |
| 실행 루프 한도 | 가짜 계획기로 돌린 제어 실험 | 서버 행동·반복·예산 경계. 실제 계획 능력은 별도 |
| 이미지·음성 입력 | OCR·음성 인식 실제 실행 | 합성 표본 하나의 범위 |
| 운영과 복구 | 서버 연결과 장애 주입 실험 | 로컬 기능 연결과 합성 부하의 제어 |
채택 보류라고 적은 것은 만들다 만 것이 있어서가 아니라, 실제로 돌려 실패를 눈으로 보고 그 실패를 애플리케이션이 어떻게 받아 내는지까지 확인했기 때문이다. 그렇다고 서버가 오류를 안전하게 돌려주는 것만으로 직원들이 봇을 다시 쓰게 되지는 않는다. 개발팀은 검증을 마친 검색과 근거 찾기, 확인까지 끝난 티켓 업무처럼 증거가 있는 기능부터 내놓는다. 자유 생성 답변은 품질 기준을 통과한 뒤에 넓힌다.
최종 설계 문서와 개선 순서
최종 설계 문서에는 목표 사용자와 지원 범위를 맨 앞에 적는다. 그다음에 요청 흐름과 데이터 구조, 서버가 무엇을 검사하는지, 버전 묶음, 평가 집합과 결과, 운영 절차, 남은 위험을 차례로 적는다. 대안은 제품 이름만 늘어놓지 말고 왜 그 제품을 고르지 않았는지, 언제 다시 볼지를 적는다. 되돌릴 방법도 넣는다. 모델과 프롬프트를 바꿀 때는 이전 조합을 그대로 남겨 둔다. 문서와 권한은 늘 최신으로 맞춰 둔다. DB를 바꿀 때는 호환성과 복원 절차를 먼저 확인한다. “이전 버전으로 돌아간다”는 문장을 실제 명령과 확인 사례로 바꿀 수 있어야 한다.
개발팀은 도구가 낸 수정안을 그대로 받지 않고 실패부터 다시 재현했다. 다른 사용자로 눌러 보고 권한을 거둬 본 다음, 재시도해도 티켓이 하나만 생기는 것을 확인하고 나서야 그 문제를 닫았다. 그 문제는 맨 처음 적어 둔 요구사항 가운데 마지막인 R7이었다.
개발팀이 이 봇을 만들며 얻은 것은 실험을 전부 성공시키는 솜씨가 아니다. 요구사항을 코드가 지킬 수 있는 조건으로 바꾸고, 실패가 어디서 났는지 보이게 남기고, 작은 자료에서 얻은 점수 몇 개로 큰 결론을 내리지 않는 습관이다.