이 글에 대해
프롬프트를 사람이 다듬는 대신 모델에게 작성하게 하는 방식을 메타 프롬프팅이라 부른다. 요즘 자주 언급되지만, 정작 본인 환경에서 얼마나 이득인지는 확인해 본 적이 없었다.
도입을 판단하려면 두 가지가 필요했다. 얼마나 좋아지는지, 그리고 얼마를 더 내야 하는지다.
그래서 실제 코드베이스에 적용해 측정했다. 회의록 앱에 같은 목표를 열여섯 번 주고, 절반은 직접 쓴 한 줄로 나머지 절반은 모델이 생성한 프롬프트로 실행한 뒤 결과물을 라벨 없이 채점하게 했다.
중간에 결론을 세 번 수정했다. 처음 네 번을 실행하고 "비용만 쓰고 이득이 없다"고 정리할 참이었는데, 표본을 늘리자 그 판단이 유지되지 않았다.
§1공개된 측정치부터 확인했다
먼저 남들이 발표한 수치를 모았다. 결과가 한 방향으로 모였다면 그대로 따르면 될 일이었다.
Suzgun과 Kalai의 메타 프롬프팅 논문은 GPT-4에서 standard prompting 대비 17.1% 향상을 보고한다. OPRO는 모델이 스스로 프롬프트를 최적화해 GSM8K 정확도를 71.8%에서 80.2%까지 끌어올렸고, GEPA는 강화학습 기반 방식보다 rollout을 678회 대 24,000회로 35배 적게 쓰고도 더 나은 결과를 냈다고 적었다.
여기까지만 보면 도입하지 않을 이유가 없다.
그런데 반대편 자료는 결이 달랐다. 다목적 프롬프트 최적화의 실패를 분석한 연구를 보면 10개 설정 중 6개에서 최적화 이전의 generic 프롬프트가 최고 성능이었다. "The Prompting Inversion" 연구는 더 직접적이어서, GPT-4o에서 성능을 올리던 복잡한 프롬프트가 GPT-5에서는 오히려 성능을 떨어뜨렸다고 관측했다.
17.1% 향상과 "안 하느니만 못하다"가 같은 기법에 대한 보고인 셈이다. 어느 쪽이 본인 환경에 해당할지는 공개된 수치만 봐서는 알 수 없었다.
§2측정 설계
대상은 본인이 만드는 macOS 회의록 앱이다. 음성을 한국어로 전사하고 회의록을 생성하는 파이프라인이 들어 있다.
목표는 열여섯 번 모두 동일하게 두고 프롬프팅 방식만 바꿨다.
사용자 프롬프트 조건은 실무에서 그냥 던질 법한 한 줄이다. 길이는 47자.
record-up 프로젝트에서 한국어 전사 및 회의록 생성 관련 성능을 고도화해줘.
메타 프롬프트 조건은 한 단계를 더 거친다. 같은 목표를 주면서 "이걸 코딩 에이전트에게 시킬 프롬프트를 작성하라"고 먼저 지시하고, 그 결과물을 실행 프롬프트로 사용했다. 실행마다 새로 생성했으므로 서로 다른 프롬프트가 여덟 개 나왔다.
조건당 여덟 번, 모두 같은 커밋에서 만든 별도 worktree에서 실행해 서로의 작업 트리를 침범하지 않게 했다.
메타 프롬프팅 실험의 구조. 같은 목표 한 줄이 두 갈래로 나뉘어, 위쪽은 그대로 여덟 개의 worktree에 전달되고 아래쪽은 프롬프트 생성 단계를 매번 새로 거쳐 평균 5,456자로 부풀려진 뒤 여덟 개의 worktree에 전달된다. 열여섯 개 결과물은 라벨이 제거된 채 3라운드 blind 채점으로 들어간다
같은 작업을 두 방식으로 실행할 때 무엇을 통제할까
처음에는 순차 실행으로 설계했다. 시간을 공정하게 비교하려던 것인데, 같은 47자를 받은 두 실행이 653초와 1,124초로 갈리는 것을 보고 접었다. 조건 내에서 1.7배씩 튀는 지표는 조건 간 비교에 쓸 수 없다.
이 시점에 이미 신호가 있었지만 그냥 넘어갔다.
§3모델이 생성한 프롬프트를 뜯어보니
여덟 개의 메타 프롬프트는 전부 같은 지시문 621자에서 나왔는데, 결과물은 4,466자에서 6,122자까지 흩어졌다.
읽어보고 눈에 띈 것은 골격이 거의 같다는 점이었다. 절 제목은 제각각인데 순서가 다섯 단계로 수렴한다. 성능을 무엇으로 볼지 정의하고, 측정을 강제하는 규칙을 세우고, 조사 후보를 나열하고, 제약을 걸고, 마지막에 보고 형식을 지정하는 순서다.
특히 판정 기준을 세우는 문장은 표현만 다를 뿐 거의 모든 프롬프트에 들어 있었다.
숫자로 증명되지 않은 변경은 채택하지 않는다.
측정 없는 변경 금지.
47자짜리 사용자 프롬프트에는 이런 항목이 하나도 없다. 모델이 스스로 채워 넣은 것이다.
채우는 내용은 왜 흩어지나
골격이 같다고 내용까지 같지는 않았다. 항목별로 몇 개에 들어갔는지 집계해 봤다.
메타 프롬프트 여덟 개의 구성 요소를 항목별로 표시한 격자. 커밋 금지와 산출물 위치 지정은 여덟 개 중 일곱 개에 들어갔고, 보고 형식은 네 개, 함정 경고는 세 개, 실험 예산 상한은 두 개에만 들어갔다. 코드베이스 파일 경로 인용은 여섯 개, 라인 번호까지 인용한 것은 네 개다
"커밋하지 말 것"은 여덟 개 중 일곱 개에 들어갔다. 이유는 단순하다. 이 저장소에는 에이전트가 읽는 규칙 파일이 있고, 거기에 이미 이렇게 적혀 있다.
작업 완료 후 절대로 자동으로 커밋하지 않는다. 사용자가 명시적으로 요청한 경우에만 커밋한다.
프롬프트를 생성하는 모델이 이 파일을 읽고 그대로 옮기기만 하면 되는 항목이었다.
반대로 "실험을 몇 개까지 하고 멈출지"는 저장소 어디에도 적혀 있지 않다. 모델이 스스로 판단해서 넣어야 하는데, 그 판단은 여덟 번 중 두 번만 나왔다.
실험 횟수는 최대 6개로 제한하고, 이득 없는 변경은 즉시 되돌린다.
이 한 줄이 들어간 프롬프트는 여덟 중 둘이다. 나중에 이 항목을 두고 한참 헛다리를 짚게 된다.
조사 깊이도 제각각이었다. 두 개는 파일 경로를 하나도 인용하지 않고 일반론으로만 작성했고, 다른 두 개는 라인 번호까지 일곱 개씩 인용했다. 한 개는 생성한 프롬프트 안에 로컬 절대 경로를 그대로 넣어서, 그 머신에서만 유효한 프롬프트가 됐다.
§4네 번 실행하고 결론을 낼 뻔했다
처음에는 조건당 두 번씩, 네 번만 실행했다. 결과는 이랬다.
| 조건당 두 번 시점 | 사용자 프롬프트 | 메타 프롬프트 |
|---|---|---|
| 시간 | 889초 | 5,205초 (5.9배) |
| 비용 | $5.16 | $14.36 (2.8배) |
| 품질 점수 | 18.83 | 19.17 (+1.8%) |
시간을 여섯 배 쓰고 비용을 세 배 가까이 냈는데 품질은 1.8% 올랐다. 이 표만 보면 판단이 명확하다. 도입할 이유가 없다.
여기서 멈췄으면 그런 글을 썼을 것이다.
걸린 것은 다른 지점이었다. 같은 47자를 받은 두 실행이 시간 1.7배, 비용 1.5배, 코드량 1.8배로 갈렸다. 조건을 나누기도 전에 같은 조건 안에서 이미 흔들리고 있었다. 1.8%라는 차이를 주장하려면 이 흔들림보다 커야 하는데, 그럴 리가 없어 보였다.
그래서 조건당 여덟 개로 늘렸다.
§5무너진 가설들
여덟 번으로 늘리자 두 번씩 돌렸을 때 세운 설명이 하나씩 깨졌다.
표본을 두 개에서 여덟 개로 늘렸을 때 세 가지 가설이 어떻게 무너졌는지 보여주는 대조. 비용 격차는 5.9배와 2.8배에서 2.6배와 1.5배로 줄었고, 예산 상한이 발산을 만든다는 설명은 상한이 있는 실행이 더 오래 걸린 사례가 나오며 뒤집혔고, 결함 발견이 메타 조건의 우위라는 관찰은 네 실행 모두가 같은 결함에 도달했다는 사실로 부정됐다
첫째, 과장이었던 비용 격차
두 번씩 돌렸을 때의 5.9배와 2.8배는 여덟 번으로 늘리자 2.6배와 1.5배로 줄었다. 초기 두 표본이 우연히 양극단에 있었던 것이다.
지금은 두 조건의 비용 구간이 $12.23에서 $16.47 사이에서 겹친다. 어느 실행이 더 비쌀지 조건만 보고는 예측할 수 없다.
둘째, 헛다리였던 예산 상한
초기 네 번 중 상한 없는 프롬프트를 받은 실행이 두 시간을 넘겼다. 그 결과를 보고 "예산 제약 누락이 발산을 만든다"고 정리했는데, 당시에는 꽤 그럴듯한 설명이라고 생각했다.
표본을 늘리니 방향이 반대인 쌍이 나왔다. 상한이 있던 실행이 4,988초, 없던 실행이 1,361초다. 프롬프트 길이가 72자밖에 차이 나지 않는데(5,736자와 5,664자) 실행 시간이 6배 갈린 쌍도 있었다.
프롬프트를 아무리 정교하게 작성해도 그 실행이 얼마나 걸릴지는 프롬프트에서 읽히지 않는다. 길이도, 조사 깊이도, 예산 상한 유무도 예측력이 없었다.
셋째, 결함을 먼저 찾은 쪽은 어디였나
이번 작업에서 가장 큰 결함은 화자 분리 결과가 통째로 버려지던 문제였다. 처음에는 메타 조건이 찾아낸 성과로 봤다. 정교한 프롬프트가 결함을 짚어냈다는 설명이 자연스러웠기 때문이다.
diff를 끝까지 읽어보니 아니었다. 47자만 받은 쪽도 원인을 정확히 짚어 주석으로 남겨두고 있었다.
// outer 배열은 화자 경계가 아니라 TranscriptionResult(= VAD 청크) 단위다.
// 청크를 통째로 한 블록으로 접으면 청크 첫 화자가 나머지 발화를 모두 삼켜
// 화자 분리 결과가 사라진다.메타 프롬프트가 "이 함정을 조심하라"고 미리 알려준 항목조차, 아무 안내 없이 시작한 쪽이 작업 도중에 스스로 찾아냈다. 차이는 지식의 유무가 아니라 거기 도달하는 경로에 있었다.
측정 도구에서 반복한 같은 실수
사용자 조건에 60분, 메타 조건에 150분 상한을 설정했다. 60분이라는 값은 초기 표본 두 개가 11분과 19분에 끝난 것을 보고 정한 것이다.
한 실행이 그 상한에 걸려 잘렸고, 150분으로 다시 실행하니 47분에 정상 종료했다. 편차 큰 표본 두 개에서 뽑은 관찰로 상한을 정했다가 빗나갔다. 이 글이 다루는 주제와 정확히 같은 실수를 실험 설계에서 저지른 셈이다.
§6여덟 개로 늘린 뒤의 결과
blind 채점은 열여섯 개 diff에서 조건 라벨을 제거하고 A부터 P로 섞은 뒤 채점자에게 넘기는 방식이다. 목표 부합도, 근거, 범위 적절성, 회귀 위험, 검증 가능성 다섯 항목을 각 5점씩, 합계 25점으로 매기게 했다. 라운드마다 배치를 다르게 섞어 세 번 실행했다.
| 평균 | 범위 | 표준편차 | |
|---|---|---|---|
| 사용자 프롬프트 (여덟 번) | 17.67 | 16.33~20.33 | 1.34 |
| 메타 프롬프트 (여덟 번) | 19.29 | 15.67~23.00 | 2.62 |
메타 조건이 9.2% 높다. 두 번씩 돌렸을 때의 1.8%보다 커졌고, 여덟 번씩 실행한 결과라 우연으로 보기는 어렵다. 상위 세 자리도 전부 메타가 차지했다.
그런데 같은 표에 다른 이야기가 들어 있다.
blind 채점 점수를 25점 만점 축에 실행별로 늘어놓은 도트 플롯. 사용자 프롬프트 여덟 실행은 16.33에서 20.33 사이 4.00점 폭에 모여 있는데, 메타 프롬프트 여덟 실행은 15.67에서 23.00까지 7.33점 폭으로 흩어져 있다. 두 조건의 평균은 17.67과 19.29로 1.62점 차이라, 조건 간 차이가 메타 조건 내부의 편차 안에 들어간다
최하위 15.67점도 메타 조건이다. 1위와 꼴찌를 같은 조건이 동시에 차지했고, 표준편차는 사용자 조건의 두 배에 가깝다. 조건 간 차이가 1.62점인데 메타 조건 내부의 폭은 7.33점이다.
운영에서는 평균보다 이 편차가 더 문제다. 메타 프롬프팅은 평균을 올리는 대신 결과를 예측하기 어렵게 만들었다. 한 번 실행해서 나온 결과가 평균 근처에 있으리라 기대할 근거가 약해졌다는 뜻이다.
§7조건을 가른 지표는 따로 있었다
이 측정에서 가장 실용적인 발견은 시간도 비용도 아니었다.
사용자 프롬프트 중앙값을 100퍼센트 기준으로 둔 메타 프롬프트의 상대 투입. 소요 시간은 263퍼센트, 비용은 148퍼센트, 추가한 코드는 186퍼센트로 늘었지만 삭제한 줄은 48퍼센트로 절반 아래로 줄었다. 프롬프트 길이는 47자에서 중앙값 5,700자로 121배가 되었다
삭제한 줄 수다. 메타 조건은 코드를 1.9배 더 추가하면서 기존 코드는 절반만 건드렸다.
시간과 비용은 실행마다 흩어져서 조건을 가르지 못했는데, 이 지표만 여덟 개 전부에서 일관되게 나왔다. 생성된 프롬프트마다 들어 있던 "최소 변경", "기존 동작을 바꾸지 말 것" 같은 제약이 실제로 작동한 결과로 보인다.
채점 결과와도 맞아떨어진다. 회귀 위험 항목에서 메타 상위권이 4.00을 받았고 검증 가능성에서는 5.00 만점이 나왔다.
다만 범위 적절성이 2.67까지 떨어진 실행도 있었다. 측정 코드를 새로 작성해 검증 가능성 점수는 얻었는데, 그 코드를 임시 디렉터리가 아니라 앱 소스 트리에 남기는 바람에 범위 점수를 잃은 경우다.
§8도입 여부
도입하되 작업을 가려서 쓰기로 했다.
품질은 9.2% 올랐고 시간은 2.6배, 비용은 1.5배 들었다. 이 정도 교환이라면 작업의 성격이 결정할 문제다.
레거시가 많거나 건드리면 안 되는 코드가 섞인 곳이라면 값을 할 것으로 본다. 삭제 줄이 절반이라는 결과가 여덟 번 전부에서 일관됐고, 그 제약을 사람이 매번 프롬프트에 적어 넣는 것보다 모델에게 맡기는 편이 싸게 먹힌다.
반대로 빠른 탐색이 목적이라면 2.6배 시간을 낼 이유가 없다. 편차가 두 배라는 점도 걸린다. 한 번 실행해서 결과를 받아야 하는 상황에는 맞지 않는다.
한 가지는 표본을 늘려도 그대로였다. 조건 간 차이보다 조건 내 편차가 컸다는 것이다. 두 번씩일 때 0.33 대 4.33이었고 여덟 번으로 늘리니 1.62 대 7.33이 됐다. 비율로는 오히려 벌어졌다.
그래서 운영 규칙을 하나 정했다. 메타 프롬프팅을 쓰는 작업은 결과를 한 번에 받지 않고 두 번 실행해서 고른다. 편차가 두 배라면 첫 실행이 하위권에 걸릴 확률도 그만큼 크다. 비용은 사용자 프롬프트 대비 3배가 되지만, 품질 최하위를 뽑을 위험을 줄이는 값으로는 낼 만하다고 봤다.
측정 과정에서 배운 것이 하나 더 있다. 두 번 실행하고 낸 판단 세 개가 전부 틀렸는데, 그중 둘에는 그럴듯한 인과 설명까지 붙어 있었다. 예산 상한이 발산을 만든다는 설명도, 정교한 프롬프트라 결함을 찾아냈다는 설명도 데이터가 여섯 개 더 쌓이자 무너졌다.
표본이 적을 때 위험한 건 데이터가 부족하다는 사실이 아니라, 그 부족한 데이터에 설명이 잘 붙는다는 점이다. 이후로 벤치마크 수치를 볼 때 향상률보다 실행 횟수를 먼저 찾아보게 됐다.