본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 16. 22:04

작은 모델, 위대한 도구: 프로덕션 환경에서의 로컬 AI 에이전트를 위한 엔지니어링

요약

대규모 모델 대신 소형 로컬 모델을 활용하여 프로덕션 환경에서 신뢰할 수 있는 AI 에이전트를 구축하는 엔지니어링 방법론을 다룹니다. LangGraph를 이용한 상태 머신 아키텍처와 Supervisor/Worker 패턴을 통해 에이전트의 안정성을 확보하는 구체적인 기술 스택을 소개합니다.

핵심 포인트

  • 대형 모델 대신 소형 로컬 모델과 엄격한 엔지니어링의 조합 강조
  • LangGraph를 활용한 상태 머신 기반의 에이전트 아키텍처 설계
  • Supervisor/Worker 패턴을 통한 작업 할당 및 오류 복구 구현
  • Gemma 4 및 Llama 3 8B 모델을 활용한 실전 테스트 결과 공유

가치 있는 코드 어시스턴트(code assistant)를 구축하려면 반드시 GPT나 Claude를 사용해야 한다는 지속적인 미신이 있습니다. 이는 사실이 아닙니다. 1조 개의 파라미터를 가진 모델은 필요하지 않습니다. 당신에게 필요한 것은 작은 로컬 모델(local model)과 그 주변을 둘러싼 매우 엄격한 엔지니어링입니다.

이것이 기업들이 나아가고 있는 방향입니다. Mark Zuckerberg가 언급했듯이, 미래는 단 하나의 전지전능한 모델이 아니라 _"모든 기업이 자신만의 특화된 AI를 갖는 것"_입니다. 그리고 이러한 특성화는 데이터 보안을 보장하기 위해 필연적으로 _파인튜닝 (fine-tuning)_과 로컬 배포(또는 주권 서버(sovereign servers) 상의 배포)를 수반합니다.

Vibrisse Agent 구축의 핵심 논지는 한 문장으로 요약될 수 있습니다: 작은 모델, 위대한 도구.

이 글에서 저는 로컬 모델을 길들이고 프로덕션 환경에서 신뢰할 수 있게 만들기 위해 구현한 기술 스택과 구체적인 엔지니어링 솔루션을 상세히 설명할 것입니다: **LangGraph, Ollama, FastAPI, React (빌드 단계 없이 임베디드 커스텀 CSS 사용)**이며, 이 모든 것은 32 GB RAM을 갖춘 머신에서 실행됩니다.

지금 바로 자신의 머신에서 에이전트를 실행해보고 싶은 분들을 위해:

// MacOs / Linux
curl -sSL https://agent.vibrisse-studio.dev/install.sh | bash

...

아키텍처: 왜 상태 머신 (LangGraph)인가?

처음에 LLM 애플리케이션을 구축할 때, 우리는 흔히 순차적인 체인(sequential chains)으로 생각하는 경향이 있습니다:
입력(Input) -> 프롬프트(Prompt) -> 도구(Tool) -> 출력(Output).
문제는 하나의 노드(node)가 실패하면, 오류를 포착하거나 충돌의 맥락을 이해할 수 없는 상태로 전체 체인이 중단된다는 점입니다.

그 지점에서 LangGraph가 등장합니다. Vibrisse의 아키텍처는 체인이 아니라 **상태 머신 (state machine)**입니다. 그래프의 모든 노드는 매우 정밀한 책임을 가지며, 전역 대화 상태(global conversation state)를 공유하고, 다음 노드로 이동하기 위해 조건부 전이(conditional transitions)를 사용합니다.

저는 Supervisor / Worker 패턴을 구현했습니다:

  • Supervisor는 사용자의 의도(intent)를 분석합니다. 이는 라우팅(routing) 외에 다른 작업은 수행하지 않습니다.
  • 이는 전문화된 Workers (RAG Worker, Search Worker, Ghost Worker 등)에게 작업을 할당(dispatch)합니다.
  • 만약 Worker가 실패하거나 더 많은 정보가 필요할 경우, 상태(state)를 다시 Supervisor에게 보낼 수 있습니다.

진짜 싸움: 소형 모델의 "게으름(Laziness)" 길들이기

이 프로젝트에서 가장 가치 있는 부분이자, 아주 적은 수의 튜토리얼만이 정직하게 기록하고 있는 부분은 바로 소형 LLM(Large Language Models)의 본성과 싸우는 것이었습니다.

무기 선택: 승리한 모델들

