저수준 소프트웨어를 오직 코딩 에이전트로만 구축하기

TMT

https://leerob.com/pixo

휴일 동안 5일에 걸쳐, 저는 Rust 기반의 이미지 압축기를 만들었습니다.

오직 코딩 에이전트만 사용해서 어디까지 갈 수 있는지 확인해보고 싶었습니다. 저는 손으로 코드를 전혀 작성하지 않았습니다. 520개의 에이전트, 3.5억 토큰, 그리고 $2871을 사용한 끝에… 극도로 멀리 갈 수 있다고 말할 수 있습니다.

저의 라이브러리 pixo⁠는 런타임 의존성이 전혀 없습니다. 모든 알고리즘을 처음부터 직접 구현했습니다. 30년 된 고도로 최적화된 C/어셈블리 라이브러리(mozjpeg⁠)에 근접한 성능을 달성합니다.

이게 가능할 거라 기대하지 않았고, 이후 계속해서 제가 얼마나 야심 차게 갈 수 있는지에 놀랐습니다. 저는 Rust 라이브러리로 시작했고, 그다음 WebAssembly로 컴파일해 웹 앱을 만들었습니다. CLI도 있고, 모든 것이 어떻게 동작하는지에 대한 포괄적인 가이드도 있습니다. 게다가 900개 이상의 테스트와 85% 커버리지가 있습니다. 여기엔 대충대충이나 감성은 전혀 없습니다.

다음은 코딩 에이전트가 저를 위해 해준 흥미로운 일들입니다:

  1. 유사한 도구들과의 벤치마크를 만들고, 성능 격차를 찾은 뒤 이를 수정했습니다
  2. WASM 바이너리를 최적화하고, 사용할 올바른 설정/플래그를 찾아 크기를 줄였습니다
  3. 코드 커버리지를 측정하고, 빈틈을 찾아 누락된 커버리지 기반으로 테스트를 작성했습니다
  4. 포괄적 테스트 스위트를 구성하기 위해 퍼블릭 도메인 이미지를 찾았습니다
  5. 모든 테스트의 정확성을 검증하기 위해 압축 스펙과 RFC를 조사했습니다
  6. 린팅, 테스트, WASM 바이너리 생성용 CI를 추가했습니다

먼저 제가 무엇을 만들었는지 보여드리겠습니다(여기서 직접 사용해보세요). 이것은 PNG나 JPEG 이미지를 받는 SvelteKit 웹 앱입니다. pixo⁠ 라이브러리를 WASM 바이너리로 로드합니다. 대부분의 이미지를 브라우저에서만, 1초 내에 최적화할 수 있습니다. 서버로 아무 것도 업로드할 필요가 없습니다.

여러 가지 프리셋(빠른/느린)을 선택할 수 있고 이미지를 리사이즈할 수 있습니다. 많은 이미지를 드롭해놓을 수 있고, 완료되면 .zip 파일로 모두 다운로드할 수 있습니다. 전후를 슬라이드로 비교하고, 픽셀 차이를 검사하기 위해 확대도 지원합니다. 꽤 멋집니다!

코딩 에이전트의 한계를 찾아서

제 지난 글에서, Cursor 웹사이트를 CMS에서 순수 코드와 Markdown으로 마이그레이션한 과정을 이야기했습니다. 핵심 요지는 이제 AI가 코드를 손쉽게 만들어내므로, 나쁜 추상화의 비용이 매우 크다는 것이었습니다. 저는 전체 마이그레이션을 Cursor Ultra 플랜($200/월) 안에서 했습니다.

하지만 이것은 제가 익숙한 도메인이었습니다. 어떤 사람들은 제가 React와 Next.js에 대한 사전 지식이 없다면 같은 결과를 얻기 어려울 것이라고 회의적으로 봤습니다.

저는 정말 야심 찬 일을 해보고 싶었습니다. AI와 코딩 에이전트가 다음에 어려움을 겪을 거라고 생각했습니다:

  1. TypeScript나 Python 대비 더 저수준의 코드(예: Rust)
  2. 매우 복잡한 컴퓨터 과학 주제(예: 압축 알고리즘)

이미지 압축은 그런 미신을 반박해볼 적절한 기회처럼 느껴졌습니다.

데이터를 가능한 한 작게 압축하기 위한 70년의 영리한 알고리즘과 최적화가 존재합니다. 우리가 컴퓨터에서 하는 거의 모든 일은 압축에 의존합니다: 웹에서 로드되는 모든 이미지, 당신이 해온 모든 영상 통화, 네트워크로 보내지는 모든 패킷, 지금 당신이 읽고 있는 텍스트… 심지어 파일 시스템 자체도요.

