-
GUI 전용 도구를 코딩 어시스턴트에 태우는 3단계 사다리IT 2026. 6. 15. 21:00
지금까지 수십 개의 커맨드라인 도구를 코딩 어시스턴트에 노출하는 이야기를 세 편에 걸쳐 했다 — 3단 깔때기로 도구를 줄이고, Descriptor로 호출법을 가르치고, 비동기 job으로 긴 작업을 다뤘다. 그런데 이 모든 전제에는 구멍이 하나 있다. "도구가 CLI일 때"라는 전제다.
현실의 도구 중에는 명령줄이 아예 없는 것들이 있다. GUI(그래픽 화면)로만 동작하는 도구 — 창을 띄우고, 버튼을 누르고, 마우스로 클릭해야 일이 되는 도구다. LLM에게는 누를 버튼도, 받아 읽을 표준 출력(stdout)도 없다. 이런 도구를 코딩 어시스턴트에 어떻게 태울 것인가?
문제: GUI는 LLM이 잡을 손잡이가 없다
코딩 어시스턴트가 도구를 부르는 방식은 결국 "명령을 문자열로 만들어 실행하고, 출력 텍스트를 받아 읽는 것"이다. GUI 도구에는 이 둘이 다 없다. 화면 좌표를 클릭하라고 시킬 수는 있지만, 그건 깨지기 쉽고 도구가 업데이트되면 좌표가 어긋난다.
그렇다고 GUI 도구를 다 포기할 수는 없다. 누군가는 그 도구가 하는 핵심 기능이 필요하다. 문제는 "어떻게 노출하느냐"가 아니라, "각 GUI 도구가 어떤 상태에 있느냐에 따라 다르게 다뤄야 한다"는 점이었다.
해결: 상태에 따라 A·B·C 세 단계로 분류
GUI 도구를 일률적으로 처리하지 않고, 소스에 손댈 수 있는지를 기준으로 세 단계 사다리에 올렸다. 핵심 원칙은 하나다 — 모든 도구는 결국 C(CLI 추출 완료)를 향한다. 그 전 단계는 임시방편일 뿐이다.
다이어그램 설명. 위 흐름도는 A·B·C 세 단계와 그 수렴을 그린다. A는 소스에 손댈 수 있는 도구로, 핵심 로직만 떼어내 명령줄용 바이너리를 새로 만드는 정공법을 택한다 — 시간이 걸리므로 그동안은 LLM에 노출하지 않는다. B는 소스가 없는 외부 GUI 바이너리라 코어를 분리할 수 없어, GUI를 바깥에서 조작해 임시로만 노출한다 — 웹 화면이면 Playwright(웹 화면을 코드로 클릭·입력하는 도구)로, 네이티브 창이면 다른 수단으로(뒤에서 자세히 본다). C는 CLI 추출이 끝났거나 원래 CLI였던 도구로, 앞 글들에서 설명한 일반 흐름에 그대로 합류한다. A의 실선과 B의 점선 화살표가 모두 C를 가리키는 게 핵심이다 — B는 종착지가 아니라 C로 가기 전 임시 정류장이다.
B를 다시 본다 — 브라우저로 못 여는 GUI가 더 많다
그런데 B를 "브라우저 자동화"라고만 적으면 절반만 맞다. 외부 GUI 바이너리의 태반은 웹 앱이 아니라 네이티브 데스크톱 앱이다 — Qt·GTK·Win32 같은 데스크톱 GUI 프레임워크로 만든 창을 띄우는 프로그램(데스크톱 이미지 편집기, CAD 뷰어, 계측 장비 제어 앱 등)이다. Playwright는 웹 브라우저 안의 DOM(웹 페이지를 이루는 요소 트리)만 잡을 수 있어서, 이런 네이티브 창에는 손이 닿지 않는다. 그러면 어떻게 하나.
먼저: "정말 GUI밖에 없나"를 의심한다
네이티브 GUI 도구를 보자마자 화면 자동화로 달려들기 전에, 숨은 비-GUI 호출 경로가 있는지부터 두드린다. 의외로 많은 GUI 바이너리가 명령줄 모드를 품고 있다 — LibreOffice는
--headless --convert-to pdf로 창 없이 문서를 변환하고, Blender는blender -b(background 모드)로 화면 없이 렌더링만 돌리며, 상당수 앱이--batch·-nogui플래그나 내장 스크립트 콘솔을 갖고 있다. 이런 경로가 하나라도 있으면 GUI 자동화를 통째로 건너뛰고 곧장 C로 승격된다. 가장 싼 해법이고, 사다리에서 제일 먼저 두드려 볼 칸이다.그래도 GUI밖에 없다면 — 인터페이스의 안정성 사다리
다이어그램 설명. 세 가지 자동화 인터페이스를 안정성 순으로 계단처럼 놓았다. 맨 아래(빨강)는 좌표·키 입력 주입 — xdotool(리눅스에서 키·마우스를 프로그램으로 흉내 내는 도구)이나 pyautogui로 "화면의 (x, y)를 클릭"을 OS 레벨에서 쏘는 방식이다. 모니터 없는 서버라면 Xvfb(가상 디스플레이 — 실제 화면 없이 메모리에 화면을 그리는 X 서버)를 띄워 그 위에서 돌린다. Playwright의 네이티브 버전이라 보면 되는데, 좌표에 의존하므로 도구가 업데이트돼 버튼이 5px만 옮겨가도 깨진다. 가운데(노랑)는 접근성 트리(Accessibility tree — 스크린 리더가 화면을 읽으라고 OS가 노출하는 UI 요소 구조)를 쓰는 방식이다. AT-SPI/dogtail(리눅스)·pywinauto(윈도우)로 "확인 버튼"을 좌표가 아니라 이름·역할로 지칭하므로 레이아웃이 바뀌어도 견딘다. 맨 위(초록)는 앱이 자체 제공하는 스크립팅 API — AppleScript(맥 앱 제어 언어), COM(윈도우 앱 자동화 인터페이스), GIMP의 Script-Fu, 앱 내장 Python 콘솔 같은 것이다. 의미 단위로 명령을 보내므로 사실상 작은 CLI에 가깝다. 오른쪽 위로 갈수록 부채가 작아지고 C에 가까워진다.
핵심은 같은 B라도 어느 칸에 앉히느냐가 부채의 크기를 정한다는 것이다. 좌표 클릭은 가장 비싼 임시방편이고(도구가 한 번 업데이트되면 다시 깨진다), 스크립팅 API는 거의 C에 닿아 있다. 그러니 같은 "GUI밖에 없는 도구"라도 잡을 수 있는 한 위 칸으로 올려 잡는 게 옳다.
장기적으로는
네이티브 GUI 도구의 종착지도 결국 C다. 길은 둘이다. 첫째, 앱이 플러그인·확장 SDK를 제공하면 거기에 얇은 헤드리스 진입점을 직접 얹는다 — 소스 전체는 못 만져도 확장점은 열려 있으니, 닫힌 바이너리에 적용하는 A인 셈이다. 둘째, CLI-native 대체 도구로 갈아탄다 — GUI 이미지 편집기 대신 ImageMagick(명령줄 이미지 변환 도구)처럼, 같은 일을 하는 명령줄 도구가 있으면 도구 자체를 바꾼다. 어느 쪽이든 스크립팅 API를 얇게 감싸 cliAdapter 흐름에 합류시키면, 그 도구는 더 이상 B의 임시 칸이 아니라 C의 정주민이 된다.
왜 이게 중요한가
GUI 도구를 만나면 가장 손쉬운 해법이 "브라우저 자동화로 화면을 클릭하게 하자"는 것이다. 그런데 이걸 정착지로 삼으면 도구가 업데이트될 때마다 좌표·선택자가 깨지고, 유지보수가 끝없이 따라붙는다. GUI 도구인 B를 명시적으로 '임시'라고 못 박는 것이 중요하다. 곧 "이건 언젠가 C로 대체될 자리"라는 선언이다.
그래서 기술 부채를 가시화해두어야 한다. 어떤 도구가 B에 있다는 건 "아직 제대로 안 된 채로 버티는 중"이라는 신호이고, A에 있다는 건 "사람이 CLI를 떼어내 줘야 할 일이 큐에 쌓여 있다"는 신호다. 사람에게 주는 가치는 "임시방편을 임시방편인 줄 알고 쓴다"는 것이고, 시스템에 주는 가치는 "GUI 도구도 일단 태우되, 모든 도구가 결국 같은 CLI 흐름으로 수렴하도록 방향이 고정된다"는 것이다.
네 편에 걸쳐, 수십 개의 도구를 코딩 어시스턴트가 잘 부르게 만드는 네 가지 축을 정리했다 — 적게 보여주고(계층 디스커버리), 스스로 가르치게 하고(Descriptor), 기다리지 않게 하고(비동기 job), 임시방편을 임시방편으로 분류하기. 도구를 더 똑똑하게 부르게 만드는 길은, 화려한 한 방이 아니라 이런 작은 설계 결정들의 합이었다.
이 글은 생성형 AI의 도움을 받아 작성되었습니다. 원본 자료를 기반으로 AI가 초안을 생성하고, 작성자가 검토·편집하였습니다.
'IT' 카테고리의 다른 글
Claude Code에서 /agents로 서브에이전트를 만드는 가장 쉬운 방법 (0) 2026.06.17 BM25 — AI가 도구 100개 중 3개를 정확히 찾아내는 방법 (0) 2026.06.16 Claude에 도구 등록하는 방법 — input_schema 설계부터 defer_loading까지 (0) 2026.06.16 도구 100개, LLM에게 필요할 때만 꺼내는 법 — Anthropic Deferred Loading 해부 (0) 2026.06.16 MCP 서버는 원격에 둬야 할까, 로컬에 둬야 할까 — 전송 방식이 결정되는 한 줄 (0) 2026.06.15 MCP sampling/createMessage: AI 도구가 AI를 부르는 역방향 설계 (0) 2026.06.14 MCP Roots 완전 분해: 서버가 클라이언트에게 먼저 묻는 역방향 설계 (0) 2026.06.13 MCP Prompts의 멀티턴 messages — 서버가 모델의 첫 생각을 설계하는 방법 (0) 2026.06.13 MCP Prompts 완전 분해: 최적 프롬프트를 서버에 봉인하고 재사용하는 방법 (0) 2026.06.13 MCP Resources 완전 분해: URI로 AI에게 데이터를 공급하는 7가지 메서드 (0) 2026.06.12