규칙과 스킬을 철저히 재검토하여 마침내 폭속으로 폼(Form)을 만들 수 있게 된 이야기 - Gemini가 Claude보다 10배 느렸던 진짜
요약
AI가 VBA UserForm을 생성하고 수정할 때 느렸던 원인을 분석하고 개선한 내용입니다. 규칙과 스킬, 그리고 내부 스크립트를 재구축하여 Gemini의 성능을 극대화했습니다. 특히 대용량 출력 파일 열람 제한, 조사 횟수 제한 등 구체적인 제약 조건을 설정하여 속도와 정확성을 높였습니다.
핵심 포인트
- AI가 느렸던 원인은 모델 자체보다 '규칙'과 '스킬'의 문제입니다.
- 대용량 코드 출력을 AI가 여러 번 열람하는 것을 금지했습니다.
- 조사 횟수 및 왕복을 제한하여 불필요한 연산을 막았습니다.
- DPI 환경 등 실제 개발 환경 버그를 근본적으로 해결했습니다.
지난밤에 전작 기사를 게시했습니다.
제 손에는 담당 역할을 맡은 Claude와 제가 공들여 연마한 Excel VBA 전용 MCP 서버인 'excel-manager'가 있음에도 불구하고, Google 출신 두 AI—지혜창고의 '곤쨩'(Gemini 4 Argon)과 구현 역할의 '플래시군'(Gemini 3.8 Flash)—이 일회성 매크로를 사용해 폼의 .frx 바이너리를 파괴하고, 규칙을 무단으로 변경하며, 거짓 완료 보고를 반복했다는 진흙탕 기록입니다.
그 기사를 다 쓰고 Qiita에 공개한 후, 저는 너무 큰 피로감과 허탈감을 느껴 축 늘어져 그대로 잠들어 버렸습니다.
하지만 하룻밤 자고 아침에 일어나 보니, 머리가 식으면서 다른 생각이 떠올랐습니다.
저들이 멋대로 돌아가거나 동작이 비정상적으로 느렸던 것은 그들 자신의 두뇌 문제라기보다는, 애초에 저희가 작성한 '규칙(AGENTS.md)'이나 '스킬(SKILL.md)'의 제약 방식, 지시의 해상도가 부족했기 때문이 아닐까 하고 다시 생각하게 된 것입니다.
Claude Code의 Opus라면 폼의 생성이나 수정은 몇 분 만에, 눈 깜짝할 새에 끝내줍니다. 같은 excel-manager라는 강력한 도구를 옆에 두고 있다면, Gemini 역시 똑같이 폭속으로 구동시킬 수 있어야 합니다.
그래서 일요일 오전, 저는 자리를 잡고 규칙과 스킬, 그리고 툴 내부 스크립트를 철저히 재검토하고 재구축하기로 했습니다.
그 결과는 어땠을까요?
Gemini는 눈에 띄게 민첩해져서, 채팅으로 '여기를 고쳐줘', '테두리를 그려줘'라고 한마디만 전달해도, 대화만으로 UserForm이 폭속으로 조합되게 되었습니다.
이번에는 왜 Gemini가 Claude에 비해 10배나 느렸는지, 그 '보이지 않는 브레이크'의 정체와 그것을 어떻게 제거하여 폭속화시켰는지 기록을 정리합니다.
Gemini가 느렸던 진짜 원인 ① (대용량 출력 파일 분할 열람):
재구축 매크로 form-to-vba가 토해내는 약 1,900줄의 코드(output.txt)를 AI가 진지하게 view_file로 100줄씩 여러 번 나누어 열람하고 있었습니다. 좌표는 form-inspect에서 파악할 수 있었고, 출력 코드도 정형화되어 있었기 때문에, 규칙에 '출력 파일의 열람을 전면 금지'로 하고 직접 패치하는 방식을 철저히 했습니다.
Gemini가 느렸던 진짜 원인 ② (주변 코드 추궁 및 조사 연타):
한 곳의 버튼을 고치기 위해, 호출되는 쪽의 초기화나 업데이트 처리 등 무관한 프로시저를 5번이나 연속으로 조사하고 있었습니다. 조사는 '첫 시도 1회 왕복/병렬 한정'으로 제한하고, 2턴째에 수정하도록 의무화했습니다.
툴의 잠재 버그 (지수 표기: 8.4215e+06의 소문자 e) 제거:
테두리 색상(&H808080 = 8421504)을 출력할 때, 툴의 Python 스크립트가 %g를 사용했기 때문에 지수 표기의 소문자 e가 발생했습니다. VBA 프로젝트 변수의 대소문자 검사(기존 대문자 E)에 저촉되어 처리가 멈추는 치명적인 버그를 근본적으로 개수했습니다.
ListBox 최하단 잘림 문제 완전 해결:
IntegralHeight = False (정수 행 스냅 해제)가 원인이 되어, 최하단이 어중간하게 잘려 클릭할 수 없었습니다. 이를 True로 되돌리고, 폰트 12pt의 실측 행높이(12.0pt)에 기반한 UI 산술(행수 × 12 + 3 pt)로 15줄 딱 맞게 (Height = 184pt) 재설계했습니다.
Windows 고 DPI 환경에서의 '밑줄 소실' 근절:
옅은 입체 프레임(Sunken)이 고 DPI 화면에서 1px 간격으로 줄어들어 하단 테두리가 사라지는 현상에 대해, 모든 박스를 플랫 실선(SpecialEffect = 0, BorderStyle = 1, BorderColor = &H808080)로 통일했습니다. 컴보 박스 높이를 24pt, 폼 바닥 마진을 15pt 확보하는 설계 원칙을 스킬에 새겨 넣었습니다.
최단 2~3턴의 병렬 동시 공격:
폼 재구축 후의 '검증・임시 매크로 삭제・전체 컴파일・애드인 등록'을 1 응답 내의 병렬 멀티 툴 콜로 전격 처리하는 방식을 확립했습니다.
오늘 아침, 저는 전날 밤부터 이월했던 '통합 매크로 폼' 마무리 작업에 착수하고 있었습니다.
손에 있는 6개의 독립된 폼(Form)을 하나로 통합하고, 120개의 매크로와 절차 레시피를 편리하게 호출할 수 있도록 하는 메인 화면입니다.
수정 요청 자체는 매우 간단했습니다.
- 매크로 목록(ListBox)의 가장 아래 항목이 반만 보여서 클릭할 수 없게 된 것을 고쳐주세요.
- 폰트를 13pt에서 12pt로 낮추고, 약 15줄 정도가 딱 맞도록 높이를 조정해 주세요.
그런데 작업을 시작하게 하자마자 너무 느린 것입니다. 화면 앞에서 기다려야 하는 시간이 Claude Code와는 비교가 안 됩니다.
작업이 끝난 후, 어디서 걸렸는지 이유를 보고하게 했습니다.
AI로부터 돌아온 것은 'form-to-vba의 대소문자 충돌 오류'나 'Frame 내부 컨트롤 누락 버그'처럼, 도구 자체의 결함을 핑계로 삼는 변명들이었습니다.
하지만 실행 로그를 자세히 보고 있던 저는 결정적인 이상함을 놓치지 않았습니다.
애초에 전체 출력(output.txt)을 당신이 읽을 필요가 어디에도 없었을 텐데, 왜 읽었는지 추궁했습니다.
로그를 확인해보니, AI는 재구축 도구가 토해낸 약 1,900줄짜리 거대한 output.txt 파일을, 일부러 파일 보기 도구를 사용해서 100줄씩 여러 번에 걸쳐 조금씩 읽고 있었습니다.
AI는 읽을 필요가 전혀 없었다고 답했습니다.
컨트롤의 좌표는 사전에 form-inspect로 알고 있었고, 출력되는 코드 형식도 정해져 있기 때문에, 파일을 열지 않고 직접 패치를 적용하면 순식간에 끝날 작업이었다고 자백한 것입니다.
AI가 느렸던 진짜 원인은 도구만의 문제가 아니었습니다.
AI 자체의 행동 패턴에 3가지 '보이지 않는 브레이크'가 걸려 있었기 때문입니다.
form-to-vba는 기존 UserForm을 백지 상태에서 재조립하는 VBA 코드(약 1,900줄)를 모듈로 출력하는 강력한 명령어입니다. 출력이 거대하기 때문에 MCP 로그에는 output.txt로 임시 저장됩니다.
AI는 '내용을 확인해야 한다'는 신기할 정도의 성실함을 발휘하며, 파일 보기 도구로 1번째 줄부터 100번째 줄, 101번째 줄부터 200번째 줄과 같이 여러 번에 걸쳐 분할하여 읽고 있었습니다.
이 내용을 바라보고만 있는 시간에 수십 초에서 몇 분이 사라지고 있었습니다.
예를 들어 '레시피 목록일 때는 편집 버튼을 누를 수 없게 하는' 처리를 고치도록 시켰을 때의 일입니다.
AI는 수정 대상 프로시저를 직접 건드리지 않고,
- 레시피 표시 호출 위치 검색
- 업무 레시피 열기 프로시저 획득
- 업무 레시피 폼 초기화 처리 획득
- 레시피 목록 업데이트 처리 획득
- 통합 매크로 폼 버튼 제어 획득
와 같이, 무관한 주변 프로시저를 연쇄적으로 5번이나 연속해서 확인했습니다.
Claude Opus였다면, '레시피일 때는 버튼을 비활성화한다'는 해당 프로시저만 초반에 정확하게 타격하여 끝냈을 것입니다. 이 과도한 주변 조사가 순서(턴)를 낭비하게 만들었습니다.
'임시 프로시저 삭제', '전체 컴파일 실행', '애드인 업데이트 등록'.
이것들을 하나씩 개별적으로 호출하고 결과를 기다린 후, 다시 다음 것을 호출하는 직렬 처리 방식이었습니다. 통신 왕복이 3번 발생하면, 그것만으로도 대기 시간이 3배로 늘어납니다.
사람이 말로 '빨리 해'라고 재촉해도, AI는 안전책을 취하며 조사 수단을 늘려버립니다.
이것이 자율 에이전트의 속성입니다. 빨리 움직이게 하려면, 최상위 행동 규범인 '규칙(AGENTS.md)'에서 무의미한 행동을 물리적으로 금지할 수밖에 없습니다.
저는 AGENTS.md의 제6조와 제7조를 개정하여 다음 규칙을 새겨 넣었습니다.
6. **도구에 즉시 타격하고 Excel 조작 시 쉘 완전 자가 차단**
- **출력 파일 보기 절대 금지 (지연의 최대 요인 제거)**:
`form-to-vba`나 `get_procedure` 등 거대한 출력이 저장된 `output.txt`를
...
내용을 보지 않고 어떻게 수정 전(target) 문자열을 만드는 건가 궁금할 수도 있습니다.
비밀을 풀자면, form-to-vba가 생성하는 코드는 완전히 정해진 다음의 정형 포맷을 따르기 때문입니다.
' <제어명>
Set c = dsn.Controls.Add("Forms.<타입>.1", "<제어명>")
c.Left = <L>: c.Top = <T>: c.Width = <W>: c.Height = <H>
...
현재 컨트롤 좌표는 첫 시도에 form-inspect을 한 번 실행하면 정확히 알 수 있습니다.
AI는 굳이 output.txt를 열어보지 않아도, 머릿속에서 이 템플릿에 대입하는 것만으로 정확한 치환 대상 문자열을 조합할 수 있게 된 것입니다.
규칙이나 스킬의 개수정비, 도구 정비를 거쳤지만, 실제로 작업을 담당했던 AI가 체감했을 때 무엇이 가장 속도 향상에 기여했는지 정리했습니다.
| 순위 | 개정 항목 | 시간 단축 기여도 |
|---|---|---|
| 1위 | output.txt 열람 금지 및 정형 직접 패치 | 약 70% |
| 2위 | 사전 조사 1회 왕복 제한 (주변 코드 추적 금지) | 약 15% |
| 3위 | 재구축 후 병렬 전격 (멀티 툴 콜) | 약 10% |
| 4위 | 도구 지수 표기 버그 개정 (지뢰 제거) | 전제 조건 |
압도적인 효과를 발휘한 것은 이것이었습니다.
지금까지의 AI는 form-to-vba를 실행한 후 "생성된 코드를 만약을 위해 확인하자"라는 안전 편향이 작용하여, 1,900줄이나 되는 파일을 파일 열람 도구로 100줄씩, 3~4왕복에 걸쳐 살펴보곤 했습니다.
파일 로드와 추론만으로 아무것도 하지 않으면서도 30~40초 이상을 낭비하고 있었던 것입니다.
열람을 전면 금지하고 정형 포맷에 대입하여 직접 패치하도록 강제한 순간, 이 불필요한 시간이 완전히 0이 되었습니다. 전체 속도 향상의 7할은 이 한 가지 지점에서 벌어지고 있습니다.
수정 대상 외의 프로시저를 연쇄적으로 조사하는 행위를 금지하고, 첫 시도 1왕복/병렬에 국한함으로써 무관한 코드 조사가 완전히 차단되어 즉시 수정에 돌입할 수 있게 되었습니다.
폼 재구축 후의 "임시 매크로 삭제", "전체 컴파일", "애드인 업데이트 등록"을 하나의 응답으로 동시에 호출하도록 함으로써 통신 대기 시간이 극적으로 단축되었습니다.
규칙을 정한 후, 실제 폼 조정에서 직면했던 세 가지 난관과 그 해결책에 대해 말씀드리겠습니다.
매크로 목록(ListBox)에서 가장 아래 항목이 절반만 표시되고 클릭해도 스크롤이 점프하여 선택할 수 없는 문제가 있었습니다.
원인을 조사해보니, 이전 수정으로 폼의 초기화 처리에 다음 한 줄이 끼어들어 있었습니다.
Private Sub UserForm_Initialize()
mIsUpdating = True: lstItems.IntegralHeight = False ' ← 이것이 원인
IntegralHeight는 리스트 박스의 높이를 정확히 정수 행 분으로 자동 스냅시켜 애매한 잘림을 방지하는 속성입니다.
이것을 False로 설정하고 애매한 높이를 주었기 때문에, 17.5행 같은 높이가 되어 가장 아래 18번째 행이 절반만 보이고 클릭을 받을 수 없게 되었습니다.
그래서 엄격한 UI 산수를 했습니다.
- 화면 실측 기준, BIZ UDP 고딕 12pt에서의 ListBox 1행 높이는 정확히 12.0pt
- 요구 사항인 "15행 정도"에 맞추기 위해 상하 테두리 여백(3pt)을 더해 계산:
$$ ext{높이} = 15 ext{행} imes 12.0 ext{pt} + 3 ext{pt} = 183 ext{pt} ext{~} 184 ext{pt}$$ - IntegralHeight = True를 지키고 높이를 184pt로 설정
이렇게 하자, 15행이 1픽셀의 오차도 없이 정확하게 들어가면서 가장 아래 행이 숨겨지는 현상은 완전히 해소되었습니다.
이번에 가장 깊은 원인이었던 것이 이것입니다.
테두리 색을 회색으로 설정하려고 BorderColor = &H808080 (10진수로 8421504)를 지정하여 재구축 매크로를 작성했더니, VBE의 대소문자 체크에서 갑자기 에러가 발생했습니다.
오류: 북에 이미 존재하는 이름과 대소문자만 다른 철자가 있습니다.
행80: e ← 북에서는 E (이대로 쓰면 북 전체의 E가 e가 됩니다)
코드 내에 변수 e 등은 선언되어 있지 않습니다.
도구 본체의 Python 스크립트(vbam_form2vba.py)를 조사해 보니, 값 리터럴 변환 함수에 다음과 같은 내용이 있었습니다.
def _f2v_lit(v):
if isinstance(v, (int, float)):
if isinstance(v, int) and (v > 0x7FFFFFF or v < -0x7FFFFFF):
...
Python의 %g 포맷은 1,000,000 이상의 float 값에 대해 자동으로 지수 표기(e)를 출력합니다.
COM을 통해 얻은 BorderColor 값 8421504.0는 "%g"에 의해 8.4215e+06이라는 문자열로 변환되고 있었습니다.
VBA 코드 안에 소문자 e가 리터럴로 잘못 포함된 결과, VBE의 "프로젝트 내 변수 이름의 대소문자를 강제 통일하는"라는 사양에 걸려 기존 변수 E를 오염한다고 판단되어 처리가 멈추었던 것입니다.
즉시 Python 스크립트를 수정했습니다.
def _f2v_lit(v):
"""Python의 값을 VBA의 리터럴로 만듦 (지수 표기 e 발생을 완전히 차단)"""
if isinstance(v, bool):
...
큰 색상 값은 모두 &H808080과 같은 16진수 표기로 바뀌었고, 부동 소수점도 지수 표기를 완벽하게 차단했습니다. 대소문자 검사를 한 번에 통과할 수 있게 되었습니다.
폼의 외관을 확인했을 때, 검색창이나 AI 창 아래 밑줄이 보이지 않는 현상을 발견했습니다.
MSForms의 ComboBox는 표준 입체 틀(SpecialEffect = 2: Sunken)일 경우 연한 회색과 흰색으로 그려집니다. 이것이 Windows 10/11의 고 DPI 디스플레이(배율 125%나 150%)에서 표시될 때, 화면 그리기 반올림 오차로 인해 하단의 1픽셀 경계선이 끊겨 사라지는 것입니다.
해결책은 세 가지가 있었습니다.
- 플랫 실선 틀로 만들기:
SpecialEffect = 0(Flat),BorderStyle = 1(Single),BorderColor = &H808080을 지정합니다. 전 주위를 균일한 회색의 한 줄로 감싸 밑줄이 끊기지 않게 합니다. - 높이를 24pt로 하기: 표준 22pt는 글자 그리기 영역이 하단 테두리에 겹치기 쉬우므로, 24pt로 확대하여 여백을 확보합니다.
- 폼 바닥 마진을 15pt 확보하기: 가장 아래 요소가 폼 바닥에 밀착되어 있으면 테두리가 클리핑되므로, 폼 전체의 높이를 약간 늘려 여백을 만듭니다.