저의 충돌 테스트(crash tests)에서 어떤 모델들이 살아남았는지 궁금하시다면: 저는 에이전트의 전체 핵심을 **Gemma 4 (e4b)**를 중심으로 구축했습니다. 왜일까요? 이 모델은 시각(vision)과 "사고(thought)" 관리를 네이티브하게 통합하면서도, 매우 구조화된 Google 스타일의 응답 형식을 제공하기 때문입니다. 하지만 평가(evaluation)와 지표(metrics) 측면에서는 Llama 3 8B로 전환해야 했습니다. 너무 작은 모델은 자신의 답변을 신뢰성 있게 평가하는 능력이 부족하다는 것이 증명되었습니다.

제약 조건과 생각하며 말하기 (Thinking Out Loud)

엄격한 제약 조건이 없다면, 로컬 모델은 항상 저항이 가장 적은 경로를 택할 것입니다. 구체적으로, 만약 당신이 확고한 지시 없이 새벽 3시에 복잡한 파일을 리팩터링(refactor)하라고 요청한다면, 모델은 자랑스럽게 다음과 같이 작성할 것입니다: // ... 나머지 코드는 여기에 있음.

해결책은 무엇일까요? 역할, 엄격한 JSON 출력 형식 (strict JSON output format), 그리고 무엇보다도 "생각하며 말하기 (think out loud)"의 의무를 부여하는 초구조화된 시스템 프롬프트(system prompts)입니다. 액션을 트리거하기 전에 <thought> 태그를 사용하도록 강제하는 것은 두 가지 측면에서 매우 중요합니다: 에이전트가 왜 잘못된 라우팅 결정을 내렸는지 디버깅(debugging)하는 것과 UX를 개선하는 것입니다.

3중 레이어의 견고한 파싱 (Triple-Layer Robust Parsing)

LLM이 JSON으로 답변하도록 강제하는 것은 전쟁의 절반에 불과합니다. 모델이 "지치거나" 컨텍스트(context)에 엉키게 되면, 잘못된 형식의 JSON을 생성할 수 있습니다. 에이전트가 충돌(crash)하는 것을 방지하기 위해, 저는 3중 레이어 파싱 시스템을 설계해야 했습니다:

  1. Layer 1 (레이어 1): 표준 JSON 파싱 (Standard JSON parsing).
  2. Layer 2 (레이어 2): 모델이 JSON 주변에 텍스트를 추가한 경우, 객체를 추출하기 위한 정규 표현식 폴백 (Regex Fallback).
  3. Layer 3 (레이어 3): JSON이 완전히 깨진 경우, 키워드 폴백 (keyword fallback)을 통해 의도를 추측하여 대체 동작을 수행합니다. 충돌(crash)이 전혀 발생하지 않습니다.

재미있는 사실 (Fun Fact): 이 접근 방식은 프로젝트 후반부에 했던 사고 실험에서 탄생했습니다: "만약 매우 사양이 낮은 기기에서, 성능이 매우 불안정한 SLM (Small Language Model, 소형 언어 모델)으로 이 에이전트를 실행해야 한다면 어떻게 될까?" 이러한 강제된 제약 조건들이 제가 계속 유지하게 된 회복 탄력성(resilience) 기술들을 탄생시켰습니다. (어쩌면 미래의 "Vibrisse-Lite"를 위한 시작점이 될지도 모르겠네요? 기대해 주세요...)

3중 레이어 검색 (Triple-Layer Retrieval): 노이즈가 아닌 정밀한 RAG

RAG (Retrieval-Augmented Generation, 검색 증강 생성)의 목적은 모델에 컨텍스트를 쑤셔 넣는 것이 아닙니다. 소형 모델에 더 많은 텍스트를 보낼수록 환각 (hallucination) 현상은 더 심해집니다. 컨텍스트는 타겟팅되어야 하며 초정밀(ultra-precise)해야 합니다. Vibrisse 에이전트는 **3중 레이어 검색 (Triple-Layer Retrieval)**을 사용합니다:

  1. 결정론적 레이어 (Deterministic Layer, Ripgrep): 정확한 쿼리용 (예: "API_KEY 변수가 어디에 정의되어 있는가?"). 100% 정확하며, 환각이 0%입니다.
  2. 의미론적 레이어 (Semantic Layer, ChromaDB): 의도를 이해하기 위한 용도 (예: "에러가 어떻게 처리되는지 보여줘").
  3. 통계적 레이어 (Statistical Layer, BM25): 표준적인 안전망 역할을 합니다.

