요즘은 쓸 만한 LLM 선택지가 너무 빨리 바뀐다. 새 모델이 나오고, 비슷한 성능을 더 낮은 가격에 제공하는 모델도 생기고, 입력 한도도 계속 커진다. 며칠 전까지 가격과 성능의 균형이 좋아 보이던 모델도, 더 싸거나 입력 한도가 더 큰 모델이 나오면 금방 다시 검토해야 하는 선택이 된다.
한두 개의 내부 도구나 작은 서비스라면 모델 이름을 코드에 직접 넣어도 된다. 하지만 LLM을 사용하는 도구와 서비스가 늘어나면 이야기가 달라진다. 모델 이름, provider, base_url, 실패했을 때 넘길 fallback 후보가 코드에 들어가기 시작하면, 모델 교체는 설정 변경이 아니라 코드 검색과 수정 작업이 된다.
authgate를 만들 때 사용자 인증 흐름을 서비스 밖으로 빼고 각 서비스가 자기 기능에 집중하게 했던 것처럼, llmgate는 LLM 모델 이름, provider, fallback 순서 같은 호출 결정을 도구와 서비스 코드 밖으로 빼려는 시도였다.
이 글은 llmgate의 설정 형식이나 내부 구현을 설명하려는 글은 아니다. 모델 호출 정책이 코드로 새어 들어오기 시작했을 때 어떤 문제가 생겼고, 왜 그 정책을 작은 호출 경계 뒤로 빼려고 했는지 정리하는 글이다.
Table of contents
Open Table of contents
1. 모델 선택 기준이 빠르게 바뀌기 시작했다
이 변화는 단순히 모델이 많아졌다는 뜻이 아니었다. 모델의 가격, 입력 한도, 과금 방식이 코드 안에 박아둘 고정값이 아니라 자주 바뀌는 운영 변수가 됐다는 뜻이었다. 월 구독형 모델 묶음이나 OpenAI 호환 API를 제공하는 로컬 모델 서버 같은 제공 방식도 같이 늘어난다.
2026년 5월 기준으로, OpenCode Go처럼 월 구독형으로 여러 코딩 모델에 접근하게 해주는 서비스가 나오고, DeepSeek V4 계열처럼 큰 입력 한도와 낮은 API 단가를 강조하는 모델도 나온다. 이 글에서 중요한 것은 특정 모델이 더 좋다는 이야기가 아니다. 이런 선택지가 계속 바뀌면 모델 호출 정책도 코드 안에 박아둘 값이 아니라 운영하면서 조정할 값이 된다.
모델 선택지가 늘어나는 것은 반갑지만, 내부 도구와 작은 서비스를 만들고 운영하는 입장에서는 다른 문제가 생긴다. 코드 작성과 수정에 더 적합한 모델, 로그 분석에 더 적합한 모델, 요약이나 분류 같은 반복 작업에 충분한 경량 모델이 나올 때마다 LLM 호출 코드를 고치고 싶지는 않았다.
2. 선택지가 많아질수록 호출 정책이 코드로 새어 들어왔다
처음에는 각 도구가 사용할 LLM 모델 이름을 직접 지정해도 자연스러워 보였다. 작업 성격에 맞는 모델을 골라 쓰면 됐고, 도구가 적을 때는 그 정도로 충분했다.
하지만 도구가 늘어나면 모델 이름만 코드에 남지 않는다. 어느 provider의 base_url을 사용할지, primary 모델이 실패했을 때 어떤 fallback 후보로 넘길지, 반복 호출의 비용을 줄이기 위해 어떤 모델로 낮출지까지 기능 코드 안으로 들어온다.
특히 저렴한 모델이나 새 provider를 호출 후보로 넣을수록 가격만 보고 고정하기는 어려웠다. 같은 모델 공급사라도 내가 쓰는 티어에 따라 rate limit이 다르고, 저렴한 호출 경로를 우선 사용할수록 응답 지연이나 일시적인 실패 가능성도 함께 고려해야 했다. 그래서 “이 모델을 쓴다”가 아니라 “이 모델을 먼저 시도하고, 안 되면 어떤 후보로 넘긴다”가 호출 정책의 일부가 됐다.
문제는 LLM 모델명이 코드에 박힌 것 자체가 아니었다. 모델 선택 정책이 기능 코드에 섞이는 것이 문제였다. 이 상태에서는 모델 교체가 코드 수정과 배포로 이어지고, fallback 방식도 도구마다 갈라진다.
3. 문제는 모델 이름이 아니라 호출 정책의 위치였다
그래서 문제는 LLM 모델 이름 자체가 아니라 호출 정책의 위치라고 봤다. 겉으로 보면 단순히 모델명을 코드 밖으로 빼는 문제처럼 보인다. 하지만 실제로는 모델 이름, provider, fallback 순서, timeout 같은 호출 결정을 어디에 둘 것인가에 가까웠다.
내가 나누고 싶었던 경계는 단순했다. 에이전트 서비스는 실행 하니스 설계에 집중하고, 모델 후보와 provider, fallback은 llmgate 뒤로 넘긴다.
기존 구조
에이전트 서비스 / 실행 하니스
└─ 모델 이름, provider, fallback을 직접 들고 있음
└─ LLM provider / 로컬 모델
llmgate를 둔 구조
에이전트 서비스 / 실행 하니스
└─ 역할 이름만 넘김: worker, cheap, planner
└─ llmgate
└─ 모델 후보, provider, fallback을 관리
└─ LLM provider / 로컬 모델
| 책임 | 기존 구조 | llmgate를 둔 구조 |
|---|---|---|
| 작업 흐름 | 에이전트 / 실행 하니스 코드 | 에이전트 / 실행 하니스 코드 |
| 도구 호출 | 에이전트 / 실행 하니스 코드 | 에이전트 / 실행 하니스 코드 |
| 프롬프트 구성 | 에이전트 / 실행 하니스 코드 | 에이전트 / 실행 하니스 코드 |
| 모델 선택 | 에이전트 / 실행 하니스 코드가 실제 모델 이름을 선택 | 에이전트 / 실행 하니스 코드는 역할 이름만 선택 |
| provider 선택 | 에이전트 / 실행 하니스 코드 | llmgate 설정 |
| fallback chain | 에이전트 / 실행 하니스 코드 | llmgate 설정 |
| 후보 모델 우선순위 | 에이전트 / 실행 하니스 코드 | llmgate 설정 |
그래서 에이전트 서비스와 자동화 코드는 모델 운영 정책을 직접 들고 있지 않아야 한다고 봤다. 실행 하니스 코드는 작업 흐름과 도구 호출, 프롬프트 구성에 집중하면 된다. 실제 모델 후보, provider, fallback 순서는 llmgate가 설정 파일에 따라 결정한다.
4. 호출자는 모델 이름 대신 역할 이름을 부른다
호출자가 표현해야 하는 것은 실제 모델 이름이 아니라 작업의 성격이라고 봤다.
- 빠르고 저렴하게 처리해도 되는 작업
- 코드 작성이나 수정처럼 정확성과 안정성이 중요한 작업
- 계획이나 리뷰처럼 더 긴 판단 과정이 필요한 작업
- 로그 분석처럼 응답 품질과 비용의 균형이 중요한 작업
- 요약, 분류, 포맷 변환처럼 로컬 모델이나 경량 모델로 반복 처리할 수 있는 작업
llmgate에서는 호출자가 실제 모델 이름 대신 worker, cheap, planner 같은 역할 이름을 사용한다. OpenAI SDK는 그대로 쓰되, SDK의 base_url을 llmgate 주소로 바꾸고, 인증 정보도 provider에 직접 붙는 값이 아니라 llmgate가 검증할 값으로 바꾼다. model 필드에는 실제 모델 이름 대신 역할 이름을 넣는다.
예를 들어 설정 파일에서 worker alias의 chain에는 코드 작업에 쓸 후보 모델들이 우선순위 순서대로 들어간다. 호출자는 worker만 부르고, 첫 번째 후보 호출이 일시적으로 실패하면 llmgate가 두 번째 후보를 시도한다. 그 후보도 실패하면 다음 후보로 넘어가는 식이다.
개념적으로는 이런 모양에 가깝다.
역할 이름: worker
1. 가장 먼저 시도할 코드 작업 모델
2. 1번이 실패하면 시도할 후보 모델
3. 필요하면 마지막 후보로 둘 로컬/경량 모델
호출 코드:
model = "worker"
쓰던 모델이 오래되거나 fallback 후보를 바꾸고 싶을 때는 호출 코드를 바꾸는 것이 아니라 worker 뒤의 후보 체인과 우선순위만 바꾼다. 호출하는 쪽은 계속 worker만 호출하면 된다.
5. prompt와 response 원문은 저장하지 않는다
호출 경계를 만들면서 가장 조심한 것은 prompt와 response 원문을 저장할지 여부였다. 게이트웨이에 DB를 붙여 prompt, response, 원문을 포함한 상세 호출 이력을 저장하기 시작하면 사용량 집계, 비용 계산, 관리자 화면 같은 기능을 llmgate 안에서 만들고 싶어진다. 그 순간 llmgate는 호출 실행기가 아니라 관리 플랫폼이 된다.
내가 원한 것은 호출 이력 관리 플랫폼이 아니었다. llmgate는 모델 호출을 실행하고, 원문이 아닌 최소 운영 메타데이터만 남기면 충분하다고 봤다. 기본적으로 prompt와 response 원문은 저장하지 않는다.
기본 로그에는 request id, 요청한 model 값, 최종 시도 모델, 결과 상태, attempts count, token usage 같은 운영 메타데이터만 남긴다. fallback 여부는 prompt와 response 원문을 보지 않아도 attempts count와 시도 기록으로 판단할 수 있다. 나중에 품질 비교나 모델 실험을 위해 prompt와 response 원문이 필요한 경우에는 별도 이벤트 스트리밍 경로로 llmgate 밖으로 내보낸다. 그 경우에도 저장과 분석은 llmgate 밖의 별도 시스템이 맡게 둔다.
원문 저장을 llmgate의 기본 책임에서 빼두면, llmgate 안에서 DB migration, backup, retention, prompt와 response 원문에 대한 보호 정책을 직접 다루지 않아도 된다. 나중에 어떤 작업이 더 저렴한 모델이나 경량 모델로도 충분한 품질을 냈는지 확인하고 싶다면, 이벤트 스트리밍으로 넘긴 데이터를 별도 시스템에서 비교하면 된다.
6. 모델 호출 정책은 GitOps로 관리한다
llmgate가 런타임 DB를 갖지 않는 대신, 모델 호출 정책은 Git에 있는 설정 파일로 관리한다. 역할 이름(alias), 후보 모델 순서, provider base_url, 실제 모델명, 호출자별 허용 alias 같은 값은 관리 화면에서 즉석으로 바꾸는 값이라기보다 변경 이유와 diff가 남아야 하는 운영 설정에 가까웠다. 모델 후보와 호출자 정책은 YAML 설정으로 관리하고, timeout 같은 런타임 한도는 별도 환경 설정으로 분리한다.
쓰던 모델이 오래되거나 호출 비용이 맞지 않으면 특정 alias의 chain에서 후보를 바꾼다. rate limit이나 일시적인 provider 오류가 자주 보이면 fallback 후보를 추가하고, 응답 품질과 latency가 안정적인 모델은 우선순위를 올린다. 기준에 맞지 않으면 Git에서 해당 변경을 되돌린다. 이 과정이 Git history에 남으면 언제 어떤 이유로 모델 호출 정책이 바뀌었는지도 확인할 수 있다.
설정을 바꾸기 위한 관리자 화면도 생각은 했지만, 지금 단계에서는 오히려 운영 대상이 하나 더 늘어나는 일이었다. 모델 호출 정책은 사람이 자주 클릭해서 바꾸는 값이 아니라, diff를 보고 리뷰하는 값에 가까웠다. 필요하면 에이전트가 GitOps 리포지토리에 설정 변경 PR을 만들고, 사람은 그 diff를 검토하고 merge하면 된다.
상태를 보기 위한 별도 대시보드도 지금은 만들지 않았다. alias별 요청 수, provider별 에러율, latency, fallback 발생 횟수 정도는 Prometheus와 Grafana에서 보면 된다. 어떤 지표를 반복해서 보고, 그 지표를 보고 fallback 순서, timeout, 후보 모델 우선순위 같은 설정을 실제로 바꾸게 되는지 분명해지기 전까지는 웹 UI를 만들 이유가 크지 않았다.
7. 필요한 것은 LLM 플랫폼이 아니라 작은 호출 경계였다
돌아보면 llmgate는 새로운 LLM 플랫폼을 만들려는 시도가 아니었다. 모델 가격은 내려가고, 입력 한도는 커지고, OpenAI 호환 API를 제공하는 상용 모델과 로컬 모델 서버도 늘어난다. 이 변화 자체는 반갑지만, 그 변화를 LLM을 사용하는 내부 도구와 작은 서비스 코드가 직접 따라가게 만들고 싶지는 않았다.
내가 필요했던 것은 LLM 모델 이름, provider, fallback 순서 같은 호출 결정을 각 도구 코드 밖으로 빼내는 작은 경계였다. 호출자는 역할을 부르고, 실제 모델 후보와 fallback 순서는 설정 파일에 따라 llmgate가 결정한다. prompt와 response 원문은 기본적으로 저장하지 않고, 역할 이름과 후보 모델 순서 같은 운영 설정은 GitOps로 관리한다.
이 구조가 운영을 얼마나 단순하게 만드는지는 실제로 써보면서 확인할 일이다. 정량적으로 딱 잘라 비교하기는 어렵겠지만, 모델 교체나 fallback 조정이 도구 코드 수정으로 번지지 않는지만 봐도 방향은 판단할 수 있을 것 같다. 지금 필요한 것은 큰 LLM 관리 플랫폼이 아니었다. 모델 변화가 빨라져도 각 도구 코드를 흔들지 않는 작은 호출 경계면 충분했다.
레퍼런스
- 작은 서비스를 계속 만들다 보니 인증부터 먼저 분리하게 됐다 — authgate를 만든 배경을 정리한 이전 글
- OpenCode Go 문서 — 2026년 5월 기준, 월 구독형 코딩 모델 묶음과 사용 한도를 본 배경 자료
- DeepSeek V4 공식 가격 문서 — 2026년 5월 기준, API 단가 흐름을 본 배경 자료
- DeepSeek V4 Preview Release — 2026년 5월 기준, 1M context length와 V4 계열 모델 공개 내용을 확인한 자료
- authgate 프로젝트 리포
- llmgate 프로젝트 리포