이미 존재하는 압축 라이브러리와 코덱은 정말 많고, 일부는 30년 이상 되었습니다! 제가 품은 터무니없이 야심 찬 생각은 런타임 의존성이 전혀 없는 Rust 라이브러리를 만들어, 모든 기반 알고리즘과 최적화를 처음부터 구현하는 것이었습니다. 그리고 손으로 코드를 쓰지 않고, 오직 코딩 에이전트만으로 이를 해내고 싶었습니다.

결국 이 작업은 거의 38,000줄의 코드가 되었고(그중 50% 이상이 테스트), 이 모든 것을 5일 만에 해냈습니다. 인간을 넘어서는 듯한, 이전에는 불가능해 보였던 속도입니다. 결과는 뒤에서 더 이야기하겠습니다.

장시간 실행되는 에이전트

대부분의 소프트웨어 엔지니어는 아직 에이전트를 중심으로 코딩하고 있지 않습니다. 온라인에서 보는 것과는 달리요. 조용한 대다수는 이 새로운 세계에 맞춰 배우고 진화하는 중입니다.

코딩 에이전트를 채택한 사람들은 Cursor 같은 제품을 사용해 조사하고, 디버그하고, 새로운 기능을 추가합니다. 이런 작업은 보통 1분에서 30분 사이가 걸립니다.

아주 소수의 개발자만이 장시간 실행되는 에이전트라는 사고방식으로 업데이트했습니다. 이 글을 읽고 있다면, 당신은 대부분보다 더 앞서 있습니다.

불과 몇 달 전과 비교해도 오늘날의 AI 코딩은 극적으로 다릅니다.

  1. 모델이 개선되었습니다. 불과 1년 전만 해도 모델은 거의 에이전트적이지 않았습니다. 도구 호출에 서툴렀고, 자주 코드를 환각했습니다. 최신 모델은 더 똑똑한 세계 지식을 가졌을 뿐 아니라, 지시를 더 잘 따르고 도구 호출도 더 능숙합니다.
  2. 코딩 에이전트가 개선되었습니다. 개선된 모델이 Cursor와 다른 코딩 에이전트 같은 제품에서 더 잘 활용되고 있습니다. 초기 컨텍스트 윈도우를 넘어가도록 모델에 자체 요약을 허용하고 계속 진행하게 하는 것, 컨텍스트 사용량을 줄이기 위해 도구 정의와 응답 크기를 가지치기하는 것, 파일 시스템에서 컨텍스트를 동적으로 로드하는 것 등 작은 디테일들이 모여 큰 차이를 만듭니다.
  3. 인지와 채택이 증가했습니다. AI 코딩 제품을 채택한 개발자들은 현재 도구의 강점과 한계를 배우고 있습니다. 종종 세부적인 계획을 먼저 세운 뒤 코드를 생성하는데, 이것이 결과를 크게 개선합니다. 내년에 훨씬 더 많은 개발자들이 AI로 코드를 작성할 것으로 예상합니다.

오늘날 에이전트와 최신 모델은 개입 없이도 쉽게 한 시간 동안 실행됩니다. 보통 계획을 주면, 더 복잡한 작업을 시켜도 처음부터 대부분 제대로 해냅니다.

이번 프로젝트에서 제가 가장 길게 실행한 Cursor 에이전트는 3시간 동안 돌았습니다(GPT 5.1 Codex Max 사용). 여러 에이전트가 수 시간씩 실행되었습니다. 아직 에이전트가 며칠간 자율적으로 실행되는 세계를 고려하지 않았다면, 내년에는 그것이 현실이 될 것이라 예상해야 합니다.

계획, 구축, 리팩터링

제가 pixo⁠를 시작할 때의 초기 계획입니다. Cursor의 Plan 모드는 가장 과소평가된 기능 중 하나입니다. 모델이 지시를 잘 따르게 되었더라도, Plan 모드의 UX는 여전히 도움이 됩니다. 아키텍처를 시각화하기 위해 Mermaid 다이어그램을 생성할 수 있는 점도 마음에 듭니다.

Mermaid 흐름 다이어그램 Cursor Plan 모드의 Mermaid 아키텍처 다이어그램

프로젝트 전반에서 저는 Opus 4.5와 GPT 5.1 Codex Max 사이를 오가며 사용했습니다. 둘 다 매우 잘 수행했지만, 서로 다르게 사용했습니다. 예를 들어, Codex는 장시간 작업에서 더 잘했고, Opus는 글쓰기에서 훨씬 뛰어났습니다.

