평가 기반 에이전트 개발: 감(vibes)에 의존한 프롬프트 튜닝을 멈춘 방법
프롬프트를 수정했습니다. 다음 실행 결과가 더 좋아 보였습니다. 이 수정이 정말 도움이 된 걸까요, 아니면 운이 좋았던 걸까요?
오랫동안 제 대답은 "그런 것 같습니다"였습니다. 명령어를 조금 수정하고, 파이프라인을 실행하고, 성공하는 것을 지켜본 뒤 배포했습니다. 이것이 바로 '감(vibes)에 의존하는 엔지니어링'입니다. 에이전트를 만드는 거의 모든 사람이 이렇게 합니다. 다른 방법은 너무 어렵게 느껴지기 때문입니다.
하지만 코딩 에이전트는 비결정론적(non-deterministic)입니다. 동일한 작업을 두 번 실행해도 서로 다른 결과가 나올 수 있습니다. 단 한 번의 성공적인 실행은 아무것도 알려주지 않습니다. 수정 사항이 효과가 있었던 것인지, 아니면 단순히 주사위 운이 좋았던 것인지 알 수 없습니다.
저는 머신러닝의 원칙을 적용하여 이 문제를 해결했습니다. 시스템 전체를 감싸는 평가 프레임워크(evaluation framework)를 구축했습니다.
프레임워크의 작동 방식은 다음과 같습니다:
• 대상(Target): 고정된 코드베이스. 점수를 비교 가능하게 유지하기 위해 변하지 않습니다. • 작업(Task): 프롬프트와 오라클(oracle)이 포함된 특정 벤치마크 항목. • 오라클(Oracle): 결정론적 검사. 반드시 통과해야 하는 셸(shell) 명령어입니다. • 변형(Variant): 새로운 플래너(planner)와 같이 테스트하려는 구체적인 변경 사항. • 시도(Trial): 단일 실행. 무작위성을 고려하기 위해 모든 작업을 여러 번 실행합니다.
저는 서로 다른 유형의 실패를 포착하기 위해 두 가지 방식의 스코어링을 사용합니다:
- 코드 그레이더(Code Graders, 결정론적): 테스트 통과율, 비용, 시간 및 파일 변경 사항을 확인합니다.
- LLM Judge (확률적): 별도의 고정된 모델이 사양(spec)의 품질과 구현 충실도(fidelity)를 평가합니다.
코드 그레이더는 코드가 실행되는지를 알려줍니다. Judge는 코드가 좋은지를 알려줍니다. 두 가지 모두가 필요합니다.
또한 평균값 사용을 중단했습니다. 평균(mean)은 에이전트에 대해 거짓말을 합니다. 작업이 3번 중 2번 성공하면 괜찮아 보이지만, 신뢰할 수 있는 것은 아닙니다. 대신 저는 두 가지 지표를 사용합니다:
- pass@k: 에이전트가 적어도 한 번은 성공했는가? (역량)
- pass^k: 에이전트가 매번 성공했는가? (신뢰성)
pass^k의 상승이 진정한 승리입니다. 이는 에이전트를 단순히 운 좋게 만든 것이 아니라, 일관성 있게 만들었음을 의미합니다.
시스템을 예리하게 유지하기 위해 깊은 이해가 필요한 어려운 작업들을 추가합니다. 에이전트가 실제 버그에서 실패하면, 그 실패를 영구적인 작업으로 전환합니다. 이를 통해 폐쇄 루프(closed loop)가 형성됩니다. 에이전트가 발전할수록 벤치마크는 더 어려워집니다.
이 인프라를 구축하는 데는 많은 노력이 들지만, 제가 만든 것 중 가장 레버리지가 큰(highest leverage) 작업입니다. 덕분에 "이게 더 나은 것 같다"라는 말이 "비용은 더 낮으면서 신뢰성은 20% 더 높다"라는 말로 바뀌었습니다.
코딩 에이전트는 데모를 보여주기는 쉽지만 신뢰를 얻기는 어렵습니다. 데모 단계를 넘어서고 싶다면, 반드시 측정하기로 결심해야 합니다.
Source: https://dev.to/rickjms/eval-driven-agent-development-how-i-stopped-tuning-prompts-on-vibes-1189
Optional learning community: https://t.me/GyaanSetuAi
