모델을 안 정하면 무엇이 실행될까: datasette-llm 기본값 폴백과 허용 목록 경계

설정 파일에서 모델 이름을 지우면 더 간단해질까, 아니면 무엇이 호출되는지 불투명해질까? datasette-llm 0.1a9의 작은 변화는 이 두 질문을 함께 던진다. 모델 선택의 앞선 단계에서 답을 찾지 못하면 LLM 라이브러리 자체의 기본 모델을 후보로 삼는다. 다만 그 후보가 현재 사용자와 용도에 허용되고 사용 가능한 목록 안에 있어야 한다. 기본값을 물려받는 일과 호출 자격을 얻는 일은 다르다.

개발자는 같은 모델 이름을 여러 곳에 반복하지 않아도 될 수 있다. 운영자는 반대로 외부 기본값 변경이 배포 동작에 미칠 영향을 따져야 한다. 여기서 중요한 것은 특정 모델의 성능이 아니라, 이름을 생략했을 때 어떤 선택 경로를 거치고 어디서 거절되는지다.

1. 줄어든 시작 옵션, 늘어난 기본값의 의미

공식 릴리스 0.1a9는 프리릴리스다. 공개 시각은 2026년 10월 31일 22:10:01 UTC, 한국 시간으로는 11월 1일 07:10:01이다. 이 글의 예약 날짜인 11월 3일은 기능 출시일이 아니다. 변경을 Datasette Agent의 대규모 업데이트로 읽어서도 안 된다. 이번에 살펴보는 대상은 다른 플러그인이 의존하는 datasette-llm의 모델 선택 처리다.

개발자 Simon Willison의 소개는 다음과 같이 짧아진 시작 명령을 보여준다.

uvx --with datasette-agent datasette content.db --internal internal.db

이는 저자가 제시한 사용 예다. 이 글에서 실행하거나 데이터베이스를 연 결과가 아니다. 이전 예시에서는 별도의 기본 모델 지정 옵션이 필요했지만, 이제 적합한 LLM 기본값을 물려받을 수 있다는 설명이다. 그렇다고 모든 환경에서 옵션 없이 실행된다는 뜻은 아니다. 설치된 모델, 키, 필터 조건이 서로 맞아야 한다.

여기서 폴백은 응답이 느리거나 품질이 낮을 때 다른 공급자로 재시도하는 기능이 아니다. 아직 추론을 보내기 전, 모델 이름이 결정되지 않은 상태를 처리하는 순서다. 최저가 모델 선택이나 비용 절감 효과를 발표한 것도 아니다.

2. 명시적 선택부터 LLM 기본값까지, 여섯 단계

고정된 릴리스의 _resolve_model_id 구현을 읽으면 우선순위가 분명하다. 앞 단계에서 모델을 찾으면 뒤 단계로 내려가지 않는다.

  1. 호출자가 전달한 명시적 model_id
  2. llm_default_model 훅이 반환한 모델
  3. 해당 용도의 purposes.<purpose>.model
  4. 전역 default_model
  5. 현재 사용자·용도에서 사용 가능한 LLM 자체 기본 모델
  6. 선택할 수 없으면 오류
명시적 모델, 기본 모델 훅, 용도별 모델, 전역 기본값, 가용한 LLM 기본값, 오류의 여섯 단계

번호 순으로 읽는 선택 우선순위. 앞 단계에서 결정되면 끝나며, 5단계만 새로운 LLM 기본값 폴백이다. 구현 해설이지 실행 로그가 아니다. 출처: github.com/datasette/datasette-llm/blob/9db9d614ac2d4a7ec4c2ec3ad4cc39ae00e6fc56/datasette_llm/__init__.py#L649-L713.

용도별 설정이나 전역 설정이 이미 있으면 새로운 마지막 폴백이 이를 덮어쓰지 않는다. 또한 훅은 용도별 설정보다 앞선다. 설정 파일만 보고 “여기 적힌 모델이 언제나 선택된다”고 단정하기 전에, 모델 선택에 관여하는 플러그인 훅이 있는지 확인할 이유다. 이 순서는 속도나 성능의 순위표가 아니라 선택 우선순위다.

LLM 기본값이라는 말에도 두 층이 있다. 사용자가 LLM에 저장한 기본 모델이 있으면 그것을 사용하고, 없으면 해당 LLM 설치의 내장 기본값을 참조한다. 따라서 특정 모델 이름 하나를 모든 설치 환경의 고정값처럼 외우기보다, 실제 실행 환경의 설정을 확인하는 편이 정확하다. LLM 공식 가이드의 확인 명령은 다음과 같다.