우리는 하나의 방법만을 선택하는 것이 아니라, 세 가지 방법을 모두 실행하고 그 결과를 병합합니다.

에이전트의 근육: MCP 허브, 웹 검색, 그리고 고스트 모드 (Ghost Mode)

LLM (Large Language Model, 거대 언어 모델) 단독으로는 그저 "병 속에 든 뇌"일 뿐입니다. 여기에 근육을 이식하려면 모든 단일 동작이 설계되고 코드로 작성되어야 한다는 점을 깨달아야 하며, 이는 에이전트의 "마법 같은" 측면을 빠르게 깨뜨리기도 합니다. 에이전트가 단순한 grep을 수행하기를 원하시나요? 그렇다면 도구(tool)를 직접 코딩해야 하고, 단독으로 테스트한 다음, Vision 동작 후에 테스트하고, 다시 웹 검색 후에 테스트하여 LangGraph가 충돌하지 않도록 보장해야 합니다.

Ghost mode

에이전트는 로컬 도구뿐만 아니라, 답변을 하기 전 가장 최신의 문서를 가져오는 데 필수적인 **Web Search (Tavily API)**와 같은 연결된 도구도 보유하고 있습니다.

MCP 허브 (Model Context Protocol)

바퀴를 새로 발명하는 대신, Anthropic의 MCP 표준을 통합했습니다. Vibrisse는 MCP Client (MCP 클라이언트) 역할을 합니다. 도구를 추가하는 것은 단순히 외부 Server (서버)를 연결하는 문제일 뿐입니다. 따라서 이 아키텍처는 Google의 webMCP와 같은 진화에 대비할 수 있는 "미래 보장형 (future-proof)" 구조를 갖추고 있습니다.

고스트 모드 (Ghost Mode): 파일 내 직접 지시 (In-File Directives)

이것은 워크플로우의 킬러 피처 (killer-feature)입니다. 에이전트의 목표는 당신에게 창에서 채팅을 강요하는 것이 아닙니다.

Ghost Mode

Ghost Mode

Python의 watchdog 라이브러리를 기반으로 한 WatcherService가 백그라운드에서 실행됩니다. 저장된 주석에서 @vibrisse: 태그가 감지되는 즉시, 코드를 생성하여 에디터에 직접 주입하는 조용한 Ghost Worker (고스트 워커)를 트리거합니다.

아키텍트 모드 (Architect Mode): Human-in-the-Loop 및 Artifacts

복잡한 작업의 경우, 자율 에이전트가 루프 내에서 수십 개의 명령을 실행하도록 내버려 두는 것은 아키텍처 측면에서의 자살 행위입니다. 브레이크가 필요합니다. 그래서 저는 LangGraph를 사용하여 Human-in-the-Loop (인간 참여형) 패턴을 구현했습니다.

그래프 중단 (interrupt_after)

구조적인 작업이 감지되면, 라우터는 전용 노드(planning_node)로 전환됩니다. 이 노드는 엄격한 XML 태그(<artifact id="plan">)로 감싸진 Markdown 형식의 실행 계획을 생성합니다.
LangGraph의 미묘한 차이점은, 그래프가 interrupt_after=["planning_node"] 지침과 함께 컴파일된다는 것입니다. 계획이 생성되는 즉시 백엔드에서 실행이 완전히 중단되고 상태가 데이터베이스에 저장됩니다.

프론트엔드 렌더링 및 상태 재개 (Frontend Rendering and State Resumption)

React 측면에서는 UI가 정규 표현식(regular expression)을 사용하여 이러한 태그들을 가로채고, 원시 XML을 숨긴 뒤 풍부한 인터랙티브 컴포넌트(CodeDiff, Mermaid 다이어그램, 또는 TaskBoard)를 생성합니다. 그 후 사용자는 제안을 "승인(Approve)"하거나 "거절(Reject)"할 수 있는 버튼을 갖게 됩니다.

이 기능의 가장 큰 기술적 함정은 무엇일까요? 바로 상태 재개 (State resumption, Resume) 입니다.
사용자가 "승인"을 클릭하면 프론트엔드는 LangGraph 그래프를 재시작하는 라우트를 호출합니다. 문제는 아무런 말 없이 대화를 재개할 경우, 작은 LLM이 컨텍스트 히스토리(context history) 끝에 자신의 메시지(AIMessage)가 놓여 있는 것을 발견하고 나머지 논의 내용을 환각(hallucinating)하기 시작한다는 점입니다.
기발한 해결책: 추론을 재시작하기 전에 상태(state)에 HumanMessage("계획이 승인되었습니다. 구현을 진행해 주세요")를 조용히 주입하는 것입니다. 이렇게 하면 모델은 명확한 지침을 갖게 되며 자신에게 무엇이 기대되는지 정확히 알게 됩니다.