이 프로젝트의 상당 부분은 제가 키보드에서 떨어져 있는 동안 만들어졌습니다. 저는 Cursor와 오가며 계획을 세우고, 그다음 주로 Codex로 클라우드에서 에이전트를 실행했습니다.

Cursor는 가상 머신을 띄우고, 제 레포를 클론하고, 작업을 시작합니다. 작업을 진행하면서 커밋을 남기고 자신의 작업을 검증합니다.

예를 들어, 이것이 제가 만든 첫 PR 중 하나입니다. 저는 이것을 휴대폰에서 시작했고, 딸에게 책을 읽어준 뒤 몇 시간 후 돌아와서 머지했습니다.

Cursor 에이전트가 만든 GitHub 풀 리퀘스트

이제 아마 이렇게 생각하실 겁니다: 어떻게 이런 방식으로 계획하고 구축하면서 망가진 코드로 끝나지 않을 수 있을까? 모델이 자신의 작업이 올바른지 검증할 수단이 필요합니다.

코딩 에이전트에게 테스트, 린트, 벤치마크 같은 검증 가능한 산출물을 주면, 그들은 실수로부터 학습하고 올바를 때까지 계속 작업합니다. 프로젝트 초기에 저는 Cursor에게 코드베이스를 포맷·린트·테스트하는 CI를 추가하라고 요청했습니다. 이제 이것은 모든 PR에서 실행되어, 에이전트가 회귀를 일으키지 않도록 보장합니다.

이제 에이전트가 저를 위해 할 수 있는 일의 짧은 목록입니다:

  1. 코드베이스에 대한 포괄적 문서를 추가(1, 2, 3, 4)
  2. 벤치마크를 추가(1)하고 성능을 갈고닦아 개선(1, 2, 3, 4)
  3. WASM 바이너리를 사용하는 웹 앱을 테스트와 함께 처음부터 빌드(1, 2)
  4. 코드 커버리지를 측정(1)하고 테스트를 갈고닦아 추가(1, 2, 3, 4)
  5. 복잡한 신규 기능을 처음부터 구현(1, 2, 3)
  6. API와 코드 품질을 리팩터링하고 개선(1, 2, 3)

Cursor는 까다로운 버그를 찾고 고치는 데에도 도움을 줬습니다. 이미지를 수동으로 테스트하는 동안, 압축된 이미지에서 시각적 아티팩트가 이상해 보이는 것을 발견했습니다. 저는 스크린샷을 찍어 에이전트에 다시 제공했고, 이슈를 디버그하기 위해 상호작용을 이어갔습니다. 회귀 테스트까지 추가해 다시 발생하지 않도록 했습니다!

압축된 이미지의 시각적 아티팩트를 디버그하는 Cursor

레포를 공개한 뒤, 누군가 이미지 리사이징을 추가하자는 제안으로 이슈를 열었습니다. 검증 가능한 산출물(테스트, 타입, 린트)에 투자했기에, 이제 새로운 기능을 추가하는 것이 쉬워졌습니다.

리사이징을 위한 API 형태가 어떻게 보일지 탐색하는 계획을 만들었습니다. Rust 레벨에서 변경을 하고, 새로운 WASM API를 노출하고, 웹 앱에서 이를 사용하고 싶었습니다. 계획을 마친 뒤, Cursor는 한 번에 동작하는 버전을 만들어냈습니다.

PR을 머지하기 전에, 저는 성능을 개선하고 디자인을 다듬고 더 많은 테스트 커버리지를 추가했습니다. 계획은 여기서 읽을 수 있고, 최종 PR도 있습니다.

대부분의 코드를 제가 리뷰했고, 변경 사항을 수동과 자동 테스트 모두로 검증했다는 점은 짚고 넘어가야겠습니다. 또한 모든 PR을 Bugbot으로 리뷰받았습니다(예시).

벤치마크와 비교

저는 다른 유사한 도구2들과의 상세한 벤치마크와, 코드량과 테스트 커버리지를 살펴보는 코드베이스 비교를 만들었습니다.

