'하지 마라'가 한 줄도 없는 프롬프트
· 에이전트한테 "하지 마라"고 말하길 그만두고, 애초에 못 하게 만드는 법을 배운 이야기. 사내용 디자인 리뷰 도구를 만들면서 겪은 시행착오.
TL;DR 에이전트한테 "코드 보지 마라"고 프롬프트에 박아도 봐버립니다. 보지 말라고 말하는 대신 코드 경로를 아예 안 줬더니 볼 수가 없어졌습니다. 근데 정보를 너무 빼면 또 멍청해집니다. 결국 뭘 빼고 뭘 줄지를 고르는 게 입력 설계였습니다.
한동안 제 프롬프트랑 CLAUDE.md에는 "~하지 마라"가 잔뜩 박혀 있었습니다. 정확히 몇 개였는지는 기억도 안 납니다. fullPage 스크린샷 찍지 마라, 코드 보지 마라, 매번 다른 형식으로 하지 마라... 뭔가 어긋날 때마다 한 줄씩 추가하다 보니 그렇게 됐습니다. 한 줄 추가하면 한 번은 고쳐졌습니다.
근데 박아둘수록 자꾸 샜습니다. 분명 적어놨는데 다음 세션에는 또 어겼습니다.
보지 말라는 규칙
제일 또렷하게 기억나는 건 회사에서 쓰려고 UI 디자인을 자동으로 리뷰하는 도구를 만들 때였습니다. 화면을 평가하는 evaluator 에이전트를 따로 뒀는데 얘한테 "코드는 보지 말고 화면만 보고 판단해라"고 시켰습니다.
프롬프트에 분명히 적었습니다. 그런데 코드를 봐버렸습니다. 화면이 아니라 구현을 읽고 "이건 cva로 잘 짜여 있네요" 같은 소리를 했습니다. 내가 보지 말라고 한 걸 정확히 한 겁니다.
여기서 좀 멈췄습니다. 보지 말라고 더 세게 적어야 하나 싶었습니다.
입력에서 빼기
문제는 "보지 마라"가 약해서가 아니었습니다. evaluator가 코드를 볼 수 있다는 게 문제였습니다.
에이전트가 정보를 너무 많이 아는 겁니다. 오히려 몰라야 거기에만 집중할 수 있겠구나, 싶었습니다. 그래서 보지 말라는 문장을 지우고 코드 경로를 아예 프롬프트에 안 넣었습니다. 스크린샷만 줬습니다. 볼 코드가 없으니 볼 수가 없습니다. 그랬더니 evaluator가 깔끔하게 화면만 보고 판단했습니다.
말로 막는 것보다 못 하게 만드는 게 훨씬 셌습니다. 그러고 나서 보니까 그동안 효과 봤던 것들이 죄다 같은 모양이었습니다. "공정하게 평가하라"고 부탁하는 대신 평가자를 아예 독립적으로 띄워서 편향될 입력을 안 주고, "형식 맞춰라" 대신 템플릿 하나로 고정해서 다르게 쓸 여지를 없애고. 전부 "하지 마라"를 "줄 입력에서 빼버리기"로 바꾼 거였습니다.
과하게 뺀 입력
여기서 신나서 한 걸음 더 갔습니다. 스크린샷도 통째로(fullPage) 주지 말고 섹션별로 잘라서만 주자. 디테일에 집중하라고. 정보를 더 빼면 더 좋아질 줄 알았습니다.
이건 역효과였습니다. evaluator가 섹션 하나하나는 잘 보는데 전체 그림을 못 봤습니다. 라운드를 돌면서 이미 통과한 부분이 다시 망가져도 모르고 넘어갔습니다. 일관성을 놓친 겁니다. 작업 노트에 "캡쳐 차등화로 evaluator가 일관성 놓치는 케이스 있나?"라고 적어둔 게 남아 있는데, 있었습니다.
그래서 다시 고쳤습니다. 변경된 영역은 잘라서 디테일용으로 주고, 전체 화면 한 장도 같이 줘서 일관성 보라고. 결국 "정보를 빼라"가 답이 아니었습니다. 뭘 빼고 뭘 줄지를 고르는 게 답이었습니다. 코드 경로는 빼도 괜찮았는데 전체 화면은 빼면 안 됐습니다. 그 경계를 어디에 긋느냐가 입력 설계의 진짜 일이었습니다.
프롬프트로 안 되는 것
입력을 깎아도 안 되는 영역이 있었습니다.
커밋하기 전에 타입체크랑 테스트, 린트를 한 번에 돌려서 확인하는 스크립트가 있습니다(보통 verify라고 부릅니다). 근데 린트가 warning을 뱉어도 이 스크립트가 그냥 통과시켰습니다. 통과냐 아니냐를 exit code로 판단하는데 warning은 exit 0이라 문제없음으로 치기 때문입니다. 에이전트는 warning을 보긴 보는데 "이건 작업 범위 밖이지" 하고 넘어갔습니다. 고치라고 말해도 의지에 맡기는 셈이라 안 통했습니다.
그래서 warning이면 exit 1로 막아버렸습니다. 그랬더니 커밋이 막히니까 그제야 로그를 다시 읽고 고쳤습니다. 규칙의 강도는 경고 메시지에 있는 게 아니라 exit code에 있었습니다. "고쳐라"가 아니라 "안 고치면 커밋이 안 됨"이어야 움직입니다.
나중에 찾아보니 dottxt라는 곳에서 이걸 깔끔하게 정리해뒀습니다. 모델이 "안 할 것"(will not)에 기대지 말고 "할 수 없게"(cannot) 만들라고. 질문이 "모델이 잘 행동했나?"에서 "우리가 허용 범위를 제대로 정했나?"로 바뀐다는 건데, 제가 더듬더듬 도달한 게 이거였습니다. 거기서는 토큰 단위에서 막는 거고 저는 프롬프트랑 쉘 스크립트로 한 겁니다.
잔소리 대신 환경
요즘은 하지 말아야 할 행동을 가능하면 린트 룰로 막고, 린트로 안 되면 커스텀 쉘 스크립트를 짜서 패턴에 어긋나는 걸 1차로 거릅니다.
다 풀린 건 아닙니다. 클로드의 메모리 기능을 쓰고 있는데 요즘은 영 별로라서, 쓸데없는 맥락이 끼기도 하고 정작 필요한 건 안 남기기도 합니다. 이것도 결국 "뭘 남기고 뭘 버릴지"의 문제일 텐데 입력 설계랑 똑같은 고민이라 아직 답을 못 정했습니다.
처음엔 에이전트한테 잔소리를 늘리는 일인 줄 알았는데 하다 보니 잔소리를 지우고 환경을 바꾸는 일이었습니다. "하지 마라"가 한 줄도 없는 프롬프트가 제일 말을 잘 듣는다는 게 좀 이상하죠.
그런데 이렇게 해도 피로감은 잘 안 줄어듭니다. 클로드 특징인지는 모르겠지만 진짜 똑똑한 주니어를 마이크로매니징하는 느낌입니다. 얘가 내리는 결정 하나하나를 눈으로 보고, 가이드하고. 코드 짜는 비용은 분명 싸졌는데 그만큼 에이전트를 매니징하는 비용이 더 커진 것 같습니다. 이걸 어떻게 풀면 좋을지는 아직 찾는 중입니다.
아직 댓글이 없어요.