의존성 없이 멀티 모델 Ollama 비교 도구를 구축한 방법
요약
Ollama를 활용해 여러 로컬 모델을 동시에 비교할 수 있는 의존성 없는 TUI 도구 구축 방법을 소개합니다. Python 표준 라이브러리만을 사용하여 별도의 설치 없이 병렬 스트리밍, 평가 모드, 벤치마크 기능을 제공합니다.
핵심 포인트
- Python 표준 라이브러리만 사용하여 의존성 없는 단일 파일 도구 구현
- curses를 활용한 실시간 병렬 토큰 스트리밍 및 통계 시각화
- RALPH, Council, Tribunal 등 고도화된 모델 평가 프레임워크 적용
- 웹 검색, 셸 명령 등 외부 도구 오케스트레이션 기능 포함
- 모듈형 구조를 하나의 파일로 결합하는 번들링 아키텍처 활용
의존성 없이 멀티 모델 Ollama 비교 도구를 구축한 방법
문제 상황
서로 다른 로컬 모델들이 동일한 프롬프트(Prompt)를 어떻게 처리하는지 비교하기 위해 ollama run을 실행하는 터미널 탭을 계속해서 여러 개 열어야 했습니다. 터미널 간에 복사 및 붙여넣기를 하는 방식은 확장성이 떨어집니다. 제대로 된 비교 도구가 필요했지만, 제가 찾은 것들은 모두 무거운 웹 UI이거나 수십 개의 pip 패키지를 요구했습니다.
접근 방식
Ollama와 직접 통신하는 curses TUI(Text User Interface)를 구축합니다. Python 표준 라이브러리만을 사용합니다. API를 위한 urllib, 인터페이스를 위한 curses, 파싱(Parsing)을 위한 json/re를 사용합니다. 파일 하나로 구성되며, pip install이 필요 없습니다.
작동 원리
병렬 스트리밍 (Side-by-side streaming). 스트리밍 뷰어는 curses 그리드(Grid) 내에서 여러 모델의 토큰(Tokens)을 동시에 렌더링합니다. 각 모델은 실시간 통계(경과 시간, 생성된 토큰 수, 초당 토큰 수)가 포함된 패널을 할당받습니다.
비교를 넘어선 평가 모드. 단순한 병렬 비교만으로는 부족했기에, 다음과 같은 구조화된 평가 모드를 추가했습니다:
-
RALPH — 자기 검토 루프(Self-review loop). 모델이 답변을 생성한 후, 자신의 답변을 비판하고 개선합니다. Ollama 임베딩(Embeddings)을 통한 코사인 유사도(Cosine similarity)를 사용하여 수렴(Convergence)을 감지합니다(모델이 더 이상 의미 있게 개선할 수 없을 때 중단됩니다).
-
Council — 다중 페르소나 토론(Multi-persona debate). 세 가지 페르소나(도메인 전문가, 회의론자, 악마의 변호인)가 여러 라운드에 걸쳐 질문에 대해 토론한 후, 종합적인 판결을 내립니다. 각 페르소나는 서로 다른 모델에서 실행될 수 있습니다.
-
Tribunal — 적대적 교차 심문(Adversarial cross-examination). 방어 모델이 주장을 펼치면, 검사 모델이 이에 이의를 제기합니다. 중재 모델이 각 이의 제기에 대해 판결을 내립니다.
벤치마크 모드 (Benchmark mode). 모든 모델에 대해 20가지 표준화된 테스트를 실행합니다: 숫자 세기, 산술, 웹 검색, URL 가져오기, 셸 명령(Shell commands), Python 실행, 파일 읽기, RSS 파싱, 임베딩 등. 각 테스트는 모델이 올바른 도구를 호출했는지 또는 올바른 출력을 생성했는지 확인합니다.
도구 오케스트레이션 (Tool orchestration). 모델에 외부 도구를 장착할 수 있습니다. 모든 기능은 선택 사항(Opt-in)이며 시작 시 확인됩니다:
- 웹 검색 (SearXNG 또는 DuckDuckGo)
- 요약을 포함한 URL 가져오기 (URL fetching)
- 셸 명령 실행 (샌드박스 처리됨)
- Python 코드 실행
- 구성 가능한 루트를 통한 파일 읽기
- 안전한 계산기 (AST 기반 화이트리스트 평가)
아키텍처 (Architecture)
소스 코드는 src/prompter/ 아래에 12개의 모듈로 구성된 모듈형 구조를 가집니다. 번들러 (Bundler)가 이를 하나의 prompter.py로 결합하여 배포합니다:
src/prompter/
header.py # Shebang + 모듈 독스트링 (docstring)
config.py # 환경 변수, 상수
...
번들러는 상대 경로 임포트 (relative imports)를 제거하고, 표준 라이브러리 (stdlib) 임포트를 중복 제거하며, 의존성 순서에 따라 연결합니다.
배운 점
-
curses는 생각보다 복잡합니다. 안전한 그리기 래퍼 (drawing wrappers)가 필수적입니다. 범위를 벗어난 쓰기 (out-of-bounds writes)는 조용히 충돌을 일으킵니다. 모든
addstr호출에는 범위 확인 (bounds check)이 필요합니다. -
urllib을 통한 토큰 스트리밍 (Token streaming)은 간단합니다. Ollama의 스트리밍 엔드포인트 (streaming endpoint)는 줄바꿈으로 구분된 JSON 청크 (chunks)를 전송합니다. 단순히 줄을 읽고 파싱하면 됩니다.
-
컨텍스트 윈도우 (Context windows)는 실제적인 제약 사항입니다. 다회차 토론 모드 (multi-round debate modes)에서는 메시지 기록이 빠르게 증가합니다. 저는 토큰 수를 추정하고 콘텐츠의 처음과 마지막 절반을 유지하는
_truncate_to_context()를 구현했습니다. -
코사인 유사도 (Cosine similarity)는 자기 검토 수렴 (self-review convergence)에 효과적입니다. 연속된 답변을 임베딩 (embedding)하고 유사도를 비교함으로써, RALPH 모드는 추가적인 검토 단계가 답변을 개선하지 못할 시점을 감지할 수 있습니다.
사용해보기
wget https://raw.githubusercontent.com/whonixnetworks/prompter/main/prompter.py
chmod +x prompter.py
python3 prompter.py
Python 3.7 이상 및 로컬에서 실행 중인 Ollama가 필요합니다. 그게 전부입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기