흥미로운 통계와 인사이트 몇 가지:

  1. pixo⁠는 다른 라이브러리들과 경쟁력이 있습니다. 제 목표는 빠르고 의존성이 없는 라이브러리를 만드는 것이었습니다. 특히 의존성을 보면 다른 라이브러리들보다 상당히 작습니다(예: libvips⁠ 194K LOC, mozjpeg⁠ 112k). 그 코드의 상당 부분이 가치 있는 버그 수정과 성능 최적화를 담고 있을 것이므로 이를 완전히 무시하려는 것은 아니지만, 이 라이브러리는 다른 선택지가 존재함을 보여주는 실험입니다. 저는 매우 읽기 쉬운 Rust 코드로 이 전체 코드베이스를 머릿속에 넣을 수 있습니다.
  2. AI는 더 많은 테스트 작성을 도와줄 수 있습니다. 이전에 모델이 양질의 테스트 작성에 어려움을 겪을 것이라고 생각했다면, 다시 시도해볼 가치가 있습니다. 저는 Cursor에게 포맷과 알고리즘의 스펙을 읽고 테스트의 정확성을 검증해 라이브러리가 기대대로 동작하는지 확인하도록 요청할 수 있었습니다. 테스트를 먼저 작성하세요; 실패하면 버그가 있다는 것을 압니다(더 나아진 TDD 복귀). pixo⁠는 다른 도구들보다 훨씬 많은 테스트(900+)를 가지고 있는데, 이는 의미가 있습니다. 20,000줄의 테스트를 작성하는 데는 엄청난 시간이 걸립니다. 85% 커버리지는 제게 충분하지만, 원한다면 모델들에게 갈아붙여 100%까지도 올릴 수 있을 겁니다.
  3. 모든 것에는 트레이드오프가 있습니다. 의존성을 0으로 두기로 한 결정도 트레이드오프입니다. libdeflate⁠ 같은 검증된 라이브러리(14K줄의 C 코드)를 쉽게 가져올 수 있었습니다. 하지만 그러면 WASM 바이너리 크기가 늘어나, 웹 앱이 사용 가능해지는 속도가 느려집니다. 159 KB에서 pixo⁠는 아주 작습니다. PNG + mozjpeg⁠를 포함한 squoosh⁠는 ~933 KB입니다. 저는 크기를 위해 약간 떨어지는 성능을 감수하겠습니다. 수천 줄의 손으로 튜닝된 C/어셈블리를 가진 다른 라이브러리들과 맞추기 위해 해야 할 일이 더 많이 남아 있을 가능성이 큽니다. 게다가 pixo⁠는 올인원입니다: 무손실 PNG, 손실(양자화) PNG, 손실 JPG, 이미지 리사이징.

제품이 그 어느 때보다 중요합니다

코드를 쓰는 것은 더 이상 병목이 아닙니다. 이것은 소프트웨어 엔지니어링에 무엇을 의미할까요?

무엇을 만들어야 할지 알아내야 합니다. 예를 들어, 저는 다음과 같은 것들을 고민하고 결정해야 했습니다:

  • Q: 어떤 이미지 포맷을 지원할까?
    • A: 저는 PNG와 JPEG만에 집중하기로 했습니다. WebP, AVIF, GIF나 다른 많은 옵션을 추가하는 것은 이 실험의 목적에 부합하지 않고, LOC와 WASM 번들의 크기를 크게 늘릴 것입니다.
  • Q: 라이브러리를 어떻게 노출할까? CLI? 크레이트? 웹 앱? 모두?
    • A: 초기 아이디어는 라이브러리만이었지만, 프로젝트가 진행되면서 점점 더 야심 찬 방향으로 갈 수 있었습니다. CLI와 웹 앱을 추가하는 것도 사소해졌고, 궁극적으로 웹 앱이 이제 제가 가장 좋아하는 부분입니다.
  • Q: 인코딩만 처리할까, 디코딩도 처리할까?
    • A: 초기에는 인코딩만 생각했지만, 첫 버전은 CLI에서 이미지를 디코딩하기 위해 외부 의존성을 끌어와야 했습니다. 나중에 디코딩 지원을 추가하는 것이 놀랄 만큼 매우 쉬웠습니다.
  • Q: API에서 어떤 설정 옵션을 노출할까?
    • A: 첫 버전의 Rust API는 동작했지만 개선될 여지가 있었습니다. 빌더 패턴을 더 잘 활용하도록 리팩터링해서, 서로 다른 위치 인자가 뒤섞이는 일을 피하기로 했습니다.
  • Q: 이미지 크기를 1% 더 줄이는 대신 WASM 바이너리가 10% 커지는 선택을 할까?
    • A: 이 라이브러리에서는 일반적으로 아니오라고 결정했습니다. 에이전트에게 추가 압축 이득을 계속 갈아보게 하고, 그에 따른 LOC와 WASM 바이너리 증가를 측정하는 실험도 했습니다. 일부는 유지하고, 일부는 폐기했습니다.

잘 설계된 시스템을 디자인해야 합니다. 영어를 쓸 수 있는 누구나 이것을 만들 수 있었을까요? 아마도요, 하지만 잘 설계된 결과에 도달했을지는 회의적입니다.

