Python Markdown 이미지 캡션 부작용 해결: Antigravity CLI에게 처음으로 일을 맡겨봤다
앞서 Python Markdown으로 HTML 출력 시 이미지 캡션을 덧붙여주기 작업을 한 뒤 여러 테스트를 해보다 코드 블록 내의 내용들도 영향을 받는 문제를 발견해서 어떻게든 해결을 해야 할 처지가 되었다. 하지만 상당히 골치 아픈 일이 될 것 같은 느낌이 들어서 선뜻 손을 못 대고 있었다.
그러다 갑자기 그게(?) 떠올랐다. 마침 Antigravity CLI를 시험해 볼 좋은 찬스 아닌가? 한번 골려(?) 봐야겠지?
Antigravity CLI의 첫 업무
터미널에서 문제가 생긴 해당 프로젝트 디렉터리로 이동한 후 agy를 입력했다. 그리고 아래와 같은 식으로 프롬프트를 입력했다.
안녕.
여긴 개인적으로 쓰는 마크다운 문서를 자동으로 HTML로 출력하고
블로그 사이트 형태로 구성하는 파이썬으로 만든 프로젝트야.
여기서 some.py라는 파일 안의 A, B, C라는 세 가지 함수가 있는데
이게 마크다운의 코드 블록 안의 내용은 건드리지 않도록
바꾸고 싶어.
Gemini CLI에서의 경험을 생각해 보면 같은 구글에서 나온 거니 비슷하게 '일단 되든 안 되든 코드를 만들어서 돌려보면서 시행착오를 계속 겪으며 일을 진행'하지 않을까 예상했다.
그런데 Antigravity CLI는... 그러니까... 음...
"아악 X나 느리다!"
다른 건 아무 생각도 안 나고 이 느낌만 강하게 들었다.
디렉터리를 탐색한다고 수 분을 기다리고, 갑자기 다른 디렉터리를 탐색한다고 수 분을 기다렸다. 그러다 프로젝트 디렉터리 루트가 아니라며 루트를 탐색하기 시작했고 또 수 분이 지났다. 이 준비에만 15분 가까이 걸렸다.
이 정도 상황이라면 이런 생각은 당연히 들 수밖에 없을 것 같다.
뭐 하여간 Gemini CLI와 특이하게 다른 점은 Antigravity CLI는 뭔가 어떤 액션을 취하려 할 때마다 5분 이상의 뭔가를 하는데 뭘 하는지 도무지 모르겠다는 특징이 있는 것 같았다.
그래도 진척이 없는 건 아니었다.
혹시 온디바이스로 굴리나 하는 생각이 들려는 찰나 드디어 뭔가 진전이 보였다. 문제의 파일을 테스트할 유닛테스트 모듈을 만들고 싶다고 물어오는 것이었다.
다만 내용을 바로 보여주지 않았다는 건 Gemini CLI와는 약간 다르긴 했다.
하여간 진행을 위해서는 당연히 동의할 수밖에 없다. 어차피 코드는 Git으로 보호(?)되고 있긴 하니 최악의 경우 망가뜨려도 별 문제는 아마 없을 거다.
이후 Antigravity CLI는 코드를 수정하거나 새로 만들어야 할 일이 있을 때만 별 다른 대화 없이 그저 '할까 말까?'를 물어왔다. 대략 20분간 대화 없이 이런 선택에 대답만 했다. '참 시크한 새로 입사한 경력직'과 업무 상 대화하는 기분이 이런 걸까?
어쨌든 이후로도 뭔가 답답한 상태가 이어졌다. 짧은 유닛테스트 한번 돌리는 것도 수 분씩 기다려야 했다.
혹시나 서버에 문제가 있는 걸까? 아니면 일부러 속도에 제한을 건 상태인 걸까? 다양한 생각이 들었다.
그래도 시간이 지나니 왠지 분위기가 바뀌는 것 같다는 느낌적인 느낌이 들 것 같은 이상한 기분이 들 것 같...
그래서 제대로 처리했을까?
대략 30분이 걸리지 않았을 즈음, 갑자기 코드가 화면에 후루룩 흘러갔다. 뭐야 에러야? 그랬더니 곧이어 다 끝났다는 멘트가 떴다.
긴가민가하며 따로 실행해 봤다.
"헉! 시X!"
입에서 긍정의 욕이 튀어나왔다.
기대와 다르게 정말 문제를 완벽하게 해결해 버렸다. 분명 Gemini CLI는 자기가 다 했다는 걸 돌려보면 실제론 에러가 나거나 다른 문제를 만들던 것과 비교하면 정말 한 번에 완벽에 가깝게 해결해 버린 느낌이다. 프롬프트는 정말 딱 한 번만 입력했으니 말이다. 물론 비교하기엔 그렇게 많이 써 본 건 아니지만 말이다.
일도 제대로 한다는 느낌을 받았다. 기능 개선 하나를 부탁했더니 테스트 코드부터 만드는 게 확실히 나보다는 제대로 처리했다. 느리긴 했지만 아무것도 모르는 초짜에게 일을 던져놓는 것보단 압도적으로 빠르게 처리한 것이기도 하고 말이다.
어쨌든 그래서 Antigravity CLI는 이런 코드를 내놨다.
def _run_excluding_code_blocks(text: str, func) -> str:
parts = re.split(r'(```[\s\S]*?```)', text)
for i in range(0, len(parts), 2):
parts[i] = func(parts[i])
return "".join(parts)
def update_image_caption(text: str) -> str:
pattern = r'!\[(.*?)\]\((.*?)\)'
replacement = r'''<figure>
<img src="\2" alt="\1" />
<figcaption>\1</figcaption>
</figure>'''
return _run_excluding_code_blocks(text, lambda t: re.sub(pattern, replacement, t))
그러니까 마크다운 텍스트에서 코드블록을 구분자로 텍스트를 분리(split)해서 각각 정규표현식을 각각 돌려버리는 굉장한 아이디어를 짜낸 것이었다. 이렇게 하면 코드블록은 구분자여서 전혀 안 건드리게 된다. 전혀 생각지 못한 방식이었는데 정말이지 배울 게 많은 녀석 같다.
이 정도면 솔직히 말해서 직접 일하는 것보다 빠르고 확실하게 처리하는 것 같다는 느낌이 들었다. 물론 프롬프트 작성을 잘해줘야 제대로 처리할 것 같긴 하지만 그래도 이게 어딘가 싶다.
고민이 갑자기 커졌다. 이거 적응되어 버리면 나중에 유료로 바뀌었을 때 어떻게 해야 할까?
마지막으로 Gemini CLI와 Antigravity CLI의 차이에 대해 Gemini가 정리해 준 내용을 붙이며 끝내보자.
Gemini CLI는 Gemini API를 터미널에서 빠르고 직접적으로 활용하는 '직관적 도구'인 반면, Antigravity CLI는 에이전트의 '지능적인 추론과 복합적인 작업(멀티 파일 편집, 도구 실행 등)'을 터미널에서 수행하기 위해 설계된 플랫폼입니다.
뭔가 많이 하니 느릴 수밖에 없을 것 같기도 하다. 뭐 그러려니 해야겠다.