
2026년의 로컬 AI (파트 3a): 처음부터 로컬 AI 에이전트를 직접 구축하며 그 어떤 튜토리얼보다 더 많은 것을 배웠습니다.
요약
로컬 우선(local-first) 하이브리드 아키텍처를 가진 자율 에이전트 'Vibrisse Agent'를 구축한 과정과 회고를 담고 있습니다. Ollama, LangGraph, MCP 통합 등을 활용하여 단순한 API 래퍼를 넘어선 견고한 에이전트 개발 경험을 공유합니다.
핵심 포인트
- Ollama와 vLLM을 활용한 로컬 우선 하이브리드 아키텍처 설계
- MCP(Model Context Protocol)를 통한 GitHub, SQLite 등 도구 통합
- Gemma 4를 활용한 멀티모달 비전 기능 구현
- 소스 코드 주석으로 에이전트를 제어하는 고스트 모드 구현
모두가 AI가 내 대신 코드를 작성해 줄 것이라고 말했습니다. 그래서 저는 AI에게 AI 에이전트를 코딩하는 것을 도와달라고 요청했습니다. 한 달 후, 강도 높은 코딩 단계와 고민의 시간들을 거치며 저는 답을 얻었습니다. 그리고 그것은 제가 예상했던 답이 아니었습니다.
이 프로젝트는 우선 깊은 필요성, 즉 자기 학습(self-training)에서 시작되었습니다. 저는 이것이 무대 뒤에서 실제로 어떻게 작동하는지 이해하고 싶었습니다. 따라서 이것은 스크립트로 업무를 자동화한 이야기가 아닙니다. AI 하이프(hype)의 보닛을 들어 올리기로 결정하고, "바이브 코딩 (vibe coding)" 방식을 거부하며, 처음부터 견고한 로컬 AI 에이전트를 구축하려고 시도했을 때 어떤 일이 일어나는지에 대한 이야기입니다.
여러분이 읽게 될 내용은 또 다른 AI를 구축하기 위해 AI와 함께한 한 달간의 비대칭 페어 프로그래밍 (asymmetric pair-programming)에 대한 가감 없고 솔직한 회고록입니다.
정확히 무엇에 관한 것인가요? (프로젝트)
맥락을 설명하자면, Vibrisse Agent는 단순한 채팅이나 터미널에 있는 흔한 API 래퍼 (wrapper)가 아닙니다. 이것은 "로컬 우선 (local-first)" 하이브리드 아키텍처로 설계된 자율 에이전트 (Python / LangGraph)입니다. 이 에이전트는 우선적으로 사용자의 기기에서 실행되지만 (Ollama 또는 vLLM을 통해 — *잠시 덧붙이자면: Mac 사용자들에게 oMLX는 정말 최고입니다! 🔥_), 복잡성이나 필요에 따라 특정 작업을 클라우드 (Groq, OpenRouter)로 동적으로 위임할 수 있습니다.
요구 사항은 야심 찼습니다:
- MCP (Model Context Protocol) 통합: 오픈 소스 생태계의 실제 도구들을 연결하기 위함입니다 — 저장소와 PR을 탐색하기 위한 GitHub, 로컬 데이터베이스를 쿼리하기 위한 SQLite, 최신 문서에 접근하기 위한 Context7, 또는 웹과 상호작용하기 위한 Fetch 등이 포함됩니다.
- 멀티모달 비전 (multimodal vision) (Gemma 4 활용): 인터페이스를 실시간으로 분석합니다.
- 온보딩 위저드 (onboarding Wizard): 동적 프롬프트 시스템과 결합되어 에이전트가 사용자의 개발자 프로필에 맞춰 자신의 행동을 조정합니다.
- 그리고 무엇보다도, 고스트 모드 (Ghost Mode): 소스 코드의 주석(
// @vibrisse: refactor this loop)에서 직접 백그라운드에서 에이전트를 제어할 수 있는 기능으로, 더 이상 창을 전환할 필요가 없습니다.
바로 이러한 수준의 요구사항 — 단순한 데모가 아닌 진짜 "제품 (product)"을 만들고자 하는 의지 — 이 저의 초기 확신들을 완전히 깨뜨려 놓았습니다.
"바이브 코딩 (Vibe Coding)"의 신화
최근 프롬프트만 입력하면 복잡한 애플리케이션을 얻을 수 있다는 끈질긴 생각이 퍼지고 있습니다. 이것이 바로 "바이브 코딩 (vibe coding)"이라 불리는 것입니다. 프롬프트를 작성하고, AI가 코드를 뱉어내면, "실행 (run)"을 클릭하기만 하면 — 짠, SaaS가 완성됩니다.
진실은 무엇일까요? 단순한 CRUD 애플리케이션의 경우에는 완전히 사실입니다. 하지만 엄격한 컨텍스트 관리 (context management), 결정론적 도구 실행 (deterministic tool execution)
솔직한 답변을 드리자면, 이는 기저에 깔린 메커니즘에 대해 더 이상 눈먼 상태로 남지 않기 위해서입니다. 직접 구축할 때 얻는 진정한 이점은 무언가 고장 났을 때(그리고 실제로 자주 고장 납니다), 왜 그런 일이 발생했는지 정확히 알고 어떻게 수리해야 하는지 알 수 있다는 점입니다.
단, 한 가지 엄격한 조건이 있습니다. 바로 생성된 코드의 모든 줄과 패턴, 그리고 로직을 이해해야 한다는 것입니다. AI의 제안에 이의를 제기할 수 있는 이러한 통찰력이 없다면, 저는 이를 **"지옥의 루프 (infernal loops)"**라고 부르는 상황에 매우 빠르게 빠지게 됩니다. 즉, AI는 자신의 컨텍스트 (context) 오류를 수정하려고 뱅뱅 돌기만 하고, 인간은 결국 무슨 일이 일어나고 있는지 더 이상 이해하지 못하게 되는 상황 말입니다.
아무도 인정하지 않는 고백:
AI가 없었다면 이 프로젝트는 이런 형태로 존재하지 못했을 것입니다. 저는 이렇게 빠르게 진행할 만큼의 시간도, Python에 대한 깊은 기초 지식도 없었습니다. AI(제 경우에는 Gemini)와 협업함으로써, 새로운 언어를 처음부터 배우는 기술적 마찰 (technical friction) 대신 **비전과 아키텍처 (architecture)**에 온전히 집중할 수 있었습니다.
하지만 여기에 함정이 있습니다. LLM은 고립된 함수를 작성하는 데는 탁월하지만, 전체적인 아키텍처를 설계하고 유지 관리하는 데는 형편없습니다. 저의 15년 웹 개발 경험이 없었다면, 이 프로젝트는 완전히 유지보수가 불가능한 3,000줄짜리 스파게티 코드 main.py 파일로 끝났을 것입니다.
AI의 도움을 받는 각 개발 단계 사이에서, 저는 프로젝트를 최신 상태 (state of the art)로 유지하고 인간이 읽을 수 있도록 만들기 위해 극단적인 "정리"와 리팩터링 (refactoring) 단계(책임 분리, 견고한 원칙 적용)를 강제로 도입해야 했습니다. AI가 급하게 "패치 (patch)"한 코드를 다시 쓰기 위해 직접 손을 더럽히며 작업해야 했던 적도 많았습니다.
언제 답변에 이의를 제기해야 하는지, 언제 방향이 근본적으로 잘못되었다고 느껴야 하는지, 그리고 당장은 "작동"하지만 사흘 뒤에 깨져버릴 솔루션을 언제 거부해야 하는지 — 이것은 프롬프트 (prompt)에서 오는 것이 아닙니다. 그것은 경험에서 오는 것입니다.
오늘날 대다수의 개발자가 AI를 사용하고 있습니다 (Stack Overflow에 따르면 약 76%). 하지만 여전히 두 가지 거짓말이 떠돌고 있습니다:
- "AI가 모든 것을 해주므로, 당신은 아무것도 알 필요가 없다."
- "진정한 개발자는 AI가 필요 없다."
현실은 경험이 협업을 생산적으로 만들었고, 그 협업이 경험을 새로운 영역에 적용 가능하게 만들었다는 것입니다. 이것은 마법이 아니라 지능적인 엔지니어링 (engineering)입니다.
비대칭 페어 프로그래밍 (Pair-Programming Asymétrique): 당신에게 말해주지 않는 것
AI와 페어 프로그래밍 (pair programming)을 할 때, 그 역학 관계는 매우 비대칭적입니다.
AI는 원시적인 힘 (brute force)을 제공합니다. AI는 파일을 즉시 읽을 수 있고, 몇 초 만에 보일러플레이트 (boilerplate) 코드를 생성하며, 지치지 않고 문서를 뒤질 수 있습니다.
개발자인 당신은 아키텍처에 대한 거부권 (veto)과 비즈니스 비전 (vision métier)을 제공합니다.
반드시 이해해야 할 한 가지가 있습니다. 클라우드 AI (Cloud AI)는 본질적으로 협조적입니다. AI는 당신이 제안하는 것에 대해 종종 "과도하게 의욕적"입니다. 때때로 제가 기술적인 벽에 부딪히고 있을 때, AI와 소통하기 위해서는 순수 개발자로서의 태도에서 벗어나야 했습니다. AI에게 엄격한 역할(예: "당신은 숙련된 AI 엔지니어(AI Engineer)입니다...")을 부여하고 그 접근 방식에 대해 도전(challenge)해야 했습니다. 그러면 갑자기 _"그것은 불가능합니다"_라는 말이 대안에 대한 구체적이고 유의미한 분석으로 변하곤 했습니다.
제가 배워야 했던 규율은 바로 "소리 내어 생각하기 (pensée à haute voix)" 세션을 도입하는 것이었습니다. 각 단계마다 AI에게 지금까지 무엇을 했는지, 무엇을 할 것인지, 그리고 왜 하는지를 요약해 달라고 요청했습니다. 영향(impacts)에 대해 논의했습니다. 순수 코딩에서 벗어나 비전을 유지하고, 저의 생각을 AI에게 전달하며 방향을 잡았습니다.
"휴먼 인 더 루프 (Human-in-the-Loop)"와 상호작용형 아티팩트 (Artefacts Interactifs)
가장 큰 깨달음 중 하나는 자율 에이전트 (agent autonome)가 모든 것을 혼자서 다 할 필요는 없다는 사실을 깨달은 것이었습니다. 복잡한 작업(예: 아키텍처 재설계)을 위해, 저는 "아키텍트 (Architecte)" 모드를 설계해야 했습니다.
한 번에 500줄의 코드를 쏟아내는 대신, 에이전트는 "아티팩트 (Artefact)"로 감싸진 상세한 계획을 생성합니다. 인터페이스는 이를 가로채 실행을 일시 중지하고, 승인 버튼과 함께 깔끔한 대화형 렌더링(시각적인 CodeDiff, 다이어그램 또는 TaskBoard와 같은 형태)을 저에게 보여줍니다.
바로 여기서 마법이 일어납니다. 에이전트가 제 파일을 수정하기 위해 도구들을 사용하기 전에, 저는 그 계획을 검토할 수 있습니다. 시스템의 핵심에 내장된 이 거부권(Veto right)은 모든 것을 바꿉니다. 프로젝트를 예측 불가능하게 망가뜨리는 "블랙박스 (Black box)" 형태의 AI에서, 초안을 제출하며 협업하는 진정한 동료로 전환되는 것입니다.
이중 학습 (아무도 예상하지 못한 부분)
이번 여정에서 얻은 가장 예상치 못한 통찰은, AI를 구축하는 법을 배우는 것이 곧 AI를 사용하는 법을 배우는 것이라는 사실입니다.
한 달간의 개발 기간 동안, 두 개의 평행한 학습 곡선이 동시에 진행되었습니다.
엔지니어링 측면에서는 모델에게 다음과 같은 것들이 필요하다는 것을 배우게 됩니다:
- 신선하고 정확한 컨텍스트 (너무 많지도, 아무것이나 되어서도 안 됨).
- 탈선하지 않도록 하는 명시적인 제약 조건 (Constraints).
- 2시간 전에 내린 결정을 "잊어버리지" 않도록 하는 정기적인 요약.
- 무엇을 구축할지에 대한 명확한 비전과 깔끔한 분할을 보장하기 위한 기능 (Features) 예측.
사용 측면에서는 결국 자기 자신에게도 정확히 똑같은 규율을 적용하게 됩니다:
- 세션을 다시 시작하기 전에 이전 내용을 요약하기.
- 맹목적으로 신뢰하는 대신 모든 답변에 의문을 제기하기 (Challenge).
- 세션이 탈선하거나, 답변이 환각 (Hallucination)을 일으키거나, 정보가 오래되었을 때 이를 포착하여 새로운 대화로 시작해야 할 시점을 아는 것.
"맥락을 절대 놓쳐서는 안 되는 에이전트를 구축하면서, 저는 제가 AI를 사용할 때 왜 맥락을 놓치게 되었는지를 결국 이해하게 되었습니다."
물론 학습을 위한 훌륭한 리소스들이 존재하지만, 세션이 궤도를 벗어날 때 발휘되는 본능은 오직 직접 구축해 봄으로써만 진정으로 얻을 수 있습니다.
모델은 설계부터 게으릅니다
여기서 우리는 "AI 설계자 (IA Architecte)"(제가 코딩할 때 사용한 Gemini)와 "AI 작업자 (IA Ouvrière)"(Vibrisse에 통합한 로컬 모델 Gemma 4 e4b / 26b)를 명확히 구분해야 합니다.
AI 설계자가 코드를 생성하는 데 탁월하다면, 로컬 AI 작업자는 설계상 게으릅니다. 제약 조건이 없다면, LLM(Large Language Model)은 저항이 가장 적은 경로를 택합니다. 모델은 최선의 해결책을 찾는 것이 아니라, 수용 가능한 해결책을 찾으려 합니다.
구체적인 발견: 만약 7B 모델을 엄격한 가드레일(guardrails) 없이 방치한다면, 그 모델은 새벽 3시에 결국 // ... rest of the code here라고 적어버릴 것입니다. 하지만 주의하세요, 이는 클라우드(Cloud) 모델에게도 똑같이 적용됩니다! 특히 컨텍스트 윈도우(context window)가 포화 상태가 될 때 더욱 그렇습니다. 이러한 게으름은 모델 특유의 타협적인 성향과 결합되어, 우리가 흐름을 놓칠 때까지 AI가 우리를 앞질러 나아가도록 매우 빠르게 방치하게 만듭니다.
이러한 게으름에 대한 해답은 초구조화된 프롬프트(ultra-structured prompts)입니다. 경험은 대체 불가능합니다. 이는 AI 대신 일을 하기 위해서가 아니라, AI가 정확히 언제 실패하고 있는지를 알기 위해서입니다.
UX/UI의 결정적 중요성
또 다른 결정적인 교훈은, 에이전트를 만들 때 UX(사용자 경험)와 UI(사용자 인터페이스)는 선택 사항이 아니라는 점입니다. 특히 응답이 클라우드보다 덜 "즉각적"일 수 있는 로컬 환경에서는 더욱 그렇습니다.
사용자에게 최대한 많은 피드백을 제공해야 합니다. 모든 동작에는 눈에 보이는 반응이 있어야 하며, 그렇지 않으면 사용자는 에이전트가 멈췄다고 생각하게 됩니다. 매끄러운 느낌을 만들고, 가독성을 세심하게 관리하며, 오류를 우아하게 처리하는 것... 좋은 인터페이스(제가 Vibrisse에서 구현한 대화형 _Thought Graph_와 같은)를 구축한다는 것은 사용자 경험 (UX)을 통해 AI의 기계적 한계를 보완하는 것입니다. 하지만 이는 상호작용을 재고하는 것이기도 합니다. 에이전트의 궁극적인 목표는 당신의 IDE 옆에 있는 또 하나의 챗봇 (chatbot)이 되는 것이 아닙니다. 목표는 그것이 보이지 않게 되어 당신의 워크플로 (workflow)에 통합되는 것입니다 (제가 "고스트 모드 (Ghost Mode)"라고 부를 것입니다).
업계의 현황: 죽지도 않았고 변하지도 않았다
개발자들이 사라질까요? 아닙니다. 하지만 직업의 성격이 변하고 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기