제너럴리스트가 되는 것이 그 어느 때보다 중요합니다. Rust가 WASM으로 컴파일된다는 점, WASM이 서버 업로드 없이 클라이언트 이미지 압축 같은 것을 가능하게 한다는 점을 모를 수도 있습니다. 이 프로젝트가 사용한 개념들을 이해하는 데 CS 기초가 매우 도움이 되었습니다. 제가 헥사 코드를 손으로 쓰거나, 수동으로 비트 시프팅을 하지는 않지만, 그것이 존재한다는 것은 압니다.

이를 보여주기 위해, 모델이 만든 웹 앱의 첫 버전은 이랬습니다. 객관적으로 “정확”하지만 엉성합니다. 이상한 AI 생성 블루 틴트가 곳곳에 있고, 과도한 텍스트, 너무 많은 노브와 버튼이 있습니다.

AI가 만든 pixo 웹 앱의 첫 버전

특히 오늘날의 다른 유사 도구들과 비교할 때 그렇습니다. 구글에서 상위에 랭크된 대부분은 광고로 넘쳐나고 매우 느리며, 즐겁게 사용할 수 없습니다. 어떤 도구는 설정 옵션이 지나치게 많고, 다른 도구는 아무 옵션이 없고 손실을 원한다고 가정합니다.

이것은 “png compress”로 구글 상위 결과입니다(훌륭한 압축 도구들도 있다는 것은 압니다).

약 30초가 걸립니다. 3초면 어떨까요?

결론

이 프로젝트로 이미지 압축, Rust, WASM에 대해 많은 것을 배웠습니다. 하지만 무엇보다, 즐거웠습니다. 사람들이 pixo⁠를 사용하기 시작할 것이라 기대하나요? 아니요, 그건 별로입니다3. 이것이 제가 제 사진을 위해 사용하는 개인용 소프트웨어라 해도, 그걸로 충분합니다.

코딩 에이전트와 AI를 최적으로 사용하는 워크플로와 전략에 대한 논의가 온라인에 많습니다. 여기서 제 가장 큰 조언은 과도하게 최적화하지 말라는 것입니다. 저는 맞춤 규칙 없이 시작했습니다. 모델이 몇 가지를 틀린 뒤에야(예: 잘못된 린팅 명령 사용, 바이너리 생성 방법 기억 못함) 규칙 파일을 나중에 추가했습니다.

비슷하게, 워크플로는 레포 안에서 충분히 놀아본 뒤에야 떠올랐습니다. 결국 제가 따로 만들던 몇 가지 프롬프트를 묶어 하나의 /release⁠ 명령으로 패키징했습니다. 하지만 이것도 빌드 과정에서 필요를 느낀 뒤에야 배운 것입니다.

오늘 코드를 작성하는 모든 사람에게 코딩 에이전트로 프로젝트를 만들어보라고 강력히 권하고 싶습니다. 과거에 소프트웨어를 만들던 방식과는 낯설고 매우 다르게 느껴질 겁니다. 하지만 지금이 재교육하고, 이 새로운 도구를 최적으로 활용하는 법을 배우기 위한 때입니다.

pixo⁠를 사용해보고 싶다면 여기에서, 혹은 전체 소스 코드를 읽어볼 수 있습니다. 이미지 최적화와 압축 트릭에 대해 더 배우고 싶다면 가이드를 읽는 것을 추천합니다. 성능 최적화 문서는 특히 재미있습니다.

Footnotes

  1. 하나의 에이전트 실행은 Cursor 안의 단일 대화(로컬 또는 웹)를 의미합니다. 3.5억 토큰의 대다수는 Cursor가 프롬프트 캐싱(Codex 또는 Opus 모델용)을 사용했기 때문에 캐시되었습니다. 비용은 API 가격 때문에 약 70%가 Opus, 30%가 Codex였습니다. 가격과 사용량은 공개된 Cursor API를 사용해 측정했습니다.

  2. 벤치마크에서 문제가 보인다면 알려주세요. 이 글의 목표는 라이브러리가 얼마나 좋은지 자랑하는 것이 아닙니다. 사람들이 기존 솔루션 대신 이것을 사용할 것이라 실제로 기대하지 않습니다. 레포에 이슈를 남겨주시면, 제가 고치겠습니다!

  3. 이 라이브러리는 Codex와 Opus가 학습했을 가능성이 높은 많은 공개 오픈소스 라이브러리 없이는 불가능했을 것이고, Cursor 에이전트가 다양한 알고리즘을 어떻게 구현하는지 이해하기 위해 찾아본 것들 덕분이기도 합니다.

Edit this page