이번에 처음으로 기사를 게시합니다.
그렇기 때문에 미흡한 기재나 누락 등이 있을 수 있으나, 댓글 등으로 지적해 주시면 감사하겠습니다.
또한, 구현 내용 및 기사 내용은 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)을 경험해 보세요!