본문으로 건너뛰기
█ █  ▄▀█  ▀█  ▀█  ▀█  █
█▀█  █▀█  █▄  █▄  █▄  █
⚡ no css · no framework · no problem ⚡

에이전트한테 '하지 마라'고 말하기를 그만둔다

· 에이전트한테 "하지 마라"고 말하길 그만두고, 애초에 못 하게 만드는 법을 배운 이야기. 사내용 디자인 리뷰 도구를 만들면서 겪은 시행착오.


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차로 거릅니다.

다 풀린 건 아닙니다. 클로드의 메모리 기능을 사용하고 있는데, 이건 요즘 영 별로인 것 같기도 하고. 쓸데없는 맥락이 끼기도 하고, 정작 필요한 건 안 남기기도 하고요. 이것도 결국 "뭘 남기고 뭘 버릴지"의 문제일 텐데, 입력 설계랑 똑같은 고민이라 아직 답을 못 정했습니다.

처음엔 에이전트한테 잔소리를 늘리는 일인 줄 알았는데, 하다 보니 잔소리를 지우고 환경을 바꾸는 일이더라고요. "하지 마라"가 한 줄도 없는 프롬프트가 제일 말을 잘 듣는다는 게 좀 이상하죠.

그런데 이렇게 해도 피로감은 잘 안 줄어듭니다. 클로드 특징인진 모르겠지만, 진짜 똑똑한 주니어를 마이크로매니징하는 느낌이거든요. 얘가 내리는 결정 하나하나를 눈으로 보고, 가이드하고, 지시하고. 코드 짜는 비용은 분명 싸졌는데, 그만큼 에이전트를 매니징하는 비용이 더 커진 것 같습니다. 이걸 어떻게 풀면 좋을지는 아직 찾는 중입니다.


댓글 0개

아직 댓글이 없어요.

GitHub에서 댓글 남기기 · GitHub 계정으로 로그인 후 이슈에 코멘트를 남기면 여기에 표시돼요.