지속성 및 컨텍스트 제한 (Persistence and Context Limits)

건망증 치료하기 (Curing Amnesia)

2시간 전에 내린 결정을 잊어버리는 에이전트는 쓸모가 없습니다. Vibrisse는 완전한 스레드 지속성(thread persistence)을 위해 SQLite를 사용하며, 매 실행 시 project_map.json을 자동으로 생성하는 기능과 결합됩니다.

또 다른 숙적은 컨텍스트 윈도우 제한 (context window limit) (이러한 작은 모델들의 경우 종종 8k 토큰)입니다. 만약 RAG가 너무 많은 파일을 가져오면 컨텍스트가 폭발합니다. 이를 처리하기 위해 Vibrisse는 토큰 소비량을 지속적으로 모니터링하고 UI의 사이드바(Sidebar)에 실시간으로 표시합니다. 개발자는 컨텍스트가 포화되어 대화를 새로 고쳐야 할 시점을 정확히 알 수 있습니다.

주권적 라우팅: 스마트한 위임 (Sovereign Routing: Delegating Smartly)

에이전트는 행동하기 전에 각 요청의 복잡성을 분석합니다:

  • 단순 요청 (Simple request) -> 로컬 모델 (Ollama). 즉각적인 결과.
  • 복잡한 요청 (Complex request) -> 에이전트가 사용자의 명시적인 동의를 얻어 더 강력한 클라우드(Cloud) 모델로 전환할 것을 제안합니다.

Sovereign Routing

가장 큰 문제: 지연 시간(Latency)과 RAM

로컬 AI의 주요 결함에 대해 솔직해져야 합니다: 바로 **지연 시간(latency)**입니다. Vision 분석과 복잡한 React 컴포넌트 생성 기능을 결합하는 것은 일반 소비자용 기기에서 최대 3분(또는 그 이상)이 걸릴 수 있습니다. 이것은 완벽한 개인 정보 보호와 로컬 실행을 위해 지불해야 할 대가입니다.

이를 관리하기 위해 Vibrisse는 실제 하드웨어 리소스 추적 기능을 통합했습니다:

  • 설치 시 A (V)RAM 확인: 온보딩 위자드(onboarding Wizard)를 통해 에이전트를 세밀하게 구성합니다.
  • 사이드바의 리소스 게이지: 실시간 기기 부하를 모니터링합니다.
  • ThinkingConsole: 사고 토큰(thought tokens)을 '실시간' 스트리밍으로 보여줍니다. 로컬 액션이 느릴 때에도 텍스트가 스크롤되는 것을 보는 것만으로도 기다리는 인지적 마찰(cognitive friction)이 크게 줄어듭니다. 이것이 바로 '속도 디자인(Speed Design)'입니다.

Hardware Discovery

황금률: 블록 단위로 테스트하기

새로운 기능을 추가할 때마다 기존 기능이 고장 날 위험이 있습니다. 라우터(의도를 읽는 부분)는 전체 아키텍처에서 가장 변덕스러운 지점입니다. 도구 설명에 아주 작은 조정만 있어도 전체가 엉망이 될 수 있습니다. 모든 것은 의미론(semantics)에 의존합니다.

절대적인 규칙은 다음과 같습니다: 테스트하고, 테스트하고, 다시 테스트하세요. 기분이 좋지 않을 때조차 말입니다. 하지만 답변이 무작위인 시스템을 어떻게 테스트할까요?
저는 RAG의 품질과 관련성을 자동적으로 평가하기 위해 RAGAS 프레임워크(Llama 3 8B 기반)를 설정했습니다. 여기에 시나리오 파일(엄격한 수동 테스트)과 경량 Python 테스트 스크립트를 추가하여 다음 블록을 추가하기 전에 라우팅 체인이 깨지지 않도록 보장합니다.

결론: 작은 모델에 대한 찬사

Vibrisse는 "세계 최고의 에이전트"는 아닙니다. 언제나 더 강력한 클라우드 (Cloud) 모델들이 존재할 것입니다. 하지만 Vibrisse는 필요한 엔지니어링의 엄격함 (engineering rigor)을 갖춘다면, 작은 모델, 위대한 도구 (Small models, Great tools) 철학이 프로덕션 (production) 환경에서도 유효하다는 것을 증명합니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0