llm models default

이 명령도 여기서는 안내만 하며 실행 결과를 제시하지 않는다. 터미널에서 확인한 설정이 서비스 환경에도 그대로 적용되는지, 실행 계정과 설정 저장 위치가 같은지는 별도로 점검해야 한다. 이는 릴리스가 보장한 배포 자동화가 아니라 운영 점검을 위한 제안이다.

3. 기본값은 후보일 뿐, 허용 목록에 자동 입장하지 않는다

README의 폴백 설명은 핵심 차이를 명시한다. 직접 설정한 default_model은 허용 목록에 자동 포함되지만, LLM 자체의 기본 모델은 그렇지 않다. “기본으로 골랐다”는 이유만으로 전역 models 경계를 넓히지 않는다.

직접 지정한 default_model은 허용 목록에 자동 포함되지만 LLM 자체 기본값은 포함되지 않는 전역 목록 비교

전역 models 기준이며 용도별 허용 목록을 설정하지 않은 범위의 비교. 자동 포함은 별도의 차단·키·훅 조건까지 무효화하는 보안 보장이 아니다. 출처: github.com/datasette/datasette-llm/blob/9db9d614ac2d4a7ec4c2ec3ad4cc39ae00e6fc56/README.md#falling-back-to-llms-default-model.

새 분기의 구현은 설치된 비동기 모델의 식별자를 구한 뒤 self.models(actor, purpose)가 돌려준 목록에 같은 모델이 있는지 확인한다. 이 목록에는 키 가용성 검사와 필터 훅이 적용된다. 전역 models로 후보를 제한하고 blocked_models로 제외한 모델이 있다면, 새 폴백이 그것을 자동 복구하거나 다른 허용 모델을 임의로 대신 고르는 것은 아니다.

키가 필요한 모델은 기본적으로 사용 가능한 키가 있어야 한다. 키가 필요 없는 모델까지 키를 요구한다는 의미는 아니다. require_keys: false 역시 이 목록의 키 가용성 필터를 끄는 설정이지, 실제 공급자의 인증 요구를 없애는 설정이 아니다. 키 없는 원격 호출이 성공한다는 결론으로 이어지지 않는다.

범위도 좁혀 읽어야 한다. 이 글에서 설명하는 경계는 새 LLM 기본값 폴백 분기의 조건이다. 명시적 모델 호출과 임의의 외부 훅까지 모두 포괄하는 보안 인증으로 확대하지 않는다. 용도별 허용 목록의 문서 설명과 구현의 합집합 처리에는 해석 차이가 있어, 아래 사례는 용도별 목록 없이 전역 허용·차단 목록만을 다룬다.

4. 모델 생략을 허용할지 결정하는 상태표

개발에서는 기본값 상속의 편의를, 배포에서는 선택 경로의 명시성을 먼저 평가한다. 다음 표는 소스에서 도출한 판단 도구다. 실제 실행 로그나 공급자 응답이 아니다. 모든 행은 명시적 모델·훅 반환값·용도별 모델·전역 기본값이 없어서 마지막 폴백에 도달했다고 가정한다. 용도별 허용 목록도 설정하지 않는다.

현재 상태 폴백 분기에서 예상되는 결과 확인할 지점
LLM 기본 모델이 설치된 비동기 모델이며 필요한 키가 있고, 목록과 훅에서 허용됨 해당 기본 모델 선택 개발 환경에서 기본값 상속이 의도한 동작인지
기본 모델이 전역 models 밖에 있음 ModelNotFoundError 기본값 변경과 허용 목록 변경을 별도 결정
기본 모델이 blocked_models에 포함됨 ModelNotFoundError 차단 의도를 우회하지 않고 설정 충돌 확인
키가 필요한 모델인데 키가 없고 require_keys가 켜짐 ModelNotFoundError 서비스 실행 환경의 키 가용성
기본 모델의 비동기 구현을 찾을 수 없음 ModelNotFoundError 모델 플러그인 설치와 식별자 해석
앞선 모델 선택이 없을 때 설치·키·필터 충족은 기본 모델 선택, 허용 밖·차단 또는 필요한 키 없음은 선택 오류