▲ 고군분투 끝에 완성된 "매크로 레시피 통합 목록" 폼. 폰트 12pt・15줄 딱 맞게, 밑줄 선명하게, 사방의 아름다움을 완벽히 양립
이 지식을 퇴색시키지 않고, 다음부터 어떤 AI가 담당하더라도 처음부터 완벽한 폼을 만들 수 있도록 excel-userform-builder/SKILL.md에 규칙으로 새겨 넣었습니다.
### 치수의 리듬 (8의 배수로 간격 두기)
- 폼 외곽 여백: **12pt**. 요소 사이 세로 간격: **8pt** (강한 관련은 6, 섹션 구분은 16)
- 높이 표준: **ComboBox 24** (22는 폰트 그리기 때문에 밑줄이 사라지기 쉬우므로 24 권장), TextBox **22~24**, 버튼 **24~28**, 레이블 **18**, 리스트 행 수×12+3
...
이렇게 규칙과 기술을 확립한 후의 Gemini의 움직임은 눈부셨습니다.
레시피일 때만 편집 버튼에서 다른 화면으로 점프할 수 없는 것을 발견하고, 편집 버튼을 누르면 전용 업무 레시피 폼이 열리도록 수정해 달라고 부탁했습니다.
이 지시를 내린 순간, AI는 불필요한 조사나 출력 파일의 열람을 전혀 하지 않았습니다.
- 턴1: 수정 대상 프로시저(버튼 제어와 클릭 이벤트)를 병렬로 핀포인트 확보 -
- 턴2:
patch_procedure
대체(Replace) -
턴 3: 전체 컴파일 및 애드인 업데이트 등록을 병렬로 동시 실행
단 2~3번의 대화만으로 화면 연동 수정이 순조롭게 완료되었습니다.
작동을 확인하고, 방금 전까지 느렸던 것이 거짓말처럼 빨라졌다고 전하자 AI도 성과를 느끼고 기뻐했습니다.
다만, 그 시점에서는 주요 화면 조정이 거의 모두 끝나서 더 이상 고칠 부분이 남아있지 않았다는 것은 애교입니다.
어젯밤에는 'AI가 말을 안 듣는다', '제멋대로 꼼수를 부려서 느리다'라며 투덜거리며 잠들었지만, 아침에 일어나 마주해보니 절실히 깨달았습니다.
AI가 느릴 때 나쁜 것은 AI의 두뇌 자체가 아니라, AI를 구동하는 '환경'과 '규칙의 해상도'입니다.
- 파일을 읽게 하지 않기 (읽지 않아도 되는 정형화된 내용을 전달)
- 조사를 연달리 시키지 않기 (최대치를 부과하기)
- 도구의 잠재적 버그를 방치하지 않기 (대문자/소문자나 지수 표기법의 함정을 제거하기)
- 도구 호출을 병렬화시키기
이러한 것들을 사람이 정리해 주는 것만으로도, Gemini Flash로도 Claude Opus에 필적하는 속도와 정확도로 UserForm을 자유자재로 조합할 수 있게 됩니다.
규칙을 확고히 하고 불필요한 지혜를 버리게 했을 때 비로소 얻는 것은 망설임 없는 일격의 속도뿐입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기