
Ollama + Gemma + Zoo Code로 코딩할 수 있는 환경 구축해 보기
요약
Ollama, Gemma, Zoo Code를 활용하여 보안이 유지되는 로컬 AI 코딩 환경을 구축하는 방법을 소개합니다. FastAPI 프록시 서버를 중간에 배치하여 로컬 LLM의 불안정한 Tool Calling 성능을 보완하고 안정적인 파일 조작을 가능하게 합니다.
핵심 포인트
- Ollama와 Gemma를 이용한 무료 로컬 AI 코딩 환경 구축
- FastAPI 프록시 서버를 통한 Tool Calling 응답 정규화
- 로컬 모델의 JSON 파싱 에러 및 불필요한 출력 문제 해결
- Zoo Code(Roo Code)와 OpenAI 호환 API 형식 간의 브릿지 역할 구현
이번에 처음으로 기사를 게시합니다.
그렇기 때문에 미흡한 기재나 누락 등이 있을 수 있으나, 댓글 등으로 지적해 주시면 감사하겠습니다.
또한, 구현 내용 및 기사 내용은 Gemini · Claude를 사용하고 있습니다.
로컬 환경에서 보안이 유지되면서도 무료로 AI 코딩 어시스턴트(페어 프로그래밍)를 구현하고 싶다고 생각한 적은 없으신가요?
본 기사에서는 Ollama, 가볍고 고성능인 모델 Gemma, 그리고 VS Code의 강력한 AI 확장 기능인 **Zoo Code (Roo Code)**를 조합한, 최강의 로컬 AI 개발 환경 구축 절차를 소개합니다.
이번 구성의 가장 큰 포인트(핵심)는 Ollama와 Zoo Code 사이에 **FastAPI로 만든 독자적인 프록시 서버(Proxy Server)**를 끼워 넣는 점입니다. 이를 통해 로컬 LLM 특유의 「Tool Calling (도구 호출)의 불안정성」을 극복하고, Zoo Code가 의도한 대로 파일을 읽고 쓸 수 있게 됩니다.
본 환경은 다음과 같은 3가지 컴포넌트로 구성됩니다.
┌──────────────┐ ┌──────────────────┐ ┌──────────────┐
│ Zoo Code │────▶│ FastAPI Proxy │────▶│ Ollama │
│ (VS Code) │◀────│ :8000 │◀────│ :11434 │
...
Zoo Code (VS Code 확장 기능): 사용자 인터페이스 및 에디터 조작 -
FastAPI (프록시 서버): 요청(Request) · 응답(Response)의 성형 (※이 부분이 핵심!) -
Ollama: LLM (Gemma 등)의 실행 엔진
Zoo Code는 「파일 읽기/쓰기」나 「명령 실행」을 수행하기 위해, LLM에 대하여 엄격한 Tool Calling (도구 호출) JSON 포맷을 요구합니다.
하지만 로컬 모델 (Gemma 등)은 OpenAI의 API처럼 완벽한 JSON 포맷을 반환하는 데 서툴거나, 불필요한 사고 과정(<thinking>)
)을 출력하여 Zoo Code 측에서 파싱 에러(Parse Error)를 일으키는 경우가 매우 많습니다.
그래서 FastAPI 중계 서버를 끼워 넣음으로써 다음과 같은 처리를 수행합니다.
요청 시 강제: LLM에 대하여 「반드시 지정된 XML 태그 <tool_call>
과 JSON 형식으로 도구를 호출할 것」이라는 시스템 프롬프트(System Prompt)를 동적으로 주입. -
응답 시 파싱: LLM이 반환한 텍스트에서 <tool_call>
블록만을 정규 표현식으로 추출하여, Zoo Code가 해석할 수 있는 OpenAI 호환의 올바른 응답 형식으로 변환하여 반환. -
폴백(Fallback): <tool_call>
태그가 발견되지 않을 경우, 마크다운(Markdown)의 JSON 코드 블록(json
)에서도 Tool Call 정보를 추출 가능.
이 프록시가 있는 덕분에 로컬 모델에서도 Zoo Code가 원활하게 작동하게 됩니다.
다음과 같은 디렉토리 구성으로 파일을 작성합니다.
GitHub에서 클론(Clone)하면 그대로 사용할 수 있습니다.
git clone https://github.com/masasi-1123/ollama-zoocode-proxy.git
cd ollama-zoocode-proxy
ollama-zoocode-proxy/
├── docker-compose.yml
└── FastAPI/
...
먼저 인프라가 되는 docker-compose.yml 입니다. Ollama 본체와 FastAPI 프록시 서버를 정의합니다.
(※ NVIDIA GPU를 사용하는 것을 전제로 한 설정입니다. 필요하지 않은 경우 deploy
섹션을 삭제해 주세요)
version: "3.8"
services:
# 1. Ollama (AI 모델 실행 환경)
...
포인트: Ollama의 image 에 커스텀 이름인 ollama_zoo_code를 붙임으로써 재빌드 시의 캐시 효율을 향상시킵니다. 또한, networks를 통해 컨테이너 간의 통신을 ollama-network라는 이름이 지정된 네트워크로 통일하고 있습니다.
Zoo Code의 요청을 Ollama용으로 변환하는 미들웨어(Middleware)가 되는 부분입니다.
# 컨테이너 설정.
FROM python:latest
# 작업 디렉토리 설정.
...
main.py
에서는 포맷 처리 (Format processing)를 적용할 모델을 TARGET_MODELS로 정의하고 있습니다. 대상이 아닌 모델은 패스스루 (Pass-through, 그대로 통과)됩니다.
# 포맷(성형) 대상 모델 리스트
TARGET_MODELS = [
"gemma4:12b",
...
💡 힌트: 자신이 사용하고 싶은 모델 이름을 TARGET_MODELS에 추가하면, 해당 모델도 포맷 대상으로 만들 수 있습니다.
요청 시 도구 사용 방법을 강제하는 시스템 프롬프트 (System prompt)를 주입합니다.
def format_request_for_ollama(request_body):
formatted_body = request_body.copy()
# Zoo code의 content: [{type: "text", text: "..."}] 형식을
...
LLM의 응답 텍스트에서 <tool_call> 태그를 정규 표현식 (Regular expression)으로 추출하여, OpenAI 호환 JSON 형식으로 변환합니다.
def parse_response_from_ollama(ollama_text):
# <tool_call>...</tool_call> 패턴을 추출
tool_call_pattern = re.compile(r"<tool_call>(.*?)</tool_call>", re.DOTALL)
# 폴백 (Fallback): 마크다운 JSON 블록 (```json ... ```)도 대상
json_block_pattern = re.compile(r"```json\s*(\{.*?\})\s*```", re.DOTALL)
matches = tool_call_pattern.findall(ollama_text)
# <tool_call>이 발견되지 않은 경우 JSON 블록을 탐색
if not matches:
...
main.py에서는 모든 HTTP 요청을 캐치하여 다음과 같은 흐름으로 처리합니다.
1. 요청 수신 → 경로 정규화 (v1/api/tags → api/tags)
2. 채팅 엔드포인트 (Chat endpoint) & 대상 모델 → 포맷 패턴
a. format_request_for_ollama()로 요청 성형
...
※ 보충: main.py 측에서는 FastAPI의 StreamingResponse/SSE를 사용하여, Ollama로부터의 응답을 일단 모두 수신한 후, OpenAI 호환 의사 스트림 (Pseudo-stream)으로서 Zoo Code에 반환하는 처리를 기술하고 있습니다.
구성이 완료되면 컨테이너를 실행하고 모델을 빌드합니다.
# 1. 컨테이너 빌드 및 실행
docker compose up -d --build
# 2. Ollama에서 베이스 모델 가져오기 (최초 1회)
...
마지막으로, VS Code 측에서 Zoo Code (Roo Code)를 열고, API 접속 대상을 Ollama가 아닌 **FastAPI 프록시 (Proxy)**로 향하게 합니다.
- Zoo Code 설정 화면 (API Provider)을 연다
- Provider를 Ollama로 설정
- Base URL:
http://localhost:8000/v1(※Ollama의 11434가 아니라, FastAPI의 8000번 포트를 지정!) - API Key: 임의의 문자열 (
dummy등) - Model ID:
gemma4:e2b(TARGET_MODELS에 포함된 모델 이름을 지정)
이것으로 설정이 완료되었습니다!
로컬 LLM을 코딩 에이전트 (Coding agent)로 활용하려고 하면, 도구 호출 (Tool calling)의 정확도 (JSON 포맷 깨짐 등)가 큰 장벽이 됩니다.
이번과 같이 FastAPI로 프록시 서버를 직접 제작하여, 프롬프트 강제와 응답 파싱 (Parsing)을 중간에 삽입함으로써, Gemma와 같은 로컬 모델로도 클라우드 API와 유사하게 Zoo Code를 능숙하게 사용할 수 있게 됩니다.
구성 전체는 docker compose up -d로 한 번에 실행할 수 있으며, GitHub에도 공개되어 있습니다.
👉 리포지토리: https://github.com/masasi-1123/ollama-zoocode-proxy
꼭 이 환경을 구축하여, 쾌적하고 안전한 로컬 AI 페어 프로그래밍 (Pair Programming)을 경험해 보세요!
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기