마지막 폴백에 도달했고 나머지 조건은 충족했다고 가정한 소스 기반 반례. require_keys의 기본 동작이며 키 불필요 모델은 키 누락 사례에서 제외한다. 출처: github.com/datasette/datasette-llm/blob/9db9d614ac2d4a7ec4c2ec3ad4cc39ae00e6fc56/datasette_llm/__init__.py#L699-L713.

허용 목록에 다른 모델이 남아 있어도 기본값 자체가 사용할 수 없다면, 이 분기는 그중 하나를 자동으로 고르지 않는다. 따라서 “모델 목록은 비어 있지 않은데 모델 생략 호출은 실패한다”는 상태가 가능하다. 이 차이를 알면 허용된 모델이 보인다는 이유만으로 기본값의 가용성까지 확인했다고 착각하지 않는다.

운영에서 전역 또는 용도별 모델을 고정하는 선택은 재현 가능한 설정을 만들기 위한 편집적 제안이다. 반대로 개인 개발에서 LLM 기본값을 공유하는 방식은 설정 중복을 줄이는 선택이 될 수 있다. 어느 쪽도 비용 절감이나 보안 향상의 실측 결과로 주장하지 않는다. 훅이 앞서 개입한다면 그 경로까지 함께 검토해야 한다.

5. 오류가 나면 모델 이름보다 선택 경로부터 좁힌다

먼저 호출에 model_id가 있는지, 기본 모델 훅이 값을 반환하는지, 용도별·전역 설정이 있는지 순서대로 확인한다. 어느 앞 단계에서 모델이 결정됐다면 마지막 폴백의 문제로 진단하면 안 된다. 폴백에 실제로 도달한 경우에만 LLM 기본값과 비동기 모델 설치 여부, 키 가용성, 전역 허용·차단 목록, 필터 훅을 비교한다.

앞선 선택, LLM 기본값과 비동기 모델 설치, 필요한 키와 목록·필터 훅으로 원인을 좁히는 세 단계

선택 경로와 가용성 조건을 분리한 편집적 진단 제안. 자동 복구 기능이나 장애 뒤 공급자 재시도를 뜻하지 않는다. 출처: github.com/datasette/datasette-llm/blob/9db9d614ac2d4a7ec4c2ec3ad4cc39ae00e6fc56/datasette_llm/__init__.py#L649-L713.

설정을 바꾸기 전에는 오류를 없애려는 목적과 정책을 바꾸려는 목적도 구분한다. 키 설정이 빠졌는데 허용 목록을 넓히거나, 의도한 차단을 풀어버리면 원인을 해결하지 않고 경계를 바꾼 셈이다. 반대로 배포에서 모델을 명시하려는 상황이라면 기본값을 계속 수정하기보다 어느 설정 계층에 선택을 고정할지 정하는 편이 명료하다.

공식 테스트에는 echo 기본값 폴백, 그룹 호출, 명시한 전역 기본값의 우선, 필터 제외 등의 사례가 있다. 다만 테스트 파일을 읽었다는 것과 테스트를 실행했다는 것은 다르다. 테스트의 sk-test 문자열도 실제 공급자 추론 성공의 증거가 아니다. 이 글의 표와 도식은 그 소스를 설명하기 위한 분석이며 별도의 검증 실행 결과가 아니다.

6. 편리한 생략과 의도한 선택을 분리하기

이번 변화는 모델 선택 설정을 생략할 수 있는 길을 추가하지만, 그 선택을 무조건 승인하지는 않는다. 앞선 설정은 계속 우선하고, 마지막 LLM 기본값은 사용 가능한 목록에 들어 있을 때만 선택된다. 개발자는 어디서 기본값이 오는지, 운영자는 어디서 허용 여부가 결정되는지를 나눠 보면 된다.

이 글은 고정된 릴리스의 문서·구현·테스트를 읽은 분석이며, 패키지 설치나 추론 실행, 성능·보안 재현 실험을 수행한 결과가 아니다. 특히 용도별 허용 목록의 결합 규칙이나 외부 훅 전반을 이 변화 하나로 일반화하지 않는다. 결론은 단순하다. 모델 이름을 덜 쓰는 편의와 실행 가능한 모델의 경계는 서로 다른 설정 결정이다.

참고 자료

댓글

이 블로그의 인기 게시물

체크아웃은 분리됐는데 Git 상태는 공유된다: Codex 0.154 worktree의 세 경계

잠근 작업이 커밋 뒤 다시 나온다: PostgreSQL 에이전트 큐의 소유권 설계

코딩 에이전트는 API 문서보다 AGENTS.md를 먼저 읽었다