코딩·개발

클라우드 API가 막힐 때 로컬 Ollama로 넘기는 폴백 — 스톨 사건 포함

레시피 L3

클라우드 LLM 레인이 막혀도 배치 분류가 멈추지 않도록 로컬 Ollama 폴백을 붙이고, 폴백이 오히려 기계를 멈추게 하는 함정을 피해요.

공개일 · 갱신일

전제

  • Ollama가 설치돼 모델 몇 개가 받아져 있는 로컬 머신, 클라우드 LLM 레인 1개.
  • 실패해도 재시도되는 배치 작업(분류·태깅·요약). 이 글은 배치 기준이에요 — 대화형 사용은 이 글에서 다루지 않아요.

단계

  1. 레인 순서를 코드 한 곳에 적어요. 라우터 주석은 이래요 — 분류·태깅 = z.ai GLM → (DeepSeek) → Ollama 로컬 → Codex, 요약·합성 = z.ai GLM 또는 Codex CLI에 Ollama 폴백. 로컬 체인은 구독 레인이 꺼졌거나 키가 없는 기계용 비상구예요.
  2. 분류 경로의 로컬 후보에 파라미터 창을 걸어요. 코드 주석은 이 창이 분류 경로의 로컬(Ollama) 폴백 후보에만 적용된다고 못 박아요 — 요약·합성 경로는 보호되지 않아요. 창은 하한 7B·상한 16B이고, 그 사이라도 13B 미만이면 "품질 저하 폴백"으로 경고를 남겨요(막지는 않아요).
  3. 후보 목록도 환경변수로 빼요. 기본값 = qwen2.5:14b, qwen2.5:7b, gemma3:12b, llama3.1:8b, phi4:latest, gpt-oss:20b.
  4. "로컬만" 모드에 모델 계열 화이트리스트를 걸어요. 같은 엔드포인트가 원격 모델을 함께 노출하면 분류가 조용히 그쪽으로 새요(표본 200건 중 65건이 원격 glm-5.3으로 나간 실측). 다만 이게 막는 것은 모델명이 새는 경로예요. 모델명만으로는 추론이 어느 서버에서 도는지 알 수 없어요. 엔드포인트가 실제 로컬인지 따로 확인하세요.
  5. 어느 모델이 처리했는지 기록해요. 분석 버전을 classify-v2/<모델>/<지문>로 남기면 품질 편차의 출처를 되짚을 수 있어요.
  6. 타임아웃을 명시해요. 로컬 호출 기본값은 120초예요.

검증 — 무엇이 보이면 성공

격리된 환경에서 1차 레인 실패를 일부러 유도하고, 다른 원격 레인(DeepSeek·Codex)도 함께 차단한 뒤 배치를 한 번 돌려 보세요. 민감한 자료로는 시험하지 마시고요. 처리 건수가 0이 아니고, 분석 버전에 로컬 모델 이름이 남고, 호출 엔드포인트와 1차 실패 로그가 같이 보이면 폴백이 작동한 거예요. 7B 미만·16B 초과는 후보에서 빠지고, 13B 미만이 뽑히면 경고가 남았는지 확인해요.

막히는 지점 — 스톨 사건

2026-09-12 실측. 상한 없이 하한만 14B로 걸어 뒀더니 14b가 없는 기계에서 후보가 20b로 밀려 올라갔고, 16GB M1 Pro에서 gpt-oss:20b가 2분 타임아웃을 반복하며 0건 처리로 끝났다. 폴백이 있는데도 파이프라인이 멈춘 것이다. 수리는 창의 양쪽을 다 막는 것이었다 — 하한 7 + 상한 16. 하한을 만족해도 메모리상 실행이 불가능한 20b급은 후보에서 뺀다. 원격 모델은 남의 하드웨어에서 도니 이 창의 대상이 아니다.

1차 레인 자격증명이 조건을 못 맞추면 그 키는 무시되고 다음 활성 레인으로 넘어간다.

실행일·도구 버전

인용한 분류·스톨 기록은 2026-09-12 것이에요(같은 파일에 09-13 요약 실측 주석도 있어요). 기본값: CLASSIFY_MIN_PARAM_B=7, CLASSIFY_MAX_PARAM_B=16, CLASSIFY_QUALITY_PARAM_B=13, CLASSIFY_MAX_TOKENS=6144. 로컬 런타임 = Ollama. 사용한 버전은 기록에 남기지 않았어요. 재현할 때는 현재 버전을 기준으로 확인하세요. 원격 분류 후보 = glm-5.3, glm-5, glm-4.6.

근거

  • ai-news-pipeline src/processors/llm_router.py — 모듈 docstring, 파라미터 창 상수 주석, 로컬 전용 화이트리스트 주석
  • 운영 핸드오프 2026-09-11 §8 (2026-09-12 추기) — 10:40·13:20 실측 기록