2026년 10월 31일 (토)

PINKSKY NEWS

매일의 기록을 뉴스처럼

테크

AI SaaS 대신 로컬 Ollama 모델 구동하기 — 공급자를 바꿀 때 실제로 고장 나는 것들

원문 제목 — Ein KI-SaaS gegen lokale Ollama-Modelle betreiben — was tatsächlich kaputt geht, wenn man den Anbieter wechselt

📄 전문 번역

필자는 LLM 공급자가 하드코딩된 상수가 아니라 런타임에 교체 가능한 DB 행인 스타터 키트를 운영하며, OpenAI, Anthropic 또는 로컬 Ollama 인스턴스를 이 구조로 바꿔 끼울 수 있다. 주된 목적은 API 크레딧을 소모하지 않고 시연하기 위한 것으로, 'localhost만 가리키면 된다'는 말이 실제보다 과소평가된 표현이라서 마찰 포인트를 공유한다는 설명이다.

로컬 모델 연결은 배포 작업이 아니라 관리자 액션으로 처리된다. POST /api/providers { "name": "Local Llama", "provider": "ollama", "baseUrl": "localhost:11434", "isActive": true } 형태로 공급자를 등록하면 채팅 코드는 그대로 유지되며, 모델명은 활성 공급자의 기본값에서 해석되므로 요청에서 아예 생략할 수도 있다. 이것이 공급자를 데이터로 다룬다는 발상의 핵심이다.

실제로 고장 나는 지점을 시간이 많이 든 순서대로 보면 다음과 같다. 첫째는 존재하지 않는 파라미터다. OpenAI 채팅 파라미터인 frequency_penalty, presence_penalty, response_format, tool choice는 모든 Ollama 모델이 지원하지 않으며, LiteLLM의 drop_params=True는 400 오류를 내는 대신 미지원 파라미터를 조용히 버린다. litellm.drop_params = True # Ollama 같은 공급자의 미지원 파라미터를 폐기한다. 멀티 공급자 앱에는 옳은 기본값이지만, 정교하게 튜닝한 temperature가 로컬 모델에는 그냥 적용되지 않는다는 뜻이므로 가정하지 말고 모델별로 확인해야 한다.

둘째는 스트리밍 프레임의 차이다. OpenAI, Anthropic, Ollama는 SSE 델타를 같은 방식으로 감싸지 않고, 특히 Ollama는 사용량만 담긴 청크와 역할만 담긴 청크를 내보낸다. 클라이언트가 방어 코드 없이 for chunk: append chunk.content 방식으로 처리하면 null 값이나 잘린 응답을 받게 되므로, 이 프로젝트는 모든 청크를 클라이언트에 보내기 전에 내부 스키마로 정규화한다. 셋째는 RAG용 임베딩이다. 기본 임베딩 모델은 OpenAI의 text-embedding-ada-002(1536차원, FAISS IndexFlatL2)인데, 완전 로컬 RAG를 원하면 로컬 임베딩 모델도 필요하고 FAISS 인덱스의 벡터 차원이 임베딩에 쓴 모델과 일치해야 한다. 모델을 바꾸면 기존 인덱스는 조용히 틀린 상태가 되므로 재참조가 아니라 재색인이 필요하다.

넷째는 지연 시간과 '200 OK 후 오류' 함정이다. Ollama의 콜드 모델 로딩은 수 초 이상 걸릴 수 있는데, 스트리밍 응답은 즉시 200을 보내므로 로딩 중 타임아웃이 500 오류가 될 수 없고 스트림 한가운데 SSE 오류 이벤트로 나타나야 한다. 웜 상태 API에서는 절대 생기지 않는 상황이라 로컬에서 놓치기 쉽다. 이런 문제는 전부 Ollama 탓이 아니라 모든 공급자가 하나의 프로토콜을 쓰는 것처럼 가정하는 대가이며, 추상화는 개발과 데모에는 그만한 가치가 있지만 유료 제품의 유일한 경로는 모델별 테스트 없이는 통과시키지 않겠다는 입장이다. 필자는 3번 항목을 다른 사람들이 어떻게 처리하는지도 묻는다. 로컬 RAG에 nomic-embed, bge, mxbai를 쓰면서 모델별로 코퍼스를 다시 임베딩하는지, 아니면 프로덕션에서 검색해야 하는 것은 별도의 OpenAI 임베딩 인덱스로 유지하는지다.

💬 주요 댓글 번역 (1)

1 익명

로컬 모델은 벡터 차원이 맞지 않아 RAG 파이프라인이 엉터리 결과를 내놓고 있었다는 사실을 깨닫기 전까지는 훌륭하다. 지난달에 정확히 같은 골치를 겪었다. 3번 항목에 대해서는 그냥 포기하고 지금은 FAISS 인덱스 두 개를 따로 운영하는데, 하나는 프로덕션에서 OpenAI를 쓸 때용 ada-002로 만든 것이고 다른 하나는 로컬 전용 데모용 nomic-embed로 만든 것이다. 둘 다 업데이트하는 게 번거롭지만 조용히 쓰레기 결과를 받는 일은 이제 없다. 절약한 디버깅 시간에 비하면 추가 디스크 공간은 무시할 수준이다.

🔍 루키 분석

레딧 사용자 Big_Burger_2904가 LLM 공급자를 DB 행으로 관리해 OpenAI, Anthropic, 로컬 Ollama를 런타임에 교체하는 스타터 키트 경험을 공유했다. 글은 미지원 파라미터, SSE 스트리밍 프레임 차이, RAG 임베딩 차원 불일치, 콜드 로딩 시 200 OK 후 오류라는 네 가지 마찰 포인트를 시간 비용 순으로 정리한다. 상위 댓글에서는 벡터 차원 불일치 문제에 대해 ada-002용과 nomic-embed용 FAISS 인덱스를 이중으로 운영하는 실무 방식이 제시되었다.

— 루키 · glm-5.3-flash:cloud