-
OpenAI-compat 표준화로 어댑터 100줄 들어내기 — passthrough가 가져온 코드 청결도IT 2026. 5. 6. 22:40
들어가며 — 어댑터가 점점 무거워지는 신호
홈서버에 6개의 자체 프로젝트(편의상 A~F)가 LLM을 부르고 있었다. 백엔드는 Ollama, 호출 방식은 프로젝트마다 미묘하게 달랐다.
- 프로젝트 A·B: Ollama
/api/chat직접 호출 (Ollama-native JSON) - 프로젝트 C: 클라이언트로부터 OpenAI-compat을 받아 Ollama-native로 변환해 백엔드에 넘기는 어댑터 (양방향)
- 프로젝트 D:
ChatOllama라이브러리 - 프로젝트 E:
requests로 Ollama 직접 호출 - 프로젝트 F: 프로젝트 C를 경유
vLLM으로 백엔드를 옮기면서 호출 방식을 모두 OpenAI-compat으로 표준화했다. 가장 흥미로운 결과는 프로젝트 C에서 일어났다 — OpenAI ↔ Ollama-native 양방향 어댑터 약 100줄이 통째로 사라졌다. 어댑터는 passthrough가 됐다.
이 글은 그 변화의 의미를 코드 청결도 관점에서 풀어쓴다. "호출 방식 통일"이라는 게 단순한 정리정돈 이상의 효과를 가진 이유.
1. 어댑터가 무엇이고 왜 필요했는가
Ollama와 OpenAI는 같은 일(LLM 호출)을 하지만 메시지 형식이 다르다.
겉보기에 비슷해 보이지만 차이가 많다.
- 모델 이름 표기 (
qwen3.6vsqwen3.6:latest) max_tokens↔options.num_predicttemperature↔options.temperature(한 단계 깊음)num_ctx는 OpenAI에 아예 없음 (Ollama는 명시 필요)think같은 Ollama 전용 옵션- 스트림 응답 형식 (SSE vs JSON-per-line)
finish_reason의 값 매핑 (Ollama는"stop"이 없고done: true로 표현)
호출자가 OpenAI 클라이언트 라이브러리를 쓰고 백엔드는 Ollama인 환경에서, 누군가는 그 차이를 메워야 한다. 그 누군가가 어댑터다.
2. 어댑터의 비용 — 100줄짜리 양방향 변환
어댑터의 진짜 비용은 줄 수가 아니다. 두 프로토콜의 차이가 미세하게 변할 때마다 어댑터가 깨진다는 점이다. Ollama가 새 버전에서
finish_reason매핑을 살짝 바꾸면, 어댑터의 SSE 재포장 로직 한 부분이 잘못된 값을 내보낸다. 이런 버그는 발견이 어렵고 재현이 까다롭다.
3. vLLM으로 옮기면서 어댑터가 사라졌다
vLLM은 OpenAI-compat 엔드포인트(
/v1/chat/completions)를 1급으로 지원한다. 클라이언트가 보낸 OpenAI body를 그대로 vLLM에 전달하고, vLLM이 돌려준 SSE를 그대로 다시 클라이언트로 흘려보낸다 — passthrough다.
4. 6개 호출자가 같은 인터페이스를 쓴다는 것
호출자가 표준 라이브러리(
openai,ChatOpenAI등)를 그대로 쓴다. 어댑터, 자체 HTTP 호출, Ollama 전용 옵션 — 모두 사라진다.이 통합의 진짜 가치는 "다음 백엔드로 옮길 때" 드러난다. 만약 vLLM에서 SGLang이나 다른 OpenAI-compat 엔진으로 옮긴다면? URL과 모델명만 바꾸면 6개 호출자가 그대로 동작한다. 이전 어댑터 시대였다면 백엔드별 어댑터를 새로 짜야 했다.
5. OpenAI API가 사실상 표준이 된 이유
OpenAI가 GPT-3.5 시절 발표한 chat completions API가 어쩌다 업계 표준이 됐는가? 세 가지 이유가 누적됐다.
- 최초의 대중적 LLM API였다. 처음 LLM을 코드로 부르기 시작한 사람들이 OpenAI 클라이언트를 썼고, 라이브러리 생태계(LangChain, LlamaIndex 등)도 그 위에 쌓였다.
- 형식이 단순하다. messages 배열 + temperature/max_tokens 정도. 지나치게 풍부하지 않아 다른 백엔드도 흉내내기 쉽다.
- Anthropic·Google·로컬 엔진이 모두 호환 모드를 제공한다. 클라이언트가 한 번 OpenAI 라이브러리를 익히면 모든 백엔드를 부를 수 있다.
그래서 이제 "OpenAI-compat 지원"은 LLM 백엔드의 기본 요건이다. vLLM이 이 표준을 잘 따르기 때문에 어댑터가 사라질 수 있었다.
정리
이 마이그레이션의 측정값(throughput, TTFT)은 GPU 세대가 바뀌면 다시 측정해야 한다. 그러나 어댑터 100줄을 들어내고 표준 인터페이스로 통합한 것은, 다음 모델·다음 백엔드로 갈아탈 때도 그대로 살아남는 자산이 된다.
- Ollama-native와 OpenAI 형식의 차이는 작아 보이지만, 매 호출마다 양방향 변환이 필요했다.
- vLLM은 OpenAI-compat을 1급 지원하므로 프록시가 passthrough가 됐다 — 어댑터 100줄 제거.
- 6개 호출자가 같은 표준 라이브러리를 쓰게 되어, 다음 백엔드로 옮길 때 호출자 코드를 안 건드려도 된다.
- OpenAI API가 사실상 표준이 된 덕에 어댑터 없는 운영이 현실적이다.
한 줄로 줄이면, "표준에 붙으면 어댑터가 사라진다." 측정 가능한 속도 이득보다, 측정 안 되는 코드 청결도 이득이 장기적으로는 더 크다 — 다음 모델로 갈아탈 때 비로소 증명된다.
이 글은 생성형 AI의 도움을 받아 작성되었습니다. 원본 자료를 기반으로 AI가 초안을 생성하고, 작성자가 검토·편집하였습니다.
'IT' 카테고리의 다른 글
로컬 챗봇 시리즈 #2 — Project 시스템 프롬프트는 왜 글로벌 Custom Instructions '다음에' 와야 하나 (0) 2026.05.08 로컬 챗봇 시리즈 #1 — 메시지 편집은 왜 그렇게 단순해야 하나: 컨텍스트 엔지니어링 관점에서 (0) 2026.05.08 Ralph Loop — bash while true + LLM CLI가 만든 어이없게 강력한 에이전트 패턴 (0) 2026.05.07 GPU 스케줄러를 Ollama warmup에서 vLLM 컨테이너로 옮긴 과정 — 시작·종료 시퀀스를 다시 짜다 (0) 2026.05.06 RAG 청크 맥락에서 thinking을 꺼야 하는 이유 — enable_thinking=False가 필요한 순간 (0) 2026.05.06 vLLM reasoning_parser — <think> 블록을 정규식 말고 구조로 받는 법 (0) 2026.05.06 KV cache FP8로 동시 요청 76배 수용하기 — LLM 메모리의 숨은 주범 정리 (0) 2026.05.06 Ollama에서 vLLM으로 백엔드를 바꿨더니 throughput이 148% 올랐다 — 같은 모델, 다른 엔진 (0) 2026.05.06 Gemma 4에서 Qwen 3.6으로 갈아탔다 — 두 모델을 모든 지표로 비교한 기록 (0) 2026.05.06 Fused 커널은 왜 3~4배 빠른가 — GPU 메모리 계층과 Marlin의 비밀 (0) 2026.05.05 - 프로젝트 A·B: Ollama